For me, this is the whole reason to get into Flightgear, as a learning experience in serial comms, programming, and having some fun with it.
While there are many ways to skin a cat, this is what I am hoping to achieve...
The Arduino language includes the "wire" library
which makes I2C communications a bit easier.
The Wire library uses 7 bit message lengths, and 7 bit addresses, but the first 8 addresses are reserved, so a maximum of 119 addresses or nodes on the network are possible using the Wire library, which should be plenty.
My plan is to divide a cockpit up into logical chunks and allocate an address / node to each chunk.
If a chunk is a panel of switches, then I'll select an Arduino board big enough to accommodate all the switches, but the number of switches per node can't exceed 7, one digital switch per message bit. the same goes for digital indicators such as lamps and dolls-eyes.
For Analogue signals such as flying controls as inputs, and needle indicators as outputs, the maximum resolution possible over 7 bits is 127, this will probably be adequate for most applications, but the result is one analogue per network address.
Now, there may be some clever things you may be able to do with sending multiple strings to one address sequentially, therefore multiplying you I/O count at the cost of update time period... but I'm just scratching the surface with learning this...
I hope to get some proof of concept work together over the coming months and publish here..
EDIT - Strike through, as learning has taken place since!
This thread is becoming a dumping ground for the learning experience, hopefully will become more useful o others as time goes on.
Ok, so I've gained some basic understanding of I2C..
It appears 32 bits are available for the messages, which relates to register size on the ATmel processors, it's the addresses that are limited to 7 bits, as the 8th bit is used to indicate send or receive.
32 bit message length can be extended to 64, but the Arduino chip's RAM may be the limiting factor, so my first experiments will be at stock 32 bit,
This is good news as it allows for 32 digital I/O signals per address, and also opens up the possibilities of having more than one analogue per address, the quantity will depend on the resolution required,
ie: 2x16bit (65,536 values - probably way over the top for a moving coil instrument)
or 4x8bit (256 values, which should be plenty)
or 8x4bit (16 values if you don't need the accuracy)
I'd got the wrong end of the stick regarding 7 bit message lengths.
I had previously thought about keeping analogue and digital signals to separate addresses, but having 32 bit integers available, the following may be possible;
Lets say for a
, I wanted one address, I could split a 32 bit register into 4 x 8 bit messages:
8 bit analogue for pitch angle
8 bit analogue for roll angle
8 bit analogue for brake lever position
8 digitals for the 8 buttons / switches required
= Making 32 bits.
Need to find some methods of putting together the code in modular lumps so that it's easily customisable for any application. But first things first, I need to simply try and make my Uno send some data to a Digispark over I2C, which I have just started soldering up.
Yes... do we make the whole property tree available via the serial XML file, or just the bits we're interested in? ie: would there be overhead costs of passing all the whole property tree to the master arduino in terms of serial data..?
I'm imagining we dump the serial XML file into a register of the master Arduino, then break it up into individual variables perhaps using channel numbers or descriptive words, building a database. The send the relevant variables to the specific node addresses of the I2C network.
Of course I'm talking about data coming form the game, this clearly needs to work both ways.
I'm nowhere near making any of it modular, at the moment I just envisage a completely non-modular design, but one that's customised for a build.. and you'd have to add lines of code for making physical changes.
The Property Tree starts out with a set of standard properties, and then various bits of the sim or aircraft (including scenery) create their own properties. In fact, the tree is very often flabby as MP aircraft create properties they need for model stuff but aren't transmitted over MP so they just appear as nil-value props. You will therefore want a communication protocol that only transmits the stuff you need. The good news is, it's pretty simple to use Nasal to generate the XML for the protocol file, using the real properties.
The approach I've taken with the software interconnecting box is to employ a script at runtime which initialises the virtual connecting cables from one point to another. That is then permanently set for the duration of that session (unless you employ a function to re-initialise the cables differently in-game, for development purposes). This is necessary because of the complexity of information exchanged via the multipin connectors. I think a similar approach will be helpful here too - the Ardunio node states will appear in their own area of the property tree, labelled according to a system which makes sense from the Arduino point of view. They are then virtually "connected" either by aliasing or by regularly updating them via a custom Nasal script. For user-friendliness, an XML file could determine which Arduino node is connected to which aircraft function, as not all aircraft observe the unofficial standard properties envisaged by FG's builders. This is the patchbay bit, effectively.
I think a test with a switch and a pot would effectively put us on the right path here. I propose using the Lightning T5 to test, as, as part of its release schedule, I will be attempting to write and install my external lights modular code. We could use it to try and connect the pot to the existing lighting dimmer in the T5 (not yet realistic) and the switch to the navigation lights switch. Incidentally, on the subject of Lightning lights, your help would be appreciated -
see this post
If the serial data starts with the eventual node address of the chunk it's sending (ie: 7 bit node address followed by 32 bit I/O data), the master Arduino can send it to where it's going on the I2C network without having to store all the values in it's own massive database, it only needs to store the address and the data for that address, as it'll sequentially be being updated from the PC's XML config!
A much neater solution than I had in mind, thank you!
Hmmm.. that's not going to work, as there are only 120 possible addresses (7 bit addresses, minus the first 8 addresses)...
I was really hoping to find a way to make it very much plug-and-play, but it looks like each project will have to specify addresses to suit. this means a custom xml file and custom node programs for each project.. not ideal.
We can standardise on some really common components, but not too many, as you'll use up all nodes available pretty quickly.
What can be done though is generate a serial.xml for each specific aircraft type, with all chunks commented out until desired. You'll be limited to 120 nodes per aircraft type. The common parts may have to be allocated node addresses on an individual aircraft basis as part of the aircraft serial.xml file, and then the node boards programmed accordingly.. just makes it less plug & play in a general manner... but can be plug and play on an individual aircraft manner if all board programs are ready made to match the serial.xml file. Mening a builder can add parts as and when time and budget allows. just means a fair bit of repeat work make common parts suit each aircraft, and will end up with different node addresses from aircraft to aircraft.
So here is a less generic, more specific version 3:
Yes, I think the revised version makes more sense. I suspect it's a bit optimistic to hope for plug-and-play, although it may be possible to use Nasal to make the experience less arduous - I had taken for granted that you would need custom XML for each hardware project, and that it would be better to smooth things out, or add low-level sophistries for whatever reason, in Nasal, which can make decisions at runtime better as well as "patching" as described below.