/*
This program 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.
This program 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 this program. If not, see .
*/
#pragma once
/*
AP_Radio implementation for CC2500 2.4GHz radio.
With thanks to cleanflight and betaflight projects
*/
#include "AP_Radio_config.h"
#if AP_RADIO_CC2500_ENABLED
#include "AP_Radio_backend.h"
#include "hal.h"
#include "telem_structure.h"
#include "driver_cc2500.h"
#define CC2500_MAX_PWM_CHANNELS 16
class AP_Radio_cc2500 : public AP_Radio_backend
{
public:
AP_Radio_cc2500(AP_Radio &radio);
// init - initialise radio
bool init(void) override;
// rest radio
bool reset(void) override;
// send a packet
bool send(const uint8_t *pkt, uint16_t len) override;
// start bind process as a receiver
void start_recv_bind(void) override;
// return time in microseconds of last received R/C packet
uint32_t last_recv_us(void) override;
// return number of input channels
uint8_t num_channels(void) override;
// return current PWM of a channel
uint16_t read(uint8_t chan) override;
// handle a data96 mavlink packet for fw upload
void handle_data_packet(mavlink_channel_t chan, const mavlink_data96_t &m) override;
// update status
void update(void) override;
// get TX fw version
uint32_t get_tx_version(void) override
{
// pack date into 16 bits for vendor_id in AUTOPILOT_VERSION
return (uint16_t(tx_date.firmware_year)<<12) + (uint16_t(tx_date.firmware_month)<<8) + tx_date.firmware_day;
}
// get radio statistics structure
const AP_Radio::stats &get_stats(void) override;
// set the 2.4GHz wifi channel used by companion computer, so it can be avoided
void set_wifi_channel(uint8_t channel) override
{
t_status.wifi_chan = channel;
}
// static probe function for device detection
static bool probe(void);
private:
AP_HAL::OwnPtr dev;
static AP_Radio_cc2500 *radio_singleton;
static thread_t *_irq_handler_ctx;
static virtual_timer_t timeout_vt;
static void irq_handler_thd(void* arg);
static void trigger_irq_radio_event(void);
static void trigger_timeout_event(virtual_timer_t* vt, void *arg);
void radio_init(void);
// semaphore between ISR and main thread
HAL_Semaphore sem;
AP_Radio::stats stats;
AP_Radio::stats last_stats;
uint16_t pwm_channels[CC2500_MAX_PWM_CHANNELS];
Radio_CC2500 cc2500;
uint8_t bindTxId[2];
int8_t bindOffset;
uint8_t bindHopData[47];
uint8_t rxNum;
uint8_t listLength;
uint8_t channr;
uint8_t chanskip;
int8_t fcc_chan;
uint32_t packet_timer;
static uint32_t irq_time_us;
uint8_t chan_count;
uint32_t lost;
uint32_t timeouts;
bool have_bind_info;
uint8_t packet3;
bool telem_send_rssi;
float rssi_filtered;
uint64_t bind_mask;
uint8_t best_lqi;
int8_t best_bindOffset;
int8_t auto_bindOffset;
uint8_t search_count;
uint8_t last_wifi_channel;
uint32_t timeTunedMs;
uint32_t autobind_start_recv_ms;
void initTuneRx(void);
void initialiseData(uint8_t adr);
void initGetBind(void);
bool tuneRx(uint8_t ccLen, uint8_t *packet);
bool getBindData(uint8_t ccLen, uint8_t *packet);
bool check_best_LQI(void);
void setChannel(uint8_t channel);
void setChannelRX(uint8_t channel);
void nextChannel(uint8_t skip);
void parse_frSkyX(const uint8_t *packet);
uint16_t calc_crc(const uint8_t *data, uint8_t len);
bool check_crc(uint8_t ccLen, uint8_t *packet);
void send_D16_telemetry(void);
void send_SRT_telemetry(void);
void irq_handler(void);
void irq_timeout(void);
// bind structure saved to storage
static const uint16_t bind_magic = 0x120c;
struct PACKED bind_info {
uint16_t magic;
uint8_t bindTxId[2];
int8_t bindOffset;
uint8_t wifi_chan;
uint8_t bindHopData[47];
};
void save_bind_info(void);
bool load_bind_info(void);
enum {
STATE_INIT = 0,
STATE_BIND,
STATE_BIND_TUNING,
STATE_BIND_BINDING,
STATE_BIND_COMPLETE,
STATE_STARTING,
STATE_DATA,
STATE_TELEMETRY,
STATE_RESUME,
STATE_FCCTEST,
STATE_SEARCH,
} protocolState;
struct config {
uint8_t reg;
uint8_t value;
};
static const config radio_config_GFSK[];
static const config radio_config[];
struct {
mavlink_channel_t chan;
bool need_ack;
uint8_t counter;
uint8_t sequence;
uint32_t offset;
uint32_t length;
uint32_t acked;
uint8_t len;
enum telem_type fw_type;
uint8_t pending_data[92];
} fwupload;
struct {
uint8_t firmware_year;
uint8_t firmware_month;
uint8_t firmware_day;
} tx_date;
struct telem_status_cc2500 t_status;
uint32_t last_pps_ms;
uint8_t tx_rssi;
uint8_t tx_pps;
bool have_tx_pps;
uint8_t last_fcc_chan;
uint32_t telem_send_count;
bool handle_D16_packet(const uint8_t *packet);
bool handle_SRT_packet(const uint8_t *packet);
bool handle_autobind_packet(const uint8_t *packet, uint8_t lqi);
bool have_channel(uint8_t channel, uint8_t count, uint8_t loop);
void setup_hopping_table_SRT(void);
uint8_t map_RSSI_to_dBm(uint8_t rssi_raw);
// check sending of fw upload ack
void check_fw_ack(void);
void map_stick_mode(uint16_t *channels);
void set_fcc_channel(void);
// check for double binding
void check_double_bind(void);
};
#endif // AP_RADIO_CC2500_ENABLED