Having the firmware image to decompile allowed me to find the settings for the radio. How close was I?
Spirit Library?
I had guessed that they may well be using the STM SPIRIT1 library and after some looking I found that this was the case. It took a little while but eventually I found the data structures thet would let me know how the radio should be configured.
SRadioInit
This is defined in the SPIRIT_Radio.h header for the library.
/**
* @brief SPIRIT Radio Init structure definition
*/
typedef struct
{
int16_t nXtalOffsetPpm;
uint32_t lFrequencyBase;
uint32_t nChannelSpace;
uint8_t cChannelNumber;
ModulationSelect xModulationSelect;
uint32_t lDatarate;
uint32_t lFreqDev;
uint32_t lBandwidth;
} SRadioInit;
The structure is passed to the init function for the radio.
uint8_t SpiritRadioInit(SRadioInit* pxSRadioInitStruct);
Finding the function did take some looking but by working backwars from the SPI references I was able to find the functions that interacted with the Spirit radio and from there found the SpiritRadioInit function. In fact I found two of them!
It turns out there are 2 seperate sets of setup routines for the radio, each with their own init structures.
2000007c 00 00 int16_t 0h nXtalOffsetPpm
2000007e 00 00 uint16_t 0h spacer0
20000080 40 ae bf 33 uint32_t 33BFAE40h lFrequencyBase
20000084 20 4e 00 00 uint32_t 4E20h nChannelSpace
20000088 00 uint8_t '\0' cChannelNumber
20000089 50 Modulati GFSK_BT05 xModulationS
2000008a 00 00 uint16_t 0h spacer1
2000008c 50 c3 00 00 uint32_t C350h lDatarate
20000090 20 4e 00 00 uint32_t 4E20h lFreqDev
20000094 a0 86 01 00 uint32_t 186A0h lBandwidth
The spacer0 and spacer1 fields were needed as the alignment wasn't correct without them, so I guess the compiler has aligned things?
The frequency is 868200000 - exactly what I had settled on using. The data rate is also an exact match at 50,000.
I had the modulation as GFSK_BT1 so I was close :-)
Packet Settings
Having found the basic radio setup, next I wanted to find the settings for the packets. I had guessed these would be Basic and so I should be looking for a PktBasicInit structure.
/**
* @brief SPIRIT Basic Packet Init structure definition. This structure allows users to set the main options
* for the Basic packet.
*/
typedef struct
{
BasicPreambleLength xPreambleLength;
BasicSyncLength xSyncLength;
uint32_t lSyncWords;
BasicFixVarLength xFixVarLength;
uint8_t cPktLengthWidth;
BasicCrcMode xCrcMode;
BasicControlLength xControlLength;
SpiritFunctionalState xAddressField;
SpiritFunctionalState xFec;
SpiritFunctionalState xDataWhitening;
}PktBasicInit;
Again, this is used by the init function. Once I had the SPI calls it was possible to work backwards and again find the function.
void SpiritPktBasicInit(PktBasicInit* pxPktBasicInit);
This led to the discovery of 2 init structures.
2000006c 20 BasicPre PKT_PREAMBLE_LENGTH_05
2000006d 06 BasicSyn PKT_SYNC_LENGTH_4BYTES xSyncLength
2000006e 00 00 uint16_t 0h spacer0
20000070 50 52 47 5a uint32_t 5A475250h lSyncWords
20000074 01 BasicFix PKT_LENGTH_VAR xFixVarLength
20000075 07 uint8_t '\a' cPktLengthWi
20000076 80 BasicCrc PKT_CRC_MODE_24BITS xCrcMode
20000077 04 BasicCon PKT_CONTROL_LENGTH_4BY
20000078 01 SpiritFu S_ENABLE xAddressField
20000079 01 SpiritFu S_ENABLE xFec
2000007a 01 SpiritFu S_ENABLE xDataWhitening
Again I found that the byte alignment wasn't an exact match and the decompiled code expected the spacer bytes to be present.
Here I found there were quite a few things I had got wrong. The 3 byte CRC was a surprise and the FEC being nabled wasn't something I had considered. Also the use of an address field with 4 bytes of control data wasn't something I had correctly detected.
Following Up
After making the changes to the radio and some slight updates to the module and test script, I grabbed some more packets.
06:46:01 - messsage of 19 bytes
Packet from ff, control bytes fc 00 34 06 [ RSSI 112, SQI 32 ]
1: 05 ff 00 c5 c5 91 d8 d6 55 81 1b 81 85 e9 07 16 4c 84 c9
06:46:10 - messsage of 19 bytes
Packet from ff, control bytes c6 00 3e 06 [ RSSI 92, SQI 32 ]
2: 05 ff 00 32 81 90 54 b1 5f 01 84 d2 80 44 20 c3 76 33 8c
06:46:12 - messsage of 19 bytes
Packet from ff, control bytes 53 00 0f 06 [ RSSI 94, SQI 32 ]
3: 05 ff 00 b4 30 06 92 44 5a 31 7b 8c 1b 70 7c e6 71 5c 8d
06:46:41 - messsage of 19 bytes
Packet from ff, control bytes fc 00 35 06 [ RSSI 112, SQI 32 ]
4: 05 ff 00 62 d5 dc d6 93 b5 ec 3c fc 94 02 39 7a e4 57 6a
06:46:50 - messsage of 19 bytes
Packet from ff, control bytes c6 00 3f 06 [ RSSI 92, SQI 32 ]
5: 05 ff 00 ea c0 bf 5d a0 71 67 82 79 8e 67 10 b3 43 6e e1
All the messages are 19 bytes and all come from the same address, 0xff. The control bytes all have a very consistent pattern.
fc 00 34 06
c6 00 3e 06
53 00 0f 06
fc 00 35 06
c6 00 3f 06
53 00 10 06
fc 00 36 06
c6 00 00 06
53 00 11 06
fc 00 37 06
c6 00 01 06
53 00 12 06
As we have 3 devices, each could relate to one and so the first number may actually be an device id? The third number appears to be a counter that wraps at 0x3F.
The 19 byte content is a little strangely sized. There is a lot of reference in the decompilation to AES like functionality, including a seeming key generation. The code appears to work on 16 byte blocks, which makes sense for AES so perhaps the CRC bytes are still attached and the messages are 16 bytes of payload plus 3 bytes of CRC?
Complexity
The decompiled code is labyrinthal as it deals with button presses, LCD, networking and also tries to sleep as much as possible to preserve batteries. Some avenues of discovery work well and I have found a lot of the HAL library code which has allowed me to gain insights into what is being done, but much of the remaining code remains a list of maths operations on seemingly random addresses. It's impressive just how quickly it all starts to make sense with the appropriate structures added and referenced, but without an external reference it's a case of deductions.
I'm also conscious that my aim isn't to fully reverse engineer the firmware for the device, just try and understand the networking such that I can replicate it without the device. Sadly things appear more interwoven than I would have liked.
If anyone has suggestions for places to find help and strategies to use to speed things up then I'd love to hear from you :-)