diff -r 6c3d9cf39f5e -r 530f6b24cf08 doc/TacticSLT.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/TacticSLT.txt Wed Nov 27 22:06:50 2013 -0500 @@ -0,0 +1,160 @@ +Tactic SLT protocol + +* Data packets * + +Channel order for SLT receiver is AETRGP. + +Data packet is transmitted every 22ms, 7 bytes length, first 5 bytes encode AETR as 10-bit unsigned numbers, last 2 - GP as 8-bit unsigned numbers. + +TX transmits every packet 3 times with interval 1ms between packets, after third packet is pauses for 20ms, thus 22ms. + +In 9ms after receiving the packet radio changes to a new frequency according to FHSS sequence. + +Bytes 0-4 encode AETR least significant bits, byte 5 encodes most significant bits, first 2 LSB for channel 1 etc. + +Pseudocode for decoding channel values: + +A = packet[0] + (uint16) ((packet[4] >> 0) & 0x3) << 8; +E = packet[1] + (uint16) ((packet[4] >> 2) & 0x3) << 8; +T = packet[2] + (uint16) ((packet[4] >> 4) & 0x3) << 8; +R = packet[3] + (uint16) ((packet[4] >> 6) & 0x3) << 8; + + +Limits as read from Anylink connected to Devo 10 with 100% scale are: + + min mid max +A B7 1FE 340 +E BA 1FE 336 +T B9 1FE 343 +R BE 1FE 341 +G 1B 80 E3 +P 1B 80 E3 + +Limits as read from Anylink connected to Devo 10 with 125% scale are: + + min mid max +A 65 1FE 389 +E 68 1FE 395 +T 6C 1FE 395 +R 68 1FE 392 +G 02 80 FC +P 02 80 FC + + +* Binding * + +Binding packets are transmitted every 2 sec on channel 0x50, address 7E B8 63 A9, lowest power settings possible. +Transmitter does it in the same batch where regular packets go, 1ms after last packet in the batch (of 3) and after it makes pause for 19ms, keeping 22ms overall cycle. +The binding packet is just 4-byte transmitter id. + +After successful binding the reciever tries packet sizes 4 to 9 on the first channel in frequency hopping sequence, and after sussessful attempt keeps this packet size. +I only witnessed packet size 7 described before. + +491 W_REGISTER(RX_PW_P0) 04 +492 W_REGISTER(RX_ADDR_P0) 7E B8 63 A9 +493 W_REGISTER(RF_CH) 50 +494 FLUSH_RX +495 W_REGISTER(STATUS) F0 +497 R_RX_PAYLOAD 7C 95 C1 70 +498 W_REGISTER(RX_ADDR_P0) 7C 95 C1 70 +499 W_REGISTER(TX_ADDR) 7C 95 C1 70 +500 W_REGISTER(RX_PW_P0) 04 +501 W_REGISTER(RF_CH) 3F +502 FLUSH_RX +503 W_REGISTER(STATUS) F0 +504 W_REGISTER(RX_PW_P0) 05 +505 W_REGISTER(RF_CH) 3F +506 FLUSH_RX +507 W_REGISTER(STATUS) F0 +508 W_REGISTER(RX_PW_P0) 06 +509 W_REGISTER(RF_CH) 3F +510 FLUSH_RX +511 W_REGISTER(STATUS) F0 +512 W_REGISTER(RX_PW_P0) 07 +513 W_REGISTER(RF_CH) 3F +514 FLUSH_RX + +* Initialization * + +0 W_REGISTER(CONFIG) 3F +1 W_REGISTER(EN_AA) 00 +2 W_REGISTER(EN_RXADDR) 01 +3 W_REGISTER(SETUP_AW) 02 +4 W_REGISTER(SETUP_RETR) 00 +5 W_REGISTER(RF_SETUP) 26 # 250kbps (nRF24L01+ only!), 0dBm +6 W_REGISTER(STATUS) F0 +7 W_REGISTER(RX_ADDR_P1) C2 C2 C2 C2 +8 W_REGISTER(RX_ADDR_P2) C3 +9 W_REGISTER(RX_ADDR_P3) C4 +10 W_REGISTER(RX_ADDR_P4) C5 +11 W_REGISTER(RX_ADDR_P5) C6 +12 W_REGISTER(RX_PW_P1) 00 +13 W_REGISTER(RX_PW_P2) 00 +14 W_REGISTER(RX_PW_P3) 00 +15 W_REGISTER(RX_PW_P4) 00 +16 W_REGISTER(RX_PW_P5) 00 +# Emit 20 bytes ?signature on channel 1 at address 9A BC DE F0 +# Does it at every start for unknown reason. +17 W_REGISTER(CONFIG) 5E +18 W_REGISTER(RX_PW_P0) 20 +19 W_REGISTER(TX_ADDR) 9A BC DE F0 +20 W_REGISTER(RX_ADDR_P0) 9A BC DE F0 +21 W_REGISTER(RF_CH) 01 +22 FLUSH_TX +23 W_REGISTER(STATUS) F0 +24 W_TX_PAYLOAD 9B 94 A1 A1 9A A0 94 BD 9D 97 8A 94 95 C3 A0 94 93 8A 91 9A 9C 9B 8F C3 91 9E 90 9E 91 8D 9E 9F +# +25 W_REGISTER(CONFIG) 3F +26 W_REGISTER(RX_PW_P0) 07 +27 W_REGISTER(RX_ADDR_P0) 7C 95 C1 70 +28 W_REGISTER(TX_ADDR) 7C 95 C1 70 +29 W_REGISTER(RF_CH) 3F + +* RF frequency hopping * + +15 radio channels in cycles + +For address 7C 95 C1 70 +3F 22 1A 18 1F 28 1C 09 11 40 23 13 47 2C 17 + +For address 84 03 35 DE +07 24 3B 11 06 03 13 17 45 1D 33 48 2E 47 2B + +Frequency hopping generation algoritm in Python: + +def gen_fq_hop(id): + fq_hop = 15 * [0] + fq_hop[0] = (id[0] & 0x3f) + 0x03 + fq_hop[1] = (id[0] >> 2) + 0x03 + fq_hop[2] = (id[0] >> 4) + (id[1] & 0x03)*0x10 + 0x03 + fq_hop[3] = (id[0] >> 6) + (id[1] & 0x0f)*0x04 + 0x03 + fq_hop[4] = (id[1] & 0x3f) + 0x03 + fq_hop[5] = (id[1] >> 2) + 0x03 + fq_hop[6] = (id[1] >> 4) + (id[2] & 0x03)*0x10 + 0x03 + fq_hop[7] = (id[1] >> 6) + (id[2] & 0x0f)*0x04 + 0x03 + fq_hop[8] = (id[2] & 0x3f) + 0x10 + fq_hop[9] = (id[2] >> 2) + 0x10 + fq_hop[10] = (id[2] >> 4) + (id[3] & 0x03)*0x10 + 0x10 + fq_hop[11] = (id[2] >> 6) + (id[3] & 0x0f)*0x04 + 0x10 + fq_hop[12] = (id[3] & 0x3f) + 0x10 + fq_hop[13] = (id[3] >> 2) + 0x10 + fq_hop[14] = (id[3] >> 4) + (id[0] & 0x03)*0x10 + 0x10 + # unique + for i in range(1,15): + done = False + while not done: + done = True + for j in range(i): + if fq_hop[i] == fq_hop[j]: + done = False + fq_hop[i] += 7 + if fq_hop[i] > 0x4f: + fq_hop[i] = fq_hop[i] % 0x50 + 0x03 + return fq_hop + + + +* Fault recovery * + +After receiving a packet in 9ms radio changes to a new frequency and waits for another packet. Normally, it comes in 13ms (9ms+13ms = 22ms - packet cycle). +If the packet did not come in 18ms, receiver switches to fault mode. Radio switches every 18ms to the next frequency 9 times, then switches to the first channel in sequence and stays on it indefinitely. \ No newline at end of file diff -r 6c3d9cf39f5e -r 530f6b24cf08 src/protocol/Makefile.inc --- a/src/protocol/Makefile.inc Wed Nov 27 08:14:15 2013 +0100 +++ b/src/protocol/Makefile.inc Wed Nov 27 22:06:50 2013 -0500 @@ -14,6 +14,7 @@ #PROTO_MODULES += $(ODIR)/protocol/frsky-2.mod PROTO_MODULES += $(ODIR)/protocol/skyartec.mod PROTO_MODULES += $(ODIR)/protocol/v202.mod +PROTO_MODULES += $(ODIR)/protocol/slt.mod ALL += $(PROTO_MODULES) else #BUILD_TARGET $(ODIR)/protocol/devo.mod : $(ODIR)/devo.bin @@ -72,4 +73,8 @@ @echo Building 'v202' module /bin/mkdir -p $(ODIR)/protocol/ 2>/dev/null; /bin/cp $< $@ +$(ODIR)/protocol/slt.mod : $(ODIR)/slt_nrf24l01.bin + @echo Building 'slt' module + /bin/mkdir -p $(ODIR)/protocol/ 2>/dev/null; /bin/cp $< $@ + endif #BUILD_TARGET diff -r 6c3d9cf39f5e -r 530f6b24cf08 src/protocol/iface_nrf24l01.h --- a/src/protocol/iface_nrf24l01.h Wed Nov 27 08:14:15 2013 +0100 +++ b/src/protocol/iface_nrf24l01.h Wed Nov 27 22:06:50 2013 -0500 @@ -40,9 +40,20 @@ NRF24L01_00_CRCO = 2, NRF24L01_00_PWR_UP = 1, NRF24L01_00_PRIM_RX = 0, - NRF24L01_07_TX_DS = 5 + NRF24L01_07_RX_DR = 6, + NRF24L01_07_TX_DS = 5, + NRF24L01_07_MAX_RT = 4, }; +// Bitrates +enum { + NRF24L01_BR_1M = 0, + NRF24L01_BR_2M, + NRF24L01_BR_250K, + NRF24L01_BR_RSVD +}; + + void NRF24L01_Initialize(); u8 NRF24L01_WriteReg(u8 reg, u8 data); u8 NRF24L01_WriteRegisterMulti(u8 reg, u8 data[], u8 length); @@ -56,9 +67,13 @@ u8 NRF24L01_Activate(u8 code); -// Bitrate 0 - 1Mbps, 1 - 2Mbps +// Bitrate 0 - 1Mbps, 1 - 2Mbps, 3 - 250K (for nRF24L01+) u8 NRF24L01_SetBitrate(u8 bitrate); u8 NRF24L01_SetPower(u8 power); +// To enable radio transmit after WritePayload you need to turn the radio +void NRF24L01_PulseCE(); + + #endif diff -r 6c3d9cf39f5e -r 530f6b24cf08 src/protocol/protocol.h --- a/src/protocol/protocol.h Wed Nov 27 08:14:15 2013 +0100 +++ b/src/protocol/protocol.h Wed Nov 27 22:06:50 2013 -0500 @@ -23,6 +23,7 @@ #endif //PROTO_HAS_CC2500 #ifdef PROTO_HAS_NRF24L01 PROTODEF(PROTOCOL_V202, NRF24L01, AETRG, V202_Cmds, "V202") +PROTODEF(PROTOCOL_SLT, NRF24L01, AETRG, SLT_Cmds, "TacticSLT") #endif //PROTO_HAS_NRF24L01 PROTODEF(PROTOCOL_PPM, TX_MODULE_LAST, NULL, PPMOUT_Cmds, "PPM") diff -r 6c3d9cf39f5e -r 530f6b24cf08 src/protocol/slt_nrf24l01.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocol/slt_nrf24l01.c Wed Nov 27 22:06:50 2013 -0500 @@ -0,0 +1,423 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Deviation is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Deviation. If not, see . + */ + +#ifdef MODULAR + //Allows the linker to properly relocate + #define SLT_Cmds PROTO_Cmds + #pragma long_calls +#endif +#include "common.h" +#include "interface.h" +#include "mixer.h" +#include "config/model.h" +#include "config/tx.h" // for Transmitter +#include "music.h" + +#ifdef MODULAR + //Some versions of gcc applythis to definitions, others to calls + //So just use long_calls everywhere + //#pragma long_calls_off + extern unsigned _data_loadaddr; + const unsigned long protocol_type = (unsigned long)&_data_loadaddr; +#endif + +#ifdef PROTO_HAS_NRF24L01 + +#include "iface_nrf24l01.h" + + +// For code readability +enum { + CHANNEL1 = 0, + CHANNEL2, + CHANNEL3, + CHANNEL4, + CHANNEL5, + CHANNEL6, + CHANNEL7, + CHANNEL8, + CHANNEL9, + CHANNEL10 +}; + +#define PAYLOADSIZE 7 +#define NFREQCHANNELS 15 +#define TXID_SIZE 4 + +static u8 packet[PAYLOADSIZE]; +static u8 packet_sent; +static u8 tx_id[TXID_SIZE]; +static u8 rf_ch_num; +static u16 counter; +static u32 packet_counter; +static u8 tx_power; + + +// +static u8 phase; +enum { + SLT_INIT2 = 0, + SLT_BIND, + SLT_DATA1, + SLT_DATA2, + SLT_DATA3 +}; + + +static u8 rf_channels[NFREQCHANNELS]; + +// Bit vector from bit position +#define BV(bit) (1 << bit) + +static const u8 init_vals[][2] = { + {NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)}, // 2-bytes CRC, radio off + {NRF24L01_01_EN_AA, 0x00}, // No Auto Acknoledgement + {NRF24L01_02_EN_RXADDR, 0x01}, // Enable data pipe 0 + {NRF24L01_03_SETUP_AW, 0x02}, // 4-byte RX/TX address + {NRF24L01_04_SETUP_RETR, 0x00}, // Disable auto retransmit + {NRF24L01_07_STATUS, 0x70}, // Clear data ready, data sent, and retransmit + {NRF24L01_11_RX_PW_P0, 4}, // bytes of data payload for pipe 1 +}; + +static void SLT_init() +{ + NRF24L01_Initialize(); + for (u32 i = 0; i < sizeof(init_vals) / sizeof(init_vals[0]); i++) + NRF24L01_WriteReg(init_vals[i][0], init_vals[i][1]); + NRF24L01_SetBitrate(NRF24L01_BR_250K); // 256kbps + NRF24L01_SetPower(Model.tx_power); + u8 rx_tx_addr[] = {0xC3, 0xC3, 0xAA, 0x55}; + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 4); + NRF24L01_FlushRx(); + + /* No space for this in module + + // Check for Beken BK2421/BK2423 chip + // It is done by using Beken specific activate code, 0x53 + // and checking that status register changed appropriately + // There is no harm to run it on nRF24L01 because following + // closing activate command changes state back even if it + // does something on nRF24L01 + NRF24L01_Activate(0x53); // magic for BK2421 bank switch + printf("Trying to switch banks\n"); + if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & 0x80) { + printf("BK2421 detected\n"); + long nul = 0; + // Beken registers don't have such nice names, so we just mention + // them by their numbers + // It's all magic, eavesdropped from real transfer and not even from the + // data sheet - it has slightly different values + NRF24L01_WriteRegisterMulti(0x00, (u8 *) "\x40\x4B\x01\xE2", 4); + NRF24L01_WriteRegisterMulti(0x01, (u8 *) "\xC0\x4B\x00\x00", 4); + NRF24L01_WriteRegisterMulti(0x02, (u8 *) "\xD0\xFC\x8C\x02", 4); + NRF24L01_WriteRegisterMulti(0x03, (u8 *) "\xF9\x00\x39\x21", 4); + NRF24L01_WriteRegisterMulti(0x04, (u8 *) "\xC1\x96\x9A\x1B", 4); + NRF24L01_WriteRegisterMulti(0x05, (u8 *) "\x24\x06\x7F\xA6", 4); + NRF24L01_WriteRegisterMulti(0x06, (u8 *) &nul, 4); + NRF24L01_WriteRegisterMulti(0x07, (u8 *) &nul, 4); + NRF24L01_WriteRegisterMulti(0x08, (u8 *) &nul, 4); + NRF24L01_WriteRegisterMulti(0x09, (u8 *) &nul, 4); + NRF24L01_WriteRegisterMulti(0x0A, (u8 *) &nul, 4); + NRF24L01_WriteRegisterMulti(0x0B, (u8 *) &nul, 4); + NRF24L01_WriteRegisterMulti(0x0C, (u8 *) "\x00\x12\x73\x00", 4); + NRF24L01_WriteRegisterMulti(0x0D, (u8 *) "\x46\xB4\x80\x00", 4); + NRF24L01_WriteRegisterMulti(0x0E, (u8 *) "\x41\x10\x04\x82\x20\x08\x08\xF2\x7D\xEF\xFF", 11); + NRF24L01_WriteRegisterMulti(0x04, (u8 *) "\xC7\x96\x9A\x1B", 4); + NRF24L01_WriteRegisterMulti(0x04, (u8 *) "\xC1\x96\x9A\x1B", 4); + } else { + printf("nRF24L01 detected\n"); + } + NRF24L01_Activate(0x53); // switch bank back + + */ + + // Implicit delay in callback + // delay(50); +} + +static void SLT_init2() +{ + NRF24L01_FlushTx(); + packet_sent = 0; + rf_ch_num = 0; + + // Turn radio power on + u8 config = BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, config); + // Implicit delay in callback + // delayMicroseconds(150); +} + +static void set_tx_id(u32 id) +{ + for (int i = TXID_SIZE-1; i >= 0; --i) { + tx_id[i] = id & 0xFF; + id >>= 8; + } + + // Frequency hopping sequence generation + + for (int i = 0; i < 4; ++i) { + int next_i = (i+1) % 4; // is & 3 better than % 4 ? + uint8_t base = i < 2 ? 0x03 : 0x10; + rf_channels[i*4 + 0] = (tx_id[i] & 0x3f) + base; + rf_channels[i*4 + 1] = (tx_id[i] >> 2) + base; + rf_channels[i*4 + 2] = (tx_id[i] >> 4) + (tx_id[next_i] & 0x03)*0x10 + base; + if (i*4 + 3 < NFREQCHANNELS) // guard for 16 channel + rf_channels[i*4 + 3] = (tx_id[i] >> 6) + (tx_id[next_i] & 0x0f)*0x04 + base; + } + + // unique + for (int i = 0; i < NFREQCHANNELS; ++i) { + u8 done = 0; + while (!done) { + done = 1; + for (int j = 0; j < i; ++j) { + if (rf_channels[i] == rf_channels[j]) { + done = 0; + rf_channels[i] += 7; + if (rf_channels[i] >= 0x50) { + rf_channels[i] = rf_channels[i] - 0x50 + 0x03; + } + } + } + } + } + printf("Using id:%02X%02X%02X%02X fh: ", tx_id[0], tx_id[1], tx_id[2], tx_id[3]); + for (int i = 0; i < NFREQCHANNELS; ++i) { + printf("%02X ", rf_channels[i]); + } + printf("\n"); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, tx_id, 4); +} + + +static s16 convert_channel(u8 num) +{ + s32 ch = Channels[num]; + if (ch < CHAN_MIN_VALUE) { + ch = CHAN_MIN_VALUE; + } else if (ch > CHAN_MAX_VALUE) { + ch = CHAN_MAX_VALUE; + } + return (s16) ch; +} + + +static void read_controls(s16 *controls) +{ + // Protocol is registered AETRG, that is + // Aileron is channel 0, Elevator - 1, Throttle - 2, Rudder - 3 + // Sometimes due to imperfect calibration or mixer settings + // throttle can be less than CHAN_MIN_VALUE or larger than + // CHAN_MAX_VALUE. As we have no space here, we hard-limit + // channels values by min..max range + for (int i = 0; i < 6; ++i) + controls[i] = convert_channel(i); + + // Print channels every second or so +/* + if ((packet_counter & 0xFF) == 1) { + printf("Raw channels: %d, %d, %d, %d, %d, %d\n", + Channels[0], Channels[1], Channels[2], Channels[3], Channels[4], Channels[5]); + printf("Aileron %d, elevator %d, throttle %d, rudder %d, gear %d, pitch %d\n", + *aileron, *elevator, *throttle, *rudder, *gear, *pitch); + } +*/ +} + + +void wait_radio() +{ + if (packet_sent) { + while (!(NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_TX_DS))) ; + } + packet_sent = 0; +} + + +void send_data(uint8_t *data, uint8_t len) +{ + wait_radio(); + NRF24L01_FlushTx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_RX_DR) | BV(NRF24L01_07_MAX_RT)); + NRF24L01_WritePayload(data, len); + NRF24L01_PulseCE(); + packet_sent = 1; +} + + +static void build_packet() +{ + // Raw controls, limited by -10000..10000 + s16 controls[6]; // aileron, elevator, throttle, rudder, gear, pitch + read_controls(controls); + uint8_t e = 0; // byte where extension 2 bits for every 10-bit channel are packed + for (int i = 0; i < 4; ++i) { + uint16_t v = (long) controls[i] * 1023 / 20000L + 512; + packet[i] = v; + e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0); + } + // Extra bits for AETR + packet[4] = e; + // 8-bit channels + packet[5] = (long) controls[4] * 255 / 20000L + 128; + packet[6] = (long) controls[5] * 255 / 20000L + 128; + + // Set radio channel - once per packet batch + u8 rf_ch = rf_channels[rf_ch_num]; + NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch); + if (++rf_ch_num >= NFREQCHANNELS) rf_ch_num = 0; + // Serial.print(rf_ch); Serial.write("\n"); +} + + +static void send_packet() +{ + send_data(packet, sizeof(packet)); + ++packet_counter; +} + + +static void send_bind_packet() +{ + wait_radio(); + + NRF24L01_SetPower(TXPOWER_100uW); + static uint8_t bind_addr[4] = {0x7E, 0xB8, 0x63, 0xA9}; + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_addr, 4); + + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x50); + send_data(tx_id, sizeof(tx_id)); + + // NB: we should wait until the packet's sent before changing TX address! + wait_radio(); +// printf("Bind packet sent\n"); + + NRF24L01_SetPower(tx_power); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, tx_id, 4); +} + + +void checkTxPower() +{ + // Check and adjust transmission power. We do this after + // transmission to not bother with timeout after power + // settings change - we have plenty of time until next + // packet. + if (! rf_ch_num && tx_power != Model.tx_power) { + // Keep transmit power updated + tx_power = Model.tx_power; + NRF24L01_SetPower(tx_power); + } +} + + +MODULE_CALLTYPE +static u16 SLT_callback() +{ + u16 delay_us = 20000; // 3 packets with 1ms intervals every 22ms + switch (phase) { + case SLT_INIT2: + SLT_init2(); + MUSIC_Play(MUSIC_TELEMALARM1); + phase = SLT_BIND; + delay_us = 150; + break; + + case SLT_BIND: + send_bind_packet(); + phase = SLT_DATA1; + delay_us = 19000; + break; + + case SLT_DATA1: + build_packet(); + send_packet(); + phase = SLT_DATA2; + delay_us = 1000; + break; + + case SLT_DATA2: + send_packet(); + phase = SLT_DATA3; + delay_us = 1000; + break; + + case SLT_DATA3: + send_packet(); + if (++counter >= 100) { + counter = 0; + phase = SLT_BIND; + delay_us = 1000; + } else { + checkTxPower(); + phase = SLT_DATA1; + } + break; + } + return delay_us; +} + +static void initialize() +{ + CLOCK_StopTimer(); + tx_power = Model.tx_power; + packet_counter = 0; + counter = 0; + SLT_init(); + phase = SLT_INIT2; + + u32 id = 0xb2c54a2f; + if (Model.fixed_id) { + id ^= Model.fixed_id + (Model.fixed_id << 16); + } else { + /* + u32* stm32id = (uint32_t*) 0x1FFFF7E8; + id ^= stm32id[0]; + id ^= stm32id[1]; + id ^= stm32id[2]; + */ + id = (Crc(&Model, sizeof(Model)) + Crc(&Transmitter, sizeof(Transmitter))) % 999999; + } + // Wikipedia Linear_feedback_shift_register, Xilinx polinomial x^32 + x^22 + x^2 + x + 1 + for (int i = 0; i < 33; ++i) { + id = (id >> 1) ^ (-(id & 1u) & 0x80200003u); + } + set_tx_id(id); + CLOCK_StartTimer(50000, SLT_callback); +} + +const void *SLT_Cmds(enum ProtoCmds cmd) +{ + switch(cmd) { + case PROTOCMD_INIT: initialize(); return 0; + case PROTOCMD_DEINIT: return 0; + case PROTOCMD_CHECK_AUTOBIND: return (void *)1L; // Always Autobind + case PROTOCMD_BIND: initialize(); return 0; + case PROTOCMD_NUMCHAN: return (void *) 6L; // A, E, T, R, G, P + case PROTOCMD_DEFAULT_NUMCHAN: return (void *)6L; + // TODO: return id correctly + case PROTOCMD_CURRENT_ID: return Model.fixed_id ? (void *)((unsigned long)Model.fixed_id) : 0; + case PROTOCMD_TELEMETRYSTATE: return (void *)(long)-1; + case PROTOCMD_SET_TXPOWER: + tx_power = Model.tx_power; + NRF24L01_SetPower(tx_power); + break; + default: break; + } + return 0; +} +#endif diff -r 6c3d9cf39f5e -r 530f6b24cf08 src/protocol/v202_nrf24l01.c --- a/src/protocol/v202_nrf24l01.c Wed Nov 27 08:14:15 2013 +0100 +++ b/src/protocol/v202_nrf24l01.c Wed Nov 27 22:06:50 2013 -0500 @@ -132,7 +132,7 @@ NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xFF); // 4ms retransmit t/o, 15 tries NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x08); // Channel 8 - NRF24L01_SetBitrate(0); // 1Mbps + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps NRF24L01_SetPower(Model.tx_power); NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit // NRF24L01_WriteReg(NRF24L01_08_OBSERVE_TX, 0x00); // no write bits in this field diff -r 6c3d9cf39f5e -r 530f6b24cf08 src/target/common_devo/protocol/nrf24l01.c --- a/src/target/common_devo/protocol/nrf24l01.c Wed Nov 27 08:14:15 2013 +0100 +++ b/src/target/common_devo/protocol/nrf24l01.c Wed Nov 27 22:06:50 2013 -0500 @@ -147,7 +147,13 @@ u8 NRF24L01_SetBitrate(u8 bitrate) { - rf_setup = (rf_setup & 0xF7) | ((bitrate & 0x01) << 3); + // Note that bitrate 250kbps (and bit RF_DR_LOW) is valid only + // for nRF24L01+. There is no way to programmatically tell it from + // older version, nRF24L01, but the older is practically phased out + // by Nordic, so we assume that we deal with with modern version. + + // Bit 0 goes to RF_DR_HIGH, bit 1 - to RF_DR_LOW + rf_setup = (rf_setup & 0xD7) | ((bitrate & 0x02) << 4) | ((bitrate & 0x01) << 3); return NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup); } @@ -188,4 +194,10 @@ return NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup); } +void NRF24L01_PulseCE() +{ + // Not implemented, CE is wired HIGH + // Should issue HIGH pulse ~15us wide +} + #endif // defined(PROTO_HAS_NRF24L01)