You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
7.6 KiB
282 lines
7.6 KiB
/* |
|
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 <http://www.gnu.org/licenses/>. |
|
*/ |
|
#pragma once |
|
|
|
#if HAL_RCINPUT_WITH_AP_RADIO |
|
|
|
/* |
|
AP_Radio implementation for Cypress 2.4GHz radio. |
|
|
|
With thanks to the SuperBitRF project |
|
See http://wiki.paparazziuav.org/wiki/SuperbitRF |
|
|
|
This implementation uses the DSMX protocol on a CYRF6936 |
|
*/ |
|
|
|
#include "AP_Radio_backend.h" |
|
#include "hal.h" |
|
#include "telem_structure.h" |
|
|
|
class AP_Radio_cypress : public AP_Radio_backend |
|
{ |
|
public: |
|
AP_Radio_cypress(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(dsm.tx_firmware_year)<<12) + (uint16_t(dsm.tx_firmware_month)<<8) + dsm.tx_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; |
|
} |
|
|
|
private: |
|
AP_HAL::OwnPtr<AP_HAL::SPIDevice> dev; |
|
static AP_Radio_cypress *radio_singleton; |
|
|
|
void radio_init(void); |
|
|
|
void dump_registers(uint8_t n); |
|
|
|
void force_initial_state(void); |
|
void set_channel(uint8_t channel); |
|
uint8_t read_status_debounced(uint8_t adr); |
|
|
|
uint8_t read_register(uint8_t reg); |
|
void write_register(uint8_t reg, uint8_t value); |
|
void write_multiple(uint8_t reg, uint8_t n, const uint8_t *data); |
|
|
|
enum { |
|
STATE_RECV, |
|
STATE_BIND, |
|
STATE_AUTOBIND, |
|
STATE_SEND_TELEM, |
|
STATE_SEND_TELEM_WAIT, |
|
STATE_SEND_FCC |
|
} state; |
|
|
|
struct config { |
|
uint8_t reg; |
|
uint8_t value; |
|
}; |
|
static const uint8_t pn_codes[5][9][8]; |
|
static const uint8_t pn_bind[]; |
|
static const config cyrf_config[]; |
|
static const config cyrf_bind_config[]; |
|
static const config cyrf_transfer_config[]; |
|
|
|
virtual_timer_t timeout_vt; |
|
static thread_t *_irq_handler_ctx; |
|
void radio_set_config(const struct config *config, uint8_t size); |
|
|
|
void start_receive(void); |
|
|
|
// main IRQ handler |
|
void irq_handler(void); |
|
|
|
// IRQ handler for packet receive |
|
void irq_handler_recv(uint8_t rx_status); |
|
|
|
// handle timeout IRQ |
|
void irq_timeout(void); |
|
|
|
// trampoline functions to take us from static IRQ function to class functions |
|
|
|
static void irq_handler_thd(void* arg); |
|
static void trigger_irq_radio_event(void); |
|
static void trigger_timeout_event(void *arg); |
|
|
|
static const uint8_t max_channels = 16; |
|
|
|
uint32_t last_debug_print_ms; |
|
|
|
void print_debug_info(void); |
|
|
|
AP_Radio::stats stats; |
|
AP_Radio::stats last_stats; |
|
|
|
enum dsm_protocol { |
|
DSM_NONE = 0, // not bound yet |
|
DSM_DSM2_1 = 0x01, // The original DSM2 protocol with 1 packet of data |
|
DSM_DSM2_2 = 0x02, // The original DSM2 protocol with 2 packets of data |
|
DSM_DSMX_1 = 0xA2, // The original DSMX protocol with 1 packet of data |
|
DSM_DSMX_2 = 0xB2, // The original DSMX protocol with 2 packets of data |
|
}; |
|
|
|
enum dsm2_sync { |
|
DSM2_SYNC_A, |
|
DSM2_SYNC_B, |
|
DSM2_OK |
|
}; |
|
|
|
// semaphore between ISR and main thread |
|
HAL_Semaphore sem; |
|
|
|
// dsm config data and status |
|
struct { |
|
uint8_t channels[23]; |
|
enum dsm_protocol protocol; |
|
uint8_t mfg_id[4]; |
|
uint8_t current_channel; |
|
uint8_t current_rf_channel; |
|
uint16_t crc_seed; |
|
uint8_t sop_col; |
|
uint8_t data_col; |
|
uint8_t last_sop_code[8]; |
|
uint8_t last_data_code[16]; |
|
|
|
uint32_t receive_start_us; |
|
uint32_t receive_timeout_msec; |
|
|
|
uint32_t last_recv_us; |
|
uint32_t last_parse_us; |
|
uint32_t last_recv_chan; |
|
uint32_t last_chan_change_us; |
|
uint16_t num_channels; |
|
uint16_t pwm_channels[max_channels]; |
|
bool need_bind_save; |
|
enum dsm2_sync sync; |
|
uint32_t crc_errors; |
|
float rssi; |
|
bool last_discrc; |
|
uint8_t last_transmit_power; |
|
uint32_t send_irq_count; |
|
uint32_t send_count; |
|
uint16_t pkt_time1 = 3000; |
|
uint16_t pkt_time2 = 7000; |
|
uint8_t tx_firmware_year; |
|
uint8_t tx_firmware_month; |
|
uint8_t tx_firmware_day; |
|
int8_t forced_channel = -1; |
|
uint8_t tx_rssi; |
|
uint8_t tx_pps; |
|
uint32_t last_autobind_send; |
|
bool have_tx_pps; |
|
uint32_t telem_send_count; |
|
uint8_t tx_bl_version; |
|
} dsm; |
|
|
|
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; |
|
|
|
// bind structure saved to storage |
|
static const uint16_t bind_magic = 0x43F6; |
|
struct PACKED bind_info { |
|
uint16_t magic; |
|
uint8_t mfg_id[4]; |
|
enum dsm_protocol protocol; |
|
}; |
|
|
|
struct telem_status t_status; |
|
|
|
// DSM specific functions |
|
void dsm_set_channel(uint8_t channel, bool is_dsm2, uint8_t sop_col, uint8_t data_col, uint16_t crc_seed); |
|
|
|
// generate DSMX channels |
|
void dsm_generate_channels_dsmx(uint8_t mfg_id[4], uint8_t channels[23]); |
|
|
|
// setup for DSMX transfers |
|
void dsm_setup_transfer_dsmx(void); |
|
|
|
// choose channel to receive on |
|
void dsm_choose_channel(void); |
|
|
|
// map for mode1/mode2 |
|
void map_stick_mode(uint16_t *channels); |
|
|
|
// parse DSM channels from a packet |
|
bool parse_dsm_channels(const uint8_t *data); |
|
|
|
// process an incoming packet |
|
void process_packet(const uint8_t *pkt, uint8_t len); |
|
|
|
// process an incoming bind packet |
|
void process_bind(const uint8_t *pkt, uint8_t len); |
|
|
|
// load bind info from storage |
|
void load_bind_info(void); |
|
|
|
// save bind info to storage |
|
void save_bind_info(void); |
|
|
|
bool is_DSM2(void); |
|
|
|
// send a 16 byte packet |
|
void transmit16(const uint8_t data[16]); |
|
|
|
void send_telem_packet(void); |
|
void irq_handler_send(uint8_t tx_status); |
|
|
|
void send_FCC_test_packet(void); |
|
|
|
// check sending of fw upload ack |
|
void check_fw_ack(void); |
|
|
|
// re-sync DSM2 |
|
void dsm2_start_sync(void); |
|
|
|
// check for double binding |
|
void check_double_bind(void); |
|
|
|
// setup a timeout handler |
|
void setup_timeout(uint32_t timeout_ms); |
|
}; |
|
|
|
#endif
|
|
|