bob@g3ukb.co.uk
ErLink_SR has only moved forward only slightly since March and I think that is probably a sideways move as it's being ported to Linux which is now my main system.
For those who might like to take a look at something a bit lighter I have put up a simple SDR project on Google Code at http://code.google.com/p/pylink-sr/. I plan to get back to Erlink shortly but I have one more non-radio open source project that I must finish first and of course the day job still gets in the way.
This is the home page of the ErLink-SR project. This project has been running for about 2 years, mostly forward, sometimes circular and with quite a bit of lateral movement. The site was in need of a clean up so all the existing content has been moved to an archive and new content will build from this new index page. The objectives, which are not changed are quite simply a platform which will support the rapid building of software radios across multiple operating systems and radio hardware implementations.
The key ideas behind this are....
|
|
A platform built from a number of components. Components are strongly functional, that is they perform a single major function and the architecture of a component is optimised for the function it performs. |
|
|
Major components of the system are easily extended and customised. |
|
|
Components are connected together by a common infrastructure. |
|
|
Components are predominently cross-platform (although there may be exceptions where a platform is not capable of providing the function). |
|
|
The infrastructure allows components to be created, connected and orchestrated across the same or multiple machines running the same or different operating systems. Distribution is transparent to the components. |
What's Changing
The archive content, which will remain available for some time is a snapshot of the state of things as of end 2007. A lot of the design has not changed since inception but some areas refused to lay down and have had several reworks. This I hope will be the final rework that will bring a cohesive system true to its objectives. Up to a few months ago I was convinced that Erlang was very strong as an infrastructure but I wobbled a lot trying to implement real code, i.e. stuff that wasn't just shipping messages around. It is only recently I have started to realise the true power of this language and have felt more comfortable with the key concepts of functional languages. It's becoming natural for me to think in terms of patterns, bindings and recursion to solve problems rather than the imperative mind-set (which of course is still retained as the other way of thinking). I even find it more natural to think of a process as an object rather than a class (although that's nothing to do with functional programming).
The upshot is that Erlink-SR is moving more Erlang centric. If it can be done in Erlang it will be and that includes the GUI (wxErlang) and the database (Mnesia). The refined system that will emerge will be Erlang and 'C'. The 'C' content will be kept to a minimum and will be limited to performance critical parts and those that require low level access.
The aim was always a componentised system where components would be strongly functional. The set of components instantiated would be driven by a profile and capability system, the essence of which is already there. Somehow that aim got compromised in the Java GUI implementation which became more monolithic and complex than it should have been. The Java API and Jython scripting capability that were subsequently added were fully capable of moving to a new thinner GUI component layer. However, the advent of the reworked wxErlang bindings presented the opportunity to move to Erlang for the GUI, thus removing a great deal of code bulk and compromise. The Java API will remain as a way to connect any JVM capable language to Erlink-SR, but, it will no longer be a necessary part of the runtime. This will simplify development and implementation and make the system more robust and easier to distribute and install. I have implemented two components of the GUI as a proof-of-concept, a filter switcher and a panadapter display. The filter switcher was to get the hang of programming wxErlang. The panadapter was to decide on an architecture for the display system and give wxErlang a bit of a stress test. For now suffice it to say the architecture includes a graphics server process that can feed multiple local and remote displays of various types and form factors. I've not worked out the finer details of the GUI yet, but it will loosely be based on one process per component with separate display windows. I've lost the inclination to combine everything in one window.
What of the pieces that are 'C'. These will all be written as shared libraries and use the linked-in driver model of Erlang. I've used this a lot and it works very nicely. Most of the pieces I have use this model, a few are 'C' nodes and need to be converted. The massive advantage of using linked-in drivers or port drivers is that having Erlang at the front makes life much easier and the shared libraries are components that can be dynamically linked so forming part of the capability system. The only down-side of linked-in drivers is that a crash in the 'C' code can take the Erlang node down. This is not really an issue once the component is debugged. I'm not keen on the port-driver model as it's implementation seems a little awkward under Windows.
With everything being a real Erlang node (no 'C' nodes or jInterface pieces) the management of the system becomes easier and more can be handed over to the OTP system.
System Context
In outline terms the system will look like the diagram below. The message router which is an Erlang process called the switcher is responsible for connecting everything together. It is a class based router of a publish/subscribe type. Suffice it to say it connects all the proceses together and supports live connect/disconnect (known as register and deregister) from processes and will then route messages between processes based on the destination class name. All control messages go through this channel. Data on the other hand takes some more efficient short cuts. Bulk data is passed between processes via shared memory. Shared memory however is not distributed so there are two servers that take care of this requirement. The graphics server responds to direct requests for graphics data usually from a UI fragment that will render that data. The UI fragment requests data in a form that can be directly plotted on its canvas. This serves two purposes, it greatly reduces the data size that is transmitted and the processing and formatting is performed in 'C' code for maximum performance. The graphics server can support many requests for different types of prepared data from local or remote nodes. A similar process will exist for audio data but the details are yet to be worked through.
Each of the rounded blocks represents one or more components in a discrete functional area. A block will always be an erlang process(es) that interfaces to the switcher. The remainder of the block can be pure erlang or can use a 'C' component in the linked-in driver model. Everything that interfaces to the SHM library does have a 'C' part. Most of the processesinfact do have some 'C' component part, either bespoke or 3rd party (such as the wxErlang bindings). The exceptions are the Application node which contains all application logic for each profile, (this uses the Finite State Machine behaviour of Erlang), and the Java API. The Java API is not required for normal operation but provides the capability to connect any JVM capable language to the system.
A block can have several different dynamically loaded parts, or indeed the whole block can have several different implementations. Which blocks/parts get instantiated is up to a configuration system based on profiles and a loader that interprets that file. In this way a StreamIn/StreamOut block can support PortAudio, Jack or any other audio system as well as built in ADC/DAC systems as in SDR5000 and HPSDR. It can also support different physical connections and protocols such as firewire, USB and audio cards. Separating the input stream, signal processing and output stream provides this flexibility.
One of the more interesting blocks is the UI. This will always have a number of instantiated components for different parts of the UI. These UI parts never need to talk to each other directly because the application is the controller in the 'MVC like' triad. An appropriate set of UI fragments can therefore be loaded for the system. Some of these are data driven and will be common across many profiles, others will be specific. This plug-in system allows fragments to come and go in a live system without interruption to service.
A most important part of the system is the database. Some care will be taken to make this a comprehensive model for the whole system and to support profiles and capabilities from the start. The Mnesia RDBMS is a fully capable distributed database with transactions and a query language based on list comprehensions. It is a very powerful engine and capable of storing relational and object data. The database will be consumed primarily by the application and the UI fragments, both of which are pure Erlang (I consider the wxErlang bindings part of Erlang). This means there is no impedence mismatch between the database and the program as Erlang terms are stored and retrieved directly. The database is used directly through a bespoke API. Should the UI and other system parts be separated across nodes on the same or different computers the database will also be transparently distributed.Database maintenance will be performed by a separate process through the same API.

The GUI System
The GUI is built entirely in Erlang using the wxErlang toolset. Caveats first - I'm no graphic designer. This interface is drawn, it's not controls and it's not a bitmap - it could certainly look a lot smarter with the right kind of talent on it. This is my choice but it's not fixed in stone. Each set of related interactors are a component, like the bar with the power button, a VFO or the noise limiters. These components are assembled onto a panel which has a grid-bag sizer. Each assembled unit is under the control of a ui_manager.Each component, which I call a ui fragment is COMPLETELY independent. Each is a process and fragments communicate with the sytem and each other in specific cases by messages; this is erlang after all.
What gets instantiated when erlink-sr is started is driven by an OTP configuration file. A given profile will start a specific set of processes including one to many ui_managers, each with its set of ui fragments. The configuration decides a lot of the behaviour, like where in the panel each fragment is placed, what happens when you click on a hot spot.
I have spent some time creating a framework to make creating fragments pretty straight forward. The framework is just two modules which have a custom behaviour, so one only has to implement the behaviour callbacks. The framework can and will get a lot better and reduce the code to be written even more, but it's a good start.
The philosophy of this interface is keep it simple, only show what needs to be shown and allow the rest to be tucked away. It will obviously mature more but it's the best component assembly system I've done and to think I once said Erlang is good for a lot of things but will never be suitable for the GUI!

The basic minimum. This is currently under control of one ui_manager. In the main panel there are 7 ui fragments. Anything that can be changed displays an enclosing rectangle on mouse over. I think most is self explanitory except perhaps the upper right which is the sub-receiver control (see next). The graphic display has had little attention and clearly needs lifting up a notch or two. It is currently under the contaol of the main ui_manager. Of course, several displays can be started if we choose so in the configuration. Next time I get back to the UI this will be the first area to attack.

Here all the sub-receivers have been turned on by just clicking the activate square. I have set the pan to spread them across the audio space.. The small numbers below the VFO's is the oscillator offset. Full marks for anyone that spots a little bug here. Note there is a lot of reuse. No fragments were created especially for the sub-receivers, it's simply configuration plus a little control logic. The sub-receivers are popups, you can take them up or down on the activate hot spot. In the second row select which one you will use. Each sub-receiver is under control of a ui-manager. Other things that have immediate action are the Bin, Nr etc. Simply toggle these on/off by clicking and the colour will change to orange when active. There are some other popups for the botton right set of values.

Ok, these are proper controls - for now. Each click on say the mode value will bring up a mode selector, what popup it chooses is just part of the configuration. The selector will stay there until you close it, so your choice. The selector has absolutely no relation with the interactor that invoked it. When a popup like this is invoked it is a completely new process which registers with the system and it's only purpose in life is to send, in this case a mode change into the system. Anyone who is interested in a mode change will get a message - not from the popup but from the application state machine which received the message from the popup. The popups that exist for the moment are for the 5 things managed by the bottom right fragment. These popups of course work just the same on the main and sub-receivers depending which you have said to use. I can certainly envisage quite complex popups for graphic equilisers, audio control and the more complex options. However, in the main many types will be reused. The popup behaviour does most of the work leaving a couple of callbacks to be filled in. Also of course they are dynamic, the buttons are built from the database depending on the current profile.
