I didn’t get very far documenting the transmitter because I was having the issues I described above, and put it aside to focus on a couple of other things. The code is almost completely different from the accessory decoder code. The only common element is the AirDCC instantiation and initialization.
It may help to look at how the transmitter and receiver work together. The throttle generates a DCC stream and the decoder decodes it. In a conventional DCC setup, the path from the throttle to the decoder is hardwired through the track. Of course the stream coming out of a microcontroller doesn’t have enough power to move a locomotive, so between the throttle and the track is a booster of some sort that takes the logic level data stream and converts it to a differential, high voltage signal. With AirWire, that path is through a pair of modems instead. It’s the same logic-level DCC stream coming out of the microcontoller, but it’s feeding the modem’s input instead of a booster. Likewise, the decoder is receiving the stream from the receiving modem’s output instead of the track. Neither microcontroller has any knowledge of the face that they are connected by wireless modems. They could just as easily be connected together with a piece of wire.
The CC1101 is a very capable RF modem, with all sorts of packetizing and error correction functions available. AirWire uses none of that stuff. Instead, it puts the modem into asynchronous mode, which means that it just blindly modulates (or demodulates) a data stream. If you put one in async transmit and the other in async receive and put them on the same frequency, they act as a virtual wire.
My code, AirDCC, handles the setup of the modem. It connects to the CC1101 via SPI, and tells it to use async mode, whether to transmit or receive, what frequency to use, and for xmit, what power level to use. That’s all it does. Once the modem is up and running, AirDCC is done until you change channel or power levels. It also has a function to tickle the modem and remind it to keep modeming, but I don’t know if that’s really needed (AirWire does it, so I replicated it). SPI is ONLY used for sending commands to the modem. The DCC goes in or out on the pin labeled GD0.
So going back to the code question: The main code that you run to generate or receive DCC is not mine. I have used both the NmraDcc and DCC_Decoder libraries for receiving, and both work great. If you look at the example program I provided, it has some documentation in it. Basically, AirDCC gets instantiated like this:
AirDcc Modem(enablePin) ;
This creates a instance of AirDCC called “Modem” and the SPI enable pin is defined elsewhere as “enablePin”. The usual SPI enable pin is 10 for the Uno/Mega/Etc.
Now, in the setup(), you have to actually start the modem:
Modem.startModem(channel, tx, power);
The arguments are the channel number (based on AirWire channels 0-16), whether it’s transmitting (boolean), and the power level (also based on AirWire power levels 1-10).
At this point, the modem is doing its thing, and you can run whatever DCC encoder or decoder code you want.
For the encoding, I was playing with DCC++. This is meant to run on an Uno or Mega with a motor shield, which serves as a booster. Whichever pin goes to the main track input on the motor shield would instead go to GD0 on the CC1101. This effectively sends the DCC stream over wireless instead of to a track.
DCC++ receives serial data over USB from JMRI or other host software. If you want to generate the commands locally, you’d have to work out a way to do that. I know there is a library version of DCC++ for this purpose, but I haven’t tried it.
I’m happy to help, but be aware that I’m heading out of the country tomorrow morning for a week, and don’t expect the particular beach I’ll be on to have internet access. I’ll going to disappear until next weekend.