10 #if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS 11 #if HAL_RCINPUT_WITH_AP_RADIO 22 #if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS 24 #define TIMEOUT_PRIORITY 250 //Right above timer thread 25 #define EVT_TIMEOUT EVENT_MASK(0) 26 #define EVT_IRQ EVENT_MASK(1) 27 #define EVT_BIND EVENT_MASK(2) 32 #define Debug(level, fmt, args...) do { if ((level) <= get_debug_level()) { hal.console->printf(fmt, ##args); }} while (0) 34 #define LP_FIFO_SIZE 16 // Physical data FIFO lengths in Radio 38 #if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS 52 radio_instance =
this;
60 #if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS 61 if(_irq_handler_ctx !=
nullptr) {
62 AP_HAL::panic(
"AP_Radio_cc2500: double instantiation of irq_handler\n");
64 chVTObjectInit(&timeout_vt);
65 _irq_handler_ctx = chThdCreateStatic(_irq_handler_wa,
66 sizeof(_irq_handler_wa),
81 if (!cc2500.lock_bus()) {
107 return pwm_channels[
chan];
127 pwm_channels[chan-1] = t_status.rssi;
128 chan_count =
MAX(chan_count, chan);
133 pwm_channels[chan-1] = t_status.pps;
134 chan_count =
MAX(chan_count, chan);
139 pwm_channels[chan-1] = tx_rssi;
140 chan_count =
MAX(chan_count, chan);
145 pwm_channels[chan-1] = tx_pps;
146 chan_count =
MAX(chan_count, chan);
149 if (now - last_pps_ms > 1000) {
151 t_status.pps = stats.recv_packets - last_stats.recv_packets;
153 if (lost != 0 || timeouts != 0) {
217 const uint16_t CRCTable[] = {
218 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
219 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
220 0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
221 0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
222 0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
223 0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
224 0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
225 0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
226 0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
227 0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
228 0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
229 0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
230 0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
231 0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
232 0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
233 0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
234 0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
235 0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
236 0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
237 0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
238 0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
239 0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
240 0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
241 0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
242 0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
243 0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
244 0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
245 0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
246 0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
247 0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
248 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
249 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
259 Debug(1,
"cc2500: radio not found\n");
263 Debug(1,
"cc2500: radio_init starting\n");
267 for (uint8_t i=0; i<
ARRAY_SIZE(radio_config); i++) {
269 cc2500.WriteRegCheck(radio_config[i].reg, radio_config[i].
value);
273 for (uint8_t c=0;c<0xFF;c++) {
287 #if CONFIG_HAL_BOARD == HAL_BOARD_PX4 288 stm32_gpiosetevent(CYRF_IRQ_INPUT,
true,
false,
false, irq_radio_trampoline);
289 #elif CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS 295 if (load_bind_info()) {
296 Debug(3,
"Loaded bind info\n");
299 protocolState = STATE_SEARCH;
303 protocolState = STATE_BIND_TUNING;
306 chVTSet(&timeout_vt, MS2ST(10), trigger_timeout_event,
nullptr);
314 chEvtSignalI(_irq_handler_ctx, EVT_IRQ);
315 chSysUnlockFromISR();
323 chVTSetI(&timeout_vt, MS2ST(10), trigger_timeout_event,
nullptr);
324 chEvtSignalI(_irq_handler_ctx, EVT_TIMEOUT);
325 chSysUnlockFromISR();
330 protocolState = STATE_BIND_TUNING;
333 chEvtSignal(_irq_handler_ctx, EVT_BIND);
334 Debug(1,
"Starting bind\n");
341 memcpy(&ofs, &m.data[0], 4);
342 Debug(4,
"got data96 of len %u from chan %u at offset %u\n", m.len, chan,
unsigned(ofs));
343 if (sem->take_nonblocking()) {
344 fwupload.chan =
chan;
345 fwupload.need_ack =
false;
346 fwupload.offset = ofs;
347 fwupload.length =
MIN(m.len-4, 92);
353 fwupload.length =
MIN(m.len, 90);
355 memcpy(&fwupload.pending_data[0], &m.data[0], fwupload.length);
359 memcpy(&fwupload.pending_data[0], &m.data[4], fwupload.length);
370 if (packet[0] != 0x1D) {
373 if (packet[1] != bindTxId[0] ||
374 packet[2] != bindTxId[1]) {
375 Debug(3,
"p1=%02x p2=%02x p6=%02x\n", packet[1], packet[2], packet[6]);
379 if (packet[7] == 0x00 ||
390 parse_frSkyX(packet);
394 uint8_t hop_chan = packet[4] & 0x3F;
395 uint8_t skip = (packet[4]>>6) | (packet[5]<<2);
396 if (channr != hop_chan) {
397 Debug(2,
"channr=%u hop_chan=%u\n", channr, hop_chan);
400 if (chanskip != skip) {
401 Debug(2,
"chanskip=%u skip=%u\n", chanskip, skip);
416 pkt->
txid[0] != bindTxId[0] ||
417 pkt->
txid[1] != bindTxId[1]) {
431 pwm_channels[4] = 1000 + (pkt->
buttons & 0x7) * 100;
432 pwm_channels[5] = 1000 + (pkt->
buttons >> 3) * 100;
441 pwm_channels[6] = data * 4;
444 tx_date.firmware_year =
data;
447 tx_date.firmware_month =
data;
450 tx_date.firmware_day =
data;
463 Debug(4,
"ack %u seq=%u acked=%u length=%u len=%u\n",
464 data, fwupload.sequence,
unsigned(fwupload.acked),
unsigned(fwupload.length), fwupload.len);
465 if (fwupload.sequence == data && sem->take_nonblocking()) {
467 fwupload.acked += fwupload.len;
468 if (fwupload.acked == fwupload.length) {
470 fwupload.need_ack =
true;
478 if (chan_count < 7) {
497 bool matched =
false;
502 matched = (ccLen == ccLen2);
506 Debug(3,
"Fifo overflow %02x\n", ccLen);
513 uint8_t packet[ccLen];
514 cc2500.ReadFifo(packet, ccLen);
521 if (ccLen != 32 && ccLen !=
sizeof(
srt_packet)+2) {
524 Debug(3,
"bad len %u\n", ccLen);
529 Debug(6,
"CC2500 IRQ state=%u\n",
unsigned(protocolState));
530 Debug(6,
"len=%u\n", ccLen);
531 for (uint8_t i=0; i<ccLen; i++) {
532 Debug(6,
"%02x:%02x ", i, packet[i]);
533 if ((i+1) % 16 == 0) {
537 if (ccLen % 16 != 0) {
542 if (!check_crc(ccLen, packet)) {
543 Debug(3,
"bad CRC ccLen=%u\n", ccLen);
547 switch (protocolState) {
548 case STATE_BIND_TUNING:
549 tuneRx(ccLen, packet);
552 case STATE_BIND_BINDING:
553 if (getBindData(ccLen, packet)) {
554 Debug(2,
"Bind complete\n");
555 protocolState = STATE_BIND_COMPLETE;
559 case STATE_BIND_COMPLETE:
560 protocolState = STATE_STARTING;
562 Debug(3,
"listLength=%u\n", listLength);
563 Debug(3,
"Saved bind info\n");
569 protocolState = STATE_SEARCH;
575 protocolState = STATE_DATA;
581 ok = handle_D16_packet(packet);
583 ok = handle_SRT_packet(packet);
587 uint8_t rssi_raw = packet[ccLen-2];
589 if (rssi_raw >= 128) {
590 rssi_dbm = ((((uint16_t)rssi_raw) * 18) >> 5) - 82;
592 rssi_dbm = ((((uint16_t)rssi_raw) * 18) >> 5) + 65;
594 rssi_filtered = 0.95 * rssi_filtered + 0.05 * rssi_dbm;
595 t_status.rssi = uint8_t(
MAX(rssi_filtered, 1));
597 stats.recv_packets++;
599 packet_timer = irq_time_us;
600 chVTSet(&timeout_vt, MS2ST(10), trigger_timeout_event,
nullptr);
605 send_D16_telemetry();
607 send_SRT_telemetry();
623 Debug(3,
"IRQ in FCCTEST state\n");
627 Debug(2,
"state %u\n", (
unsigned)protocolState);
635 if (
get_fcc_test() != 0 && protocolState != STATE_FCCTEST) {
636 protocolState = STATE_FCCTEST;
639 send_D16_telemetry();
642 switch (protocolState) {
643 case STATE_BIND_TUNING: {
644 if (bindOffset >= 126) {
645 if (check_best_LQI()) {
651 if (now - timeTunedMs > 20) {
654 Debug(6,
"bindOffset=%d\n",
int(bindOffset));
666 if (now - packet_timer > 50*sync_time_us) {
667 Debug(3,
"searching %u\n",
unsigned(now - packet_timer));
673 protocolState = STATE_SEARCH;
678 chVTSet(&timeout_vt, MS2ST(9), trigger_timeout_event,
nullptr);
689 case STATE_FCCTEST: {
691 protocolState = STATE_DATA;
692 Debug(1,
"Ending FCCTEST\n");
696 send_D16_telemetry();
709 eventmask_t evt = chEvtWaitAny(ALL_EVENTS);
711 radio_instance->cc2500.lock_bus();
715 if (radio_instance->protocolState == STATE_FCCTEST) {
718 radio_instance->irq_handler();
723 radio_instance->irq_handler();
725 radio_instance->irq_timeout();
729 radio_instance->initTuneRx();
735 radio_instance->cc2500.unlock_bus();
745 best_bindOffset = bindOffset;
789 if (best_lqi >= 50) {
792 bindOffset = best_bindOffset;
795 protocolState = STATE_BIND_BINDING;
798 Debug(2,
"Bind tuning %d with Lqi %u\n", best_bindOffset, best_lqi);
808 if (bindOffset >= 126) {
811 if (check_best_LQI()) {
816 if ((packet[ccLen - 1] & 0x80) && packet[2] == 0x01) {
817 uint8_t Lqi = packet[ccLen - 1] & 0x7F;
818 if (Lqi < best_lqi) {
820 best_bindOffset = bindOffset;
832 if ((packet[ccLen - 1] & 0x80) && packet[2] == 0x01) {
833 if (bind_mask == 0) {
834 bindTxId[0] = packet[3];
835 bindTxId[1] = packet[4];
836 }
else if (bindTxId[0] != packet[3] ||
837 bindTxId[1] != packet[4]) {
838 Debug(2,
"Bind restart\n");
843 for (uint8_t n = 0; n < 5; n++) {
844 uint8_t c = packet[5] + n;
845 if (c <
sizeof(bindHopData)) {
846 bindHopData[c] = packet[6 + n];
847 bind_mask |= (uint64_t(1)<<c);
848 listLength =
MAX(listLength, c+1);
852 return (listLength == 47 && bind_mask == ((uint64_t(1)<<47)-1));
870 setChannel(bindHopData[
channr]);
877 c[0] = (uint16_t)((packet[10] <<8)& 0xF00) | packet[9];
878 c[1] = (uint16_t)((packet[11]<<4)&0xFF0) | (packet[10]>>4);
879 c[2] = (uint16_t)((packet[13] <<8)& 0xF00) | packet[12];
880 c[3] = (uint16_t)((packet[14]<<4)&0xFF0) | (packet[13]>>4);
881 c[4] = (uint16_t)((packet[16] <<8)& 0xF00) | packet[15];
882 c[5] = (uint16_t)((packet[17]<<4)&0xFF0) | (packet[16]>>4);
883 c[6] = (uint16_t)((packet[19] <<8)& 0xF00) | packet[18];
884 c[7] = (uint16_t)((packet[20]<<4)&0xFF0) | (packet[19]>>4);
887 for (uint8_t i=0;i<8;i++) {
897 uint16_t word_temp = (((c[i]-64)<<1)/3+860);
898 if ((word_temp > 800) && (word_temp < 2200)) {
901 pwm_channels[
chan] = word_temp;
902 if (chan >= chan_count) {
913 for(uint8_t i=0; i < len; i++) {
914 crc = (crc<<8) ^ (CRCTable[((uint8_t)(crc>>8) ^ *data++) & 0xFF]);
924 uint16_t lcrc = calc_crc(packet,
sizeof(
struct srt_packet)-2);
925 return lcrc == ((pkt->
crc[0]<<8) | pkt->
crc[1]);
926 }
else if (ccLen == 32) {
928 uint16_t lcrc = calc_crc(&packet[3],(ccLen-7));
929 return ((lcrc >>8)==packet[ccLen-4] && (lcrc&0x00FF)==packet[ccLen-3]);
941 struct bind_info info;
943 info.magic = bind_magic;
944 info.bindTxId[0] = bindTxId[0];
945 info.bindTxId[1] = bindTxId[1];
946 info.bindOffset = bindOffset;
947 info.listLength = listLength;
948 memcpy(info.bindHopData, bindHopData,
sizeof(info.bindHopData));
949 bind_storage.write_block(0, &info,
sizeof(info));
959 struct bind_info info;
961 if (!bind_storage.read_block(&info, 0,
sizeof(info)) || info.magic != bind_magic) {
965 bindTxId[0] = info.bindTxId[0];
966 bindTxId[1] = info.bindTxId[1];
967 bindOffset = info.bindOffset;
968 listLength = info.listLength;
969 memcpy(bindHopData, info.bindHopData,
sizeof(bindHopData));
981 memset(frame, 0,
sizeof(frame));
983 frame[0] =
sizeof(frame)-1;
984 frame[1] = bindTxId[0];
985 frame[2] = bindTxId[1];
987 if (telem_send_rssi) {
988 frame[4] =
MAX(
MIN(t_status.rssi, 0x7f),1) | 0x80;
992 telem_send_rssi = !telem_send_rssi;
994 uint16_t lcrc = calc_crc(&frame[3], 10);
1003 cc2500.WriteFifo(frame,
sizeof(frame));
1016 pkt.
length =
sizeof(pkt)-1;
1030 if (fwupload.length != 0 &&
1031 fwupload.length > fwupload.acked &&
1032 ((fwupload.counter++ & 0x07) != 0) &&
1033 sem->take_nonblocking()) {
1034 pkt.
type = fwupload.fw_type;
1036 uint32_t len = fwupload.length>fwupload.acked?fwupload.length - fwupload.acked:0;
1041 Debug(4,
"sent fw seq=%u offset=%u len=%u type=%u\n",
1051 pkt.
txid[0] = bindTxId[0];
1052 pkt.
txid[1] = bindTxId[1];
1054 uint16_t lcrc = calc_crc((
const uint8_t *)&pkt,
sizeof(pkt)-2);
1055 pkt.crc[0] = lcrc>>8;
1056 pkt.crc[1] = lcrc&0xFF;
1063 cc2500.WriteFifo((
const uint8_t *)&pkt,
sizeof(pkt));
1073 if (fwupload.need_ack && sem->take_nonblocking()) {
1075 fwupload.need_ack =
false;
1076 uint8_t data16[16] {};
1077 uint32_t ack_to = fwupload.offset + fwupload.acked;
1078 memcpy(&data16[0], &ack_to, 4);
1079 mavlink_msg_data16_send(fwupload.chan, 42, 4, data16);
1080 Debug(4,
"sent ack DATA16\n");
1085 #endif // HAL_RCINPUT_WITH_AP_RADIO 1086 #endif // CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS bool get_soft_armed() const
void nextChannel(uint8_t skip)
static thread_t * _irq_handler_ctx
uint8_t get_tx_rssi_chan(void) const
bool send(const uint8_t *pkt, uint16_t len) override
static void trigger_timeout_event(void *arg)
#define TELEM_FLAG_POS_OK
uint8_t get_debug_level(void) const
virtual float board_voltage(void)=0
AP_Radio_cc2500(AP_Radio &radio)
struct telem_status status
AP_HAL::UARTDriver * console
bool tuneRx(uint8_t ccLen, uint8_t *packet)
void update(void) override
uint8_t get_rssi_chan(void) const
void save_bind_info(void)
bool getBindData(uint8_t ccLen, uint8_t *packet)
AP_HAL::OwnPtr< AP_HAL::Device > get_device(const char *name)
virtual Semaphore * new_semaphore(void)
uint16_t read(uint8_t chan) override
void send_D16_telemetry(void)
virtual bool reset(void)=0
void setChannel(uint8_t channel)
static auto MAX(const A &one, const B &two) -> decltype(one > two ? one :two)
void start_recv_bind(void) override
static uint32_t irq_time_us
virtual bool attach_interrupt(uint8_t interrupt_num, AP_HAL::Proc p, uint8_t mode)=0
uint32_t last_recv_us(void) override
virtual void printf(const char *,...) FMT_PRINTF(2
bool reset(void) override
uint8_t num_channels(void) override
#define CC2500_MAX_CHANNELS
#define Debug(fmt, args ...)
int8_t get_fcc_test(void) const
#define HAL_GPIO_INTERRUPT_RISING
void initialiseData(uint8_t adr)
uint32_t failsafe_battery
bool handle_D16_packet(const uint8_t *packet)
#define TELEM_FLAG_ARM_OK
#define TELEM_FLAG_BATT_OK
bool check_crc(uint8_t ccLen, uint8_t *packet)
static virtual_timer_t timeout_vt
static void trigger_irq_radio_event(void)
#define CC2500_READ_BURST
void parse_frSkyX(const uint8_t *packet)
static AP_Radio_cc2500 * radio_instance
uint8_t get_tx_buzzer_adjust(void) const
bool handle_SRT_packet(const uint8_t *packet)
void send_SRT_telemetry(void)
bool check_best_LQI(void)
static struct notify_flags_and_values_type flags
uint8_t get_transmit_power(void) const
AP_HAL::AnalogSource * chan
virtual void delay_microseconds(uint16_t us)=0
uint8_t get_tx_pps_chan(void) const
uint8_t get_tx_max_power(void) const
#define TELEM_FLAG_GPS_OK
const AP_Radio::stats & get_stats(void) override
uint16_t calc_crc(const uint8_t *data, uint8_t len)
void panic(const char *errormsg,...) FMT_PRINTF(1
static const config radio_config[]
uint8_t get_pps_chan(void) const
bool load_bind_info(void)
THD_WORKING_AREA(_timer_thread_wa, 2048)
void handle_data_packet(mavlink_channel_t chan, const mavlink_data96_t &m) override
static void irq_handler_thd(void *arg)
AP_HAL::Scheduler * scheduler
AP_Radio::ap_radio_protocol get_protocol(void) const
union telem_packet_cc2500::@175 payload
AP_HAL::AnalogIn * analogin