1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-19 04:52:12 +01:00

Merged in webbbn/librepilot/LP-190-add-openlrsng-rx-support-to-oplink (pull request #278)

LP 190 add openlrsng rx support to oplink
This commit is contained in:
Alessio Morale 2016-07-16 16:29:56 +02:00
commit efc8f3337e
40 changed files with 5166 additions and 1841 deletions

View File

@ -91,6 +91,8 @@ SRC += $(PIOSCOMMON)/pios_srxl.c
SRC += $(PIOSCOMMON)/pios_exbus.c
SRC += $(PIOSCOMMON)/pios_sdcard.c
SRC += $(PIOSCOMMON)/pios_sensors.c
SRC += $(PIOSCOMMON)/pios_openlrs.c
SRC += $(PIOSCOMMON)/pios_openlrs_rcvr.c
## Misc library functions
SRC += $(FLIGHTLIB)/sanitycheck.c
@ -111,6 +113,8 @@ SRC += $(PIOSCOMMON)/pios_com_msg.c
SRC += $(PIOSCOMMON)/pios_crc.c
SRC += $(PIOSCOMMON)/pios_deltatime.c
SRC += $(PIOSCOMMON)/pios_led.c
SRC += $(PIOSCOMMON)/pios_semaphore.c
SRC += $(PIOSCOMMON)/pios_thread.c
ifneq ($(PIOS_OMITS_USB),YES)
## PIOS USB related files

View File

@ -153,21 +153,21 @@ static void systemTask(__attribute__((unused)) void *parameters)
// Get the stats from the radio device
struct rfm22b_stats radio_stats;
PIOS_RFM22B_GetStats(pios_rfm22b_id, &radio_stats);
oplinkStatus.HeapRemaining = xPortGetFreeHeapSize();
if (pios_rfm22b_id) {
// Update the status
oplinkStatus.HeapRemaining = xPortGetFreeHeapSize();
oplinkStatus.DeviceID = PIOS_RFM22B_DeviceID(pios_rfm22b_id);
oplinkStatus.RxGood = radio_stats.rx_good;
oplinkStatus.RxCorrected = radio_stats.rx_corrected;
oplinkStatus.RxErrors = radio_stats.rx_error;
oplinkStatus.RxMissed = radio_stats.rx_missed;
oplinkStatus.RxFailure = radio_stats.rx_failure;
oplinkStatus.TxDropped = radio_stats.tx_dropped;
oplinkStatus.TxFailure = radio_stats.tx_failure;
oplinkStatus.DeviceID = PIOS_RFM22B_DeviceID(pios_rfm22b_id);
oplinkStatus.RxGood = radio_stats.rx_good;
oplinkStatus.RxCorrected = radio_stats.rx_corrected;
oplinkStatus.RxErrors = radio_stats.rx_error;
oplinkStatus.RxMissed = radio_stats.rx_missed;
oplinkStatus.RxFailure = radio_stats.rx_failure;
oplinkStatus.TxDropped = radio_stats.tx_dropped;
oplinkStatus.TxFailure = radio_stats.tx_failure;
oplinkStatus.Resets = radio_stats.resets;
oplinkStatus.Timeouts = radio_stats.timeouts;
oplinkStatus.RSSI = radio_stats.rssi;
oplinkStatus.RSSI = radio_stats.rssi;
oplinkStatus.LinkQuality = radio_stats.link_quality;
if (first_time) {
first_time = false;
@ -190,8 +190,6 @@ static void systemTask(__attribute__((unused)) void *parameters)
oplinkStatus.TXSeq = radio_stats.tx_seq;
oplinkStatus.RXSeq = radio_stats.rx_seq;
oplinkStatus.LinkState = radio_stats.link_state;
} else {
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED;
}
if (radio_stats.link_state == OPLINKSTATUS_LINKSTATE_CONNECTED) {

View File

@ -131,7 +131,7 @@ static int32_t RadioComBridgeStart(void)
OPLinkSettingsGet(&oplinkSettings);
// Check if this is the coordinator modem
data->isCoordinator = (oplinkSettings.Coordinator == OPLINKSETTINGS_COORDINATOR_TRUE);
data->isCoordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR);
// We will not parse/send UAVTalk if any ports are configured as Serial (except for over the USB HID port).
data->parseUAVTalk = ((oplinkSettings.MainPort != OPLINKSETTINGS_MAINPORT_SERIAL) &&
@ -170,13 +170,13 @@ static int32_t RadioComBridgeStart(void)
}
// Configure our UAVObjects for updates.
UAVObjConnectQueue(UAVObjGetByID(OPLINKSTATUS_OBJID), data->uavtalkEventQueue, EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ);
UAVObjConnectQueue(UAVObjGetByID(OBJECTPERSISTENCE_OBJID), data->uavtalkEventQueue, EV_UPDATED | EV_UPDATED_MANUAL);
if (data->isCoordinator) {
UAVObjConnectQueue(UAVObjGetByID(OPLINKRECEIVER_OBJID), data->radioEventQueue, EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ);
} else {
UAVObjConnectQueue(UAVObjGetByID(OPLINKRECEIVER_OBJID), data->uavtalkEventQueue, EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ);
}
registerObject(OPLinkStatusHandle());
if (data->isCoordinator) {
registerObject(RadioComBridgeStatsHandle());
@ -475,18 +475,18 @@ static void PPMInputTask(__attribute__((unused)) void *parameters)
// Wait for the receiver semaphore.
if (xSemaphoreTake(sem, PPM_INPUT_TIMEOUT) == pdTRUE) {
// Read the receiver inputs.
for (uint8_t i = 0; i < OPLINKRECEIVER_CHANNEL_NUMELEM; ++i) {
for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) {
channels[i] = PIOS_RCVR_Read(PIOS_PPM_RECEIVER, i + 1);
}
} else {
// Failsafe
for (uint8_t i = 0; i < OPLINKRECEIVER_CHANNEL_NUMELEM; ++i) {
for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) {
channels[i] = PIOS_RCVR_INVALID;
}
}
// Pass the channel values to the radio device.
PIOS_RFM22B_PPMSet(pios_rfm22b_id, channels);
PIOS_RFM22B_PPMSet(pios_rfm22b_id, channels, RFM22B_PPM_NUM_CHANNELS);
}
}

View File

@ -676,6 +676,9 @@ static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm
case MANUALCONTROLSETTINGS_CHANNELGROUPS_OPLINK:
group = RECEIVERACTIVITY_ACTIVEGROUP_OPLINK;
break;
case MANUALCONTROLSETTINGS_CHANNELGROUPS_OPENLRS:
group = RECEIVERACTIVITY_ACTIVEGROUP_OPENLRS;
break;
default:
PIOS_Assert(0);
break;

View File

@ -266,6 +266,7 @@ static void systemTask(__attribute__((unused)) void *parameters)
// Update the OPLinkStatus UAVO
OPLinkStatusData oplinkStatus;
OPLinkStatusGet(&oplinkStatus);
oplinkStatus.HeapRemaining = xPortGetFreeHeapSize();
if (pios_rfm22b_id) {
// Get the other device stats.
@ -282,18 +283,17 @@ static void systemTask(__attribute__((unused)) void *parameters)
static uint16_t prev_tx_seq = 0;
static uint16_t prev_rx_seq = 0;
oplinkStatus.HeapRemaining = xPortGetFreeHeapSize();
oplinkStatus.DeviceID = PIOS_RFM22B_DeviceID(pios_rfm22b_id);
oplinkStatus.RxGood = radio_stats.rx_good;
oplinkStatus.RxCorrected = radio_stats.rx_corrected;
oplinkStatus.RxErrors = radio_stats.rx_error;
oplinkStatus.RxMissed = radio_stats.rx_missed;
oplinkStatus.RxFailure = radio_stats.rx_failure;
oplinkStatus.TxDropped = radio_stats.tx_dropped;
oplinkStatus.TxFailure = radio_stats.tx_failure;
oplinkStatus.DeviceID = PIOS_RFM22B_DeviceID(pios_rfm22b_id);
oplinkStatus.RxGood = radio_stats.rx_good;
oplinkStatus.RxCorrected = radio_stats.rx_corrected;
oplinkStatus.RxErrors = radio_stats.rx_error;
oplinkStatus.RxMissed = radio_stats.rx_missed;
oplinkStatus.RxFailure = radio_stats.rx_failure;
oplinkStatus.TxDropped = radio_stats.tx_dropped;
oplinkStatus.TxFailure = radio_stats.tx_failure;
oplinkStatus.Resets = radio_stats.resets;
oplinkStatus.Timeouts = radio_stats.timeouts;
oplinkStatus.RSSI = radio_stats.rssi;
oplinkStatus.RSSI = radio_stats.rssi;
oplinkStatus.LinkQuality = radio_stats.link_quality;
if (first_time) {
first_time = false;

View File

@ -272,7 +272,8 @@ int32_t TelemetryInitialize(void)
OPLinkSettingsData data;
OPLinkSettingsGet(&data);
if (data.PPMOnly) {
bool ppm_only = (data.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL);
if (ppm_only) {
radio_port = 0;
} else {
radio_port = PIOS_COM_RF;

View File

@ -0,0 +1,1513 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_RFM22B Radio Functions
* @brief PIOS OpenLRS interface for for the RFM22B radio
* @{
*
* @file pios_openlrs.c
* @author Tau Labs, http://taulabs.org, Copyright (C) 2015
* @author dRonin, http://dronin.org Copyright (C) 2015
* @author LibrePilot, http://librepilot.org Copyright (C) 2016
* @brief Implements an OpenLRS driver for the RFM22B
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_OPENLRS
#include <pios_spi_priv.h>
#include <pios_openlrs_priv.h>
#include <pios_openlrs_rcvr_priv.h>
#include <pios_semaphore.h>
#include <pios_thread.h>
#include <taskinfo.h>
#include "flightstatus.h"
#include "flightbatterystate.h"
#include "oplinksettings.h"
#include "oplinkstatus.h"
#include "pios_rfm22b_regs.h"
#define STACK_SIZE_BYTES 800
#define TASK_PRIORITY PIOS_THREAD_PRIO_NORMAL
static void rx_reset(struct pios_openlrs_dev *openlrs_dev);
static void rfmSetCarrierFrequency(struct pios_openlrs_dev *openlrs_dev, uint32_t f);
static uint8_t rfmGetRSSI(struct pios_openlrs_dev *openlrs_dev);
static void to_rx_mode(struct pios_openlrs_dev *openlrs_dev);
static void tx_packet(struct pios_openlrs_dev *openlrs_dev, uint8_t *pkt, uint8_t size);
static struct pios_openlrs_dev *pios_openlrs_alloc();
static bool pios_openlrs_validate(struct pios_openlrs_dev *openlrs_dev);
// SPI read/write functions
static void rfm22_assertCs(struct pios_openlrs_dev *openlrs_dev);
static void rfm22_deassertCs(struct pios_openlrs_dev *openlrs_dev);
static void rfm22_claimBus(struct pios_openlrs_dev *openlrs_dev);
static void rfm22_releaseBus(struct pios_openlrs_dev *openlrs_dev);
static void rfm22_write_claim(struct pios_openlrs_dev *openlrs_dev,
uint8_t addr, uint8_t data);
static void rfm22_write(struct pios_openlrs_dev *openlrs_dev, uint8_t addr,
uint8_t data);
static uint8_t rfm22_read_claim(struct pios_openlrs_dev *openlrs_dev,
uint8_t addr);
static uint8_t rfm22_read(struct pios_openlrs_dev *openlrs_dev,
uint8_t addr);
// Private constants
const struct rfm22_modem_regs {
uint32_t bps;
uint8_t r_1c, r_1d, r_1e, r_20, r_21, r_22, r_23, r_24, r_25, r_2a, r_6e, r_6f, r_70, r_71, r_72;
} modem_params[] = {
{ 4800, 0x1a, 0x40, 0x0a, 0xa1, 0x20, 0x4e, 0xa5, 0x00, 0x1b, 0x1e, 0x27, 0x52, 0x2c, 0x23, 0x30 }, // 50000 0x00
{ 9600, 0x05, 0x40, 0x0a, 0xa1, 0x20, 0x4e, 0xa5, 0x00, 0x20, 0x24, 0x4e, 0xa5, 0x2c, 0x23, 0x30 }, // 25000 0x00
{ 19200, 0x06, 0x40, 0x0a, 0xd0, 0x00, 0x9d, 0x49, 0x00, 0x7b, 0x28, 0x9d, 0x49, 0x2c, 0x23, 0x30 }, // 25000 0x01
{ 57600, 0x05, 0x40, 0x0a, 0x45, 0x01, 0xd7, 0xdc, 0x03, 0xb8, 0x1e, 0x0e, 0xbf, 0x00, 0x23, 0x2e },
{ 125000, 0x8a, 0x40, 0x0a, 0x60, 0x01, 0x55, 0x55, 0x02, 0xad, 0x1e, 0x20, 0x00, 0x00, 0x23, 0xc8 },
};
static const uint8_t pktsizes[8] = { 0, 7, 11, 12, 16, 17, 21, 0 };
static const uint8_t OUT_FF[64] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
const uint8_t default_hop_list[] = { DEFAULT_HOPLIST };
const uint32_t packet_advance_time_us = 1500;
const uint32_t packet_timeout_us = 1000;
const struct rfm22_modem_regs bind_params =
{ 9600, 0x05, 0x40, 0x0a, 0xa1, 0x20, 0x4e, 0xa5, 0x00, 0x20, 0x24, 0x4e, 0xa5, 0x2c, 0x23, 0x30 };
static uint32_t minFreq()
{
return MIN_RFM_FREQUENCY_433;
}
static uint32_t maxFreq()
{
return MAX_RFM_FREQUENCY_433;
}
static uint32_t defCarrierFreq()
{
return DEFAULT_CARRIER_FREQUENCY_433;
}
static uint32_t bindingFreq()
{
return BINDING_FREQUENCY_433;
}
/*****************************************************************************
* OpenLRS data formatting utilities
*****************************************************************************/
static uint8_t getPacketSize(struct bind_data *bd)
{
return pktsizes[(bd->flags & 0x07)];
}
static uint32_t getInterval(struct bind_data *bd)
{
uint32_t ret;
// Sending a x byte packet on bps y takes about (emperical)
// usec = (x + 15) * 8200000 / baudrate
#define BYTES_AT_BAUD_TO_USEC(bytes, bps, div) ((uint32_t)((bytes) + (div ? 20 : 15)) * 8200000L / (uint32_t)(bps))
ret = (BYTES_AT_BAUD_TO_USEC(getPacketSize(bd), modem_params[bd->modem_params].bps, bd->flags & DIVERSITY_ENABLED) + 2000);
if (bd->flags & TELEMETRY_MASK) {
ret += (BYTES_AT_BAUD_TO_USEC(TELEMETRY_PACKETSIZE, modem_params[bd->modem_params].bps, bd->flags & DIVERSITY_ENABLED) + 1000);
}
// round up to ms
ret = ((ret + 999) / 1000) * 1000;
// enable following to limit packet rate to 50Hz at most
#ifdef LIMIT_RATE_TO_50HZ
if (ret < 20000) {
ret = 20000;
}
#endif
return ret;
}
static void unpackChannels(uint8_t config, int16_t PPM[], uint8_t *p)
{
uint8_t i;
for (i = 0; i <= (config / 2); i++) { // 4ch packed in 5 bytes
PPM[0] = (((uint16_t)p[4] & 0x03) << 8) + p[0];
PPM[1] = (((uint16_t)p[4] & 0x0c) << 6) + p[1];
PPM[2] = (((uint16_t)p[4] & 0x30) << 4) + p[2];
PPM[3] = (((uint16_t)p[4] & 0xc0) << 2) + p[3];
p += 5;
PPM += 4;
}
if (config & 1) { // 4ch packed in 1 byte;
PPM[0] = (((uint16_t)p[0] >> 6) & 3) * 333 + 12;
PPM[1] = (((uint16_t)p[0] >> 4) & 3) * 333 + 12;
PPM[2] = (((uint16_t)p[0] >> 2) & 3) * 333 + 12;
PPM[3] = (((uint16_t)p[0] >> 0) & 3) * 333 + 12;
}
}
// ! Apply the OpenLRS rescaling to the channels
static void rescaleChannels(int16_t PPM[])
{
for (uint32_t i = 0; i < OPENLRS_PPM_NUM_CHANNELS; i++) {
int16_t x = PPM[i];
int16_t ret;
if (x < 12) {
ret = 808 + x * 16;
} else if (x < 1012) {
ret = x + 988;
} else if (x < 1024) {
ret = 2000 + (x - 1011) * 16;
} else {
ret = 2192;
}
PPM[i] = ret;
}
}
static uint8_t countSetBits(uint16_t x)
{
x = x - ((x >> 1) & 0x5555);
x = (x & 0x3333) + ((x >> 2) & 0x3333);
x = x + (x >> 4);
x &= 0x0F0F;
return (x * 0x0101) >> 8;
}
/*****************************************************************************
* OpenLRS hardware access
*****************************************************************************/
#define NOP() __asm__ __volatile__ ("nop")
#define RF22B_PWRSTATE_POWERDOWN 0x00
#define RF22B_PWRSTATE_READY RFM22_opfc1_xton
#define RF22B_PWRSTATE_RX (RFM22_opfc1_rxon | RFM22_opfc1_xton)
#define RF22B_PWRSTATE_TX (RFM22_opfc1_txon | RFM22_opfc1_xton)
#define RF22B_PACKET_SENT_INTERRUPT RFM22_ie1_enpksent
#define RF22B_RX_PACKET_RECEIVED_IRQ RFM22_ie1_enpkvalid
static void rfmSetChannel(struct pios_openlrs_dev *openlrs_dev, uint8_t ch)
{
// DEBUG_PRINTF(3,"rfmSetChannel %d\r\n", ch);
uint8_t magicLSB = (openlrs_dev->bind_data.rf_magic & 0xff) ^ ch;
rfm22_claimBus(openlrs_dev);
rfm22_write(openlrs_dev, RFM22_frequency_hopping_channel_select, openlrs_dev->bind_data.hopchannel[ch]);
rfm22_write(openlrs_dev, RFM22_transmit_header3 + 3, magicLSB);
rfm22_write(openlrs_dev, RFM22_check_header3 + 3, magicLSB);
rfm22_releaseBus(openlrs_dev);
}
static uint8_t rfmGetRSSI(struct pios_openlrs_dev *openlrs_dev)
{
return rfm22_read_claim(openlrs_dev, 0x26);
}
static uint16_t rfmGetAFCC(struct pios_openlrs_dev *openlrs_dev)
{
return ((uint16_t)rfm22_read_claim(openlrs_dev, 0x2B) << 2) | ((uint16_t)rfm22_read_claim(openlrs_dev, 0x2C) >> 6);
}
static void setModemRegs(struct pios_openlrs_dev *openlrs_dev, const struct rfm22_modem_regs *r)
{
DEBUG_PRINTF(3, "setModemRegs\r\n");
rfm22_claimBus(openlrs_dev);
rfm22_write(openlrs_dev, RFM22_if_filter_bandwidth, r->r_1c);
rfm22_write(openlrs_dev, RFM22_afc_loop_gearshift_override, r->r_1d);
rfm22_write(openlrs_dev, RFM22_afc_timing_control, r->r_1e);
rfm22_write(openlrs_dev, RFM22_clk_recovery_oversampling_ratio, r->r_20);
rfm22_write(openlrs_dev, RFM22_clk_recovery_offset2, r->r_21);
rfm22_write(openlrs_dev, RFM22_clk_recovery_offset1, r->r_22);
rfm22_write(openlrs_dev, RFM22_clk_recovery_offset0, r->r_23);
rfm22_write(openlrs_dev, RFM22_clk_recovery_timing_loop_gain1, r->r_24);
rfm22_write(openlrs_dev, RFM22_clk_recovery_timing_loop_gain0, r->r_25);
rfm22_write(openlrs_dev, RFM22_afc_limiter, r->r_2a);
rfm22_write(openlrs_dev, RFM22_tx_data_rate1, r->r_6e);
rfm22_write(openlrs_dev, RFM22_tx_data_rate0, r->r_6f);
rfm22_write(openlrs_dev, RFM22_modulation_mode_control1, r->r_70);
rfm22_write(openlrs_dev, RFM22_modulation_mode_control2, r->r_71);
rfm22_write(openlrs_dev, RFM22_frequency_deviation, r->r_72);
rfm22_releaseBus(openlrs_dev);
}
static void rfmSetCarrierFrequency(struct pios_openlrs_dev *openlrs_dev, uint32_t f)
{
/* Protect ourselves from out-of-band frequencies. Ideally we'd latch
* an error here and prevent tx, but this is good enough to protect
* the hardware. */
if ((f < minFreq(openlrs_dev->band)) ||
(f > maxFreq(openlrs_dev->band))) {
f = defCarrierFreq(openlrs_dev->band);
}
// DEBUG_PRINTF(3,"rfmSetCarrierFrequency %d\r\n", f);
uint16_t fb, fc, hbsel;
if (f < 480000000) {
hbsel = 0;
fb = f / 10000000 - 24;
fc = (f - (fb + 24) * 10000000) * 4 / 625;
} else {
hbsel = 1;
fb = f / 20000000 - 24;
fc = (f - (fb + 24) * 20000000) * 2 / 625;
}
rfm22_claimBus(openlrs_dev);
rfm22_write(openlrs_dev, RFM22_frequency_band_select, RFM22_fbs_sbse + (hbsel ? RFM22_fbs_hbsel : 0) + (fb & RFM22_fb_mask));
rfm22_write(openlrs_dev, RFM22_nominal_carrier_frequency1, (fc >> 8));
rfm22_write(openlrs_dev, RFM22_nominal_carrier_frequency0, (fc & 0xff));
rfm22_releaseBus(openlrs_dev);
}
static void init_rfm(struct pios_openlrs_dev *openlrs_dev, uint8_t isbind)
{
DEBUG_PRINTF(2, "init_rfm %d\r\n", isbind);
if (!isbind) {
DEBUG_PRINTF(2, "Binding settings:\r\n");
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " version: %d\r\n", openlrs_dev->bind_data.version);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " serial_baudrate: %d\r\n", openlrs_dev->bind_data.serial_baudrate);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " rf_frequency: %d\r\n", openlrs_dev->bind_data.rf_frequency);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " rf_power: %d\r\n", openlrs_dev->bind_data.rf_power);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " rf_channel_spacing: %d\r\n", openlrs_dev->bind_data.rf_channel_spacing);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " modem_params: %d\r\n", openlrs_dev->bind_data.modem_params);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " flags: %d\r\n", openlrs_dev->bind_data.flags);
PIOS_Thread_Sleep(10);
}
rfm22_claimBus(openlrs_dev);
openlrs_dev->it_status1 = rfm22_read(openlrs_dev, RFM22_interrupt_status1); // read status, clear interrupt
openlrs_dev->it_status2 = rfm22_read(openlrs_dev, RFM22_interrupt_status2);
rfm22_write(openlrs_dev, RFM22_interrupt_enable2, 0x00); // disable interrupts
rfm22_write(openlrs_dev, RFM22_op_and_func_ctrl1, RF22B_PWRSTATE_READY); // disable lbd, wakeup timer, use internal 32768,xton = 1; in ready mode
rfm22_write(openlrs_dev, RFM22_xtal_osc_load_cap, 0x7f); // c = 12.5p
rfm22_write(openlrs_dev, RFM22_cpu_output_clk, 0x05);
switch (openlrs_dev->cfg.gpio_direction) {
case GPIO0_TX_GPIO1_RX:
rfm22_write(openlrs_dev, RFM22_gpio0_config, RFM22_gpio0_config_txstate); // gpio0 TX State
rfm22_write(openlrs_dev, RFM22_gpio1_config, RFM22_gpio1_config_rxstate); // gpio1 RX State
break;
case GPIO0_RX_GPIO1_TX:
rfm22_write(openlrs_dev, RFM22_gpio0_config, RFM22_gpio0_config_rxstate); // gpio0 RX State
rfm22_write(openlrs_dev, RFM22_gpio1_config, RFM22_gpio1_config_txstate); // gpio1 TX State
break;
}
rfm22_write(openlrs_dev, RFM22_gpio2_config, 0xfd); // gpio 2 VDD
rfm22_write(openlrs_dev, RFM22_io_port_config, RFM22_io_port_default); // gpio 0, 1,2 NO OTHER FUNCTION.
rfm22_releaseBus(openlrs_dev);
if (isbind) {
setModemRegs(openlrs_dev, &bind_params);
} else {
setModemRegs(openlrs_dev, &modem_params[openlrs_dev->bind_data.modem_params]);
}
// Packet settings
rfm22_claimBus(openlrs_dev);
rfm22_write(openlrs_dev, RFM22_data_access_control, 0x8c); // enable packet handler, msb first, enable crc,
rfm22_write(openlrs_dev, RFM22_header_control1, 0x0f); // no broadcast, check header bytes 3,2,1,0
rfm22_write(openlrs_dev, RFM22_header_control2, 0x42); // 4 byte header, 2 byte synch, variable pkt size
rfm22_write(openlrs_dev, RFM22_preamble_length, (openlrs_dev->bind_data.flags & DIVERSITY_ENABLED) ? 0x14 : 0x0a); // 40 bit preamble, 80 with diversity
rfm22_write(openlrs_dev, RFM22_preamble_detection_ctrl1, 0x2a); // preath = 5 (20bits), rssioff = 2
rfm22_write(openlrs_dev, RFM22_sync_word3, 0x2d); // synchronize word 3
rfm22_write(openlrs_dev, RFM22_sync_word2, 0xd4); // synchronize word 2
rfm22_write(openlrs_dev, RFM22_sync_word1, 0x00); // synch word 1 (not used)
rfm22_write(openlrs_dev, RFM22_sync_word0, 0x00); // synch word 0 (not used)
uint32_t magic = isbind ? BIND_MAGIC : openlrs_dev->bind_data.rf_magic;
for (uint8_t i = 0; i < 4; i++) {
rfm22_write(openlrs_dev, RFM22_transmit_header3 + i, (magic >> 24) & 0xff); // tx header
rfm22_write(openlrs_dev, RFM22_check_header3 + i, (magic >> 24) & 0xff); // rx header
magic = magic << 8; // advance to next byte
}
rfm22_write(openlrs_dev, RFM22_header_enable3, 0xff); // all the bit to be checked
rfm22_write(openlrs_dev, RFM22_header_enable2, 0xff); // all the bit to be checked
rfm22_write(openlrs_dev, RFM22_header_enable1, 0xff); // all the bit to be checked
rfm22_write(openlrs_dev, RFM22_header_enable0, 0xff); // all the bit to be checked
if (isbind) {
rfm22_write(openlrs_dev, RFM22_tx_power, BINDING_POWER);
} else {
rfm22_write(openlrs_dev, RFM22_tx_power, openlrs_dev->bind_data.rf_power);
}
rfm22_write(openlrs_dev, RFM22_frequency_hopping_channel_select, 0);
rfm22_write(openlrs_dev, RFM22_frequency_hopping_step_size, openlrs_dev->bind_data.rf_channel_spacing); // channel spacing
rfm22_write(openlrs_dev, RFM22_frequency_offset1, 0x00);
rfm22_write(openlrs_dev, RFM22_frequency_offset2, 0x00); // no offset
rfm22_releaseBus(openlrs_dev);
rfmSetCarrierFrequency(openlrs_dev, isbind ? bindingFreq(openlrs_dev->band) : openlrs_dev->bind_data.rf_frequency);
}
static void to_rx_mode(struct pios_openlrs_dev *openlrs_dev)
{
// DEBUG_PRINTF(3,"to_rx_mode\r\n");
rfm22_claimBus(openlrs_dev);
openlrs_dev->it_status1 = rfm22_read(openlrs_dev, RFM22_interrupt_status1);
openlrs_dev->it_status2 = rfm22_read(openlrs_dev, RFM22_interrupt_status2);
rfm22_write(openlrs_dev, RFM22_op_and_func_ctrl1, RF22B_PWRSTATE_READY);
rfm22_releaseBus(openlrs_dev);
PIOS_Thread_Sleep(10);
rx_reset(openlrs_dev);
NOP();
}
static void clearFIFO(struct pios_openlrs_dev *openlrs_dev)
{
// DEBUG_PRINTF(3,"clearFIFO\r\n");
rfm22_claimBus(openlrs_dev);
rfm22_write(openlrs_dev, RFM22_op_and_func_ctrl2, 0x03);
rfm22_write(openlrs_dev, RFM22_op_and_func_ctrl2, 0x00);
rfm22_releaseBus(openlrs_dev);
}
static void rx_reset(struct pios_openlrs_dev *openlrs_dev)
{
// DEBUG_PRINTF(3,"rx_reset\r\n");
rfm22_write_claim(openlrs_dev, RFM22_op_and_func_ctrl1, RF22B_PWRSTATE_READY);
rfm22_write_claim(openlrs_dev, RFM22_rx_fifo_control, 36); // threshold for rx almost full, interrupt when 1 byte received
clearFIFO(openlrs_dev);
rfm22_claimBus(openlrs_dev);
rfm22_write(openlrs_dev, RFM22_op_and_func_ctrl1, RF22B_PWRSTATE_RX); // to rx mode
rfm22_write(openlrs_dev, RFM22_interrupt_enable1, RF22B_RX_PACKET_RECEIVED_IRQ);
openlrs_dev->it_status1 = rfm22_read(openlrs_dev, RFM22_interrupt_status1); // read the Interrupt Status1 register
openlrs_dev->it_status2 = rfm22_read(openlrs_dev, RFM22_interrupt_status2);
rfm22_releaseBus(openlrs_dev);
}
// TODO: move into dev structure
uint32_t tx_start = 0;
static void tx_packet_async(struct pios_openlrs_dev *openlrs_dev, uint8_t *pkt, uint8_t size)
{
rfm22_claimBus(openlrs_dev);
rfm22_write(openlrs_dev, RFM22_transmit_packet_length, size); // total tx size
for (uint8_t i = 0; i < size; i++) {
rfm22_write(openlrs_dev, RFM22_fifo_access, pkt[i]);
}
rfm22_write(openlrs_dev, RFM22_interrupt_enable1, RF22B_PACKET_SENT_INTERRUPT);
openlrs_dev->it_status1 = rfm22_read(openlrs_dev, RFM22_interrupt_status1); // read the Interrupt Status1 register
openlrs_dev->it_status2 = rfm22_read(openlrs_dev, RFM22_interrupt_status2);
tx_start = PIOS_DELAY_GetuS();
rfm22_write(openlrs_dev, RFM22_op_and_func_ctrl1, RF22B_PWRSTATE_TX); // to tx mode
rfm22_releaseBus(openlrs_dev);
openlrs_dev->rf_mode = Transmit;
}
static void tx_packet(struct pios_openlrs_dev *openlrs_dev, uint8_t *pkt, uint8_t size)
{
tx_packet_async(openlrs_dev, pkt, size);
PIOS_Semaphore_Take(openlrs_dev->sema_isr, 25);
#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_RFM22B)
// Update the watchdog timer
PIOS_WDG_UpdateFlag(PIOS_WDG_RFM22B);
#endif /* PIOS_WDG_RFM22B */
if (openlrs_dev->rf_mode == Transmit) {
DEBUG_PRINTF(2, "OLRS ERR: tx_packet timeout\r\n");
init_rfm(openlrs_dev, false); // reset modem
}
}
static void beacon_tone(struct pios_openlrs_dev *openlrs_dev, int16_t hz, int16_t len __attribute__((unused))) // duration is now in half seconds.
{
DEBUG_PRINTF(2, "beacon_tone: %d %d\r\n", hz, len * 2);
int16_t d = 500000 / hz; // better resolution
#if defined(PIOS_LED_LINK)
PIOS_LED_On(PIOS_LED_LINK);
#endif /* PIOS_LED_LINK */
if (d < 1) {
d = 1;
}
rfm22_claimBus(openlrs_dev);
// This need fixed for F1
#ifdef GPIO_Mode_OUT
GPIO_TypeDef *gpio = openlrs_dev->cfg.spi_cfg->mosi.gpio;
uint16_t pin_source = openlrs_dev->cfg.spi_cfg->mosi.init.GPIO_Pin;
uint8_t remap = openlrs_dev->cfg.spi_cfg->remap;
GPIO_InitTypeDef init = {
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_OUT,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_UP
};
init.GPIO_Pin = pin_source;
// Set MOSI to digital out for bit banging
GPIO_PinAFConfig(gpio, pin_source, 0);
GPIO_Init(gpio, &init);
uint32_t raw_time = PIOS_DELAY_GetRaw();
int16_t cycles = (len * 500000 / d);
for (int16_t i = 0; i < cycles; i++) {
GPIO_SetBits(gpio, pin_source);
PIOS_DELAY_WaituS(d);
GPIO_ResetBits(gpio, pin_source);
PIOS_DELAY_WaituS(d);
// Make sure to give other tasks time to do things
if (PIOS_DELAY_DiffuS(raw_time) > 10000) {
PIOS_Thread_Sleep(1);
raw_time = PIOS_DELAY_GetRaw();
}
}
GPIO_Init(gpio, (GPIO_InitTypeDef *)&openlrs_dev->cfg.spi_cfg->mosi.init);
GPIO_PinAFConfig(gpio, pin_source, remap);
#endif /* ifdef GPIO_Mode_OUT */
rfm22_releaseBus(openlrs_dev);
#if defined(PIOS_LED_LINK)
PIOS_LED_Off(PIOS_LED_LINK);
#endif /* PIOS_LED_LINK */
#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_RFM22B)
// Update the watchdog timer
PIOS_WDG_UpdateFlag(PIOS_WDG_RFM22B);
#endif /* PIOS_WDG_RFM22B */
}
static uint8_t beaconGetRSSI(struct pios_openlrs_dev *openlrs_dev)
{
uint16_t rssiSUM = 0;
rfmSetCarrierFrequency(openlrs_dev, openlrs_dev->beacon_frequency);
rfm22_write_claim(openlrs_dev, RFM22_frequency_hopping_channel_select, 0); // ch 0 to avoid offset
PIOS_Thread_Sleep(1);
rssiSUM += rfmGetRSSI(openlrs_dev);
PIOS_Thread_Sleep(1);
rssiSUM += rfmGetRSSI(openlrs_dev);
PIOS_Thread_Sleep(1);
rssiSUM += rfmGetRSSI(openlrs_dev);
PIOS_Thread_Sleep(1);
rssiSUM += rfmGetRSSI(openlrs_dev);
return rssiSUM >> 2;
}
static void beacon_send(struct pios_openlrs_dev *openlrs_dev, bool static_tone)
{
DEBUG_PRINTF(2, "beacon_send\r\n");
rfm22_claimBus(openlrs_dev);
openlrs_dev->it_status1 = rfm22_read(openlrs_dev, 0x03); // read status, clear interrupt
openlrs_dev->it_status2 = rfm22_read(openlrs_dev, 0x04);
rfm22_write(openlrs_dev, 0x06, 0x00); // no wakeup up, lbd,
rfm22_write(openlrs_dev, 0x07, RF22B_PWRSTATE_READY); // disable lbd, wakeup timer, use internal 32768,xton = 1; in ready mode
rfm22_write(openlrs_dev, 0x09, 0x7f); // (default) c = 12.5p
rfm22_write(openlrs_dev, 0x0a, 0x05);
rfm22_write(openlrs_dev, 0x0b, 0x12); // gpio0 TX State
rfm22_write(openlrs_dev, 0x0c, 0x15); // gpio1 RX State
rfm22_write(openlrs_dev, 0x0d, 0xfd); // gpio 2 micro-controller clk output
rfm22_write(openlrs_dev, 0x0e, 0x00); // gpio 0, 1,2 NO OTHER FUNCTION.
rfm22_write(openlrs_dev, 0x70, 0x2C); // disable manchest
rfm22_write(openlrs_dev, 0x30, 0x00); // disable packet handling
rfm22_write(openlrs_dev, 0x79, 0); // start channel
rfm22_write(openlrs_dev, 0x7a, 0x05); // 50khz step size (10khz x value) // no hopping
rfm22_write(openlrs_dev, 0x71, 0x12); // trclk=[00] no clock, dtmod=[01] direct using SPI, fd8=0 eninv=0 modtyp=[10] FSK
rfm22_write(openlrs_dev, 0x72, 0x02); // fd (frequency deviation) 2*625Hz == 1.25kHz
rfm22_write(openlrs_dev, 0x73, 0x00);
rfm22_write(openlrs_dev, 0x74, 0x00); // no offset
rfm22_releaseBus(openlrs_dev);
rfmSetCarrierFrequency(openlrs_dev, openlrs_dev->beacon_frequency);
rfm22_write_claim(openlrs_dev, 0x6d, 0x07); // 7 set max power 100mW
PIOS_Thread_Sleep(10);
rfm22_write_claim(openlrs_dev, 0x07, RF22B_PWRSTATE_TX); // to tx mode
PIOS_Thread_Sleep(10);
if (static_tone) {
uint8_t i = 0;
while (i++ < 20) {
beacon_tone(openlrs_dev, 440, 1);
}
} else {
// close encounters tune
// G, A, F, F(lower octave), C
// octave 3: 392 440 349 175 261
beacon_tone(openlrs_dev, 392, 1);
rfm22_write(openlrs_dev, 0x6d, 0x05); // 5 set mid power 25mW
PIOS_Thread_Sleep(10);
beacon_tone(openlrs_dev, 440, 1);
rfm22_write(openlrs_dev, 0x6d, 0x04); // 4 set mid power 13mW
PIOS_Thread_Sleep(10);
beacon_tone(openlrs_dev, 349, 1);
rfm22_write(openlrs_dev, 0x6d, 0x02); // 2 set min power 3mW
PIOS_Thread_Sleep(10);
beacon_tone(openlrs_dev, 175, 1);
rfm22_write(openlrs_dev, 0x6d, 0x00); // 0 set min power 1.3mW
PIOS_Thread_Sleep(10);
beacon_tone(openlrs_dev, 261, 2);
}
rfm22_write_claim(openlrs_dev, 0x07, RF22B_PWRSTATE_READY);
}
/*****************************************************************************
* High level OpenLRS functions
*****************************************************************************/
// TODO: these should move into device structure, or deleted
// if not useful to be reported via GCS
#define ntohl(v) \
( \
(((v) & 0xFF000000) >> 24) | \
(((v) & 0x00FF0000) >> 8) | \
(((v) & 0x0000FF00) << 8) | \
(((v) & 0x000000FF) << 24))
static uint8_t pios_openlrs_bind_receive(struct pios_openlrs_dev *openlrs_dev, uint32_t timeout)
{
uint32_t start = PIOS_Thread_Systime();
uint8_t rxb;
init_rfm(openlrs_dev, true);
// TODO: move openlrs_dev->rf_mode into dev structure
openlrs_dev->rf_mode = Receive;
to_rx_mode(openlrs_dev);
DEBUG_PRINTF(2, "Waiting bind\r\n");
DEBUG_PRINTF(2, "timeout: %d\r\n", timeout);
DEBUG_PRINTF(2, "start: %d\r\n", start);
uint32_t i = 0;
while ((!timeout) || ((PIOS_Thread_Systime() - start) < timeout)) {
PIOS_Thread_Sleep(1);
#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_RFM22B)
// Update the watchdog timer
PIOS_WDG_UpdateFlag(PIOS_WDG_RFM22B);
#endif /* PIOS_WDG_RFM22B */
if (i++ % 100 == 0) {
// DEBUG_PRINTF(2,"Waiting bind\r\n");
#if defined(PIOS_LED_LINK)
PIOS_LED_Toggle(PIOS_LED_LINK);
#endif /* PIOS_LED_LINK */
}
if (openlrs_dev->rf_mode == Received) {
DEBUG_PRINTF(2, "Got pkt\r\n");
// TODO: parse data packet (write command for that)
rfm22_claimBus(openlrs_dev);
rfm22_assertCs(openlrs_dev);
PIOS_SPI_TransferByte(openlrs_dev->spi_id, 0x7f);
rxb = PIOS_SPI_TransferByte(openlrs_dev->spi_id, 0x00);
if (rxb == 'b') {
PIOS_SPI_TransferBlock(openlrs_dev->spi_id, OUT_FF,
(uint8_t *)&openlrs_dev->bind_data, sizeof(struct bind_data), NULL);
rfm22_deassertCs(openlrs_dev);
rfm22_releaseBus(openlrs_dev);
#if defined(PIOS_INCLUDE_DEBUG_CONSOLE)
if (2 <= DEBUG_LEVEL && pios_com_debug_id > 0) {
DEBUG_PRINTF(2, "Binding settings:\r\n");
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " version: %d\r\n", openlrs_dev->bind_data.version);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " serial_baudrate: %d\r\n", openlrs_dev->bind_data.serial_baudrate);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " rf_frequency: %d\r\n", openlrs_dev->bind_data.rf_frequency);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " rf_power: %d\r\n", openlrs_dev->bind_data.rf_power);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " rf_channel_spacing: %d\r\n", openlrs_dev->bind_data.rf_channel_spacing);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " modem_params: %d\r\n", openlrs_dev->bind_data.modem_params);
PIOS_Thread_Sleep(10);
DEBUG_PRINTF(2, " flags: %d\r\n", openlrs_dev->bind_data.flags);
PIOS_Thread_Sleep(10);
for (uint32_t j = 0; j < MAXHOPS; j++) {
DEBUG_PRINTF(2, " hop channel: %d\r\n", openlrs_dev->bind_data.hopchannel[j]);
PIOS_Thread_Sleep(10);
}
}
#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */
if (openlrs_dev->bind_data.version == BINDING_VERSION) {
DEBUG_PRINTF(2, "data good\r\n");
rxb = 'B';
tx_packet(openlrs_dev, &rxb, 1); // ACK that we got bound
OPLinkSettingsData binding;
OPLinkSettingsGet(&binding);
binding.Version = openlrs_dev->bind_data.version;
binding.SerialBaudrate = openlrs_dev->bind_data.serial_baudrate;
binding.RFFrequency = openlrs_dev->bind_data.rf_frequency;
binding.CoordID = openlrs_dev->bind_data.rf_magic;
binding.RFPower = openlrs_dev->bind_data.rf_power;
binding.RFChannelSpacing = openlrs_dev->bind_data.rf_channel_spacing;
binding.ModemParams = openlrs_dev->bind_data.modem_params;
binding.Flags = openlrs_dev->bind_data.flags;
for (uint32_t j = 0; j < OPLINKSETTINGS_HOPCHANNEL_NUMELEM; j++) {
binding.HopChannel[j] = openlrs_dev->bind_data.hopchannel[j];
}
binding.BeaconFrequency = openlrs_dev->beacon_frequency;
binding.BeaconDelay = openlrs_dev->beacon_delay;
binding.BeaconPeriod = openlrs_dev->beacon_period;
OPLinkSettingsSet(&binding);
UAVObjSave(OPLinkSettingsHandle(), 0);
#if defined(PIOS_LED_LINK)
PIOS_LED_Toggle(PIOS_LED_LINK);
#endif /* PIOS_LED_LINK */
return 1;
}
} else {
rfm22_deassertCs(openlrs_dev);
rfm22_releaseBus(openlrs_dev);
}
openlrs_dev->rf_mode = Receive;
rx_reset(openlrs_dev);
}
}
return 0;
}
#if defined(PIOS_INCLUDE_DEBUG_CONSOLE)
static void printVersion(uint16_t v)
{
char ver[8];
ver[0] = '0' + ((v >> 8) & 0x0f);
ver[1] = '.';
ver[2] = '0' + ((v >> 4) & 0x0f);
if (v & 0x0f) {
ver[3] = '.';
ver[4] = '0' + (v & 0x0f);
ver[5] = '\r';
ver[6] = '\n';
ver[7] = '\0';
} else {
ver[3] = '\r';
ver[4] = '\n';
ver[5] = '\0';
}
DEBUG_PRINTF(2, ver);
}
#endif /* if defined(PIOS_INCLUDE_DEBUG_CONSOLE) */
static void pios_openlrs_setup(struct pios_openlrs_dev *openlrs_dev, bool bind)
{
DEBUG_PRINTF(2, "OpenLRSng RX setup starting. Binding: %e\r\n", bind);
PIOS_Thread_Sleep(5);
#if defined(PIOS_INCLUDE_DEBUG_CONSOLE)
printVersion(OPENLRSNG_VERSION);
#endif
// Get the OPLinkStatus UAVO
OPLinkStatusData oplink_status;
OPLinkStatusGet(&oplink_status);
if (bind) {
oplink_status.LinkState = OPLINKSTATUS_LINKSTATE_BINDING;
if (pios_openlrs_bind_receive(openlrs_dev, 0)) {
// TODO: save binding settings bindWriteEeprom();
DEBUG_PRINTF(2, "Saved bind data to EEPROM (not really yet -- TODO)\r\n");
}
}
oplink_status.LinkState = OPLINKSTATUS_LINKSTATE_BOUND;
DEBUG_PRINTF(2, "Entering normal mode\r\n");
init_rfm(openlrs_dev, 0); // Configure the RFM22B's registers for normal operation
openlrs_dev->rf_channel = 0;
rfmSetChannel(openlrs_dev, openlrs_dev->rf_channel);
// Count hopchannels as we need it later
openlrs_dev->hopcount = 0;
while ((openlrs_dev->hopcount < MAXHOPS) && (openlrs_dev->bind_data.hopchannel[openlrs_dev->hopcount] != 0)) {
openlrs_dev->hopcount++;
}
// ################### RX SYNC AT STARTUP #################
openlrs_dev->rf_mode = Receive;
to_rx_mode(openlrs_dev);
openlrs_dev->link_acquired = 0;
openlrs_dev->lastPacketTimeUs = PIOS_DELAY_GetuS();
// Update the OPLinkStatus UAVO
OPLinkStatusSet(&oplink_status);
DEBUG_PRINTF(2, "OpenLRSng RX setup complete\r\n");
}
static void pios_openlrs_rx_loop(struct pios_openlrs_dev *openlrs_dev)
{
uint32_t timeUs, timeMs;
#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_RFM22B)
// Update the watchdog timer
PIOS_WDG_UpdateFlag(PIOS_WDG_RFM22B);
#endif /* PIOS_WDG_RFM22B */
if (rfm22_read_claim(openlrs_dev, 0x0C) == 0) { // detect the locked module and reboot
DEBUG_PRINTF(2, "OLRS ERR: RX hang\r\n");
init_rfm(openlrs_dev, 0);
to_rx_mode(openlrs_dev);
}
// Get the OPLinkStatus UAVO
OPLinkStatusData oplink_status;
OPLinkStatusGet(&oplink_status);
// Update the RSSI
oplink_status.RSSI = openlrs_dev->rssi;
timeUs = PIOS_DELAY_GetuS();
timeMs = PIOS_Thread_Systime();
// DEBUG_PRINTF(2,"Time: %d\r\n", timeUs);
uint8_t *tx_buf = openlrs_dev->tx_buf; // convenient variable
if (openlrs_dev->rf_mode == Received) {
DEBUG_PRINTF(2, "Packet Received. Dt=%d\r\n", timeUs - openlrs_dev->lastPacketTimeUs);
// Read the packet from RFM22b
rfm22_claimBus(openlrs_dev);
rfm22_assertCs(openlrs_dev);
PIOS_SPI_TransferByte(openlrs_dev->spi_id, 0x7F);
uint32_t packet_size = getPacketSize(&openlrs_dev->bind_data);
PIOS_SPI_TransferBlock(openlrs_dev->spi_id, OUT_FF,
openlrs_dev->rx_buf, packet_size, NULL);
rfm22_deassertCs(openlrs_dev);
rfm22_releaseBus(openlrs_dev);
openlrs_dev->lastAFCCvalue = rfmGetAFCC(openlrs_dev);
#if defined(PIOS_LED_LINK)
PIOS_LED_Toggle(PIOS_LED_LINK);
#endif /* PIOS_LED_LINK */
openlrs_dev->lastPacketTimeUs = timeUs;
openlrs_dev->numberOfLostPackets = 0;
oplink_status.LinkQuality <<= 1;
oplink_status.LinkQuality |= 1;
if ((openlrs_dev->rx_buf[0] & 0x3e) == 0x00) {
// This flag indicates receiving PPM data
unpackChannels(openlrs_dev->bind_data.flags & 7, openlrs_dev->ppm, openlrs_dev->rx_buf + 1);
rescaleChannels(openlrs_dev->ppm);
// Call the PPM received callback if it's available.
if (openlrs_dev->openlrs_rcvr_id) {
#if defined(PIOS_INCLUDE_OPENLRS_RCVR)
PIOS_OpenLRS_Rcvr_UpdateChannels(openlrs_dev->openlrs_rcvr_id, openlrs_dev->ppm);
#endif
}
if (openlrs_dev->ppm_callback) {
openlrs_dev->ppm_callback(openlrs_dev->ppm);
}
} else {
// Not PPM data. Push into serial RX buffer.
if ((openlrs_dev->rx_buf[0] & 0x38) == 0x38) {
if ((openlrs_dev->rx_buf[0] ^ tx_buf[0]) & 0x80) {
// We got new data... (not retransmission)
tx_buf[0] ^= 0x80; // signal that we got it
bool rx_need_yield;
uint8_t data_len = openlrs_dev->rx_buf[0] & 7;
if (openlrs_dev->rx_in_cb && (data_len > 0)) {
(openlrs_dev->rx_in_cb)(openlrs_dev->rx_in_context, &openlrs_dev->rx_buf[1], data_len, NULL, &rx_need_yield);
}
}
}
}
// Flag to indicate ever got a link
openlrs_dev->link_acquired |= true;
oplink_status.LinkState = OPLINKSTATUS_LINKSTATE_CONNECTED;
openlrs_dev->beacon_armed = false; // when receiving packets make sure beacon cannot emit
// When telemetry is enabled we ack packets and send info about FC back
if (openlrs_dev->bind_data.flags & TELEMETRY_MASK) {
if ((tx_buf[0] ^ openlrs_dev->rx_buf[0]) & 0x40) {
// resend last message
} else {
tx_buf[0] &= 0xc0;
tx_buf[0] ^= 0x40; // swap sequence as we have new data
// Check for data on serial link
uint8_t bytes = 0;
// Append data from the com interface if applicable.
if (openlrs_dev->tx_out_cb) {
// Try to get some data to send
bool need_yield = false;
bytes = (openlrs_dev->tx_out_cb)(openlrs_dev->tx_out_context, &tx_buf[1], 8, NULL, &need_yield);
}
if (bytes > 0) {
tx_buf[0] |= (0x37 + bytes);
} else {
// tx_buf[0] lowest 6 bits left at 0
tx_buf[1] = openlrs_dev->rssi;
if (FlightBatteryStateHandle()) {
FlightBatteryStateData bat;
FlightBatteryStateGet(&bat);
// FrSky protocol normally uses 3.3V at 255 but
// divider from display can be set internally
tx_buf[2] = (uint8_t)bat.Voltage / 25.0f * 255;
tx_buf[3] = (uint8_t)bat.Current / 60.0f * 255;
} else {
tx_buf[2] = 0; // these bytes carry analog info. package
tx_buf[3] = 0; // battery here
}
tx_buf[4] = (openlrs_dev->lastAFCCvalue >> 8);
tx_buf[5] = openlrs_dev->lastAFCCvalue & 0xff;
tx_buf[6] = countSetBits(oplink_status.LinkQuality & 0x7fff);
}
}
// This will block until sent
tx_packet(openlrs_dev, tx_buf, 9);
}
// Once a packet has been processed, flip back into receiving mode
openlrs_dev->rf_mode = Receive;
rx_reset(openlrs_dev);
openlrs_dev->willhop = 1;
}
if (openlrs_dev->link_acquired) {
// For missing packets to be properly trigger a well timed channel hop, this method should be called fairly close (but not sooner)
// than 1ms after the packet was expected to trigger this path
if ((openlrs_dev->numberOfLostPackets < openlrs_dev->hopcount) && (PIOS_DELAY_GetuSSince(openlrs_dev->lastPacketTimeUs) > (getInterval(&openlrs_dev->bind_data) + packet_timeout_us))) {
DEBUG_PRINTF(2, "OLRS WARN: Lost packet: %d\r\n", openlrs_dev->numberOfLostPackets);
// we lost packet, hop to next channel
oplink_status.LinkQuality <<= 1;
openlrs_dev->willhop = 1;
if (openlrs_dev->numberOfLostPackets == 0) {
openlrs_dev->linkLossTimeMs = timeMs;
openlrs_dev->nextBeaconTimeMs = 0;
}
openlrs_dev->numberOfLostPackets++;
openlrs_dev->lastPacketTimeUs += getInterval(&openlrs_dev->bind_data);
openlrs_dev->willhop = 1;
} else if ((openlrs_dev->numberOfLostPackets >= openlrs_dev->hopcount) && (PIOS_DELAY_GetuSSince(openlrs_dev->lastPacketTimeUs) > (getInterval(&openlrs_dev->bind_data) * openlrs_dev->hopcount))) {
DEBUG_PRINTF(2, "ORLS WARN: Trying to resync\r\n");
// hop slowly to allow resync with TX
oplink_status.LinkQuality = 0;
openlrs_dev->willhop = 1;
openlrs_dev->lastPacketTimeUs = timeUs;
}
if (openlrs_dev->numberOfLostPackets) {
#if defined(PIOS_LED_LINK)
PIOS_LED_Off(PIOS_LED_LINK);
#endif /* PIOS_LED_LINK */
if (openlrs_dev->failsafeDelay &&
(oplink_status.LinkState == OPLINKSTATUS_LINKSTATE_CONNECTED) &&
((timeMs - openlrs_dev->linkLossTimeMs) > ((uint32_t)openlrs_dev->failsafeDelay))) {
DEBUG_PRINTF(2, "Failsafe activated: %d %d\r\n", timeMs, openlrs_dev->linkLossTimeMs);
oplink_status.LinkState = OPLINKSTATUS_LINKSTATE_DISCONNECTED;
// failsafeApply();
openlrs_dev->nextBeaconTimeMs = (timeMs + 1000UL * openlrs_dev->beacon_period) | 1; // beacon activating...
}
if ((openlrs_dev->beacon_frequency) && (openlrs_dev->nextBeaconTimeMs) &&
((timeMs - openlrs_dev->nextBeaconTimeMs) < 0x80000000)) {
// Indicate that the beacon is now active so we can trigger extra ones below
openlrs_dev->beacon_armed = true;
DEBUG_PRINTF(2, "Beacon time: %d\r\n", openlrs_dev->nextBeaconTimeMs);
// Only beacon when disarmed
uint8_t armed;
FlightStatusArmedGet(&armed);
if (armed == FLIGHTSTATUS_ARMED_DISARMED) {
beacon_send(openlrs_dev, false); // play cool tune
init_rfm(openlrs_dev, 0); // go back to normal RX
rx_reset(openlrs_dev);
openlrs_dev->nextBeaconTimeMs = (timeMs + 1000UL * openlrs_dev->beacon_period) | 1; // avoid 0 in time
}
}
}
} else {
// Waiting for first packet, hop slowly
if (PIOS_DELAY_GetuSSince(openlrs_dev->lastPacketTimeUs) > (getInterval(&openlrs_dev->bind_data) * openlrs_dev->hopcount)) {
// DEBUG_PRINTF(3,"Trying to get first packet\r\n");
openlrs_dev->lastPacketTimeUs = timeUs;
openlrs_dev->willhop = 1;
}
}
if (openlrs_dev->willhop == 1) {
openlrs_dev->rf_channel++;
if ((openlrs_dev->rf_channel == MAXHOPS) || (openlrs_dev->bind_data.hopchannel[openlrs_dev->rf_channel] == 0)) {
openlrs_dev->rf_channel = 0;
}
if ((openlrs_dev->beacon_frequency) && (openlrs_dev->nextBeaconTimeMs) && openlrs_dev->beacon_armed) {
// Listen for RSSI on beacon channel briefly for 'trigger'
uint8_t brssi = beaconGetRSSI(openlrs_dev);
if (brssi > ((openlrs_dev->beacon_rssi_avg >> 2) + 20)) {
openlrs_dev->nextBeaconTimeMs = timeMs + 1000L;
}
openlrs_dev->beacon_rssi_avg = (openlrs_dev->beacon_rssi_avg * 3 + brssi * 4) >> 2;
rfmSetCarrierFrequency(openlrs_dev, openlrs_dev->bind_data.rf_frequency);
}
rfmSetChannel(openlrs_dev, openlrs_dev->rf_channel);
rx_reset(openlrs_dev);
openlrs_dev->willhop = 0;
}
// Update UAVO
OPLinkStatusSet(&oplink_status);
}
uint8_t PIOS_OpenLRS_RSSI_Get(void)
{
// Get the OPLinkStatus UAVO
OPLinkStatusData oplink_status;
OPLinkStatusGet(&oplink_status);
if (oplink_status.LinkState != OPLINKSTATUS_LINKSTATE_CONNECTED) {
return 0;
} else {
OPLinkStatusData openlrs_status;
OPLinkStatusGet(&openlrs_status);
OPLinkSettingsData openlrs_data;
OPLinkSettingsGet(&openlrs_data);
uint16_t LQ = oplink_status.LinkQuality & 0x7fff;
// count number of 1s in LinkQuality
LQ = LQ - ((LQ >> 1) & 0x5555);
LQ = (LQ & 0x3333) + ((LQ >> 2) & 0x3333);
LQ = LQ + (LQ >> 4);
LQ &= 0x0F0F;
LQ = (LQ * 0x0101) >> 8;
switch (openlrs_data.RSSIType) {
case OPLINKSETTINGS_RSSITYPE_COMBINED:
if ((uint8_t)LQ == 15) {
return (uint8_t)((oplink_status.RSSI >> 1) + 128);
} else {
return LQ * 9;
}
case OPLINKSETTINGS_RSSITYPE_RSSI:
return openlrs_status.RSSI;
case OPLINKSETTINGS_RSSITYPE_LINKQUALITY:
return (uint8_t)(LQ << 4);
default:
return 0;
}
}
}
/*****************************************************************************
* PPM Code
*****************************************************************************/
/**
* Register a OpenLRS_Rcvr interface to inform of PPM packets
*
* @param[in] rfm22b_dev The RFM22B device ID.
* @param[in] rfm22b_rcvr_id The receiver device to inform of PPM packets
*/
void PIOS_OpenLRS_RegisterRcvr(uint32_t openlrs_id, uint32_t openlrs_rcvr_id)
{
struct pios_openlrs_dev *openlrs_dev =
(struct pios_openlrs_dev *)openlrs_id;
if (!pios_openlrs_validate(openlrs_dev)) {
return;
}
openlrs_dev->openlrs_rcvr_id = openlrs_rcvr_id;
}
/**
* Register a OpenLRS_Rcvr interface to inform of PPM packets using a generic callback.
*
* @param[in] openlrs_id The OpenLRS device ID.
* @param[in] callback The callback function.
*/
void PIOS_OpenLRS_RegisterPPMCallback(uint32_t openlrs_id, PIOS_OpenLRS_PPMReceivedCallback callback)
{
struct pios_openlrs_dev *openlrs_dev =
(struct pios_openlrs_dev *)openlrs_id;
if (!pios_openlrs_validate(openlrs_dev)) {
return;
}
openlrs_dev->ppm_callback = callback;
}
/*****************************************************************************
* Task and device setup
*****************************************************************************/
static void pios_openlrs_task(void *parameters);
// ! Global device handle, required for IRQ handler
static struct pios_openlrs_dev *g_openlrs_dev;
/**
* Initialise an RFM22B device
*
* @param[out] rfm22b_id A pointer to store the device ID in.
* @param[in] spi_id The SPI bus index.
* @param[in] slave_num The SPI bus slave number.
* @param[in] cfg The device configuration.
*/
int32_t PIOS_OpenLRS_Init(uint32_t *openlrs_id, uint32_t spi_id,
uint32_t slave_num,
const struct pios_openlrs_cfg *cfg)
{
PIOS_DEBUG_Assert(rfm22b_id);
PIOS_DEBUG_Assert(cfg);
// Allocate the device structure.
struct pios_openlrs_dev *openlrs_dev = pios_openlrs_alloc();
if (!openlrs_dev) {
return -1;
}
*openlrs_id = (uint32_t)openlrs_dev;
g_openlrs_dev = openlrs_dev;
// Hardcode the band for now.
openlrs_dev->band = 430000000;
// Store the SPI handle
openlrs_dev->slave_num = slave_num;
openlrs_dev->spi_id = spi_id;
// Before initializing everything, make sure device found
uint8_t device_type = rfm22_read(openlrs_dev, RFM22_DEVICE_TYPE) & RFM22_DT_MASK;
if (device_type != 0x08) {
return -1;
}
// Initialize the com callbacks.
openlrs_dev->rx_in_cb = NULL;
openlrs_dev->tx_out_cb = NULL;
// Initialize the "PPM" callback.
openlrs_dev->openlrs_rcvr_id = 0;
openlrs_dev->ppm_callback = 0;
OPLinkSettingsInitialize();
OPLinkStatusInitialize();
DEBUG_PRINTF(2, "OpenLRS UAVOs Initialized\r\n");
OPLinkSettingsData binding;
OPLinkSettingsGet(&binding);
if (binding.Version == BINDING_VERSION) {
openlrs_dev->bind_data.version = binding.Version;
openlrs_dev->bind_data.serial_baudrate = binding.SerialBaudrate;
openlrs_dev->bind_data.rf_frequency = binding.RFFrequency;
openlrs_dev->bind_data.rf_magic = binding.CoordID;
openlrs_dev->bind_data.rf_power = binding.RFPower;
openlrs_dev->bind_data.rf_channel_spacing = binding.RFChannelSpacing;
openlrs_dev->bind_data.modem_params = binding.ModemParams;
openlrs_dev->bind_data.flags = binding.Flags;
for (uint32_t i = 0; i < OPLINKSETTINGS_HOPCHANNEL_NUMELEM; i++) {
openlrs_dev->bind_data.hopchannel[i] = binding.HopChannel[i];
}
}
// Copy beacon settings over
openlrs_dev->beacon_frequency = binding.BeaconFrequency;
openlrs_dev->beacon_delay = binding.BeaconDelay;
openlrs_dev->beacon_period = binding.BeaconPeriod;
openlrs_dev->failsafeDelay = binding.FailsafeDelay;
// Bind the configuration to the device instance
openlrs_dev->cfg = *cfg;
// Initialize the external interrupt.
PIOS_EXTI_Init(cfg->exti_cfg);
// Register the watchdog timer for the radio driver task
#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_RFM22B)
PIOS_WDG_RegisterFlag(PIOS_WDG_RFM22B);
#endif /* PIOS_WDG_RFM22B */
// Start the driver task. This task controls the radio state machine and removed all of the IO from the IRQ handler.
openlrs_dev->taskHandle = PIOS_Thread_Create(pios_openlrs_task, "PIOS_OpenLRS_Task", STACK_SIZE_BYTES, (void *)openlrs_dev, TASK_PRIORITY);
// TaskMonitorAdd(TASKINFO_RUNNING_MODEMRX, openlrs_dev->taskHandle);
return 0;
}
/**
* The task that controls the radio state machine.
*
* @param[in] paramters The task parameters.
*/
static void pios_openlrs_task(void *parameters)
{
struct pios_openlrs_dev *openlrs_dev = (struct pios_openlrs_dev *)parameters;
if (!pios_openlrs_validate(openlrs_dev)) {
return;
}
DEBUG_PRINTF(2, "Setup started\r\n");
if (openlrs_dev->bind_data.version == BINDING_VERSION) {
pios_openlrs_setup(openlrs_dev, false);
} else {
pios_openlrs_setup(openlrs_dev, true);
}
DEBUG_PRINTF(2, "Setup complete\r\n");
bool rssi_sampled = false;
while (1) {
#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_RFM22B)
// Update the watchdog timer
PIOS_WDG_UpdateFlag(PIOS_WDG_RFM22B);
#endif /* PIOS_WDG_RFM22B */
/* This block of code determines the timing of when to call the loop method. It reaches a bit into
* the internal state of that method to get the optimal timings. This is to keep the loop method as
* similar as possible to the openLRSng implementation (for easier maintenance of compatibility)
* while minimizing overhead spinning in a while loop.
*
* There are three reasons to go into loop:
* 1. the ISR was triggered (packet was received)
* 2. a little before the expected packet (to sample the RSSI while receiving packet)
* 3. a little after expected packet (to channel hop when a packet was missing)
*/
uint32_t delay_ms = 0;
uint32_t time_since_packet_us = PIOS_DELAY_GetuSSince(openlrs_dev->lastPacketTimeUs);
if (!rssi_sampled) {
// If we had not sampled RSSI yet, schedule a bit early to try and catch while "packet is in the air"
uint32_t time_till_measure_rssi_us = (getInterval(&openlrs_dev->bind_data) - packet_advance_time_us) - time_since_packet_us;
delay_ms = (time_till_measure_rssi_us + 999) / 1000;
// DEBUG_PRINTF(3, "T1: %d\r\n", delay_ms);
} else {
// If we have sampled RSSI we want to schedule to hop when a packet has been missed
uint32_t time_till_timeout_us = (getInterval(&openlrs_dev->bind_data) + packet_timeout_us) - time_since_packet_us;
delay_ms = (time_till_timeout_us + 999) / 1000;
// DEBUG_PRINTF(3, "T2: %d %d\r\n", time_till_timeout_us,delay_ms, time_since_packet_us);
}
// Maximum delay based on packet time
const uint32_t max_delay = (getInterval(&openlrs_dev->bind_data) + packet_timeout_us) / 1000;
if (delay_ms > max_delay) {
delay_ms = max_delay;
}
if (PIOS_Semaphore_Take(openlrs_dev->sema_isr, delay_ms) == false) {
if (!rssi_sampled) {
// We timed out to sample RSSI
if (openlrs_dev->numberOfLostPackets < 2) {
openlrs_dev->lastRSSITimeUs = openlrs_dev->lastPacketTimeUs;
openlrs_dev->rssi = rfmGetRSSI(openlrs_dev); // Read the RSSI value
// DEBUG_PRINTF(3, "Sampled RSSI: %d %d\r\n", openlrs_dev->RSSI, delay);
}
} else {
// We timed out because packet was missed
DEBUG_PRINTF(3, "ISR Timeout. Missed packet: %d %d %d\r\n", delay, getInterval(&openlrs_dev->bind_data), time_since_packet_us);
pios_openlrs_rx_loop(openlrs_dev);
}
rssi_sampled = true;
} else {
// DEBUG_PRINTF(3, "ISR %d %d %d\r\n", delay, getInterval(&openlrs_dev->bind_data), time_since_packet_us);
// Process incoming data
pios_openlrs_rx_loop(openlrs_dev);
// When a packet has been received (processed below) indicate we need to sample a new RSSI
rssi_sampled = false;
}
// DEBUG_PRINTF(3, "Processing time %d\r\n", PIOS_DELAY_GetuSSince(openlrs_dev->lastPacketTimeUs));
}
}
bool PIOS_OpenLRS_EXT_Int(void)
{
struct pios_openlrs_dev *openlrs_dev = g_openlrs_dev;
if (!pios_openlrs_validate(openlrs_dev)) {
return false;
}
if (openlrs_dev->rf_mode == Transmit) {
openlrs_dev->rf_mode = Transmitted;
} else if (openlrs_dev->rf_mode == Receive) {
openlrs_dev->rf_mode = Received;
}
// Indicate to main task that an ISR occurred
bool woken = false;
PIOS_Semaphore_Give_FromISR(openlrs_dev->sema_isr, &woken);
return woken;
}
/**
* Allocate the device structure
*/
static struct pios_openlrs_dev *pios_openlrs_alloc(void)
{
struct pios_openlrs_dev *openlrs_dev;
openlrs_dev = (struct pios_openlrs_dev *)pios_malloc(sizeof(*openlrs_dev));
if (!openlrs_dev) {
return NULL;
}
openlrs_dev->spi_id = 0;
// Create the ISR signal
openlrs_dev->sema_isr = PIOS_Semaphore_Create();
if (!openlrs_dev->sema_isr) {
pios_free(openlrs_dev);
return NULL;
}
openlrs_dev->magic = PIOS_OPENLRS_DEV_MAGIC;
return openlrs_dev;
}
/**
* Validate that the device structure is valid.
*
* @param[in] openlrs_dev The OpenLRS device structure pointer.
*/
static bool pios_openlrs_validate(struct pios_openlrs_dev *openlrs_dev)
{
return openlrs_dev != NULL
&& openlrs_dev->magic == PIOS_OPENLRS_DEV_MAGIC;
}
/*****************************************************************************
* SPI Read/Write Functions
*****************************************************************************/
/**
* Assert the chip select line.
*
* @param[in] rfm22b_dev The RFM22B device.
*/
static void rfm22_assertCs(struct pios_openlrs_dev *openlrs_dev)
{
PIOS_DELAY_WaituS(1);
if (openlrs_dev->spi_id != 0) {
PIOS_SPI_RC_PinSet(openlrs_dev->spi_id,
openlrs_dev->slave_num, 0);
}
}
/**
* Deassert the chip select line.
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
*/
static void rfm22_deassertCs(struct pios_openlrs_dev *openlrs_dev)
{
if (openlrs_dev->spi_id != 0) {
PIOS_SPI_RC_PinSet(openlrs_dev->spi_id,
openlrs_dev->slave_num, 1);
}
}
/**
* Claim the SPI bus.
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
*/
static void rfm22_claimBus(struct pios_openlrs_dev *openlrs_dev)
{
if (openlrs_dev->spi_id != 0) {
PIOS_SPI_ClaimBus(openlrs_dev->spi_id);
}
}
/**
* Release the SPI bus.
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
*/
static void rfm22_releaseBus(struct pios_openlrs_dev *openlrs_dev)
{
if (openlrs_dev->spi_id != 0) {
PIOS_SPI_ReleaseBus(openlrs_dev->spi_id);
}
}
/**
* Claim the semaphore and write a byte to a register
*
* @param[in] rfm22b_dev The RFM22B device.
* @param[in] addr The address to write to
* @param[in] data The datat to write to that address
*/
static void rfm22_write_claim(struct pios_openlrs_dev *openlrs_dev,
uint8_t addr, uint8_t data)
{
rfm22_claimBus(openlrs_dev);
rfm22_assertCs(openlrs_dev);
uint8_t buf[2] = { addr | 0x80, data };
PIOS_SPI_TransferBlock(openlrs_dev->spi_id, buf, NULL, sizeof(buf),
NULL);
rfm22_deassertCs(openlrs_dev);
rfm22_releaseBus(openlrs_dev);
}
/**
* Claim the semaphore and write a byte to a register
*
* @param[in] rfm22b_dev The RFM22B device.
* @param[in] addr The address to write to
* @param[in] data The datat to write to that address
*/
static uint8_t rfm22_read_claim(struct pios_openlrs_dev *openlrs_dev,
uint8_t addr)
{
uint8_t out[2] = { addr &0x7F, 0xFF };
uint8_t in[2];
rfm22_claimBus(openlrs_dev);
rfm22_assertCs(openlrs_dev);
PIOS_SPI_TransferBlock(openlrs_dev->spi_id, out, in, sizeof(out),
NULL);
rfm22_deassertCs(openlrs_dev);
rfm22_releaseBus(openlrs_dev);
return in[1];
}
/**
* Write a byte to a register without claiming the semaphore
*
* @param[in] rfm22b_dev The RFM22B device.
* @param[in] addr The address to write to
* @param[in] data The datat to write to that address
*/
static void rfm22_write(struct pios_openlrs_dev *openlrs_dev, uint8_t addr,
uint8_t data)
{
rfm22_assertCs(openlrs_dev);
uint8_t buf[2] = { addr | 0x80, data };
PIOS_SPI_TransferBlock(openlrs_dev->spi_id, buf, NULL, sizeof(buf),
NULL);
rfm22_deassertCs(openlrs_dev);
}
/**
* Read a byte from an RFM22b register without claiming the bus
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
* @param[in] addr The address to read from
* @return Returns the result of the register read
*/
static uint8_t rfm22_read(struct pios_openlrs_dev *openlrs_dev, uint8_t addr)
{
uint8_t out[2] = { addr &0x7F, 0xFF };
uint8_t in[2];
rfm22_assertCs(openlrs_dev);
PIOS_SPI_TransferBlock(openlrs_dev->spi_id, out, in, sizeof(out),
NULL);
rfm22_deassertCs(openlrs_dev);
return in[1];
}
#endif /* PIOS_INCLUDE_OPENLRS */
/**
* @}
* @}
*/

View File

@ -0,0 +1,223 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_RFM22B Radio Functions
* @brief PIOS OpenLRS interface for for the RFM22B radio
* @{
*
* @file pios_openlrs_rcvr.c
* @author Tau Labs, http://taulabs.org, Copyright (C) 2015
* @brief Implements an OpenLRS driver for the RFM22B
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_OPENLRS
#include "pios_openlrs_priv.h"
#include <uavobjectmanager.h>
#include <oplinkreceiver.h>
#include <pios_openlrs_priv.h>
#include <pios_openlrs_rcvr_priv.h>
#define PIOS_OPENLRS_RCVR_TIMEOUT_MS 100
/* Provide a RCVR driver */
static int32_t PIOS_OpenLRS_Rcvr_Get(uint32_t rcvr_id, uint8_t channel);
static void PIOS_OpenLRS_Rcvr_Supervisor(uint32_t ppm_id);
const struct pios_rcvr_driver pios_openlrs_rcvr_driver = {
.read = PIOS_OpenLRS_Rcvr_Get,
};
/* Local Variables */
enum pios_openlrs_rcvr_dev_magic {
PIOS_OPENLRS_RCVR_DEV_MAGIC = 0x07ac9e2144ff5329,
};
struct pios_openlrs_rcvr_dev {
enum pios_openlrs_rcvr_dev_magic magic;
int16_t channels[OPENLRS_PPM_NUM_CHANNELS];
uint8_t supv_timer;
bool fresh;
};
static void openlrs_rcvr_update_uavo(struct pios_openlrs_rcvr_dev *pios_rfm22b_rcvr_dev);
static bool PIOS_OpenLRS_Rcvr_Validate(struct pios_openlrs_rcvr_dev
*openlrs_rcvr_dev)
{
return openlrs_rcvr_dev->magic == PIOS_OPENLRS_RCVR_DEV_MAGIC;
}
static struct pios_openlrs_rcvr_dev *PIOS_OpenLRS_Rcvr_alloc(void)
{
struct pios_openlrs_rcvr_dev *openlrs_rcvr_dev;
openlrs_rcvr_dev =
(struct pios_openlrs_rcvr_dev *)
pios_malloc(sizeof(*openlrs_rcvr_dev));
if (!openlrs_rcvr_dev) {
return NULL;
}
openlrs_rcvr_dev->magic = PIOS_OPENLRS_RCVR_DEV_MAGIC;
openlrs_rcvr_dev->fresh = false;
openlrs_rcvr_dev->supv_timer = 0;
return openlrs_rcvr_dev;
}
extern int32_t PIOS_OpenLRS_Rcvr_Init(uint32_t *openlrs_rcvr_id, uintptr_t openlrs_id)
{
struct pios_openlrs_rcvr_dev *openlrs_rcvr_dev;
/* Allocate the device structure */
openlrs_rcvr_dev =
(struct pios_openlrs_rcvr_dev *)PIOS_OpenLRS_Rcvr_alloc();
if (!openlrs_rcvr_dev) {
return -1;
}
/* Register uavobj callback */
OPLinkReceiverInitialize();
*openlrs_rcvr_id = (uintptr_t)openlrs_rcvr_dev;
PIOS_OpenLRS_RegisterRcvr(openlrs_id, *openlrs_rcvr_id);
/* Register the failsafe timer callback. */
if (!PIOS_RTC_RegisterTickCallback
(PIOS_OpenLRS_Rcvr_Supervisor, *openlrs_rcvr_id)) {
PIOS_DEBUG_Assert(0);
}
return 0;
}
/**
* Called from the core driver to set the channel values whenever a
* PPM packet is received. This method stores the data locally as well
* as sets the data into the OPLinkReceiver UAVO for visibility
*/
int32_t PIOS_OpenLRS_Rcvr_UpdateChannels(uint32_t openlrs_rcvr_id, int16_t *channels)
{
/* Recover our device context */
struct pios_openlrs_rcvr_dev *openlrs_rcvr_dev =
(struct pios_openlrs_rcvr_dev *)openlrs_rcvr_id;
if (!PIOS_OpenLRS_Rcvr_Validate(openlrs_rcvr_dev)) {
/* Invalid device specified */
return -1;
}
for (uint32_t i = 0; i < OPENLRS_PPM_NUM_CHANNELS; i++) {
openlrs_rcvr_dev->channels[i] = channels[i];
}
openlrs_rcvr_update_uavo(openlrs_rcvr_dev);
// let supervisor know we have new data
openlrs_rcvr_dev->fresh = true;
return 0;
}
/**
* Get the value of an input channel
* \param[in] channel Number of the channel desired (zero based)
* \output PIOS_RCVR_INVALID channel not available
* \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver
* \output >=0 channel value
*/
static int32_t PIOS_OpenLRS_Rcvr_Get(uint32_t openlrs_rcvr_id, uint8_t channel)
{
if (channel >= OPENLRS_PPM_NUM_CHANNELS) {
/* channel is out of range */
return PIOS_RCVR_INVALID;
}
/* Recover our device context */
struct pios_openlrs_rcvr_dev *openlrs_rcvr_dev =
(struct pios_openlrs_rcvr_dev *)openlrs_rcvr_id;
if (!PIOS_OpenLRS_Rcvr_Validate(openlrs_rcvr_dev)) {
/* Invalid device specified */
return PIOS_RCVR_INVALID;
}
return openlrs_rcvr_dev->channels[channel];
}
static void PIOS_OpenLRS_Rcvr_Supervisor(uint32_t openlrs_rcvr_id)
{
/* Recover our device context */
struct pios_openlrs_rcvr_dev *openlrs_rcvr_dev =
(struct pios_openlrs_rcvr_dev *)openlrs_rcvr_id;
if (!PIOS_OpenLRS_Rcvr_Validate(openlrs_rcvr_dev)) {
/* Invalid device specified */
return;
}
/*
* RTC runs at 625Hz.
*/
if (++(openlrs_rcvr_dev->supv_timer) <
(PIOS_OPENLRS_RCVR_TIMEOUT_MS * 1000 / 625)) {
return;
}
openlrs_rcvr_dev->supv_timer = 0;
if (!openlrs_rcvr_dev->fresh) {
for (int32_t i = 0; i < OPLINKRECEIVER_CHANNEL_NUMELEM;
i++) {
openlrs_rcvr_dev->channels[i] = PIOS_RCVR_TIMEOUT;
}
}
openlrs_rcvr_dev->fresh = false;
}
static void openlrs_rcvr_update_uavo(struct pios_openlrs_rcvr_dev *rcvr_dev)
{
// Also store the received data in a UAVO for easy
// debugging. However this is not what is used in
// ManualControl (it fetches directly from this driver)
OPLinkReceiverData rcvr;
for (uint8_t i = 0; i < OPENLRS_PPM_NUM_CHANNELS; i++) {
if (i < OPLINKRECEIVER_CHANNEL_NUMELEM) {
rcvr.Channel[i] = rcvr_dev->channels[i];
}
}
for (int i = OPENLRS_PPM_NUM_CHANNELS - 1; i < OPLINKRECEIVER_CHANNEL_NUMELEM; i++) {
rcvr.Channel[i] = PIOS_RCVR_INVALID;
}
OPLinkReceiverSet(&rcvr);
}
#endif /* PIOS_INCLUDE_OPENLRS */
/**
* @}
* @}
*/

View File

@ -191,7 +191,7 @@ static void PIOS_oplinkrcvr_Supervisor(uint32_t oplinkrcvr_id)
static uint8_t PIOS_OPLinkRCVR_Quality_Get(__attribute__((unused)) uint32_t oplinkrcvr_id)
{
uint8_t oplink_quality;
uint16_t oplink_quality;
OPLinkStatusLinkQualityGet(&oplink_quality);

View File

@ -40,7 +40,7 @@
// 6-byte (32-bit) preamble .. alternating 0's & 1's
// 4-byte (32-bit) sync
// 1-byte packet length (number of data bytes to follow)
// 0 to 255 user data bytes
// 0 to 251 user data bytes
// 4 byte ECC
//
// OR in PPM only mode:
@ -59,6 +59,7 @@
#ifdef PIOS_INCLUDE_RFM22B
#include <pios_spi_priv.h>
#include <pios_rfm22b_regs.h>
#include <pios_rfm22b_priv.h>
#include <pios_ppm_out.h>
#include <ecc.h>
@ -437,7 +438,7 @@ int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, uint32_t spi_id, uint32_t slave_nu
// Initialize the channels.
PIOS_RFM22B_SetChannelConfig(*rfm22b_id, RFM22B_DEFAULT_RX_DATARATE, RFM22B_DEFAULT_MIN_CHANNEL,
RFM22B_DEFAULT_MAX_CHANNEL, false, false, false, false);
RFM22B_DEFAULT_MAX_CHANNEL, false, true, false);
// Create the event queue
rfm22b_dev->eventQueue = xQueueCreate(EVENT_QUEUE_SIZE, sizeof(enum pios_radio_event));
@ -591,18 +592,17 @@ void PIOS_RFM22B_SetTxPower(uint32_t rfm22b_id, enum rfm22b_tx_power tx_pwr)
* @param[in] min_chan The minimum channel.
* @param[in] max_chan The maximum channel.
* @param[in] coordinator Is this modem an coordinator.
* @param[in] data_mode Should this modem send/receive data packets?
* @param[in] ppm_mode Should this modem send/receive ppm packets?
* @param[in] oneway Only the coordinator can send packets if true.
* @param[in] ppm_only Should this modem run in ppm only mode?
*/
void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datarate, uint8_t min_chan, uint8_t max_chan, bool coordinator, bool oneway, bool ppm_mode, bool ppm_only)
void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datarate, uint8_t min_chan, uint8_t max_chan, bool coordinator, bool data_mode, bool ppm_mode)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
bool ppm_only = ppm_mode && !data_mode;
if (!PIOS_RFM22B_Validate(rfm22b_dev)) {
return;
}
ppm_mode = ppm_mode || ppm_only;
rfm22b_dev->coordinator = coordinator;
rfm22b_dev->ppm_send_mode = ppm_mode && coordinator;
rfm22b_dev->ppm_recv_mode = ppm_mode && !coordinator;
@ -615,7 +615,7 @@ void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datar
datarate = RFM22B_PPM_ONLY_DATARATE;
rfm22b_dev->datarate = RFM22B_PPM_ONLY_DATARATE;
} else {
rfm22b_dev->one_way_link = oneway;
rfm22b_dev->one_way_link = false;
rfm22b_dev->datarate = datarate;
}
rfm22b_dev->packet_time = (ppm_mode ? packet_time_ppm[datarate] : packet_time[datarate]);
@ -1105,8 +1105,9 @@ void PIOS_RFM22B_SetPPMCallback(uint32_t rfm22b_id, PPMReceivedCallback cb)
*
* @param[in] rfm22b_dev The RFM22B device ID.
* @param[in] channels The PPM channel values.
* @param[out] nchan The number of channels to set.
*/
extern void PIOS_RFM22B_PPMSet(uint32_t rfm22b_id, int16_t *channels)
extern void PIOS_RFM22B_PPMSet(uint32_t rfm22b_id, int16_t *channels, uint8_t nchan)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -1115,7 +1116,7 @@ extern void PIOS_RFM22B_PPMSet(uint32_t rfm22b_id, int16_t *channels)
}
for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) {
rfm22b_dev->ppm[i] = channels[i];
rfm22b_dev->ppm[i] = (i < nchan) ? channels[i] : PIOS_RCVR_INVALID;
}
}
@ -1124,8 +1125,9 @@ extern void PIOS_RFM22B_PPMSet(uint32_t rfm22b_id, int16_t *channels)
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
* @param[out] channels The PPM channel values.
* @param[out] nchan The number of channels to get.
*/
extern void PIOS_RFM22B_PPMGet(uint32_t rfm22b_id, int16_t *channels)
extern void PIOS_RFM22B_PPMGet(uint32_t rfm22b_id, int16_t *channels, uint8_t nchan)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -1141,8 +1143,8 @@ extern void PIOS_RFM22B_PPMGet(uint32_t rfm22b_id, int16_t *channels)
return;
}
for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) {
channels[i] = rfm22b_dev->ppm[i];
for (uint8_t i = 0; i < nchan; ++i) {
channels[i] = (i < RFM22B_PPM_NUM_CHANNELS) ? rfm22b_dev->ppm[i] : PIOS_RCVR_INVALID;
}
}

View File

@ -0,0 +1,411 @@
/**
******************************************************************************
* @file pios_semaphore.c
* @author Tau Labs, http://taulabs.org, Copyright (C) 2013-2014
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_Semaphore Semaphore Abstraction
* @{
* @brief Abstracts the concept of a binary semaphore to hide different implementations
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#include "pios_semaphore.h"
#if !defined(PIOS_INCLUDE_FREERTOS) && !defined(PIOS_INCLUDE_CHIBIOS) && !defined(PIOS_INCLUDE_IRQ)
#error "pios_semaphore.c requires either PIOS_INCLUDE_FREERTOS, PIOS_INCLUDE_CHIBIOS or PIOS_INCLUDE_IRQ to be defined"
#endif
#if defined(PIOS_INCLUDE_FREERTOS)
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
// portTICK_RATE_MS is in [ms/tick].
// See http://sourceforge.net/tracker/?func=detail&aid=3498382&group_id=111543&atid=659636
#define TICKS2MS(t) ((t) * (portTICK_RATE_MS))
#define MS2TICKS(m) ((m) / (portTICK_RATE_MS))
/**
*
* @brief Creates a binary semaphore.
*
* @returns instance of @p struct pios_semaphore or NULL on failure
*
*/
struct pios_semaphore *PIOS_Semaphore_Create(void)
{
struct pios_semaphore *sema = pios_malloc(sizeof(struct pios_semaphore));
if (sema == NULL) {
return NULL;
}
/*
* The initial state of a binary semaphore is "given".
* FreeRTOS executes a "give" upon creation.
*/
xSemaphoreHandle temp;
vSemaphoreCreateBinary(temp);
sema->sema_handle = (uintptr_t)temp;
return sema;
}
/**
*
* @brief Takes binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[in] timeout_ms timeout for acquiring the lock in milliseconds
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
{
PIOS_Assert(sema != NULL);
portTickType timeout_ticks;
if (timeout_ms == PIOS_SEMAPHORE_TIMEOUT_MAX) {
timeout_ticks = portMAX_DELAY;
} else {
timeout_ticks = MS2TICKS(timeout_ms);
}
return xSemaphoreTake(sema->sema_handle, timeout_ticks) == pdTRUE;
}
/**
*
* @brief Gives binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
{
PIOS_Assert(sema != NULL);
return xSemaphoreGive(sema->sema_handle) == pdTRUE;
}
/* Workaround for simulator version of FreeRTOS. */
#if !defined(SIM_POSIX)
/**
*
* @brief Takes binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
PIOS_Assert(woken != NULL);
signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
bool result = xSemaphoreTakeFromISR(sema->sema_handle, &xHigherPriorityTaskWoken) == pdTRUE;
*woken = *woken || xHigherPriorityTaskWoken == pdTRUE;
return result;
}
/**
*
* @brief Gives binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
PIOS_Assert(woken != NULL);
signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
bool result = xSemaphoreGiveFromISR(sema->sema_handle, &xHigherPriorityTaskWoken) == pdTRUE;
*woken = *woken || xHigherPriorityTaskWoken == pdTRUE;
return result;
}
#endif /* !defined(SIM_POSIX) */
#elif defined(PIOS_INCLUDE_CHIBIOS)
/**
*
* @brief Creates a binary semaphore.
*
* @returns instance of @p struct pios_semaphore or NULL on failure
*
*/
struct pios_semaphore *PIOS_Semaphore_Create(void)
{
struct pios_semaphore *sema = PIOS_malloc(sizeof(struct pios_semaphore));
if (sema == NULL) {
return NULL;
}
/*
* The initial state of a binary semaphore is "given".
*/
chBSemInit(&sema->sema, false);
return sema;
}
/**
*
* @brief Takes binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[in] timeout_ms timeout for acquiring the lock in milliseconds
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
{
PIOS_Assert(sema != NULL);
if (timeout_ms == PIOS_SEMAPHORE_TIMEOUT_MAX) {
return chBSemWait(&sema->sema) == RDY_OK;
} else if (timeout_ms == 0) {
return chBSemWaitTimeout(&sema->sema, TIME_IMMEDIATE) == RDY_OK;
} else {
return chBSemWaitTimeout(&sema->sema, MS2ST(timeout_ms)) == RDY_OK;
}
}
/**
*
* @brief Gives binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
{
PIOS_Assert(sema != NULL);
chBSemSignal(&sema->sema);
return true;
}
/**
*
* @brief Takes binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take_FromISR(struct pios_semaphore *sema, bool *woken)
{
/* Waiting on a semaphore within an interrupt is not supported by ChibiOS. */
PIOS_Assert(false);
return false;
}
/**
*
* @brief Gives binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
PIOS_Assert(woken != NULL);
chSysLockFromIsr();
chBSemSignalI(&sema->sema);
chSysUnlockFromIsr();
return true;
}
#elif defined(PIOS_INCLUDE_IRQ)
/**
*
* @brief Creates a binary semaphore.
*
* @returns instance of @p struct pios_semaphore or NULL on failure
*
*/
struct pios_semaphore *PIOS_Semaphore_Create(void)
{
struct pios_semaphore *sema = PIOS_malloc_no_dma(sizeof(struct pios_semaphore));
if (sema == NULL) {
return NULL;
}
/*
* The initial state of a binary semaphore is "given".
*/
sema->sema_count = 1;
return sema;
}
/**
*
* @brief Takes binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[in] timeout_ms timeout for acquiring the lock in milliseconds
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
{
PIOS_Assert(sema != NULL);
uint32_t start = PIOS_DELAY_GetRaw();
uint32_t temp_sema_count;
do {
PIOS_IRQ_Disable();
if ((temp_sema_count = sema->sema_count) != 0) {
--sema->sema_count;
}
PIOS_IRQ_Enable();
} while (temp_sema_count == 0 &&
PIOS_DELAY_DiffuS(start) < timeout_ms * 1000);
return temp_sema_count != 0;
}
/**
*
* @brief Gives binary semaphore.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
{
PIOS_Assert(sema != NULL);
bool result = true;
PIOS_IRQ_Disable();
if (sema->sema_count == 0) {
++sema->sema_count;
} else {
result = false;
}
PIOS_IRQ_Enable();
return result;
}
/* Workaround for simulator version of FreeRTOS. */
#if !defined(SIM_POSIX)
/**
*
* @brief Takes binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Take_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
bool result = true;
PIOS_IRQ_Disable();
if (sema->sema_count != 0) {
--sema->sema_count;
} else {
result = false;
}
PIOS_IRQ_Enable();
return result;
}
/**
*
* @brief Gives binary semaphore from ISR context.
*
* @param[in] sema pointer to instance of @p struct pios_semaphore
* @param[out] woken pointer to bool which will be set true if a context switch is required
*
* @returns true on success or false on timeout or failure
*
*/
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
{
PIOS_Assert(sema != NULL);
bool result = true;
PIOS_IRQ_Disable();
if (sema->sema_count == 0) {
++sema->sema_count;
} else {
result = false;
}
PIOS_IRQ_Enable();
return result;
}
#endif /* !defined(SIM_POSIX) */
#endif /* defined(PIOS_INCLUDE_IRQ) */

View File

@ -0,0 +1,441 @@
/**
******************************************************************************
* @file pios_thread.c
* @author Tau Labs, http://taulabs.org, Copyright (C) 2014
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_Thread Thread Abstraction
* @{
* @brief Abstracts the concept of a thread to hide different implementations
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#include "pios_thread.h"
#if !defined(PIOS_INCLUDE_FREERTOS) && !defined(PIOS_INCLUDE_CHIBIOS)
#error "pios_thread.c requires PIOS_INCLUDE_FREERTOS or PIOS_INCLUDE_CHIBIOS"
#endif
#if defined(PIOS_INCLUDE_FREERTOS)
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
// portTICK_RATE_MS is in [ms/tick].
// See http://sourceforge.net/tracker/?func=detail&aid=3498382&group_id=111543&atid=659636
#define TICKS2MS(t) ((t) * (portTICK_RATE_MS))
#define MS2TICKS(m) ((m) / (portTICK_RATE_MS))
/**
*
* @brief Creates a thread.
*
* @param[in] fp pointer to thread function
* @param[in] namep pointer to thread name
* @param[in] stack_bytes stack size in bytes
* @param[in] argp pointer to argument which will be passed to thread function
* @param[in] prio thread priority
*
* @returns instance of @p struct pios_thread or NULL on failure
*
*/
struct pios_thread *PIOS_Thread_Create(void (*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
{
struct pios_thread *thread = pios_malloc(sizeof(struct pios_thread));
if (thread == NULL) {
return NULL;
}
thread->task_handle = (uintptr_t)NULL;
if (xTaskCreate(fp, (const char *)namep, stack_bytes / 4, argp, prio, (xTaskHandle *)&thread->task_handle) != pdPASS) {
pios_free(thread);
return NULL;
}
return thread;
}
#if (INCLUDE_vTaskDelete == 1)
/**
*
* @brief Destroys an instance of @p struct pios_thread.
*
* @param[in] threadp pointer to instance of @p struct pios_thread
*
*/
void PIOS_Thread_Delete(struct pios_thread *threadp)
{
if (threadp == NULL) {
vTaskDelete(NULL);
} else {
vTaskDelete((xTaskHandle)threadp->task_handle);
}
}
#else
#error "PIOS_Thread_Delete requires INCLUDE_vTaskDelete to be defined 1"
#endif /* (INCLUDE_vTaskDelete == 1) */
/**
*
* @brief Returns the current system time.
*
* @returns current system time
*
*/
uint32_t PIOS_Thread_Systime(void)
{
return (uint32_t)TICKS2MS(xTaskGetTickCount());
}
#if (INCLUDE_vTaskDelay == 1)
/**
*
* @brief Suspends execution of current thread at least for specified time.
*
* @param[in] time_ms time in milliseconds to suspend thread execution
*
*/
void PIOS_Thread_Sleep(uint32_t time_ms)
{
if (time_ms == PIOS_THREAD_TIMEOUT_MAX) {
vTaskDelay(portMAX_DELAY);
} else {
vTaskDelay((portTickType)MS2TICKS(time_ms));
}
}
#else
#error "PIOS_Thread_Sleep requires INCLUDE_vTaskDelay to be defined 1"
#endif /* (INCLUDE_vTaskDelay == 1) */
#if (INCLUDE_vTaskDelayUntil == 1)
/**
*
* @brief Suspends execution of current thread for a regular interval.
*
* @param[in] previous_ms pointer to system time of last execution,
* must have been initialized with PIOS_Thread_Systime() on first invocation
* @param[in] increment_ms time of regular interval in milliseconds
*
*/
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
{
portTickType temp = MS2TICKS(*previous_ms);
vTaskDelayUntil(&temp, (portTickType)MS2TICKS(increment_ms));
*previous_ms = TICKS2MS(temp);
}
#else
#error "PIOS_Thread_Sleep requires INCLUDE_vTaskDelayUntil to be defined 1"
#endif /* (INCLUDE_vTaskDelayUntil == 1) */
/**
*
* @brief Returns stack usage of a thread.
*
* @param[in] threadp pointer to instance of @p struct pios_thread
*
* @return stack usage in bytes
*
*/
uint32_t PIOS_Thread_Get_Stack_Usage(struct pios_thread *threadp)
{
#if (INCLUDE_uxTaskGetStackHighWaterMark == 1)
/* @note: This will fail when FreeRTOS TCB structure changes. */
return uxTaskGetStackHighWaterMark((xTaskHandle)threadp->task_handle) * 4;
#else
return 1024;
#endif /* (INCLUDE_uxTaskGetStackHighWaterMark == 1) */
}
/**
*
* @brief Returns runtime of a thread.
*
* @param[in] threadp pointer to instance of @p struct pios_thread
*
* @return runtime in milliseconds
*
*/
uint32_t PIOS_Thread_Get_Runtime(struct pios_thread *threadp)
{
#if (INCLUDE_uxTaskGetRunTime == 1)
return uxTaskGetRunTime((xTaskHandle)threadp->task_handle);
#else
(void)threadp;
return 0;
#endif /* (INCLUDE_uxTaskGetRunTime == 1) */
}
/**
*
* @brief Suspends execution of all threads.
*
*/
void PIOS_Thread_Scheduler_Suspend(void)
{
vTaskSuspendAll();
}
/**
*
* @brief Resumes execution of all threads.
*
*/
void PIOS_Thread_Scheduler_Resume(void)
{
xTaskResumeAll();
}
#elif defined(PIOS_INCLUDE_CHIBIOS)
#define ST2MS(n) (((((n) - 1UL) * 1000UL) / CH_FREQUENCY) + 1UL)
/**
* Compute size that is at rounded up to the nearest
* multiple of 8
*/
static uint32_t ceil_size(uint32_t size)
{
const uint32_t a = sizeof(stkalign_t);
size = size + (a - size % a);
return size;
}
/**
* ChibiOS stack expects alignment (both start and end)
* to 8 byte boundaries. This makes sure to allocate enough
* memory and return an address that has the requested size
* or more with these constraints.
*/
static uint8_t *align8_alloc(uint32_t size)
{
// round size up to at nearest multiple of 8 + 4 bytes to guarantee
// sufficient size within. This is because PIOS_malloc only guarantees
// uintptr_t alignment which is 4 bytes.
size = size + sizeof(uintptr_t);
uint8_t *wap = PIOS_malloc(size);
// shift start point to nearest 8 byte boundary.
uint32_t pad = ((uint32_t)wap) % sizeof(stkalign_t);
wap = wap + pad;
return wap;
}
/**
*
* @brief Creates a thread.
*
* @param[in] fp pointer to thread function
* @param[in] namep pointer to thread name
* @param[in] stack_bytes stack size in bytes
* @param[in] argp pointer to argument which will be passed to thread function
* @param[in] prio thread priority
*
* @returns instance of @p struct pios_thread or NULL on failure
*
*/
struct pios_thread *PIOS_Thread_Create(void (*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
{
struct pios_thread *thread = PIOS_malloc_no_dma(sizeof(struct pios_thread));
if (thread == NULL) {
return NULL;
}
#ifdef SIM_POSIX
if (stack_bytes < PIOS_THREAD_STACK_SIZE_MIN) {
stack_bytes = PIOS_THREAD_STACK_SIZE_MIN;
}
#endif
// Use special functions to ensure ChibiOS stack requirements
stack_bytes = ceil_size(stack_bytes);
uint8_t *wap = align8_alloc(stack_bytes);
if (wap == NULL) {
PIOS_free(thread);
return NULL;
}
thread->threadp = chThdCreateStatic(wap, stack_bytes, prio, (msg_t (*)(void *))fp, argp);
if (thread->threadp == NULL) {
PIOS_free(thread);
PIOS_free(wap);
return NULL;
}
#if CH_USE_REGISTRY
thread->threadp->p_name = namep;
#endif /* CH_USE_REGISTRY */
return thread;
}
#if (CH_USE_WAITEXIT == TRUE)
/**
*
* @brief Destroys an instance of @p struct pios_thread.
*
* @param[in] threadp pointer to instance of @p struct pios_thread
*
*/
void PIOS_Thread_Delete(struct pios_thread *threadp)
{
if (threadp == NULL) {
chThdExit(0);
} else {
chThdTerminate(threadp->threadp);
chThdWait(threadp->threadp);
}
}
#else
#error "PIOS_Thread_Delete requires CH_USE_WAITEXIT to be defined TRUE"
#endif /* (CH_USE_WAITEXIT == TRUE) */
/**
*
* @brief Returns the current system time.
*
* @returns current system time
*
*/
uint32_t PIOS_Thread_Systime(void)
{
return (uint32_t)ST2MS(chTimeNow());
}
/**
*
* @brief Suspends execution of current thread at least for specified time.
*
* @param[in] time_ms time in milliseconds to suspend thread execution
*
*/
void PIOS_Thread_Sleep(uint32_t time_ms)
{
if (time_ms == PIOS_THREAD_TIMEOUT_MAX) {
chThdSleep(TIME_INFINITE);
} else {
chThdSleep(MS2ST(time_ms));
}
}
/**
*
* @brief Suspends execution of current thread for a regular interval.
*
* @param[in] previous_ms pointer to system time of last execution,
* must have been initialized with PIOS_Thread_Systime() on first invocation
* @param[in] increment_ms time of regular interval in milliseconds
*
*/
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
{
systime_t future = MS2ST(*previous_ms) + MS2ST(increment_ms);
chSysLock();
systime_t now = chTimeNow();
int mustDelay =
now < MS2ST(*previous_ms) ?
(now < future && future < MS2ST(*previous_ms)) :
(now < future || future < MS2ST(*previous_ms));
if (mustDelay) {
chThdSleepS(future - now);
}
chSysUnlock();
*previous_ms = ST2MS(future);
}
/**
*
* @brief Returns stack usage of a thread.
*
* @param[in] threadp pointer to instance of @p struct pios_thread
*
* @return stack usage in bytes
*/
uint32_t PIOS_Thread_Get_Stack_Usage(struct pios_thread *threadp)
{
#if CH_DBG_FILL_THREADS
uint32_t *stack = (uint32_t *)((size_t)threadp->threadp + sizeof(*threadp->threadp));
uint32_t *stklimit = stack;
while (*stack ==
((CH_STACK_FILL_VALUE << 24) |
(CH_STACK_FILL_VALUE << 16) |
(CH_STACK_FILL_VALUE << 8) |
(CH_STACK_FILL_VALUE << 0))) {
++stack;
}
return (stack - stklimit) * 4;
#else
return 0;
#endif /* CH_DBG_FILL_THREADS */
}
/**
*
* @brief Returns runtime of a thread.
*
* @param[in] threadp pointer to instance of @p struct pios_thread
*
* @return runtime in milliseconds
*
*/
uint32_t PIOS_Thread_Get_Runtime(struct pios_thread *threadp)
{
chSysLock();
uint32_t result = threadp->threadp->ticks_total;
threadp->threadp->ticks_total = 0;
chSysUnlock();
return result;
}
/**
*
* @brief Suspends execution of all threads.
*
*/
void PIOS_Thread_Scheduler_Suspend(void)
{
chSysLock();
}
/**
*
* @brief Resumes execution of all threads.
*
*/
void PIOS_Thread_Scheduler_Resume(void)
{
chSysUnlock();
}
#endif /* defined(PIOS_INCLUDE_CHIBIOS) */

View File

@ -0,0 +1,54 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_RFM22B Radio Functions
* @brief PIOS OpenLRS interface for for the RFM22B radio
* @{
*
* @file pios_openlrs.h
* @author Tau Labs, http://taulabs.org, Copyright (C) 2015
* @author dRonin, http://dronin.org Copyright (C) 2015
* @brief Implements an OpenLRS driver for the RFM22B
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_OPENLRS_H
#define PIOS_OPENLRS_H
/* Global Types */
struct pios_openlrs_cfg {
const struct pios_spi_cfg *spi_cfg; /* Pointer to SPI interface configuration */
const struct pios_exti_cfg *exti_cfg; /* Pointer to the EXTI configuration */
enum gpio_direction gpio_direction; /* Definition comes from pios_rfm22b.h */
};
typedef void (*PIOS_OpenLRS_PPMReceivedCallback)(const int16_t *channels);
extern int32_t PIOS_OpenLRS_Init(uint32_t *openlrs_id, uint32_t spi_id,
uint32_t slave_num, const struct pios_openlrs_cfg *cfg);
extern void PIOS_OpenLRS_RegisterRcvr(uint32_t openlrs_id, uint32_t rfm22b_rcvr_id);
extern void PIOS_OpenLRS_RegisterPPMCallback(uint32_t openlrs_id, PIOS_OpenLRS_PPMReceivedCallback callback);
extern uint8_t PIOS_OpenLRS_RSSI_Get(void);
#endif /* PIOS_OPENLRS_H */
/**
* @}
* @}
*/

View File

@ -0,0 +1,208 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_RFM22B Radio Functions
* @brief PIOS OpenLRS interface for for the RFM22B radio
* @{
*
* @file pios_openlrs_priv.h
* @author Tau Labs, http://taulabs.org, Copyright (C) 2015
* @author dRonin, http://dronin.org Copyright (C) 2015
* @brief Implements an OpenLRS driver for the RFM22B
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_OPENLRS_PRIV_H
#define PIOS_OPENLRS_PRIV_H
#include "pios_openlrs.h"
#define OPENLRSNG_VERSION 0x0382
#define MAXHOPS 24
#define OPENLRS_PPM_NUM_CHANNELS 16
// Factory setting values, modify via the CLI
// ####### RADIOLINK RF POWER (beacon is always 100/13/1.3mW) #######
// 7 == 100mW (or 1000mW with M3)
// 6 == 50mW (use this when using booster amp), (800mW with M3)
// 5 == 25mW
// 4 == 13mW
// 3 == 6mW
// 2 == 3mW
// 1 == 1.6mW
// 0 == 1.3mW
#define DEFAULT_RF_POWER 7
#define DEFAULT_CHANNEL_SPACING 5 // 50kHz
#define DEFAULT_HOPLIST 22, 10, 19, 34, 49, 41
#define DEFAULT_RF_MAGIC 0xDEADFEED
// 0 -- 4800bps, best range
// 1 -- 9600bps, medium range
// 2 -- 19200bps, medium range
#define DEFAULT_DATARATE 2
// BIND_DATA flag masks
#define TELEMETRY_OFF 0x00
#define TELEMETRY_PASSTHRU 0x08
#define TELEMETRY_FRSKY 0x10 // covers smartport if used with &
#define TELEMETRY_SMARTPORT 0x18
#define TELEMETRY_MASK 0x18
#define CHANNELS_4_4 0x01
#define CHANNELS_8 0x02
#define CHANNELS_8_4 0x03
#define CHANNELS_12 0x04
#define CHANNELS_12_4 0x05
#define CHANNELS_16 0x06
#define DIVERSITY_ENABLED 0x80
#define DEFAULT_FLAGS (CHANNELS_8 | TELEMETRY_PASSTHRU)
// helper macro for European PMR channels
#define EU_PMR_CH(x) (445993750L + 12500L * (x)) // valid for ch1-ch8
// helper macro for US FRS channels 1-7
#define US_FRS_CH(x) (462537500L + 25000L * (x)) // valid for ch1-ch7
#define DEFAULT_BEACON_FREQUENCY 0 // disable beacon
#define DEFAULT_BEACON_DEADTIME 30 // time to wait until go into beacon mode (30s)
#define DEFAULT_BEACON_INTERVAL 10 // interval between beacon transmits (10s)
#define BINDING_POWER 0x06 // not lowest since may result fail with RFM23BP
#define TELEMETRY_PACKETSIZE 9
#define BIND_MAGIC (0xDEC1BE15 + (OPENLRSNG_VERSION & 0xfff0))
#define BINDING_VERSION ((OPENLRSNG_VERSION & 0x0ff0) >> 4)
// HW frequency limits
#define MIN_RFM_FREQUENCY_868 848000000
#define MAX_RFM_FREQUENCY_868 888000000
#define DEFAULT_CARRIER_FREQUENCY_868 868000000 // Hz (ch 0)
#define BINDING_FREQUENCY_868 868000000 // Hz
#define MIN_RFM_FREQUENCY_915 895000000
#define MAX_RFM_FREQUENCY_915 935000000
#define DEFAULT_CARRIER_FREQUENCY_915 915000000 // Hz (ch 0)
#define BINDING_FREQUENCY_915 915000000 // Hz
#define MIN_RFM_FREQUENCY_433 413000000
#define MAX_RFM_FREQUENCY_433 463000000
#define DEFAULT_CARRIER_FREQUENCY_433 435000000 // Hz (ch 0)
#define BINDING_FREQUENCY_433 435000000 // Hz
#define RFM22_DEVICE_TYPE 0x00 // R
#define RFM22_DT_MASK 0x1F
struct bind_data {
uint8_t version;
uint32_t serial_baudrate;
uint32_t rf_frequency;
uint32_t rf_magic;
uint8_t rf_power;
uint8_t rf_channel_spacing;
uint8_t hopchannel[MAXHOPS];
uint8_t modem_params;
uint8_t flags;
} __attribute__((packed));
enum RF_MODE {
Available, Transmit, Receive, Transmitted, Received,
};
enum pios_openlrs_dev_magic {
PIOS_OPENLRS_DEV_MAGIC = 0x18c97ab6,
};
struct pios_openlrs_dev {
enum pios_openlrs_dev_magic magic;
struct pios_openlrs_cfg cfg;
// The SPI bus information
uint32_t spi_id;
uint32_t slave_num;
double band;
// The task handle
struct pios_thread *taskHandle;
// The COM callback functions.
pios_com_callback rx_in_cb;
uint32_t rx_in_context;
pios_com_callback tx_out_cb;
uint32_t tx_out_context;
// The event queue handle
struct pios_semaphore *sema_isr;
// The PPM buffer
int16_t ppm[OPENLRS_PPM_NUM_CHANNELS];
// RFM22B RCVR interface
uintptr_t openlrs_rcvr_id;
// PPM callback.
PIOS_OpenLRS_PPMReceivedCallback ppm_callback;
// Flag to indicate if link every acquired
bool link_acquired;
// Active bound information data
struct bind_data bind_data;
// Beacon settings
uint32_t beacon_frequency;
uint8_t beacon_delay;
uint8_t beacon_period;
bool beacon_armed;
enum RF_MODE rf_mode;
uint32_t rf_channel;
uint8_t it_status1;
uint8_t it_status2;
uint8_t rx_buf[64];
uint8_t tx_buf[9];
int8_t rssi;
// Variables from OpenLRS for radio control
uint8_t hopcount;
uint32_t lastPacketTimeUs;
uint32_t numberOfLostPackets;
uint16_t lastAFCCvalue;
uint32_t lastRSSITimeUs;
bool willhop;
uint32_t nextBeaconTimeMs;
uint32_t linkLossTimeMs;
uint32_t failsafeDelay;
uint32_t beacon_rssi_avg;
};
bool PIOS_OpenLRS_EXT_Int(void);
#endif /* PIOS_OPENLRS_PRIV_H */
/**
* @}
* @}
*/

View File

@ -0,0 +1,47 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_RFM22b RFM22b receiver functions
* @brief Deals with the RFM22b module
* @{
*
* @file pios_rfm22b_rcvr_priv.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
* @author Tau Labs, http://taulabs.org, Copyright (C) 2014
* @brief TauLabs Link receiver private functions
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_OPENLRS_RCVR_PRIV_H
#define PIOS_OPENLRS_RCVR_PRIV_H
#include <pios.h>
extern const struct pios_rcvr_driver pios_openlrs_rcvr_driver;
extern int32_t PIOS_OpenLRS_Rcvr_Init(uint32_t *openlrs_rcvr_id, uintptr_t openlrs_id);
extern int32_t PIOS_OpenLRS_Rcvr_UpdateChannels(uint32_t openlrs_rcvr_id, int16_t *channels);
#endif /* PIOS_OPENLRS_RCVR_PRIV_H */
/**
* @}
* @}
*/

View File

@ -104,7 +104,7 @@ struct rfm22b_stats {
extern int32_t PIOS_RFM22B_Init(uint32_t *rfb22b_id, uint32_t spi_id, uint32_t slave_num, const struct pios_rfm22b_cfg *cfg);
extern void PIOS_RFM22B_Reinit(uint32_t rfb22b_id);
extern void PIOS_RFM22B_SetTxPower(uint32_t rfm22b_id, enum rfm22b_tx_power tx_pwr);
extern void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datarate, uint8_t min_chan, uint8_t max_chan, bool coordinator, bool oneway, bool ppm_mode, bool ppm_only);
extern void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datarate, uint8_t min_chan, uint8_t max_chan, bool coordinator, bool ppm_mode, bool ppm_only);
extern void PIOS_RFM22B_SetCoordinatorID(uint32_t rfm22b_id, uint32_t coord_id);
extern void PIOS_RFM22B_SetDeviceID(uint32_t rfm22b_id, uint32_t device_id);
extern uint32_t PIOS_RFM22B_DeviceID(uint32_t rfb22b_id);
@ -117,8 +117,8 @@ extern bool PIOS_RFM22B_TransmitPacket(uint32_t rfm22b_id, uint8_t *p, uint8_t l
extern pios_rfm22b_int_result PIOS_RFM22B_ProcessTx(uint32_t rfm22b_id);
extern pios_rfm22b_int_result PIOS_RFM22B_ProcessRx(uint32_t rfm22b_id);
extern void PIOS_RFM22B_SetPPMCallback(uint32_t rfm22b_id, PPMReceivedCallback cb);
extern void PIOS_RFM22B_PPMSet(uint32_t rfm22b_id, int16_t *channels);
extern void PIOS_RFM22B_PPMGet(uint32_t rfm22b_id, int16_t *channels);
extern void PIOS_RFM22B_PPMSet(uint32_t rfm22b_id, int16_t *channels, uint8_t nchan);
extern void PIOS_RFM22B_PPMGet(uint32_t rfm22b_id, int16_t *channels, uint8_t nchan);
/* Global Variables */
extern const struct pios_com_driver pios_rfm22b_com_driver;

View File

@ -39,488 +39,8 @@
// ************************************
#define RFM22B_MAX_PACKET_LEN 64
#define RFM22B_NUM_CHANNELS 251
// ************************************
#define RFM22_DEVICE_VERSION_V2 0x02
#define RFM22_DEVICE_VERSION_A0 0x04
#define RFM22_DEVICE_VERSION_B1 0x06
// ************************************
#define BIT0 (1u << 0)
#define BIT1 (1u << 1)
#define BIT2 (1u << 2)
#define BIT3 (1u << 3)
#define BIT4 (1u << 4)
#define BIT5 (1u << 5)
#define BIT6 (1u << 6)
#define BIT7 (1u << 7)
// ************************************
#define RFM22_DEVICE_TYPE 0x00 // R
#define RFM22_DT_MASK 0x1F
#define RFM22_DEVICE_VERSION 0x01 // R
#define RFM22_DV_MASK 0x1F
#define RFM22_device_status 0x02 // R
#define RFM22_ds_cps_mask 0x03 // Chip Power State mask
#define RFM22_ds_cps_idle 0x00 // IDLE Chip Power State
#define RFM22_ds_cps_rx 0x01 // RX Chip Power State
#define RFM22_ds_cps_tx 0x02 // TX Chip Power State
// #define RFM22_ds_lockdet 0x04 //
// #define RFM22_ds_freqerr 0x08 //
#define RFM22_ds_headerr 0x10 // Header Error Status. Indicates if the received packet has a header check error
#define RFM22_ds_rxffem 0x20 // RX FIFO Empty Status
#define RFM22_ds_ffunfl 0x40 // RX/TX FIFO Underflow Status
#define RFM22_ds_ffovfl 0x80 // RX/TX FIFO Overflow Status
#define RFM22_interrupt_status1 0x03 // R
#define RFM22_is1_icrerror BIT0 // CRC Error. When set to 1 the cyclic redundancy check is failed.
#define RFM22_is1_ipkvalid BIT1 // Valid Packet Received.When set to 1 a valid packet has been received.
#define RFM22_is1_ipksent BIT2 // Packet Sent Interrupt. When set to1 a valid packet has been transmitted.
#define RFM22_is1_iext BIT3 // External Interrupt. When set to 1 an interrupt occurred on one of the GPIO<49>s if it is programmed so. The status can be checked in register 0Eh. See GPIOx Configuration section for the details.
#define RFM22_is1_irxffafull BIT4 // RX FIFO Almost Full.When set to 1 the RX FIFO has met its almost full threshold and needs to be read by the microcontroller.
#define RFM22_is1_ixtffaem BIT5 // TX FIFO Almost Empty. When set to 1 the TX FIFO is almost empty and needs to be filled.
#define RFM22_is1_itxffafull BIT6 // TX FIFO Almost Full. When set to 1 the TX FIFO has met its almost full threshold and needs to be transmitted.
#define RFM22_is1_ifferr BIT7 // FIFO Underflow/Overflow Error. When set to 1 the TX or RX FIFO has overflowed or underflowed.
#define RFM22_interrupt_status2 0x04 // R
#define RFM22_is2_ipor BIT0 // Power-on-Reset (POR). When the chip detects a Power on Reset above the desired setting this bit will be set to 1.
#define RFM22_is2_ichiprdy BIT1 // Chip Ready (XTAL). When a chip ready event has been detected this bit will be set to 1.
#define RFM22_is2_ilbd BIT2 // Low Battery Detect. When a low battery event is been detected this bit will be set to 1. This interrupt event is saved even if it is not enabled by the mask register bit and causes an interrupt after it is enabled.
#define RFM22_is2_iwut BIT3 // Wake-Up-Timer. On the expiration of programmed wake-up timer this bit will be set to 1.
#define RFM22_is2_irssi BIT4 // RSSI. When RSSI level exceeds the programmed threshold this bit will be set to 1.
#define RFM22_is2_ipreainval BIT5 // Invalid Preamble Detected. When the preamble is not found within a period of time set by the invalid preamble detection threshold in Register 54h, this bit will be set to 1.
#define RFM22_is2_ipreaval BIT6 // Valid Preamble Detected. When a preamble is detected this bit will be set to 1.
#define RFM22_is2_iswdet BIT7 // Sync Word Detected. When a sync word is detected this bit will be set to 1.
#define RFM22_interrupt_enable1 0x05 // R/W
#define RFM22_ie1_encrcerror BIT0 // Enable CRC Error. When set to 1 the CRC Error interrupt will be enabled.
#define RFM22_ie1_enpkvalid BIT1 // Enable Valid Packet Received. When ipkvalid = 1 the Valid Packet Received Interrupt will be enabled.
#define RFM22_ie1_enpksent BIT2 // Enable Packet Sent. When ipksent =1 the Packet Sense Interrupt will be enabled.
#define RFM22_ie1_enext BIT3 // Enable External Interrupt. When set to 1 the External Interrupt will be enabled.
#define RFM22_ie1_enrxffafull BIT4 // Enable RX FIFO Almost Full. When set to 1 the RX FIFO Almost Full interrupt will be enabled.
#define RFM22_ie1_entxffaem BIT5 // Enable TX FIFO Almost Empty. When set to 1 the TX FIFO Almost Empty interrupt will be enabled.
#define RFM22_ie1_entxffafull BIT6 // Enable TX FIFO Almost Full. When set to 1 the TX FIFO Almost Full interrupt will be enabled.
#define RFM22_ie1_enfferr BIT7 // Enable FIFO Underflow/Overflow. When set to 1 the FIFO Underflow/Overflow interrupt will be enabled.
#define RFM22_interrupt_enable2 0x06 // R/W
#define RFM22_ie2_enpor BIT0 // Enable POR. When set to 1 the POR interrupt will be enabled.
#define RFM22_ie2_enchiprdy BIT1 // Enable Chip Ready (XTAL). When set to 1 the Chip Ready interrupt will be enabled.
#define RFM22_ie2_enlbd BIT2 // Enable Low Battery Detect. When set to 1 the Low Battery Detect interrupt will be enabled.
#define RFM22_ie2_enwut BIT3 // Enable Wake-Up Timer. When set to 1 the Wake-Up Timer interrupt will be enabled.
#define RFM22_ie2_enrssi BIT4 // Enable RSSI. When set to 1 the RSSI Interrupt will be enabled.
#define RFM22_ie2_enpreainval BIT5 // Enable Invalid Preamble Detected. When mpreadet =1 the Invalid Preamble Detected Interrupt will be enabled.
#define RFM22_ie2_enpreaval BIT6 // Enable Valid Preamble Detected. When mpreadet =1 the Valid Preamble Detected Interrupt will be enabled.
#define RFM22_ie2_enswdet BIT7 // Enable Sync Word Detected. When mpreadet =1 the Preamble Detected Interrupt will be enabled.
#define RFM22_op_and_func_ctrl1 0x07 // R/W
#define RFM22_opfc1_xton 0x01 // READY Mode (Xtal is ON).
#define RFM22_opfc1_pllon 0x02 // TUNE Mode (PLL is ON). When pllon = 1 the PLL will remain enabled in Idle State. This will for faster turn-around time at the cost of increased current consumption in Idle State.
#define RFM22_opfc1_rxon 0x04 // RX on in Manual Receiver Mode. Automatically cleared if Multiple Packets config. is disabled and a valid packet received.
#define RFM22_opfc1_txon 0x08 // TX on in Manual Transmit Mode. Automatically cleared in FIFO mode once the packet is sent. Transmission can be aborted during packet transmission, however, when no data has been sent yet, transmission can only be aborted after the device is programmed to <20>unmodulated carrier<65> ("Register 71h. Modulation Mode Control 2").
#define RFM22_opfc1_x32ksel 0x10 // 32,768 kHz Crystal Oscillator Select. 0: RC oscillator 1: 32 kHz crystal
#define RFM22_opfc1_enwt 0x20 // Enable Wake-Up-Timer. Enabled when enwt = 1. If the Wake-up-Timer function is enabled it will operate in any mode and notify the microcontroller through the GPIO interrupt when the timer expires.
#define RFM22_opfc1_enlbd 0x40 // Enable Low Battery Detect. When this bit is set to 1 the Low Battery Detector circuit and threshold comparison will be enabled.
#define RFM22_opfc1_swres 0x80 // Software Register Reset Bit. This bit may be used to reset all registers simultaneously to a DEFAULT state, without the need for sequentially writing to each individual register. The RESET is accomplished by setting swres = 1. This bit will be automatically cleared.
#define RFM22_op_and_func_ctrl2 0x08 // R/W
#define RFM22_opfc2_ffclrtx 0x01 // TX FIFO Reset/Clear. This has to be a two writes operation: Setting ffclrtx =1 followed by ffclrtx = 0 will clear the contents of the TX FIFO.
#define RFM22_opfc2_ffclrrx 0x02 // RX FIFO Reset/Clear. This has to be a two writes operation: Setting ffclrrx =1 followed by ffclrrx = 0 will clear the contents of the RX FIFO.
#define RFM22_opfc2_enldm 0x04 // Enable Low Duty Cycle Mode. If this bit is set to 1 then the chip turns on the RX regularly. The frequency should be set in the Wake-Up Timer Period register, while the minimum ON time should be set in the Low-Duty Cycle Mode Duration register. The FIFO mode should be enabled also.
#define RFM22_opfc2_autotx 0x08 // Automatic Transmission. When autotx = 1 the transceiver will enter automatically TX State when the FIFO is almost full. When the FIFO is empty it will automatically return to the Idle State.
#define RFM22_opfc2_rxmpk 0x10 // RX Multi Packet. When the chip is selected to use FIFO Mode (dtmod[1:0]) and RX Packet Handling (enpacrx) then it will fill up the FIFO with multiple valid packets if this bit is set, otherwise the transceiver will automatically leave the RX State after the first valid packet has been received.
#define RFM22_opfc2_antdiv_mask 0xE0 // Enable Antenna Diversity. The GPIO must be configured for Antenna Diversity for the algorithm to work properly.
#define RFM22_xtal_osc_load_cap 0x09 // R/W
#define RFM22_xolc_xlc_mask 0x7F // Tuning Capacitance for the 30 MHz XTAL.
#define RFM22_xolc_xtalshft 0x80 // Additional capacitance to course shift the frequency if xlc[6:0] is not sufficient. Not binary with xlc[6:0].
#define RFM22_cpu_output_clk 0x0A // R/W
#define RFM22_coc_30MHz 0x00
#define RFM22_coc_15MHz 0x01
#define RFM22_coc_10MHz 0x02
#define RFM22_coc_4MHz 0x03
#define RFM22_coc_3MHz 0x04
#define RFM22_coc_2MHz 0x05
#define RFM22_coc_1MHz 0x06
#define RFM22_coc_32768Hz 0x07
#define RFM22_coc_enlfc 0x08
#define RFM22_coc_0cycle 0x00
#define RFM22_coc_128cycles 0x10
#define RFM22_coc_256cycles 0x20
#define RFM22_coc_512cycles 0x30
#define RFM22_gpio0_config 0x0B // R/W
#define RFM22_gpio0_config_por 0x00 // Power-On-Reset (output)
#define RFM22_gpio0_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
#define RFM22_gpio0_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
#define RFM22_gpio0_config_ddi 0x03 // Direct Digital Input
#define RFM22_gpio0_config_eife 0x04 // External Interrupt, falling edge (input)
#define RFM22_gpio0_config_eire 0x05 // External Interrupt, rising edge (input)
#define RFM22_gpio0_config_eisc 0x06 // External Interrupt, state change (input)
#define RFM22_gpio0_config_ai 0x07 // ADC Analog Input
#define RFM22_gpio0_config_atni 0x08 // Reserved (Analog Test N Input)
#define RFM22_gpio0_config_atpi 0x09 // Reserved (Analog Test P Input)
#define RFM22_gpio0_config_ddo 0x0A // Direct Digital Output
#define RFM22_gpio0_config_dto 0x0B // Reserved (Digital Test Output)
#define RFM22_gpio0_config_atno 0x0C // Reserved (Analog Test N Output)
#define RFM22_gpio0_config_atpo 0x0D // Reserved (Analog Test P Output)
#define RFM22_gpio0_config_rv 0xOE // Reference Voltage (output)
#define RFM22_gpio0_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
#define RFM22_gpio0_config_txd 0x10 // TX Data input for direct modulation (input)
#define RFM22_gpio0_config_err 0x11 // External Retransmission Request (input)
#define RFM22_gpio0_config_txstate 0x12 // TX State (output)
#define RFM22_gpio0_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
#define RFM22_gpio0_config_rxd 0x14 // RX Data (output)
#define RFM22_gpio0_config_rxstate 0x15 // RX State (output)
#define RFM22_gpio0_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
#define RFM22_gpio0_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
#define RFM22_gpio0_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
#define RFM22_gpio0_config_vpd 0x19 // Valid Preamble Detected (output)
#define RFM22_gpio0_config_ipd 0x1A // Invalid Preamble Detected (output)
#define RFM22_gpio0_config_swd 0x1B // Sync Word Detected (output)
#define RFM22_gpio0_config_cca 0x1C // Clear Channel Assessment (output)
#define RFM22_gpio0_config_vdd 0x1D // VDD
#define RFM22_gpio0_config_pup 0x20
#define RFM22_gpio0_config_drv0 0x00 // output drive level
#define RFM22_gpio0_config_drv1 0x40 // output drive level
#define RFM22_gpio0_config_drv2 0x80 // output drive level
#define RFM22_gpio0_config_drv3 0xC0 // output drive level
#define RFM22_gpio1_config 0x0C // R/W
#define RFM22_gpio1_config_ipor 0x00 // Inverted Power-On-Reset (output)
#define RFM22_gpio1_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
#define RFM22_gpio1_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
#define RFM22_gpio1_config_ddi 0x03 // Direct Digital Input
#define RFM22_gpio1_config_eife 0x04 // External Interrupt, falling edge (input)
#define RFM22_gpio1_config_eire 0x05 // External Interrupt, rising edge (input)
#define RFM22_gpio1_config_eisc 0x06 // External Interrupt, state change (input)
#define RFM22_gpio1_config_ai 0x07 // ADC Analog Input
#define RFM22_gpio1_config_atni 0x08 // Reserved (Analog Test N Input)
#define RFM22_gpio1_config_atpi 0x09 // Reserved (Analog Test P Input)
#define RFM22_gpio1_config_ddo 0x0A // Direct Digital Output
#define RFM22_gpio1_config_dto 0x0B // Reserved (Digital Test Output)
#define RFM22_gpio1_config_atno 0x0C // Reserved (Analog Test N Output)
#define RFM22_gpio1_config_atpo 0x0D // Reserved (Analog Test P Output)
#define RFM22_gpio1_config_rv 0xOE // Reference Voltage (output)
#define RFM22_gpio1_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
#define RFM22_gpio1_config_txd 0x10 // TX Data input for direct modulation (input)
#define RFM22_gpio1_config_err 0x11 // External Retransmission Request (input)
#define RFM22_gpio1_config_txstate 0x12 // TX State (output)
#define RFM22_gpio1_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
#define RFM22_gpio1_config_rxd 0x14 // RX Data (output)
#define RFM22_gpio1_config_rxstate 0x15 // RX State (output)
#define RFM22_gpio1_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
#define RFM22_gpio1_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
#define RFM22_gpio1_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
#define RFM22_gpio1_config_vpd 0x19 // Valid Preamble Detected (output)
#define RFM22_gpio1_config_ipd 0x1A // Invalid Preamble Detected (output)
#define RFM22_gpio1_config_swd 0x1B // Sync Word Detected (output)
#define RFM22_gpio1_config_cca 0x1C // Clear Channel Assessment (output)
#define RFM22_gpio1_config_vdd 0x1D // VDD
#define RFM22_gpio1_config_pup 0x20
#define RFM22_gpio1_config_drv0 0x00 // output drive level
#define RFM22_gpio1_config_drv1 0x40 // output drive level
#define RFM22_gpio1_config_drv2 0x80 // output drive level
#define RFM22_gpio1_config_drv3 0xC0 // output drive level
#define RFM22_gpio2_config 0x0D // R/W
#define RFM22_gpio2_config_mc 0x00 // Microcontroller Clock (output)
#define RFM22_gpio2_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
#define RFM22_gpio2_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
#define RFM22_gpio2_config_ddi 0x03 // Direct Digital Input
#define RFM22_gpio2_config_eife 0x04 // External Interrupt, falling edge (input)
#define RFM22_gpio2_config_eire 0x05 // External Interrupt, rising edge (input)
#define RFM22_gpio2_config_eisc 0x06 // External Interrupt, state change (input)
#define RFM22_gpio2_config_ai 0x07 // ADC Analog Input
#define RFM22_gpio2_config_atni 0x08 // Reserved (Analog Test N Input)
#define RFM22_gpio2_config_atpi 0x09 // Reserved (Analog Test P Input)
#define RFM22_gpio2_config_ddo 0x0A // Direct Digital Output
#define RFM22_gpio2_config_dto 0x0B // Reserved (Digital Test Output)
#define RFM22_gpio2_config_atno 0x0C // Reserved (Analog Test N Output)
#define RFM22_gpio2_config_atpo 0x0D // Reserved (Analog Test P Output)
#define RFM22_gpio2_config_rv 0xOE // Reference Voltage (output)
#define RFM22_gpio2_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
#define RFM22_gpio2_config_txd 0x10 // TX Data input for direct modulation (input)
#define RFM22_gpio2_config_err 0x11 // External Retransmission Request (input)
#define RFM22_gpio2_config_txstate 0x12 // TX State (output)
#define RFM22_gpio2_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
#define RFM22_gpio2_config_rxd 0x14 // RX Data (output)
#define RFM22_gpio2_config_rxstate 0x15 // RX State (output)
#define RFM22_gpio2_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
#define RFM22_gpio2_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
#define RFM22_gpio2_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
#define RFM22_gpio2_config_vpd 0x19 // Valid Preamble Detected (output)
#define RFM22_gpio2_config_ipd 0x1A // Invalid Preamble Detected (output)
#define RFM22_gpio2_config_swd 0x1B // Sync Word Detected (output)
#define RFM22_gpio2_config_cca 0x1C // Clear Channel Assessment (output)
#define RFM22_gpio2_config_vdd 0x1D // VDD
#define RFM22_gpio2_config_pup 0x20
#define RFM22_gpio2_config_drv0 0x00 // output drive level
#define RFM22_gpio2_config_drv1 0x40 // output drive level
#define RFM22_gpio2_config_drv2 0x80 // output drive level
#define RFM22_gpio2_config_drv3 0xC0 // output drive level
#define RFM22_io_port_config 0x0E // R/W
#define RFM22_io_port_extitst2 0x40 // External Interrupt Status. If the GPIO2 is programmed to be external interrupt sources then the status can be read here.
#define RFM22_io_port_extitst1 0x20 // External Interrupt Status. If the GPIO1 is programmed to be external interrupt sources then the status can be read here.
#define RFM22_io_port_extitst0 0x10 // External Interrupt Status. If the GPIO0 is programmed to be external interrupt sources then the status can be read here.
#define RFM22_io_port_itsdo 0x08 // Interrupt Request Output on the SDO Pin. nIRQ output is present on the SDO pin if this bit is set and the nSEL input is inactive (high).
#define RFM22_io_port_dio2 0x04 // Direct I/O for GPIO2. If the GPIO2 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO2 is configured to be a direct input then the value of the pin can be read here.
#define RFM22_io_port_dio1 0x02 // Direct I/O for GPIO1. If the GPIO1 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO1 is configured to be a direct input then the value of the pin can be read here.
#define RFM22_io_port_dio0 0x01 // Direct I/O for GPIO0. If the GPIO0 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO0 is configured to be a direct input then the value of the pin can be read here.
#define RFM22_io_port_default 0x00 // GPIO pins are default
#define RFM22_adc_config 0x0F // R/W
#define RFM22_ac_adcgain0 0x00
#define RFM22_ac_adcgain1 0x01
#define RFM22_ac_adcgain2 0x02
#define RFM22_ac_adcgain3 0x03
#define RFM22_ac_adcref_bg 0x00
#define RFM22_ac_adcref_vdd3 0x08
#define RFM22_ac_adcref_vdd2 0x0C
#define RFM22_ac_adcsel_temp_sensor 0x00
#define RFM22_ac_adcsel_gpio0 0x10
#define RFM22_ac_adcsel_gpio1 0x20
#define RFM22_ac_adcsel_gpio2 0x30
#define RFM22_ac_adcsel_gpio01 0x40
#define RFM22_ac_adcsel_gpio12 0x50
#define RFM22_ac_adcsel_gpio02 0x60
#define RFM22_ac_adcsel_gpio_gnd 0x70
#define RFM22_ac_adcstartbusy 0x80
#define RFM22_adc_sensor_amp_offset 0x10 // R/W
#define RFM22_asao_adcoffs_mask 0x0F // ADC Sensor Amplifier Offset. The offset can be calculated as Offset = adcoffs[2:0] x VDD/1000; MSB = adcoffs[3] = Sign bit.
#define RFM22_adc_value 0x11 // R .. Internal 8 bit ADC Output Value.
#define RFM22_temp_sensor_calib 0x12 // R/W
#define RFM22_tsc_tstrim_mask 0x0F // Temperature Sensor Trim Value.
#define RFM22_tsc_entstrim 0x10 // Temperature Sensor Trim Enable.
#define RFM22_tsc_entsoffs 0x20 // Temperature Sensor Offset to Convert from K to <20>C.
#define RFM22_tsc_tsrange0 0x00 // Temperature Sensor Range Selection. <20>64C to +64C 0.5C resolution
#define RFM22_tsc_tsrange1 0x40 // -40 to +85C with 1.0C resolution
#define RFM22_tsc_tsrange2 0x80 // 0C to 85C with 0.5C resolution
#define RFM22_tsc_tsrange3 0xC0 // -40F to 216F with 1.0F resolution
#define RFM22_temp_value_offset 0x13 // R/W
#define RFM22_wakeup_timer_period1 0x14 // R/W
#define RFM22_wakeup_timer_period2 0x15 // R/W
#define RFM22_wakeup_timer_period3 0x16 // R/W
#define RFM22_wakeup_timer_value1 0x17 // R
#define RFM22_wakeup_timer_value2 0x18 // R
#define RFM22_low_dutycycle_mode_duration 0x19 // R/W
#define RFM22_low_battery_detector_threshold 0x1A // R/W
#define RFM22_battery_volateg_level 0x1B // R
#define RFM22_if_filter_bandwidth 0x1C // R/W
#define RFM22_iffbw_filset_mask 0x0F
#define RFM22_iffbw_ndec_exp_mask 0x70
#define RFM22_iffbw_dwn3_bypass 0x80
#define RFM22_afc_loop_gearshift_override 0x1D // R/W
#define RFM22_afc_lp_gs_ovrd_afcgearl_mask 0x07 // AFC Low Gear Setting.
#define RFM22_afc_lp_gs_ovrd_afcgearh_mask 0x38 // AFC High Gear Setting.
#define RFM22_afc_lp_gs_ovrd_enafc 0x40 // AFC Enable.
#define RFM22_afc_lp_gs_ovrd_afcbd 0x80 // If set, the tolerated AFC frequency error will be halved.
#define RFM22_afc_timing_control 0x1E // R/W
#define RFM22_clk_recovery_gearshift_override 0x1F // R/W
#define RFM22_clk_recovery_oversampling_ratio 0x20 // R/W
#define RFM22_clk_recovery_offset2 0x21 // R/W
#define RFM22_clk_recovery_offset1 0x22 // R/W
#define RFM22_clk_recovery_offset0 0x23 // R/W
#define RFM22_clk_recovery_timing_loop_gain1 0x24 // R/W
#define RFM22_clk_recovery_timing_loop_gain0 0x25 // R/W
#define RFM22_rssi 0x26 // R
#define RFM22_rssi_threshold_clear_chan_indicator 0x27 // R/W
#define RFM22_antenna_diversity_register1 0x28 // R
#define RFM22_antenna_diversity_register2 0x29 // R
#define RFM22_afc_limiter 0x2A // R/W .. AFC_pull_in_range = <20>AFCLimiter[7:0] x (hbsel+1) x 625 Hz
#define RFM22_afc_correction_read 0x2B // R
#define RFM22_ook_counter_value1 0x2C // R/W
#define RFM22_ook_counter_value2 0x2D // R/W
#define RFM22_slicer_peak_hold 0x2E // R/W
#define RFM22_data_access_control 0x30 // R/W
#define RFM22_dac_crc_ccitt 0x00 //
#define RFM22_dac_crc_crc16 0x01 //
#define RFM22_dac_crc_iec16 0x02 //
#define RFM22_dac_crc_biacheva 0x03 //
#define RFM22_dac_encrc 0x04 // CRC Enable. Cyclic Redundancy Check generation is enabled if this bit is set.
#define RFM22_dac_enpactx 0x08 // Enable Packet TX Handling. If FIFO Mode (dtmod = 10) is being used automatic packet handling may be enabled. Setting enpactx = 1 will enable automatic packet handling in the TX path. Register 30<33>4D allow for various configurations of the packet structure. Setting enpactx = 0 will not do any packet handling in the TX path. It will only transmit what is loaded to the FIFO.
#define RFM22_dac_skip2ph 0x10 // Skip 2nd Phase of Preamble Detection. If set, we skip the second phase of the preamble detection (under certain conditions) if antenna diversity is enabled.
#define RFM22_dac_crcdonly 0x20 // CRC Data Only Enable. When this bit is set to 1 the CRC is calculated on and checked against the packet data fields only.
#define RFM22_dac_lsbfrst 0x40 // LSB First Enable. The LSB of the data will be transmitted/received first if this bit is set.
#define RFM22_dac_enpacrx 0x80 // Enable Packet RX Handling. If FIFO Mode (dtmod = 10) is being used automatic packet handling may be enabled. Setting enpacrx = 1 will enable automatic packet handling in the RX path. Register 30<33>4D allow for various configurations of the packet structure. Setting enpacrx = 0 will not do any packet handling in the RX path. It will only receive everything after the sync word and fill up the RX FIFO.
#define RFM22_ezmac_status 0x31 // R
#define RFM22_ezmac_status_pksent 0x01 // Packet Sent. A 1 a packet has been sent by the radio. (Same bit as in register 03, but reading it does not reset the IRQ)
#define RFM22_ezmac_status_pktx 0x02 // Packet Transmitting. When 1 the radio is currently transmitting a packet.
#define RFM22_ezmac_status_crcerror 0x04 // CRC Error. When 1 a Cyclic Redundancy Check error has been detected. (Same bit as in register 03, but reading it does not reset the IRQ)
#define RFM22_ezmac_status_pkvalid 0x08 // Valid Packet Received. When a 1 a valid packet has been received by the receiver. (Same bit as in register 03, but reading it does not reset the IRQ)
#define RFM22_ezmac_status_pkrx 0x10 // Packet Receiving. When 1 the radio is currently receiving a valid packet.
#define RFM22_ezmac_status_pksrch 0x20 // Packet Searching. When 1 the radio is searching for a valid packet.
#define RFM22_ezmac_status_rxcrc1 0x40 // If high, it indicates the last CRC received is all one<6E>s. May indicated Transmitter underflow in case of CRC error.
#define RFM22_header_control1 0x32 // R/W
#define RFM22_header_cntl1_bcen_none 0x00 // No broadcast address enable.
#define RFM22_header_cntl1_bcen_0 0x10 // Broadcast address enable for header byte 0.
#define RFM22_header_cntl1_bcen_1 0x20 // Broadcast address enable for header byte 1.
#define RFM22_header_cntl1_bcen_2 0x40 // Broadcast address enable for header byte 2.
#define RFM22_header_cntl1_bcen_3 0x80 // Broadcast address enable for header byte 3.
#define RFM22_header_cntl1_hdch_none 0x00 // No Received Header check
#define RFM22_header_cntl1_hdch_0 0x01 // Received Header check for byte 0.
#define RFM22_header_cntl1_hdch_1 0x02 // Received Header check for byte 1.
#define RFM22_header_cntl1_hdch_2 0x04 // Received Header check for byte 2.
#define RFM22_header_cntl1_hdch_3 0x08 // Received Header check for byte 3.
#define RFM22_header_control2 0x33 // R/W
#define RFM22_header_cntl2_prealen 0x01 // MSB of Preamble Length. See register Preamble Length.
#define RFM22_header_cntl2_synclen_3 0x00 // Synchronization Word 3
#define RFM22_header_cntl2_synclen_32 0x02 // Synchronization Word 3 followed by 2
#define RFM22_header_cntl2_synclen_321 0x04 // Synchronization Word 3 followed by 2 followed by 1
#define RFM22_header_cntl2_synclen_3210 0x06 // Synchronization Word 3 followed by 2 followed by 1 followed by 0
#define RFM22_header_cntl2_fixpklen 0x08 // Fix Packet Length. When fixpklen = 1 the packet length (pklen[7:0]) is not included in the header. When fixpklen = 0 the packet length is included in the header.
#define RFM22_header_cntl2_hdlen_none 0x00 // no header
#define RFM22_header_cntl2_hdlen_3 0x10 // header 3
#define RFM22_header_cntl2_hdlen_32 0x20 // header 3 and 2
#define RFM22_header_cntl2_hdlen_321 0x30 // header 3 and 2 and 1
#define RFM22_header_cntl2_hdlen_3210 0x40 // header 3 and 2 and 1 and 0
#define RFM22_header_cntl2_skipsyn 0x80 // If high, the system will ignore the syncword search timeout reset. The chip will not return to searching for Preamble, but instead will remain searching for Sync word.
#define RFM22_preamble_length 0x34 // R/W
#define RFM22_preamble_detection_ctrl1 0x35 // R/W
#define RFM22_pre_det_ctrl1_preath_mask 0xF8 // Number of nibbles processed during detection.
#define RFM22_pre_det_ctrl1_rssi_offset_mask 0x07 // Value added as offset to RSSI calculation. Every increment in this register results in an increment of +4 dB in the RSSI.
#define RFM22_sync_word3 0x36 // R/W
#define RFM22_sync_word2 0x37 // R/W
#define RFM22_sync_word1 0x38 // R/W
#define RFM22_sync_word0 0x39 // R/W
#define RFM22_transmit_header3 0x3A // R/W
#define RFM22_transmit_header2 0x3B // R/W
#define RFM22_transmit_header1 0x3C // R/W
#define RFM22_transmit_header0 0x3D // R/W
#define RFM22_transmit_packet_length 0x3E // R/W
#define RFM22_check_header3 0x3F // R/W
#define RFM22_check_header2 0x40 // R/W
#define RFM22_check_header1 0x41 // R/W
#define RFM22_check_header0 0x42 // R/W
#define RFM22_header_enable3 0x43 // R/W
#define RFM22_header_enable2 0x44 // R/W
#define RFM22_header_enable1 0x45 // R/W
#define RFM22_header_enable0 0x46 // R/W
#define RFM22_received_header3 0x47 // R
#define RFM22_received_header2 0x48 // R
#define RFM22_received_header1 0x49 // R
#define RFM22_received_header0 0x4A // R
#define RFM22_received_packet_length 0x4B // R
#define RFM22_adc8_control 0x4F // R/W
#define RFM22_channel_filter_coeff_addr 0x60 // R/W
#define RFM22_ch_fil_coeff_ad_inv_pre_th_mask 0xF0 //
#define RFM22_ch_fil_coeff_ad_chfiladd_mask 0x0F // Channel Filter Coefficient Look-up Table Address. The address for channel filter coefficients used in the RX path.
#define RFM22_xtal_osc_por_ctrl 0x62 // R/W
#define RFM22_xtal_osc_por_ctrl_pwst_mask 0xE0 // Internal Power States of the Chip.
#define RFM22_xtal_osc_por_ctrl_clkhyst 0x10 // Clock Hysteresis Setting.
#define RFM22_xtal_osc_por_ctrl_enbias2x 0x08 // 2 Times Higher Bias Current Enable.
#define RFM22_xtal_osc_por_ctrl_enamp2x 0x04 // 2 Times Higher Amplification Enable.
#define RFM22_xtal_osc_por_ctrl_bufovr 0x02 // Output Buffer Enable Override.
#define RFM22_xtal_osc_por_ctrl_enbuf 0x01 // Output Buffer Enable.
#define RFM22_agc_override1 0x69 // R/W
#define RFM22_agc_ovr1_sgi 0x40 // AGC Loop, Set Gain Increase. If set to 0 then gain increasing will not be allowed. If set to 1 then gain increasing is allowed, default is 0.
#define RFM22_agc_ovr1_agcen 0x20 // Automatic Gain Control Enable. When this bit is set then the result of the control can be read out from bits [4:0], otherwise the gain can be controlled manually by writing into bits [4:0].
#define RFM22_agc_ovr1_lnagain 0x10 // LNA Gain Select. 0 = min gain = 5dB, 1 = max gain = 25 dB.
#define RFM22_agc_ovr1_pga_mask 0x0F // PGA Gain Override Value.
#define RFM22_tx_power 0x6D // R/W
#define RFM22_tx_pwr_lna_sw 0x08 // LNA Switch Controller. If set, lna_sw control from the digital will go high during TX modes, and low during other times. If reset, the digital control signal is low at all times.
#define RFM22_tx_data_rate1 0x6E // R/W
#define RFM22_tx_data_rate0 0x6F // R/W
#define RFM22_modulation_mode_control1 0x70 // R/W
#define RFM22_mmc1_enwhite 0x01 // Data Whitening is Enabled if this bit is set.
#define RFM22_mmc1_enmanch 0x02 // Manchester Coding is Enabled if this bit is set.
#define RFM22_mmc1_enmaninv 0x04 // Manchester Data Inversion is Enabled if this bit is set.
#define RFM22_mmc1_manppol 0x08 // Manchester Preamble Polarity (will transmit a series of 1 if set, or series of 0 if reset).
#define RFM22_mmc1_enphpwdn 0x10 // If set, the Packet Handler will be powered down when chip is in low power mode.
#define RFM22_mmc1_txdtrtscale 0x20 // This bit should be set for Data Rates below 30 kbps.
#define RFM22_modulation_mode_control2 0x71 // R/W
#define RFM22_mmc2_modtyp_mask 0x03 // Modulation type.
#define RFM22_mmc2_modtyp_none 0x00 //
#define RFM22_mmc2_modtyp_ook 0x01 //
#define RFM22_mmc2_modtyp_fsk 0x02 //
#define RFM22_mmc2_modtyp_gfsk 0x03 //
#define RFM22_mmc2_fd 0x04 // MSB of Frequency Deviation Setting, see "Register 72h. Frequency Deviation".
#define RFM22_mmc2_eninv 0x08 // Invert TX and RX Data.
#define RFM22_mmc2_dtmod_mask 0x30 // Modulation source.
#define RFM22_mmc2_dtmod_dm_gpio 0x00 //
#define RFM22_mmc2_dtmod_dm_sdi 0x10 //
#define RFM22_mmc2_dtmod_fifo 0x20 //
#define RFM22_mmc2_dtmod_pn9 0x30 //
#define RFM22_mmc2_trclk_mask 0xC0 // TX Data Clock Configuration.
#define RFM22_mmc2_trclk_clk_none 0x00 //
#define RFM22_mmc2_trclk_clk_gpio 0x40 //
#define RFM22_mmc2_trclk_clk_sdo 0x80 //
#define RFM22_mmc2_trclk_clk_nirq 0xC0 //
#define RFM22_frequency_deviation 0x72 // R/W
#define RFM22_frequency_offset1 0x73 // R/W
#define RFM22_frequency_offset2 0x74 // R/W
#define RFM22_frequency_band_select 0x75 // R/W
#define RFM22_fb_mask 0x1F
#define RFM22_fbs_hbsel 0x20
#define RFM22_fbs_sbse 0x40
#define RFM22_nominal_carrier_frequency1 0x76 // R/W
#define RFM22_nominal_carrier_frequency0 0x77 // R/W
#define RFM22_frequency_hopping_channel_select 0x79 // R/W
#define RFM22_frequency_hopping_step_size 0x7A // R/W
#define RFM22_tx_fifo_control1 0x7C // R/W .. TX FIFO Almost Full Threshold (0 - 63)
#define RFM22_tx_fifo_control1_mask 0x3F
#define RFM22_tx_fifo_control2 0x7D // R/W .. TX FIFO Almost Empty Threshold (0 - 63)
#define RFM22_tx_fifo_control2_mask 0x3F
#define RFM22_rx_fifo_control 0x7E // R/W .. RX FIFO Almost Full Threshold (0 - 63)
#define RFM22_rx_fifo_control_mask 0x3F
#define RFM22_fifo_access 0x7F // R/W
#define RFM22B_MAX_PACKET_LEN 64
#define RFM22B_NUM_CHANNELS 251
// External type definitions

View File

@ -0,0 +1,521 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_RFM22B Radio Functions
* @brief PIOS interface for RFM22B Radio
* @{
*
* @file pios_rfm22b_regs.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @author Tau Labs, http://taulabs.org, Copyright (C) 2014
* @author LibrePilot, http://librepilot.org, Copyright (C) 2016
* @brief RFM22B private definitions.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_RFM22B_REGS_H
#define PIOS_RFM22B_REGS_H
// ************************************
#define RFM22_DEVICE_VERSION_V2 0x02
#define RFM22_DEVICE_VERSION_A0 0x04
#define RFM22_DEVICE_VERSION_B1 0x06
// ************************************
#define BIT0 (1u << 0)
#define BIT1 (1u << 1)
#define BIT2 (1u << 2)
#define BIT3 (1u << 3)
#define BIT4 (1u << 4)
#define BIT5 (1u << 5)
#define BIT6 (1u << 6)
#define BIT7 (1u << 7)
// ************************************
#define RFM22_DEVICE_TYPE 0x00 // R
#define RFM22_DT_MASK 0x1F
#define RFM22_DEVICE_VERSION 0x01 // R
#define RFM22_DV_MASK 0x1F
#define RFM22_device_status 0x02 // R
#define RFM22_ds_cps_mask 0x03 // Chip Power State mask
#define RFM22_ds_cps_idle 0x00 // IDLE Chip Power State
#define RFM22_ds_cps_rx 0x01 // RX Chip Power State
#define RFM22_ds_cps_tx 0x02 // TX Chip Power State
// #define RFM22_ds_lockdet 0x04 //
// #define RFM22_ds_freqerr 0x08 //
#define RFM22_ds_headerr 0x10 // Header Error Status. Indicates if the received packet has a header check error
#define RFM22_ds_rxffem 0x20 // RX FIFO Empty Status
#define RFM22_ds_ffunfl 0x40 // RX/TX FIFO Underflow Status
#define RFM22_ds_ffovfl 0x80 // RX/TX FIFO Overflow Status
#define RFM22_interrupt_status1 0x03 // R
#define RFM22_is1_icrerror BIT0 // CRC Error. When set to 1 the cyclic redundancy check is failed.
#define RFM22_is1_ipkvalid BIT1 // Valid Packet Received.When set to 1 a valid packet has been received.
#define RFM22_is1_ipksent BIT2 // Packet Sent Interrupt. When set to1 a valid packet has been transmitted.
#define RFM22_is1_iext BIT3 // External Interrupt. When set to 1 an interrupt occurred on one of the GPIO<49>s if it is programmed so. The status can be checked in register 0Eh. See GPIOx Configuration section for the details.
#define RFM22_is1_irxffafull BIT4 // RX FIFO Almost Full.When set to 1 the RX FIFO has met its almost full threshold and needs to be read by the microcontroller.
#define RFM22_is1_ixtffaem BIT5 // TX FIFO Almost Empty. When set to 1 the TX FIFO is almost empty and needs to be filled.
#define RFM22_is1_itxffafull BIT6 // TX FIFO Almost Full. When set to 1 the TX FIFO has met its almost full threshold and needs to be transmitted.
#define RFM22_is1_ifferr BIT7 // FIFO Underflow/Overflow Error. When set to 1 the TX or RX FIFO has overflowed or underflowed.
#define RFM22_interrupt_status2 0x04 // R
#define RFM22_is2_ipor BIT0 // Power-on-Reset (POR). When the chip detects a Power on Reset above the desired setting this bit will be set to 1.
#define RFM22_is2_ichiprdy BIT1 // Chip Ready (XTAL). When a chip ready event has been detected this bit will be set to 1.
#define RFM22_is2_ilbd BIT2 // Low Battery Detect. When a low battery event is been detected this bit will be set to 1. This interrupt event is saved even if it is not enabled by the mask register bit and causes an interrupt after it is enabled.
#define RFM22_is2_iwut BIT3 // Wake-Up-Timer. On the expiration of programmed wake-up timer this bit will be set to 1.
#define RFM22_is2_irssi BIT4 // RSSI. When RSSI level exceeds the programmed threshold this bit will be set to 1.
#define RFM22_is2_ipreainval BIT5 // Invalid Preamble Detected. When the preamble is not found within a period of time set by the invalid preamble detection threshold in Register 54h, this bit will be set to 1.
#define RFM22_is2_ipreaval BIT6 // Valid Preamble Detected. When a preamble is detected this bit will be set to 1.
#define RFM22_is2_iswdet BIT7 // Sync Word Detected. When a sync word is detected this bit will be set to 1.
#define RFM22_interrupt_enable1 0x05 // R/W
#define RFM22_ie1_encrcerror BIT0 // Enable CRC Error. When set to 1 the CRC Error interrupt will be enabled.
#define RFM22_ie1_enpkvalid BIT1 // Enable Valid Packet Received. When ipkvalid = 1 the Valid Packet Received Interrupt will be enabled.
#define RFM22_ie1_enpksent BIT2 // Enable Packet Sent. When ipksent =1 the Packet Sense Interrupt will be enabled.
#define RFM22_ie1_enext BIT3 // Enable External Interrupt. When set to 1 the External Interrupt will be enabled.
#define RFM22_ie1_enrxffafull BIT4 // Enable RX FIFO Almost Full. When set to 1 the RX FIFO Almost Full interrupt will be enabled.
#define RFM22_ie1_entxffaem BIT5 // Enable TX FIFO Almost Empty. When set to 1 the TX FIFO Almost Empty interrupt will be enabled.
#define RFM22_ie1_entxffafull BIT6 // Enable TX FIFO Almost Full. When set to 1 the TX FIFO Almost Full interrupt will be enabled.
#define RFM22_ie1_enfferr BIT7 // Enable FIFO Underflow/Overflow. When set to 1 the FIFO Underflow/Overflow interrupt will be enabled.
#define RFM22_interrupt_enable2 0x06 // R/W
#define RFM22_ie2_enpor BIT0 // Enable POR. When set to 1 the POR interrupt will be enabled.
#define RFM22_ie2_enchiprdy BIT1 // Enable Chip Ready (XTAL). When set to 1 the Chip Ready interrupt will be enabled.
#define RFM22_ie2_enlbd BIT2 // Enable Low Battery Detect. When set to 1 the Low Battery Detect interrupt will be enabled.
#define RFM22_ie2_enwut BIT3 // Enable Wake-Up Timer. When set to 1 the Wake-Up Timer interrupt will be enabled.
#define RFM22_ie2_enrssi BIT4 // Enable RSSI. When set to 1 the RSSI Interrupt will be enabled.
#define RFM22_ie2_enpreainval BIT5 // Enable Invalid Preamble Detected. When mpreadet =1 the Invalid Preamble Detected Interrupt will be enabled.
#define RFM22_ie2_enpreaval BIT6 // Enable Valid Preamble Detected. When mpreadet =1 the Valid Preamble Detected Interrupt will be enabled.
#define RFM22_ie2_enswdet BIT7 // Enable Sync Word Detected. When mpreadet =1 the Preamble Detected Interrupt will be enabled.
#define RFM22_op_and_func_ctrl1 0x07 // R/W
#define RFM22_opfc1_xton 0x01 // READY Mode (Xtal is ON).
#define RFM22_opfc1_pllon 0x02 // TUNE Mode (PLL is ON). When pllon = 1 the PLL will remain enabled in Idle State. This will for faster turn-around time at the cost of increased current consumption in Idle State.
#define RFM22_opfc1_rxon 0x04 // RX on in Manual Receiver Mode. Automatically cleared if Multiple Packets config. is disabled and a valid packet received.
#define RFM22_opfc1_txon 0x08 // TX on in Manual Transmit Mode. Automatically cleared in FIFO mode once the packet is sent. Transmission can be aborted during packet transmission, however, when no data has been sent yet, transmission can only be aborted after the device is programmed to <20>unmodulated carrier<65> ("Register 71h. Modulation Mode Control 2").
#define RFM22_opfc1_x32ksel 0x10 // 32,768 kHz Crystal Oscillator Select. 0: RC oscillator 1: 32 kHz crystal
#define RFM22_opfc1_enwt 0x20 // Enable Wake-Up-Timer. Enabled when enwt = 1. If the Wake-up-Timer function is enabled it will operate in any mode and notify the microcontroller through the GPIO interrupt when the timer expires.
#define RFM22_opfc1_enlbd 0x40 // Enable Low Battery Detect. When this bit is set to 1 the Low Battery Detector circuit and threshold comparison will be enabled.
#define RFM22_opfc1_swres 0x80 // Software Register Reset Bit. This bit may be used to reset all registers simultaneously to a DEFAULT state, without the need for sequentially writing to each individual register. The RESET is accomplished by setting swres = 1. This bit will be automatically cleared.
#define RFM22_op_and_func_ctrl2 0x08 // R/W
#define RFM22_opfc2_ffclrtx 0x01 // TX FIFO Reset/Clear. This has to be a two writes operation: Setting ffclrtx =1 followed by ffclrtx = 0 will clear the contents of the TX FIFO.
#define RFM22_opfc2_ffclrrx 0x02 // RX FIFO Reset/Clear. This has to be a two writes operation: Setting ffclrrx =1 followed by ffclrrx = 0 will clear the contents of the RX FIFO.
#define RFM22_opfc2_enldm 0x04 // Enable Low Duty Cycle Mode. If this bit is set to 1 then the chip turns on the RX regularly. The frequency should be set in the Wake-Up Timer Period register, while the minimum ON time should be set in the Low-Duty Cycle Mode Duration register. The FIFO mode should be enabled also.
#define RFM22_opfc2_autotx 0x08 // Automatic Transmission. When autotx = 1 the transceiver will enter automatically TX State when the FIFO is almost full. When the FIFO is empty it will automatically return to the Idle State.
#define RFM22_opfc2_rxmpk 0x10 // RX Multi Packet. When the chip is selected to use FIFO Mode (dtmod[1:0]) and RX Packet Handling (enpacrx) then it will fill up the FIFO with multiple valid packets if this bit is set, otherwise the transceiver will automatically leave the RX State after the first valid packet has been received.
#define RFM22_opfc2_antdiv_mask 0xE0 // Enable Antenna Diversity. The GPIO must be configured for Antenna Diversity for the algorithm to work properly.
#define RFM22_xtal_osc_load_cap 0x09 // R/W
#define RFM22_xolc_xlc_mask 0x7F // Tuning Capacitance for the 30 MHz XTAL.
#define RFM22_xolc_xtalshft 0x80 // Additional capacitance to course shift the frequency if xlc[6:0] is not sufficient. Not binary with xlc[6:0].
#define RFM22_cpu_output_clk 0x0A // R/W
#define RFM22_coc_30MHz 0x00
#define RFM22_coc_15MHz 0x01
#define RFM22_coc_10MHz 0x02
#define RFM22_coc_4MHz 0x03
#define RFM22_coc_3MHz 0x04
#define RFM22_coc_2MHz 0x05
#define RFM22_coc_1MHz 0x06
#define RFM22_coc_32768Hz 0x07
#define RFM22_coc_enlfc 0x08
#define RFM22_coc_0cycle 0x00
#define RFM22_coc_128cycles 0x10
#define RFM22_coc_256cycles 0x20
#define RFM22_coc_512cycles 0x30
#define RFM22_gpio0_config 0x0B // R/W
#define RFM22_gpio0_config_por 0x00 // Power-On-Reset (output)
#define RFM22_gpio0_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
#define RFM22_gpio0_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
#define RFM22_gpio0_config_ddi 0x03 // Direct Digital Input
#define RFM22_gpio0_config_eife 0x04 // External Interrupt, falling edge (input)
#define RFM22_gpio0_config_eire 0x05 // External Interrupt, rising edge (input)
#define RFM22_gpio0_config_eisc 0x06 // External Interrupt, state change (input)
#define RFM22_gpio0_config_ai 0x07 // ADC Analog Input
#define RFM22_gpio0_config_atni 0x08 // Reserved (Analog Test N Input)
#define RFM22_gpio0_config_atpi 0x09 // Reserved (Analog Test P Input)
#define RFM22_gpio0_config_ddo 0x0A // Direct Digital Output
#define RFM22_gpio0_config_dto 0x0B // Reserved (Digital Test Output)
#define RFM22_gpio0_config_atno 0x0C // Reserved (Analog Test N Output)
#define RFM22_gpio0_config_atpo 0x0D // Reserved (Analog Test P Output)
#define RFM22_gpio0_config_rv 0xOE // Reference Voltage (output)
#define RFM22_gpio0_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
#define RFM22_gpio0_config_txd 0x10 // TX Data input for direct modulation (input)
#define RFM22_gpio0_config_err 0x11 // External Retransmission Request (input)
#define RFM22_gpio0_config_txstate 0x12 // TX State (output)
#define RFM22_gpio0_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
#define RFM22_gpio0_config_rxd 0x14 // RX Data (output)
#define RFM22_gpio0_config_rxstate 0x15 // RX State (output)
#define RFM22_gpio0_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
#define RFM22_gpio0_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
#define RFM22_gpio0_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
#define RFM22_gpio0_config_vpd 0x19 // Valid Preamble Detected (output)
#define RFM22_gpio0_config_ipd 0x1A // Invalid Preamble Detected (output)
#define RFM22_gpio0_config_swd 0x1B // Sync Word Detected (output)
#define RFM22_gpio0_config_cca 0x1C // Clear Channel Assessment (output)
#define RFM22_gpio0_config_vdd 0x1D // VDD
#define RFM22_gpio0_config_pup 0x20
#define RFM22_gpio0_config_drv0 0x00 // output drive level
#define RFM22_gpio0_config_drv1 0x40 // output drive level
#define RFM22_gpio0_config_drv2 0x80 // output drive level
#define RFM22_gpio0_config_drv3 0xC0 // output drive level
#define RFM22_gpio1_config 0x0C // R/W
#define RFM22_gpio1_config_ipor 0x00 // Inverted Power-On-Reset (output)
#define RFM22_gpio1_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
#define RFM22_gpio1_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
#define RFM22_gpio1_config_ddi 0x03 // Direct Digital Input
#define RFM22_gpio1_config_eife 0x04 // External Interrupt, falling edge (input)
#define RFM22_gpio1_config_eire 0x05 // External Interrupt, rising edge (input)
#define RFM22_gpio1_config_eisc 0x06 // External Interrupt, state change (input)
#define RFM22_gpio1_config_ai 0x07 // ADC Analog Input
#define RFM22_gpio1_config_atni 0x08 // Reserved (Analog Test N Input)
#define RFM22_gpio1_config_atpi 0x09 // Reserved (Analog Test P Input)
#define RFM22_gpio1_config_ddo 0x0A // Direct Digital Output
#define RFM22_gpio1_config_dto 0x0B // Reserved (Digital Test Output)
#define RFM22_gpio1_config_atno 0x0C // Reserved (Analog Test N Output)
#define RFM22_gpio1_config_atpo 0x0D // Reserved (Analog Test P Output)
#define RFM22_gpio1_config_rv 0xOE // Reference Voltage (output)
#define RFM22_gpio1_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
#define RFM22_gpio1_config_txd 0x10 // TX Data input for direct modulation (input)
#define RFM22_gpio1_config_err 0x11 // External Retransmission Request (input)
#define RFM22_gpio1_config_txstate 0x12 // TX State (output)
#define RFM22_gpio1_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
#define RFM22_gpio1_config_rxd 0x14 // RX Data (output)
#define RFM22_gpio1_config_rxstate 0x15 // RX State (output)
#define RFM22_gpio1_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
#define RFM22_gpio1_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
#define RFM22_gpio1_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
#define RFM22_gpio1_config_vpd 0x19 // Valid Preamble Detected (output)
#define RFM22_gpio1_config_ipd 0x1A // Invalid Preamble Detected (output)
#define RFM22_gpio1_config_swd 0x1B // Sync Word Detected (output)
#define RFM22_gpio1_config_cca 0x1C // Clear Channel Assessment (output)
#define RFM22_gpio1_config_vdd 0x1D // VDD
#define RFM22_gpio1_config_pup 0x20
#define RFM22_gpio1_config_drv0 0x00 // output drive level
#define RFM22_gpio1_config_drv1 0x40 // output drive level
#define RFM22_gpio1_config_drv2 0x80 // output drive level
#define RFM22_gpio1_config_drv3 0xC0 // output drive level
#define RFM22_gpio2_config 0x0D // R/W
#define RFM22_gpio2_config_mc 0x00 // Microcontroller Clock (output)
#define RFM22_gpio2_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
#define RFM22_gpio2_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
#define RFM22_gpio2_config_ddi 0x03 // Direct Digital Input
#define RFM22_gpio2_config_eife 0x04 // External Interrupt, falling edge (input)
#define RFM22_gpio2_config_eire 0x05 // External Interrupt, rising edge (input)
#define RFM22_gpio2_config_eisc 0x06 // External Interrupt, state change (input)
#define RFM22_gpio2_config_ai 0x07 // ADC Analog Input
#define RFM22_gpio2_config_atni 0x08 // Reserved (Analog Test N Input)
#define RFM22_gpio2_config_atpi 0x09 // Reserved (Analog Test P Input)
#define RFM22_gpio2_config_ddo 0x0A // Direct Digital Output
#define RFM22_gpio2_config_dto 0x0B // Reserved (Digital Test Output)
#define RFM22_gpio2_config_atno 0x0C // Reserved (Analog Test N Output)
#define RFM22_gpio2_config_atpo 0x0D // Reserved (Analog Test P Output)
#define RFM22_gpio2_config_rv 0xOE // Reference Voltage (output)
#define RFM22_gpio2_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
#define RFM22_gpio2_config_txd 0x10 // TX Data input for direct modulation (input)
#define RFM22_gpio2_config_err 0x11 // External Retransmission Request (input)
#define RFM22_gpio2_config_txstate 0x12 // TX State (output)
#define RFM22_gpio2_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
#define RFM22_gpio2_config_rxd 0x14 // RX Data (output)
#define RFM22_gpio2_config_rxstate 0x15 // RX State (output)
#define RFM22_gpio2_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
#define RFM22_gpio2_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
#define RFM22_gpio2_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
#define RFM22_gpio2_config_vpd 0x19 // Valid Preamble Detected (output)
#define RFM22_gpio2_config_ipd 0x1A // Invalid Preamble Detected (output)
#define RFM22_gpio2_config_swd 0x1B // Sync Word Detected (output)
#define RFM22_gpio2_config_cca 0x1C // Clear Channel Assessment (output)
#define RFM22_gpio2_config_vdd 0x1D // VDD
#define RFM22_gpio2_config_pup 0x20
#define RFM22_gpio2_config_drv0 0x00 // output drive level
#define RFM22_gpio2_config_drv1 0x40 // output drive level
#define RFM22_gpio2_config_drv2 0x80 // output drive level
#define RFM22_gpio2_config_drv3 0xC0 // output drive level
#define RFM22_io_port_config 0x0E // R/W
#define RFM22_io_port_extitst2 0x40 // External Interrupt Status. If the GPIO2 is programmed to be external interrupt sources then the status can be read here.
#define RFM22_io_port_extitst1 0x20 // External Interrupt Status. If the GPIO1 is programmed to be external interrupt sources then the status can be read here.
#define RFM22_io_port_extitst0 0x10 // External Interrupt Status. If the GPIO0 is programmed to be external interrupt sources then the status can be read here.
#define RFM22_io_port_itsdo 0x08 // Interrupt Request Output on the SDO Pin. nIRQ output is present on the SDO pin if this bit is set and the nSEL input is inactive (high).
#define RFM22_io_port_dio2 0x04 // Direct I/O for GPIO2. If the GPIO2 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO2 is configured to be a direct input then the value of the pin can be read here.
#define RFM22_io_port_dio1 0x02 // Direct I/O for GPIO1. If the GPIO1 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO1 is configured to be a direct input then the value of the pin can be read here.
#define RFM22_io_port_dio0 0x01 // Direct I/O for GPIO0. If the GPIO0 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO0 is configured to be a direct input then the value of the pin can be read here.
#define RFM22_io_port_default 0x00 // GPIO pins are default
#define RFM22_adc_config 0x0F // R/W
#define RFM22_ac_adcgain0 0x00
#define RFM22_ac_adcgain1 0x01
#define RFM22_ac_adcgain2 0x02
#define RFM22_ac_adcgain3 0x03
#define RFM22_ac_adcref_bg 0x00
#define RFM22_ac_adcref_vdd3 0x08
#define RFM22_ac_adcref_vdd2 0x0C
#define RFM22_ac_adcsel_temp_sensor 0x00
#define RFM22_ac_adcsel_gpio0 0x10
#define RFM22_ac_adcsel_gpio1 0x20
#define RFM22_ac_adcsel_gpio2 0x30
#define RFM22_ac_adcsel_gpio01 0x40
#define RFM22_ac_adcsel_gpio12 0x50
#define RFM22_ac_adcsel_gpio02 0x60
#define RFM22_ac_adcsel_gpio_gnd 0x70
#define RFM22_ac_adcstartbusy 0x80
#define RFM22_adc_sensor_amp_offset 0x10 // R/W
#define RFM22_asao_adcoffs_mask 0x0F // ADC Sensor Amplifier Offset. The offset can be calculated as Offset = adcoffs[2:0] x VDD/1000; MSB = adcoffs[3] = Sign bit.
#define RFM22_adc_value 0x11 // R .. Internal 8 bit ADC Output Value.
#define RFM22_temp_sensor_calib 0x12 // R/W
#define RFM22_tsc_tstrim_mask 0x0F // Temperature Sensor Trim Value.
#define RFM22_tsc_entstrim 0x10 // Temperature Sensor Trim Enable.
#define RFM22_tsc_entsoffs 0x20 // Temperature Sensor Offset to Convert from K to C.
#define RFM22_tsc_tsrange0 0x00 // Temperature Sensor Range Selection. -40C to +64C 0.5C resolution
#define RFM22_tsc_tsrange1 0x40 // -40 to +85C with 1.0C resolution
#define RFM22_tsc_tsrange2 0x80 // 0C to 85C with 0.5C resolution
#define RFM22_tsc_tsrange3 0xC0 // -40F to 216F with 1.0F resolution
#define RFM22_temp_value_offset 0x13 // R/W
#define RFM22_wakeup_timer_period1 0x14 // R/W
#define RFM22_wakeup_timer_period2 0x15 // R/W
#define RFM22_wakeup_timer_period3 0x16 // R/W
#define RFM22_wakeup_timer_value1 0x17 // R
#define RFM22_wakeup_timer_value2 0x18 // R
#define RFM22_low_dutycycle_mode_duration 0x19 // R/W
#define RFM22_low_battery_detector_threshold 0x1A // R/W
#define RFM22_battery_volateg_level 0x1B // R
#define RFM22_if_filter_bandwidth 0x1C // R/W
#define RFM22_iffbw_filset_mask 0x0F
#define RFM22_iffbw_ndec_exp_mask 0x70
#define RFM22_iffbw_dwn3_bypass 0x80
#define RFM22_afc_loop_gearshift_override 0x1D // R/W
#define RFM22_afc_lp_gs_ovrd_afcgearl_mask 0x07 // AFC Low Gear Setting.
#define RFM22_afc_lp_gs_ovrd_afcgearh_mask 0x38 // AFC High Gear Setting.
#define RFM22_afc_lp_gs_ovrd_enafc 0x40 // AFC Enable.
#define RFM22_afc_lp_gs_ovrd_afcbd 0x80 // If set, the tolerated AFC frequency error will be halved.
#define RFM22_afc_timing_control 0x1E // R/W
#define RFM22_clk_recovery_gearshift_override 0x1F // R/W
#define RFM22_clk_recovery_oversampling_ratio 0x20 // R/W
#define RFM22_clk_recovery_offset2 0x21 // R/W
#define RFM22_clk_recovery_offset1 0x22 // R/W
#define RFM22_clk_recovery_offset0 0x23 // R/W
#define RFM22_clk_recovery_timing_loop_gain1 0x24 // R/W
#define RFM22_clk_recovery_timing_loop_gain0 0x25 // R/W
#define RFM22_rssi 0x26 // R
#define RFM22_rssi_threshold_clear_chan_indicator 0x27 // R/W
#define RFM22_antenna_diversity_register1 0x28 // R
#define RFM22_antenna_diversity_register2 0x29 // R
#define RFM22_afc_limiter 0x2A // R/W .. AFC_pull_in_range = <20>AFCLimiter[7:0] x (hbsel+1) x 625 Hz
#define RFM22_afc_correction_read 0x2B // R
#define RFM22_ook_counter_value1 0x2C // R/W
#define RFM22_ook_counter_value2 0x2D // R/W
#define RFM22_slicer_peak_hold 0x2E // R/W
#define RFM22_data_access_control 0x30 // R/W
#define RFM22_dac_crc_ccitt 0x00 //
#define RFM22_dac_crc_crc16 0x01 //
#define RFM22_dac_crc_iec16 0x02 //
#define RFM22_dac_crc_biacheva 0x03 //
#define RFM22_dac_encrc 0x04 // CRC Enable. Cyclic Redundancy Check generation is enabled if this bit is set.
#define RFM22_dac_enpactx 0x08 // Enable Packet TX Handling. If FIFO Mode (dtmod = 10) is being used automatic packet handling may be enabled. Setting enpactx = 1 will enable automatic packet handling in the TX path. Register 30<33>4D allow for various configurations of the packet structure. Setting enpactx = 0 will not do any packet handling in the TX path. It will only transmit what is loaded to the FIFO.
#define RFM22_dac_skip2ph 0x10 // Skip 2nd Phase of Preamble Detection. If set, we skip the second phase of the preamble detection (under certain conditions) if antenna diversity is enabled.
#define RFM22_dac_crcdonly 0x20 // CRC Data Only Enable. When this bit is set to 1 the CRC is calculated on and checked against the packet data fields only.
#define RFM22_dac_lsbfrst 0x40 // LSB First Enable. The LSB of the data will be transmitted/received first if this bit is set.
#define RFM22_dac_enpacrx 0x80 // Enable Packet RX Handling. If FIFO Mode (dtmod = 10) is being used automatic packet handling may be enabled. Setting enpacrx = 1 will enable automatic packet handling in the RX path. Register 30<33>4D allow for various configurations of the packet structure. Setting enpacrx = 0 will not do any packet handling in the RX path. It will only receive everything after the sync word and fill up the RX FIFO.
#define RFM22_ezmac_status 0x31 // R
#define RFM22_ezmac_status_pksent 0x01 // Packet Sent. A 1 a packet has been sent by the radio. (Same bit as in register 03, but reading it does not reset the IRQ)
#define RFM22_ezmac_status_pktx 0x02 // Packet Transmitting. When 1 the radio is currently transmitting a packet.
#define RFM22_ezmac_status_crcerror 0x04 // CRC Error. When 1 a Cyclic Redundancy Check error has been detected. (Same bit as in register 03, but reading it does not reset the IRQ)
#define RFM22_ezmac_status_pkvalid 0x08 // Valid Packet Received. When a 1 a valid packet has been received by the receiver. (Same bit as in register 03, but reading it does not reset the IRQ)
#define RFM22_ezmac_status_pkrx 0x10 // Packet Receiving. When 1 the radio is currently receiving a valid packet.
#define RFM22_ezmac_status_pksrch 0x20 // Packet Searching. When 1 the radio is searching for a valid packet.
#define RFM22_ezmac_status_rxcrc1 0x40 // If high, it indicates the last CRC received is all one<6E>s. May indicated Transmitter underflow in case of CRC error.
#define RFM22_header_control1 0x32 // R/W
#define RFM22_header_cntl1_bcen_none 0x00 // No broadcast address enable.
#define RFM22_header_cntl1_bcen_0 0x10 // Broadcast address enable for header byte 0.
#define RFM22_header_cntl1_bcen_1 0x20 // Broadcast address enable for header byte 1.
#define RFM22_header_cntl1_bcen_2 0x40 // Broadcast address enable for header byte 2.
#define RFM22_header_cntl1_bcen_3 0x80 // Broadcast address enable for header byte 3.
#define RFM22_header_cntl1_hdch_none 0x00 // No Received Header check
#define RFM22_header_cntl1_hdch_0 0x01 // Received Header check for byte 0.
#define RFM22_header_cntl1_hdch_1 0x02 // Received Header check for byte 1.
#define RFM22_header_cntl1_hdch_2 0x04 // Received Header check for byte 2.
#define RFM22_header_cntl1_hdch_3 0x08 // Received Header check for byte 3.
#define RFM22_header_control2 0x33 // R/W
#define RFM22_header_cntl2_prealen 0x01 // MSB of Preamble Length. See register Preamble Length.
#define RFM22_header_cntl2_synclen_3 0x00 // Synchronization Word 3
#define RFM22_header_cntl2_synclen_32 0x02 // Synchronization Word 3 followed by 2
#define RFM22_header_cntl2_synclen_321 0x04 // Synchronization Word 3 followed by 2 followed by 1
#define RFM22_header_cntl2_synclen_3210 0x06 // Synchronization Word 3 followed by 2 followed by 1 followed by 0
#define RFM22_header_cntl2_fixpklen 0x08 // Fix Packet Length. When fixpklen = 1 the packet length (pklen[7:0]) is not included in the header. When fixpklen = 0 the packet length is included in the header.
#define RFM22_header_cntl2_hdlen_none 0x00 // no header
#define RFM22_header_cntl2_hdlen_3 0x10 // header 3
#define RFM22_header_cntl2_hdlen_32 0x20 // header 3 and 2
#define RFM22_header_cntl2_hdlen_321 0x30 // header 3 and 2 and 1
#define RFM22_header_cntl2_hdlen_3210 0x40 // header 3 and 2 and 1 and 0
#define RFM22_header_cntl2_skipsyn 0x80 // If high, the system will ignore the syncword search timeout reset. The chip will not return to searching for Preamble, but instead will remain searching for Sync word.
#define RFM22_preamble_length 0x34 // R/W
#define RFM22_preamble_detection_ctrl1 0x35 // R/W
#define RFM22_pre_det_ctrl1_preath_mask 0xF8 // Number of nibbles processed during detection.
#define RFM22_pre_det_ctrl1_rssi_offset_mask 0x07 // Value added as offset to RSSI calculation. Every increment in this register results in an increment of +4 dB in the RSSI.
#define RFM22_sync_word3 0x36 // R/W
#define RFM22_sync_word2 0x37 // R/W
#define RFM22_sync_word1 0x38 // R/W
#define RFM22_sync_word0 0x39 // R/W
#define RFM22_transmit_header3 0x3A // R/W
#define RFM22_transmit_header2 0x3B // R/W
#define RFM22_transmit_header1 0x3C // R/W
#define RFM22_transmit_header0 0x3D // R/W
#define RFM22_transmit_packet_length 0x3E // R/W
#define RFM22_check_header3 0x3F // R/W
#define RFM22_check_header2 0x40 // R/W
#define RFM22_check_header1 0x41 // R/W
#define RFM22_check_header0 0x42 // R/W
#define RFM22_header_enable3 0x43 // R/W
#define RFM22_header_enable2 0x44 // R/W
#define RFM22_header_enable1 0x45 // R/W
#define RFM22_header_enable0 0x46 // R/W
#define RFM22_received_header3 0x47 // R
#define RFM22_received_header2 0x48 // R
#define RFM22_received_header1 0x49 // R
#define RFM22_received_header0 0x4A // R
#define RFM22_received_packet_length 0x4B // R
#define RFM22_adc8_control 0x4F // R/W
#define RFM22_channel_filter_coeff_addr 0x60 // R/W
#define RFM22_ch_fil_coeff_ad_inv_pre_th_mask 0xF0 //
#define RFM22_ch_fil_coeff_ad_chfiladd_mask 0x0F // Channel Filter Coefficient Look-up Table Address. The address for channel filter coefficients used in the RX path.
#define RFM22_xtal_osc_por_ctrl 0x62 // R/W
#define RFM22_xtal_osc_por_ctrl_pwst_mask 0xE0 // Internal Power States of the Chip.
#define RFM22_xtal_osc_por_ctrl_clkhyst 0x10 // Clock Hysteresis Setting.
#define RFM22_xtal_osc_por_ctrl_enbias2x 0x08 // 2 Times Higher Bias Current Enable.
#define RFM22_xtal_osc_por_ctrl_enamp2x 0x04 // 2 Times Higher Amplification Enable.
#define RFM22_xtal_osc_por_ctrl_bufovr 0x02 // Output Buffer Enable Override.
#define RFM22_xtal_osc_por_ctrl_enbuf 0x01 // Output Buffer Enable.
#define RFM22_agc_override1 0x69 // R/W
#define RFM22_agc_ovr1_sgi 0x40 // AGC Loop, Set Gain Increase. If set to 0 then gain increasing will not be allowed. If set to 1 then gain increasing is allowed, default is 0.
#define RFM22_agc_ovr1_agcen 0x20 // Automatic Gain Control Enable. When this bit is set then the result of the control can be read out from bits [4:0], otherwise the gain can be controlled manually by writing into bits [4:0].
#define RFM22_agc_ovr1_lnagain 0x10 // LNA Gain Select. 0 = min gain = 5dB, 1 = max gain = 25 dB.
#define RFM22_agc_ovr1_pga_mask 0x0F // PGA Gain Override Value.
#define RFM22_tx_power 0x6D // R/W
#define RFM22_tx_pwr_lna_sw 0x08 // LNA Switch Controller. If set, lna_sw control from the digital will go high during TX modes, and low during other times. If reset, the digital control signal is low at all times.
#define RFM22_tx_data_rate1 0x6E // R/W
#define RFM22_tx_data_rate0 0x6F // R/W
#define RFM22_modulation_mode_control1 0x70 // R/W
#define RFM22_mmc1_enwhite 0x01 // Data Whitening is Enabled if this bit is set.
#define RFM22_mmc1_enmanch 0x02 // Manchester Coding is Enabled if this bit is set.
#define RFM22_mmc1_enmaninv 0x04 // Manchester Data Inversion is Enabled if this bit is set.
#define RFM22_mmc1_manppol 0x08 // Manchester Preamble Polarity (will transmit a series of 1 if set, or series of 0 if reset).
#define RFM22_mmc1_enphpwdn 0x10 // If set, the Packet Handler will be powered down when chip is in low power mode.
#define RFM22_mmc1_txdtrtscale 0x20 // This bit should be set for Data Rates below 30 kbps.
#define RFM22_modulation_mode_control2 0x71 // R/W
#define RFM22_mmc2_modtyp_mask 0x03 // Modulation type.
#define RFM22_mmc2_modtyp_none 0x00 //
#define RFM22_mmc2_modtyp_ook 0x01 //
#define RFM22_mmc2_modtyp_fsk 0x02 //
#define RFM22_mmc2_modtyp_gfsk 0x03 //
#define RFM22_mmc2_fd 0x04 // MSB of Frequency Deviation Setting, see "Register 72h. Frequency Deviation".
#define RFM22_mmc2_eninv 0x08 // Invert TX and RX Data.
#define RFM22_mmc2_dtmod_mask 0x30 // Modulation source.
#define RFM22_mmc2_dtmod_dm_gpio 0x00 //
#define RFM22_mmc2_dtmod_dm_sdi 0x10 //
#define RFM22_mmc2_dtmod_fifo 0x20 //
#define RFM22_mmc2_dtmod_pn9 0x30 //
#define RFM22_mmc2_trclk_mask 0xC0 // TX Data Clock Configuration.
#define RFM22_mmc2_trclk_clk_none 0x00 //
#define RFM22_mmc2_trclk_clk_gpio 0x40 //
#define RFM22_mmc2_trclk_clk_sdo 0x80 //
#define RFM22_mmc2_trclk_clk_nirq 0xC0 //
#define RFM22_frequency_deviation 0x72 // R/W
#define RFM22_frequency_offset1 0x73 // R/W
#define RFM22_frequency_offset2 0x74 // R/W
#define RFM22_frequency_band_select 0x75 // R/W
#define RFM22_fb_mask 0x1F
#define RFM22_fbs_hbsel 0x20
#define RFM22_fbs_sbse 0x40
#define RFM22_nominal_carrier_frequency1 0x76 // R/W
#define RFM22_nominal_carrier_frequency0 0x77 // R/W
#define RFM22_frequency_hopping_channel_select 0x79 // R/W
#define RFM22_frequency_hopping_step_size 0x7A // R/W
#define RFM22_tx_fifo_control1 0x7C // R/W .. TX FIFO Almost Full Threshold (0 - 63)
#define RFM22_tx_fifo_control1_mask 0x3F
#define RFM22_tx_fifo_control2 0x7D // R/W .. TX FIFO Almost Empty Threshold (0 - 63)
#define RFM22_tx_fifo_control2_mask 0x3F
#define RFM22_rx_fifo_control 0x7E // R/W .. RX FIFO Almost Full Threshold (0 - 63)
#define RFM22_rx_fifo_control_mask 0x3F
#define RFM22_fifo_access 0x7F // R/W
#endif /* PIOS_RFM22B_REGS_H */
/**
* @}
* @}
*/

View File

@ -0,0 +1,71 @@
/**
******************************************************************************
* @file pios_semaphore.h
* @author Tau Labs, http://taulabs.org, Copyright (C) 2013-2014
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_Semaphore Semaphore Abstraction
* @{
* @brief Abstracts the concept of a binary semaphore to hide different implementations
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_SEMAPHORE_H_
#define PIOS_SEMAPHORE_H_
#define PIOS_SEMAPHORE_TIMEOUT_MAX 0xffffffff
#include <stdint.h>
#include <stdbool.h>
struct pios_semaphore {
#if defined(PIOS_INCLUDE_FREERTOS)
uintptr_t sema_handle;
#elif defined(PIOS_INCLUDE_CHIBIOS)
BinarySemaphore sema;
#elif defined(PIOS_INCLUDE_IRQ)
uint32_t sema_count;
#endif /* defined(PIOS_INCLUDE_IRQ) */
};
/*
* The following functions implement the concept of a binary semaphore usable
* with PIOS_INCLUDE_FREERTOS, PIOS_INCLUDE_CHIBIOS or PIOS_INCLUDE_IRQ.
*
* Note that this is not the same as:
* - counting semaphore
* - mutex
* - recursive mutex
*
* see FreeRTOS documentation for details: http://www.freertos.org/a00113.html
* see ChibiOS documentation for details: http://chibios.sourceforge.net/html/group__synchronization.html
*/
struct pios_semaphore *PIOS_Semaphore_Create(void);
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms);
bool PIOS_Semaphore_Give(struct pios_semaphore *sema);
bool PIOS_Semaphore_Take_FromISR(struct pios_semaphore *sema, bool *woken);
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken);
#endif /* PIOS_SEMAPHORE_H_ */
/**
* @}
* @}
*/

View File

@ -0,0 +1,93 @@
/**
******************************************************************************
* @file pios_thread.h
* @author Tau Labs, http://taulabs.org, Copyright (C) 2014
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_Thread Thread Abstraction
* @{
* @brief Abstracts the concept of a thread to hide different implementations
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_THREAD_H_
#define PIOS_THREAD_H_
#define PIOS_THREAD_TIMEOUT_MAX 0xffffffff
#include <stdint.h>
#include <stdbool.h>
#if defined(PIOS_INCLUDE_FREERTOS)
#include "FreeRTOSConfig.h"
enum pios_thread_prio_e {
PIOS_THREAD_PRIO_LOW = 1,
PIOS_THREAD_PRIO_NORMAL = 2,
PIOS_THREAD_PRIO_HIGH = 3,
PIOS_THREAD_PRIO_HIGHEST = 4, /* @note: this has to match (configMAX_PRIORITIES - 1) */
};
#define PIOS_THREAD_STACK_SIZE_MIN (configMINIMAL_STACK_SIZE * 4)
struct pios_thread {
uintptr_t task_handle;
};
#elif defined(PIOS_INCLUDE_CHIBIOS)
#include "ch.h"
enum pios_thread_prio_e {
PIOS_THREAD_PRIO_LOW = LOWPRIO,
PIOS_THREAD_PRIO_NORMAL = NORMALPRIO,
PIOS_THREAD_PRIO_HIGH = NORMALPRIO + 32,
PIOS_THREAD_PRIO_HIGHEST = HIGHPRIO,
};
#define PIOS_THREAD_STACK_SIZE_MIN THD_WA_SIZE(4096 + PORT_INT_REQUIRED_STACK)
struct pios_thread {
Thread *threadp;
};
#endif /* defined(PIOS_INCLUDE_CHIBIOS) */
/*
* The following functions implement the concept of a thread usable
* with PIOS_INCLUDE_FREERTOS.
*
* see FreeRTOS documentation for details: http://www.freertos.org/a00019.html
*/
struct pios_thread *PIOS_Thread_Create(void (*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio);
void PIOS_Thread_Delete(struct pios_thread *threadp);
uint32_t PIOS_Thread_Systime(void);
void PIOS_Thread_Sleep(uint32_t time_ms);
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms);
uint32_t PIOS_Thread_Get_Stack_Usage(struct pios_thread *threadp);
uint32_t PIOS_Thread_Get_Runtime(struct pios_thread *threadp);
void PIOS_Thread_Scheduler_Suspend(void);
void PIOS_Thread_Scheduler_Resume(void);
#endif /* PIOS_THREAD_H_ */
/**
* @}
* @}
*/

View File

@ -298,8 +298,6 @@ static const struct pios_exti_cfg pios_exti_rfm22b_cfg __exti_config = {
},
};
#include <pios_rfm22b_priv.h>
struct pios_rfm22b_cfg pios_rfm22b_cfg = {
.spi_cfg = &pios_spi_rfm22b_cfg,
.exti_cfg = &pios_exti_rfm22b_cfg,
@ -314,6 +312,51 @@ const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(__attribute__((unus
return &pios_rfm22b_cfg;
}
#if defined(PIOS_INCLUDE_OPENLRS)
#include <pios_openlrs_priv.h>
static const struct pios_exti_cfg pios_exti_openlrs_cfg __exti_config = {
.vector = PIOS_OpenLRS_EXT_Int,
.line = EXTI_Line2,
.pin = {
.gpio = GPIOA,
.init = {
.GPIO_Pin = GPIO_Pin_2,
.GPIO_Mode = GPIO_Mode_IN_FLOATING,
},
},
.irq = {
.init = {
.NVIC_IRQChannel = EXTI2_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.exti = {
.init = {
.EXTI_Line = EXTI_Line2,
.EXTI_Mode = EXTI_Mode_Interrupt,
.EXTI_Trigger = EXTI_Trigger_Falling,
.EXTI_LineCmd = ENABLE,
},
},
};
struct pios_openlrs_cfg pios_openlrs_cfg = {
.spi_cfg = &pios_spi_rfm22b_cfg,
.exti_cfg = &pios_exti_openlrs_cfg,
};
// ! Compatibility layer for various hardware revisions
const struct pios_openlrs_cfg *PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(__attribute__((unused)) uint32_t board_revision)
{
return &pios_openlrs_cfg;
}
#endif /* PIOS_INCLUDE_OpenLRS */
#endif /* PIOS_INCLUDE_RFM22B */
#if defined(PIOS_INCLUDE_ADC)

View File

@ -59,6 +59,8 @@ ifndef TESTAPP
SRC += $(FLIGHT_UAVOBJ_DIR)/objectpersistence.c
SRC += $(FLIGHT_UAVOBJ_DIR)/oplinkreceiver.c
SRC += $(FLIGHT_UAVOBJ_DIR)/radiocombridgestats.c
SRC += $(FLIGHT_UAVOBJ_DIR)/flightbatterystate.c
SRC += $(FLIGHT_UAVOBJ_DIR)/flightstatus.c
else
## Test Code
SRC += $(OPTESTS)/test_common.c

View File

@ -120,6 +120,7 @@
#define PIOS_INCLUDE_RFM22B
#define PIOS_INCLUDE_RFM22B_COM
#define PIOS_INCLUDE_PPM_OUT
#define PIOS_INCLUDE_OPENLRS
/* #define PIOS_RFM22B_DEBUG_ON_TELEM */
/* PIOS misc peripherals */

View File

@ -32,6 +32,7 @@
#include <pios_board_info.h>
#include <pios_ppm_out.h>
#include <oplinksettings.h>
#include <pios_openlrs.h>
#include <taskinfo.h>
#ifdef PIOS_INCLUDE_SERVO
#include <pios_servo.h>
@ -224,10 +225,15 @@ void PIOS_Board_Init(void)
// Configure the main port
OPLinkSettingsData oplinkSettings;
OPLinkSettingsGet(&oplinkSettings);
bool is_coordinator = (oplinkSettings.Coordinator == OPLINKSETTINGS_COORDINATOR_TRUE);
bool is_oneway = (oplinkSettings.OneWay == OPLINKSETTINGS_ONEWAY_TRUE);
bool ppm_only = (oplinkSettings.PPMOnly == OPLINKSETTINGS_PPMONLY_TRUE);
bool ppm_mode = false;
bool is_coordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR);
bool openlrs = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPENLRS);
bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL);
bool data_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATA) ||
(oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL));
bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) &&
((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs));
bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) ||
(oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL));
bool servo_main = false;
bool servo_flexi = false;
switch (oplinkSettings.MainPort) {
@ -269,7 +275,6 @@ void PIOS_Board_Init(void)
PIOS_PPM_Out_Init(&pios_ppm_out_id, &pios_main_ppm_out_cfg);
}
#endif /* PIOS_INCLUDE_PPM_OUT */
ppm_mode = true;
#endif /* PIOS_INCLUDE_PPM */
break;
}
@ -316,7 +321,6 @@ void PIOS_Board_Init(void)
PIOS_PPM_Out_Init(&pios_ppm_out_id, &pios_flexi_ppm_out_cfg);
}
#endif /* PIOS_INCLUDE_PPM */
ppm_mode = true;
break;
}
case OPLINKSETTINGS_FLEXIPORT_PWM:
@ -348,7 +352,6 @@ void PIOS_Board_Init(void)
servo_count = 2;
PIOS_Servo_Init(&pios_servo_flexi_cfg);
}
ppm_mode = ppm_mode || (servo_count > 0);
#endif
// Initialize out status object.
@ -364,92 +367,104 @@ void PIOS_Board_Init(void)
oplinkStatus.BoardRevision = bdinfo->board_rev;
/* Initalize the RFM22B radio COM device. */
if (oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) {
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED;
if (is_enabled) {
if (openlrs) {
#if defined(PIOS_INCLUDE_OPENLRS)
const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(bdinfo->board_rev);
uint32_t openlrs_id;
// Configure the RFM22B device
const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev);
if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) {
PIOS_Assert(0);
}
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED;
// Configure the radio com interface
uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN);
uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN);
PIOS_Assert(rx_buffer);
PIOS_Assert(tx_buffer);
if (PIOS_COM_Init(&pios_com_rfm22b_id, &pios_rfm22b_com_driver, pios_rfm22b_id,
rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN,
tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) {
PIOS_Assert(0);
}
PIOS_OpenLRS_Init(&openlrs_id, PIOS_RFM22_SPI_PORT, 0, openlrs_cfg);
PIOS_OpenLRS_RegisterPPMCallback(openlrs_id, PIOS_Board_PPM_callback);
#endif /* PIOS_INCLUDE_OPENLRS */
} else {
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED;
// Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex.
enum rfm22b_datarate datarate = RFM22_datarate_64000;
switch (oplinkSettings.ComSpeed) {
case OPLINKSETTINGS_COMSPEED_4800:
datarate = RFM22_datarate_9600;
break;
case OPLINKSETTINGS_COMSPEED_9600:
datarate = RFM22_datarate_19200;
break;
case OPLINKSETTINGS_COMSPEED_19200:
datarate = RFM22_datarate_32000;
break;
case OPLINKSETTINGS_COMSPEED_38400:
datarate = RFM22_datarate_64000;
break;
case OPLINKSETTINGS_COMSPEED_57600:
datarate = RFM22_datarate_100000;
break;
case OPLINKSETTINGS_COMSPEED_115200:
datarate = RFM22_datarate_192000;
break;
}
// Configure the RFM22B device
const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev);
if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) {
PIOS_Assert(0);
}
/* Set the modem Tx power level */
switch (oplinkSettings.MaxRFPower) {
case OPLINKSETTINGS_MAXRFPOWER_125:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0);
break;
case OPLINKSETTINGS_MAXRFPOWER_16:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1);
break;
case OPLINKSETTINGS_MAXRFPOWER_316:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2);
break;
case OPLINKSETTINGS_MAXRFPOWER_63:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3);
break;
case OPLINKSETTINGS_MAXRFPOWER_126:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4);
break;
case OPLINKSETTINGS_MAXRFPOWER_25:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5);
break;
case OPLINKSETTINGS_MAXRFPOWER_50:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6);
break;
case OPLINKSETTINGS_MAXRFPOWER_100:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7);
break;
default:
// do nothing
break;
}
// Configure the radio com interface
uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN);
uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN);
PIOS_Assert(rx_buffer);
PIOS_Assert(tx_buffer);
if (PIOS_COM_Init(&pios_com_rfm22b_id, &pios_rfm22b_com_driver, pios_rfm22b_id,
rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN,
tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) {
PIOS_Assert(0);
}
// Set the radio configuration parameters.
PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID);
PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID);
PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, is_oneway, ppm_mode, ppm_only);
// Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex.
enum rfm22b_datarate datarate = RFM22_datarate_64000;
switch (oplinkSettings.ComSpeed) {
case OPLINKSETTINGS_COMSPEED_4800:
datarate = RFM22_datarate_9600;
break;
case OPLINKSETTINGS_COMSPEED_9600:
datarate = RFM22_datarate_19200;
break;
case OPLINKSETTINGS_COMSPEED_19200:
datarate = RFM22_datarate_32000;
break;
case OPLINKSETTINGS_COMSPEED_38400:
datarate = RFM22_datarate_64000;
break;
case OPLINKSETTINGS_COMSPEED_57600:
datarate = RFM22_datarate_100000;
break;
case OPLINKSETTINGS_COMSPEED_115200:
datarate = RFM22_datarate_192000;
break;
}
/* Set the PPM callback if we should be receiving PPM. */
if (ppm_mode || (ppm_only && !is_coordinator)) {
PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback);
}
/* Set the modem Tx power level */
switch (oplinkSettings.MaxRFPower) {
case OPLINKSETTINGS_MAXRFPOWER_125:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0);
break;
case OPLINKSETTINGS_MAXRFPOWER_16:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1);
break;
case OPLINKSETTINGS_MAXRFPOWER_316:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2);
break;
case OPLINKSETTINGS_MAXRFPOWER_63:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3);
break;
case OPLINKSETTINGS_MAXRFPOWER_126:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4);
break;
case OPLINKSETTINGS_MAXRFPOWER_25:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5);
break;
case OPLINKSETTINGS_MAXRFPOWER_50:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6);
break;
case OPLINKSETTINGS_MAXRFPOWER_100:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7);
break;
default:
// do nothing
break;
}
// Reinitialize the modem to affect the changes.
PIOS_RFM22B_Reinit(pios_rfm22b_id);
// Set the radio configuration parameters.
PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID);
PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID);
PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode);
/* Set the PPM callback if we should be receiving PPM. */
if (ppm_mode || (ppm_only && !is_coordinator)) {
PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback);
}
// Reinitialize the modem to affect the changes.
PIOS_RFM22B_Reinit(pios_rfm22b_id);
} // openlrs
} else {
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED;
}

View File

@ -675,6 +675,72 @@ const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(uint32_t board_revi
#endif /* PIOS_INCLUDE_RFM22B */
#if defined(PIOS_INCLUDE_OPENLRS)
#include <pios_openlrs_priv.h>
static const struct pios_exti_cfg pios_exti_openlrs_cfg __exti_config = {
.vector = PIOS_OpenLRS_EXT_Int,
.line = EXTI_Line2,
.pin = {
.gpio = GPIOD,
.init = {
.GPIO_Pin = GPIO_Pin_2,
.GPIO_Speed = GPIO_Speed_100MHz,
.GPIO_Mode = GPIO_Mode_IN,
.GPIO_OType = GPIO_OType_OD,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
.irq = {
.init = {
.NVIC_IRQChannel = EXTI2_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.exti = {
.init = {
.EXTI_Line = EXTI_Line2, // matches above GPIO pin
.EXTI_Mode = EXTI_Mode_Interrupt,
.EXTI_Trigger = EXTI_Trigger_Falling,
.EXTI_LineCmd = ENABLE,
},
},
};
const struct pios_openlrs_cfg pios_openlrs_rm1_cfg = {
.spi_cfg = &pios_spi_telem_flash_cfg,
.exti_cfg = &pios_exti_openlrs_cfg,
.gpio_direction = GPIO0_RX_GPIO1_TX,
};
const struct pios_openlrs_cfg pios_openlrs_rm2_cfg = {
.spi_cfg = &pios_spi_telem_flash_cfg,
.exti_cfg = &pios_exti_openlrs_cfg,
.gpio_direction = GPIO0_TX_GPIO1_RX,
};
const struct pios_openlrs_cfg *PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(uint32_t board_revision)
{
switch (board_revision) {
case 2:
return &pios_openlrs_rm1_cfg;
break;
case 3:
return &pios_openlrs_rm2_cfg;
break;
default:
PIOS_DEBUG_Assert(0);
}
return NULL;
}
#endif /* PIOS_INCLUDE_OPENLRS */
#endif /* PIOS_INCLUDE_SPI */
#if defined(PIOS_INCLUDE_FLASH)

View File

@ -109,6 +109,7 @@
#define PIOS_INCLUDE_EXBUS
#define PIOS_INCLUDE_GCSRCVR
#define PIOS_INCLUDE_OPLINKRCVR
#define PIOS_INCLUDE_OPENLRS_RCVR
/* PIOS abstract receiver interface */
#define PIOS_INCLUDE_RCVR
@ -133,6 +134,7 @@
/* PIOS radio modules */
#define PIOS_INCLUDE_RFM22B
#define PIOS_INCLUDE_RFM22B_COM
#define PIOS_INCLUDE_OPENLRS
/* #define PIOS_INCLUDE_PPM_OUT */
/* #define PIOS_RFM22B_DEBUG_ON_TELEM */

View File

@ -35,6 +35,8 @@
#include <oplinkstatus.h>
#include <oplinkreceiver.h>
#include <pios_oplinkrcvr_priv.h>
#include <pios_openlrs.h>
#include <pios_openlrs_rcvr_priv.h>
#include <taskinfo.h>
#include <pios_ws2811.h>
#include <auxmagsettings.h>
@ -366,11 +368,10 @@ static void PIOS_Board_configure_ppm(const struct pios_ppm_cfg *ppm_cfg)
static void PIOS_Board_PPM_callback(const int16_t *channels)
{
uint8_t max_chan = (RFM22B_PPM_NUM_CHANNELS < OPLINKRECEIVER_CHANNEL_NUMELEM) ? RFM22B_PPM_NUM_CHANNELS : OPLINKRECEIVER_CHANNEL_NUMELEM;
OPLinkReceiverData opl_rcvr;
for (uint8_t i = 0; i < max_chan; ++i) {
opl_rcvr.Channel[i] = channels[i];
for (uint8_t i = 0; i < OPLINKRECEIVER_CHANNEL_NUMELEM; ++i) {
opl_rcvr.Channel[i] = (i < RFM22B_PPM_NUM_CHANNELS) ? channels[i] : PIOS_RCVR_TIMEOUT;
}
OPLinkReceiverSet(&opl_rcvr);
}
@ -847,96 +848,119 @@ void PIOS_Board_Init(void)
oplinkStatus.BoardRevision = bdinfo->board_rev;
/* Is the radio turned on? */
bool is_coordinator = (oplinkSettings.Coordinator == OPLINKSETTINGS_COORDINATOR_TRUE);
bool is_oneway = (oplinkSettings.OneWay == OPLINKSETTINGS_ONEWAY_TRUE);
bool ppm_mode = (oplinkSettings.PPM == OPLINKSETTINGS_PPM_TRUE);
bool ppm_only = (oplinkSettings.PPMOnly == OPLINKSETTINGS_PPMONLY_TRUE);
if (oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) {
/* Configure the RFM22B device. */
const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev);
if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) {
PIOS_Assert(0);
bool is_coordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR);
bool openlrs = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPENLRS);
bool data_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATA) ||
(oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL));
bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) ||
(oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL));
bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL);
bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) &&
((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs));
if (is_enabled) {
if (openlrs) {
#if defined(PIOS_INCLUDE_OPENLRS_RCVR)
const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(bdinfo->board_rev);
uint32_t openlrs_id;
PIOS_OpenLRS_Init(&openlrs_id, PIOS_RFM22_SPI_PORT, 0, openlrs_cfg);
{
uint32_t openlrsrcvr_id;
PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, openlrs_id);
uint32_t openlrsrcvr_rcvr_id;
if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) {
PIOS_Assert(0);
}
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPENLRS] = openlrsrcvr_rcvr_id;
}
#endif /* PIOS_INCLUDE_OPENLRS_RCVR */
} else {
/* Configure the RFM22B device. */
const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev);
if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) {
PIOS_Assert(0);
}
/* Configure the radio com interface */
uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN);
uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN);
PIOS_Assert(rx_buffer);
PIOS_Assert(tx_buffer);
if (PIOS_COM_Init(&pios_com_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id,
rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN,
tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) {
PIOS_Assert(0);
}
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED;
// Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex.
enum rfm22b_datarate datarate = RFM22_datarate_64000;
switch (oplinkSettings.ComSpeed) {
case OPLINKSETTINGS_COMSPEED_4800:
datarate = RFM22_datarate_9600;
break;
case OPLINKSETTINGS_COMSPEED_9600:
datarate = RFM22_datarate_19200;
break;
case OPLINKSETTINGS_COMSPEED_19200:
datarate = RFM22_datarate_32000;
break;
case OPLINKSETTINGS_COMSPEED_38400:
datarate = RFM22_datarate_64000;
break;
case OPLINKSETTINGS_COMSPEED_57600:
datarate = RFM22_datarate_100000;
break;
case OPLINKSETTINGS_COMSPEED_115200:
datarate = RFM22_datarate_192000;
break;
}
/* Set the radio configuration parameters. */
PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID);
PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID);
PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode);
/* Set the PPM callback if we should be receiving PPM. */
if (ppm_mode || (ppm_only && !is_coordinator)) {
PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback);
}
/* Set the modem Tx power level */
switch (oplinkSettings.MaxRFPower) {
case OPLINKSETTINGS_MAXRFPOWER_125:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0);
break;
case OPLINKSETTINGS_MAXRFPOWER_16:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1);
break;
case OPLINKSETTINGS_MAXRFPOWER_316:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2);
break;
case OPLINKSETTINGS_MAXRFPOWER_63:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3);
break;
case OPLINKSETTINGS_MAXRFPOWER_126:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4);
break;
case OPLINKSETTINGS_MAXRFPOWER_25:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5);
break;
case OPLINKSETTINGS_MAXRFPOWER_50:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6);
break;
case OPLINKSETTINGS_MAXRFPOWER_100:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7);
break;
default:
// do nothing
break;
}
/* Reinitialize the modem. */
PIOS_RFM22B_Reinit(pios_rfm22b_id);
}
/* Configure the radio com interface */
uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN);
uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN);
PIOS_Assert(rx_buffer);
PIOS_Assert(tx_buffer);
if (PIOS_COM_Init(&pios_com_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id,
rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN,
tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) {
PIOS_Assert(0);
}
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED;
// Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex.
enum rfm22b_datarate datarate = RFM22_datarate_64000;
switch (oplinkSettings.ComSpeed) {
case OPLINKSETTINGS_COMSPEED_4800:
datarate = RFM22_datarate_9600;
break;
case OPLINKSETTINGS_COMSPEED_9600:
datarate = RFM22_datarate_19200;
break;
case OPLINKSETTINGS_COMSPEED_19200:
datarate = RFM22_datarate_32000;
break;
case OPLINKSETTINGS_COMSPEED_38400:
datarate = RFM22_datarate_64000;
break;
case OPLINKSETTINGS_COMSPEED_57600:
datarate = RFM22_datarate_100000;
break;
case OPLINKSETTINGS_COMSPEED_115200:
datarate = RFM22_datarate_192000;
break;
}
/* Set the radio configuration parameters. */
PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID);
PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID);
PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, is_oneway, ppm_mode, ppm_only);
/* Set the PPM callback if we should be receiving PPM. */
if (ppm_mode || (ppm_only && !is_coordinator)) {
PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback);
}
/* Set the modem Tx power level */
switch (oplinkSettings.MaxRFPower) {
case OPLINKSETTINGS_MAXRFPOWER_125:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0);
break;
case OPLINKSETTINGS_MAXRFPOWER_16:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1);
break;
case OPLINKSETTINGS_MAXRFPOWER_316:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2);
break;
case OPLINKSETTINGS_MAXRFPOWER_63:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3);
break;
case OPLINKSETTINGS_MAXRFPOWER_126:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4);
break;
case OPLINKSETTINGS_MAXRFPOWER_25:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5);
break;
case OPLINKSETTINGS_MAXRFPOWER_50:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6);
break;
case OPLINKSETTINGS_MAXRFPOWER_100:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7);
break;
default:
// do nothing
break;
}
/* Reinitialize the modem. */
PIOS_RFM22B_Reinit(pios_rfm22b_id);
} else {
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED;
}
@ -1103,6 +1127,8 @@ void PIOS_Board_Init(void)
}
}
#endif // PIOS_INCLUDE_ADC
DEBUG_PRINTF(2, "Board complete\r\n");
}
/**

View File

@ -431,7 +431,7 @@ static const struct pios_exti_cfg pios_exti_rfm22b_cfg __exti_config = {
},
};
const struct pios_rfm22b_cfg pios_rfm22b_rm2_cfg = {
const struct pios_rfm22b_cfg pios_rfm22b_cfg = {
.spi_cfg = &pios_spi_telem_flash_cfg,
.exti_cfg = &pios_exti_rfm22b_cfg,
.RFXtalCap = 0x7f,
@ -441,11 +441,60 @@ const struct pios_rfm22b_cfg pios_rfm22b_rm2_cfg = {
const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(__attribute__((unused)) uint32_t board_revision)
{
return &pios_rfm22b_rm2_cfg;
return &pios_rfm22b_cfg;
}
#endif /* PIOS_INCLUDE_RFM22B */
#if defined(PIOS_INCLUDE_OPENLRS)
#include <pios_openlrs_priv.h>
static const struct pios_exti_cfg pios_exti_openlrs_cfg __exti_config = {
.vector = PIOS_OpenLRS_EXT_Int,
.line = EXTI_Line2,
.pin = {
.gpio = GPIOD,
.init = {
.GPIO_Pin = GPIO_Pin_2,
.GPIO_Speed = GPIO_Speed_100MHz,
.GPIO_Mode = GPIO_Mode_IN,
.GPIO_OType = GPIO_OType_OD,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
.irq = {
.init = {
.NVIC_IRQChannel = EXTI2_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.exti = {
.init = {
.EXTI_Line = EXTI_Line2, // matches above GPIO pin
.EXTI_Mode = EXTI_Mode_Interrupt,
.EXTI_Trigger = EXTI_Trigger_Falling,
.EXTI_LineCmd = ENABLE,
},
},
};
const struct pios_openlrs_cfg pios_openlrs_cfg = {
.spi_cfg = &pios_spi_telem_flash_cfg,
.exti_cfg = &pios_exti_openlrs_cfg,
.gpio_direction = GPIO0_TX_GPIO1_RX,
};
const struct pios_openlrs_cfg *PIOS_BOARD_HW_DEFS_GetOpenLRSCfg()
{
return &pios_openlrs_cfg;
}
#endif /* PIOS_INCLUDE_OPENLRS */
#endif /* PIOS_INCLUDE_SPI */
#if defined(PIOS_INCLUDE_FLASH)

View File

@ -128,6 +128,6 @@ UAVOBJSRCFILENAMES += takeofflocation
UAVOBJSRCFILENAMES += perfcounter
UAVOBJSRCFILENAMES += systemidentsettings
UAVOBJSRCFILENAMES += systemidentstate
UAVOBJSRC = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),$(FLIGHT_UAVOBJ_DIR)/$(UAVOBJSRCFILE).c )
UAVOBJDEFINE = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),-DUAVOBJ_INIT_$(UAVOBJSRCFILE) )

View File

@ -113,6 +113,7 @@
#define PIOS_INCLUDE_EXBUS
#define PIOS_INCLUDE_GCSRCVR
#define PIOS_INCLUDE_OPLINKRCVR
#define PIOS_INCLUDE_OPENLRS_RCVR
/* PIOS abstract receiver interface */
#define PIOS_INCLUDE_RCVR
@ -138,6 +139,7 @@
/* PIOS radio modules */
#define PIOS_INCLUDE_RFM22B
#define PIOS_INCLUDE_RFM22B_COM
#define PIOS_INCLUDE_OPENLRS
/* #define PIOS_INCLUDE_PPM_OUT */
/* #define PIOS_RFM22B_DEBUG_ON_TELEM */

View File

@ -35,6 +35,8 @@
#include <oplinkstatus.h>
#include <oplinkreceiver.h>
#include <pios_oplinkrcvr_priv.h>
#include <pios_openlrs.h>
#include <pios_openlrs_rcvr_priv.h>
#include <taskinfo.h>
#include <pios_ws2811.h>
#include <sanitycheck.h>
@ -366,11 +368,10 @@ static void PIOS_Board_configure_hott(const struct pios_usart_cfg *usart_cfg, en
static void PIOS_Board_PPM_callback(const int16_t *channels)
{
uint8_t max_chan = (RFM22B_PPM_NUM_CHANNELS < OPLINKRECEIVER_CHANNEL_NUMELEM) ? RFM22B_PPM_NUM_CHANNELS : OPLINKRECEIVER_CHANNEL_NUMELEM;
OPLinkReceiverData opl_rcvr;
for (uint8_t i = 0; i < max_chan; ++i) {
opl_rcvr.Channel[i] = channels[i];
for (uint8_t i = 0; i < OPLINKRECEIVER_CHANNEL_NUMELEM; ++i) {
opl_rcvr.Channel[i] = (i < RFM22B_PPM_NUM_CHANNELS) ? channels[i] : PIOS_RCVR_TIMEOUT;
}
OPLinkReceiverSet(&opl_rcvr);
}
@ -787,95 +788,119 @@ void PIOS_Board_Init(void)
oplinkStatus.BoardRevision = bdinfo->board_rev;
/* Is the radio turned on? */
bool is_coordinator = (oplinkSettings.Coordinator == OPLINKSETTINGS_COORDINATOR_TRUE);
bool is_oneway = (oplinkSettings.OneWay == OPLINKSETTINGS_ONEWAY_TRUE);
bool ppm_mode = (oplinkSettings.PPM == OPLINKSETTINGS_PPM_TRUE);
bool ppm_only = (oplinkSettings.PPMOnly == OPLINKSETTINGS_PPMONLY_TRUE);
if (oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) {
/* Configure the RFM22B device. */
const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev);
if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) {
PIOS_Assert(0);
bool is_coordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR);
bool openlrs = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPENLRS);
bool data_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATA) ||
(oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL));
bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) ||
(oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL));
bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL);
bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) &&
((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs));
if (is_enabled) {
if (openlrs) {
#if defined(PIOS_INCLUDE_OPENLRS_RCVR)
const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg();
uint32_t openlrs_id;
PIOS_OpenLRS_Init(&openlrs_id, PIOS_RFM22_SPI_PORT, 0, openlrs_cfg);
{
uint32_t openlrsrcvr_id;
PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, openlrs_id);
uint32_t openlrsrcvr_rcvr_id;
if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) {
PIOS_Assert(0);
}
pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPENLRS] = openlrsrcvr_rcvr_id;
}
#endif /* PIOS_INCLUDE_OPENLRS_RCVR */
} else {
/* Configure the RFM22B device. */
const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev);
if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) {
PIOS_Assert(0);
}
/* Configure the radio com interface */
uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN);
uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN);
PIOS_Assert(rx_buffer);
PIOS_Assert(tx_buffer);
if (PIOS_COM_Init(&pios_com_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id,
rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN,
tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) {
PIOS_Assert(0);
}
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED;
// Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex.
enum rfm22b_datarate datarate = RFM22_datarate_64000;
switch (oplinkSettings.ComSpeed) {
case OPLINKSETTINGS_COMSPEED_4800:
datarate = RFM22_datarate_9600;
break;
case OPLINKSETTINGS_COMSPEED_9600:
datarate = RFM22_datarate_19200;
break;
case OPLINKSETTINGS_COMSPEED_19200:
datarate = RFM22_datarate_32000;
break;
case OPLINKSETTINGS_COMSPEED_38400:
datarate = RFM22_datarate_64000;
break;
case OPLINKSETTINGS_COMSPEED_57600:
datarate = RFM22_datarate_100000;
break;
case OPLINKSETTINGS_COMSPEED_115200:
datarate = RFM22_datarate_192000;
break;
}
/* Set the radio configuration parameters. */
PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID);
PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID);
PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode);
/* Set the PPM callback if we should be receiving PPM. */
if (ppm_mode || (ppm_only && !is_coordinator)) {
PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback);
}
/* Set the modem Tx poer level */
switch (oplinkSettings.MaxRFPower) {
case OPLINKSETTINGS_MAXRFPOWER_125:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0);
break;
case OPLINKSETTINGS_MAXRFPOWER_16:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1);
break;
case OPLINKSETTINGS_MAXRFPOWER_316:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2);
break;
case OPLINKSETTINGS_MAXRFPOWER_63:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3);
break;
case OPLINKSETTINGS_MAXRFPOWER_126:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4);
break;
case OPLINKSETTINGS_MAXRFPOWER_25:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5);
break;
case OPLINKSETTINGS_MAXRFPOWER_50:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6);
break;
case OPLINKSETTINGS_MAXRFPOWER_100:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7);
break;
default:
// do nothing
break;
}
/* Reinitialize the modem. */
PIOS_RFM22B_Reinit(pios_rfm22b_id);
}
/* Configure the radio com interface */
uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN);
uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN);
PIOS_Assert(rx_buffer);
PIOS_Assert(tx_buffer);
if (PIOS_COM_Init(&pios_com_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id,
rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN,
tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) {
PIOS_Assert(0);
}
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED;
// Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex.
enum rfm22b_datarate datarate = RFM22_datarate_64000;
switch (oplinkSettings.ComSpeed) {
case OPLINKSETTINGS_COMSPEED_4800:
datarate = RFM22_datarate_9600;
break;
case OPLINKSETTINGS_COMSPEED_9600:
datarate = RFM22_datarate_19200;
break;
case OPLINKSETTINGS_COMSPEED_19200:
datarate = RFM22_datarate_32000;
break;
case OPLINKSETTINGS_COMSPEED_38400:
datarate = RFM22_datarate_64000;
break;
case OPLINKSETTINGS_COMSPEED_57600:
datarate = RFM22_datarate_100000;
break;
case OPLINKSETTINGS_COMSPEED_115200:
datarate = RFM22_datarate_192000;
break;
}
/* Set the radio configuration parameters. */
PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID);
PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, is_oneway, ppm_mode, ppm_only);
/* Set the PPM callback if we should be receiving PPM. */
if (ppm_mode || (ppm_only && !is_coordinator)) {
PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback);
}
/* Set the modem Tx poer level */
switch (oplinkSettings.MaxRFPower) {
case OPLINKSETTINGS_MAXRFPOWER_125:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0);
break;
case OPLINKSETTINGS_MAXRFPOWER_16:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1);
break;
case OPLINKSETTINGS_MAXRFPOWER_316:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2);
break;
case OPLINKSETTINGS_MAXRFPOWER_63:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3);
break;
case OPLINKSETTINGS_MAXRFPOWER_126:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4);
break;
case OPLINKSETTINGS_MAXRFPOWER_25:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5);
break;
case OPLINKSETTINGS_MAXRFPOWER_50:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6);
break;
case OPLINKSETTINGS_MAXRFPOWER_100:
PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7);
break;
default:
// do nothing
break;
}
/* Reinitialize the modem. */
PIOS_RFM22B_Reinit(pios_rfm22b_id);
} else {
oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED;
}

View File

@ -75,10 +75,8 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren
addWidgetBinding("OPLinkSettings", "MinChannel", m_oplink->MinimumChannel);
addWidgetBinding("OPLinkSettings", "MaxChannel", m_oplink->MaximumChannel);
addWidgetBinding("OPLinkSettings", "CoordID", m_oplink->CoordID);
addWidgetBinding("OPLinkSettings", "Coordinator", m_oplink->Coordinator);
addWidgetBinding("OPLinkSettings", "OneWay", m_oplink->OneWayLink);
addWidgetBinding("OPLinkSettings", "PPMOnly", m_oplink->PPMOnly);
addWidgetBinding("OPLinkSettings", "PPM", m_oplink->PPM);
addWidgetBinding("OPLinkSettings", "Protocol", m_oplink->Protocol);
addWidgetBinding("OPLinkSettings", "LinkType", m_oplink->LinkType);
addWidgetBinding("OPLinkSettings", "ComSpeed", m_oplink->ComSpeed);
addWidgetBinding("OPLinkSettings", "CustomDeviceID", m_oplink->CustomDeviceID);
@ -104,12 +102,15 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren
addWidgetBinding("OPLinkStatus", "TXPacketRate", m_oplink->TXPacketRate);
// Connect the selection changed signals.
connect(m_oplink->PPMOnly, SIGNAL(toggled(bool)), this, SLOT(ppmOnlyChanged()));
connect(m_oplink->Coordinator, SIGNAL(toggled(bool)), this, SLOT(updateCoordID()));
connect(m_oplink->Protocol, SIGNAL(valueChanged(int)), this, SLOT(protocolChanged()));
connect(m_oplink->LinkType, SIGNAL(valueChanged(int)), this, SLOT(linkTypeChanged()));
connect(m_oplink->MinimumChannel, SIGNAL(valueChanged(int)), this, SLOT(minChannelChanged()));
connect(m_oplink->MaximumChannel, SIGNAL(valueChanged(int)), this, SLOT(maxChannelChanged()));
connect(m_oplink->CustomDeviceID, SIGNAL(editingFinished()), this, SLOT(updateCustomDeviceID()));
// Connect the Unbind button
connect(m_oplink->UnbindButton, SIGNAL(released()), this, SLOT(unbind()));
m_oplink->CustomDeviceID->setInputMask("HHHHHHHH");
m_oplink->CoordID->setInputMask("HHHHHHHH");
@ -215,9 +216,7 @@ void ConfigOPLinkWidget::updateSettings(UAVObject *object)
m_oplink->FlexiPortLabel->setVisible(false);
m_oplink->VCPPort->setVisible(false);
m_oplink->VCPPortLabel->setVisible(false);
m_oplink->FlexiIOPort->setVisible(false);
m_oplink->FlexiIOPortLabel->setVisible(false);
m_oplink->PPM->setEnabled(true);
m_oplink->LinkType->setEnabled(true);
break;
case 0x03: // OPLinkMini
m_oplink->MainPort->setVisible(true);
@ -226,24 +225,7 @@ void ConfigOPLinkWidget::updateSettings(UAVObject *object)
m_oplink->FlexiPortLabel->setVisible(true);
m_oplink->VCPPort->setVisible(true);
m_oplink->VCPPortLabel->setVisible(true);
m_oplink->FlexiIOPort->setVisible(false);
m_oplink->FlexiIOPortLabel->setVisible(false);
m_oplink->PPM->setEnabled(false);
connect(m_oplink->MainPort, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePPMOptions()));
connect(m_oplink->FlexiPort, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePPMOptions()));
break;
case 0x0a: // OPLink? (No. This is wrong. 0x0A is gpsplatinum.)
m_oplink->MainPort->setVisible(true);
m_oplink->MainPortLabel->setVisible(true);
m_oplink->FlexiPort->setVisible(true);
m_oplink->FlexiPortLabel->setVisible(true);
m_oplink->VCPPort->setVisible(true);
m_oplink->VCPPortLabel->setVisible(true);
m_oplink->FlexiIOPort->setVisible(true);
m_oplink->FlexiIOPortLabel->setVisible(true);
m_oplink->PPM->setEnabled(false);
connect(m_oplink->MainPort, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePPMOptions()));
connect(m_oplink->FlexiPort, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePPMOptions()));
m_oplink->LinkType->setEnabled(true);
break;
default:
// This shouldn't happen.
@ -256,10 +238,9 @@ void ConfigOPLinkWidget::updateSettings(UAVObject *object)
void ConfigOPLinkWidget::updateEnableControls()
{
enableControls(true);
updatePPMOptions();
updateCustomDeviceID();
updateCoordID();
ppmOnlyChanged();
protocolChanged();
}
void ConfigOPLinkWidget::disconnected()
@ -269,47 +250,32 @@ void ConfigOPLinkWidget::disconnected()
}
}
void ConfigOPLinkWidget::updatePPMOptions()
void ConfigOPLinkWidget::protocolChanged()
{
bool is_oplm = m_oplink->MainPort->isVisible();
bool is_enabled = !isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_DISABLED);
bool is_coordinator = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKCOORDINATOR);
bool is_receiver = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKRECEIVER);
bool is_openlrs = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPENLRS);
bool is_ppm_only = isComboboxOptionSelected(m_oplink->LinkType, OPLinkSettings::LINKTYPE_CONTROL);
bool is_oplm = m_oplink->MainPort->isVisible();
bool is_bound = (m_oplink->CoordID->text() != "");
if (!is_oplm) {
return;
}
bool is_coordinator = m_oplink->Coordinator->isChecked();
bool is_ppm_active = ((isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_PPM)) ||
(isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_PPM)));
m_oplink->PPM->setEnabled(false);
m_oplink->PPM->setChecked(is_ppm_active);
m_oplink->PPMOnly->setEnabled(is_ppm_active);
if (!is_ppm_active) {
m_oplink->PPMOnly->setChecked(false);
QString selectPort = tr("Please select a port for PPM function.");
m_oplink->PPMOnly->setToolTip(selectPort);
m_oplink->PPM->setToolTip(selectPort);
} else {
if (is_coordinator) {
m_oplink->PPMOnly->setToolTip(tr("Only PPM packets will be transmitted and baudrate set to 9600 bauds by default."));
m_oplink->PPM->setToolTip(tr("PPM packets will be transmitted by this modem."));
} else {
m_oplink->PPMOnly->setToolTip(tr("Only PPM packets will be received and baudrate set to 9600 bauds by default."));
m_oplink->PPM->setToolTip(tr("PPM packets will be received by this modem."));
}
}
m_oplink->ComSpeed->setEnabled(!is_ppm_only && !is_openlrs && is_enabled);
m_oplink->CoordID->setEnabled(is_receiver & is_enabled);
m_oplink->UnbindButton->setEnabled(is_bound && !is_coordinator && is_enabled);
m_oplink->CustomDeviceID->setEnabled(is_coordinator);
m_oplink->MinimumChannel->setEnabled(is_receiver || is_coordinator);
m_oplink->MaximumChannel->setEnabled(is_receiver || is_coordinator);
m_oplink->MainPort->setEnabled(is_oplm);
m_oplink->FlexiPort->setEnabled(is_oplm);
m_oplink->VCPPort->setEnabled((is_receiver || is_coordinator) && is_oplm);
m_oplink->LinkType->setEnabled(is_enabled && !is_openlrs);
m_oplink->MaxRFTxPower->setEnabled(is_enabled && !is_openlrs);
}
void ConfigOPLinkWidget::ppmOnlyChanged()
void ConfigOPLinkWidget::linkTypeChanged()
{
bool is_ppm_only = m_oplink->PPMOnly->isChecked();
bool is_oplm = m_oplink->MainPort->isVisible();
m_oplink->PPM->setEnabled(!is_ppm_only && !is_oplm);
m_oplink->OneWayLink->setEnabled(!is_ppm_only);
m_oplink->ComSpeed->setEnabled(!is_ppm_only);
protocolChanged();
}
void ConfigOPLinkWidget::minChannelChanged()
@ -358,13 +324,11 @@ void ConfigOPLinkWidget::channelChanged(bool isMax)
void ConfigOPLinkWidget::updateCoordID()
{
bool is_coordinator = m_oplink->Coordinator->isChecked();
bool coordinatorNotSet = (m_oplink->CoordID->text() == "0");
if (settingsUpdated && coordinatorNotSet) {
m_oplink->CoordID->clear();
}
m_oplink->CoordID->setEnabled(!is_coordinator);
}
void ConfigOPLinkWidget::updateCustomDeviceID()
@ -376,6 +340,25 @@ void ConfigOPLinkWidget::updateCustomDeviceID()
m_oplink->CustomDeviceID->setPlaceholderText("AutoGen");
}
}
void ConfigOPLinkWidget::unbind()
{
if (settingsUpdated) {
// Clear the coordinator ID
oplinkSettingsObj->getField("CoordID")->setValue(0);
m_oplink->CoordID->setText("0");
// Clear the OpenLRS settings
oplinkSettingsObj->getField("Version")->setValue(0);
oplinkSettingsObj->getField("SerialBaudrate")->setValue(0);
oplinkSettingsObj->getField("RFFrequency")->setValue(0);
oplinkSettingsObj->getField("RFPower")->setValue(0);
oplinkSettingsObj->getField("RFChannelSpacing")->setValue(0);
oplinkSettingsObj->getField("ModemParams")->setValue(0);
oplinkSettingsObj->getField("Flags")->setValue(0);
}
}
/**
@}
@}

View File

@ -62,12 +62,13 @@ protected:
private slots:
void disconnected();
void updatePPMOptions();
void ppmOnlyChanged();
void linkTypeChanged();
void protocolChanged();
void minChannelChanged();
void maxChannelChanged();
void updateCoordID();
void updateCustomDeviceID();
void unbind();
void channelChanged(bool isMax);
};

View File

@ -154,6 +154,7 @@ void InputChannelForm::groupUpdated()
case ManualControlSettings::CHANNELGROUPS_PPM:
case ManualControlSettings::CHANNELGROUPS_SRXL:
case ManualControlSettings::CHANNELGROUPS_EXBUS:
case ManualControlSettings::CHANNELGROUPS_OPENLRS:
count = 16;
break;
case ManualControlSettings::CHANNELGROUPS_SBUS:

View File

@ -20,7 +20,10 @@
<attribute name="title">
<string>OPLink Configuration</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
@ -33,10 +36,7 @@
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
@ -49,26 +49,713 @@
<rect>
<x>0</x>
<y>0</y>
<width>812</width>
<height>566</height>
<width>947</width>
<height>575</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="3">
<spacer name="horizontalSpacer_3">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="configurationGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>900</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="title">
<string>Configuration</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="6">
<widget class="QLabel" name="FlexiPortLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Flexi Port</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="CoordID">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>90</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>This is the coordinator ID we currently are bound to.
To manually bind to a specific coordinator, just type
or paste its device ID in this box and save.
The device must be rebooted for the binding to take place.</string>
</property>
<property name="maxLength">
<number>8</number>
</property>
<property name="cursorMoveStyle">
<enum>Qt::LogicalMoveStyle</enum>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="UnbindButton">
<property name="toolTip">
<string>Clear the binding/coordinator ID</string>
</property>
<property name="text">
<string>Unbind</string>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSpinBox" name="MaximumChannel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz.</string>
</property>
<property name="maximum">
<number>250</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="MaxFreq">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>440.000 (MHz)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="6">
<widget class="QLabel" name="VCPPortLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>VCP Port</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="MaximumChannelLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Max Chan</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="MinimumChannelLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Min Chan</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="7">
<widget class="QComboBox" name="FlexiPort">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Choose the function for the flexi port.</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="Protocol">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Set the modem protocol</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="modelColumn">
<number>0</number>
</property>
</widget>
</item>
<item row="4" column="7">
<widget class="QComboBox" name="VCPPort">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Choose the function for the USB virtual com port.</string>
</property>
</widget>
</item>
<item row="1" column="7">
<widget class="QComboBox" name="ComSpeed">
<property name="toolTip">
<string>Com speed in bps.</string>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSpinBox" name="MinimumChannel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz.</string>
</property>
<property name="maximum">
<number>250</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="MinFreq">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>430.000 (MHz)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="ProtocolLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Protocol</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="ComSpeedLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Com Speed</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QComboBox" name="MaxRFTxPower">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Set the maximum TX output power the modem will use (mW)
0 to disable the modem.</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="modelColumn">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="LinkTypeLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Link Type</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="CustomDeviceIDLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Device ID</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="LinkType">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Configure what type of packets will be sent over the link</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="modelColumn">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="CustomDeviceID">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>90</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Enter your custom ID for this device as a hexadecimal value,
this allows device clones. Be sure only one device with this
ID transmits at the same time!
Leave blank to use autogenerated Device ID.</string>
</property>
<property name="maxLength">
<number>8</number>
</property>
<property name="frame">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>false</bool>
</property>
<property name="placeholderText">
<string/>
</property>
<property name="cursorMoveStyle">
<enum>Qt::LogicalMoveStyle</enum>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QLabel" name="MaxRFTxPowerLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Max Power</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QLabel" name="MainPortLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Main Port</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="7">
<widget class="QComboBox" name="MainPort">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Choose the function for the main port.</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="CoordIDLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Coordinator ID</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="5">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="levelGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>RX Level</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="PairSignalStrengthLabel1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>-100dB</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QProgressBar" name="PairSignalStrengthBar1">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="minimum">
<number>-127</number>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>-127</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="format">
<string>%v dBm</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="3">
<widget class="QGroupBox" name="groupBox_3">
<item row="1" column="0">
<widget class="QGroupBox" name="statusGroupBox">
<property name="minimumSize">
<size>
<width>430</width>
@ -106,7 +793,67 @@
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<layout class="QGridLayout" name="gridLayout_4" rowstretch="0,0,0,0,0,0,0,0">
<item row="0" column="4">
<widget class="QLabel" name="DeviceIDLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Device ID</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="SerialNumber">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="toolTip">
<string>The modems serial number</string>
</property>
<property name="frame">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLineEdit" name="DeviceID">
<property name="minimumSize">
@ -140,7 +887,7 @@
<bool>true</bool>
</property>
<property name="placeholderText">
<string>AA00FF99</string>
<string/>
</property>
</widget>
</item>
@ -196,7 +943,23 @@
<bool>true</bool>
</property>
<property name="placeholderText">
<string>Disconnected</string>
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="CorrectedLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RX Corrected</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
@ -244,38 +1007,6 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="CorrectedLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RX Corrected</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLabel" name="RXSeqLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RX Seq. No.</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="7">
<widget class="QLineEdit" name="TXRate">
<property name="minimumSize">
@ -348,30 +1079,8 @@
</property>
</widget>
</item>
<item row="3" column="7">
<widget class="QLineEdit" name="RXRate">
<property name="maximumSize">
<size>
<width>101</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="frame">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="GoodLabel">
<item row="3" column="4">
<widget class="QLabel" name="RXSeqLabel">
<property name="font">
<font>
<weight>50</weight>
@ -379,7 +1088,7 @@
</font>
</property>
<property name="text">
<string>RX Good</string>
<string>RX Seq. No.</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -423,8 +1132,8 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="ErrorsLabel">
<item row="2" column="0">
<widget class="QLabel" name="GoodLabel">
<property name="font">
<font>
<weight>50</weight>
@ -432,13 +1141,35 @@
</font>
</property>
<property name="text">
<string>RX Errors</string>
<string>RX Good</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="7">
<widget class="QLineEdit" name="RXRate">
<property name="maximumSize">
<size>
<width>101</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="frame">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="Corrected">
<property name="sizePolicy">
@ -476,22 +1207,6 @@
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="MissedPacketsLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RX Missed</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="5">
<widget class="QLineEdit" name="Timeouts">
<property name="maximumSize">
@ -514,6 +1229,38 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="ErrorsLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RX Errors</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="MissedPacketsLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RX Missed</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="4">
<widget class="QLabel" name="TimeoutsLabel">
<property name="font">
@ -571,52 +1318,8 @@
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="SerialNumber">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="toolTip">
<string>The modems serial number</string>
</property>
<property name="frame">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="DeviceIDLabel">
<item row="2" column="6">
<widget class="QLabel" name="TXRateLabel">
<property name="font">
<font>
<weight>50</weight>
@ -624,23 +1327,7 @@
</font>
</property>
<property name="text">
<string>Device ID</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="LinkQualityLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Link Quality</string>
<string>TX Rate (B/s)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -685,8 +1372,8 @@
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QLabel" name="TXRateLabel">
<item row="1" column="4">
<widget class="QLabel" name="LinkQualityLabel">
<property name="font">
<font>
<weight>50</weight>
@ -694,7 +1381,7 @@
</font>
</property>
<property name="text">
<string>TX Rate (B/s)</string>
<string>Link Quality</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -813,41 +1500,6 @@
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QLabel" name="FreeHeapLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Free Heap</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="5">
<widget class="QLineEdit" name="FreeHeap">
<property name="maximumSize">
<size>
<width>101</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLineEdit" name="TxFailure">
<property name="maximumSize">
@ -870,8 +1522,27 @@
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="TxFailureLabel">
<item row="5" column="5">
<widget class="QLineEdit" name="FreeHeap">
<property name="maximumSize">
<size>
<width>101</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QLabel" name="FreeHeapLabel">
<property name="font">
<font>
<weight>50</weight>
@ -879,7 +1550,23 @@
</font>
</property>
<property name="text">
<string>TX Failure</string>
<string>Free Heap</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="ResentLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>TX Dropped</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -917,8 +1604,8 @@
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="ResentLabel">
<item row="3" column="2">
<widget class="QLabel" name="TxFailureLabel">
<property name="font">
<font>
<weight>50</weight>
@ -926,15 +1613,15 @@
</font>
</property>
<property name="text">
<string>TX Dropped</string>
<string>TX Failure</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="RxFailureLabel">
<item row="7" column="4">
<widget class="QLabel" name="ResetsLabel">
<property name="font">
<font>
<weight>50</weight>
@ -942,7 +1629,7 @@
</font>
</property>
<property name="text">
<string>RX Failure</string>
<string>Resets</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -986,6 +1673,22 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="RxFailureLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RX Failure</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="5">
<widget class="QLineEdit" name="Resets">
<property name="minimumSize">
@ -1014,38 +1717,6 @@
</property>
</widget>
</item>
<item row="7" column="4">
<widget class="QLabel" name="ResetsLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Resets</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="6">
<widget class="QLabel" name="UAVTalkErrorsLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>UAVTalk Errors</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="7">
<widget class="QLineEdit" name="UAVTalkErrors">
<property name="maximumSize">
@ -1068,6 +1739,22 @@
</property>
</widget>
</item>
<item row="7" column="6">
<widget class="QLabel" name="UAVTalkErrorsLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>UAVTalk Errors</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="6">
<widget class="QLabel" name="TXPacketRateLabel">
<property name="font">
@ -1106,22 +1793,6 @@
</property>
</widget>
</item>
<item row="6" column="6">
<widget class="QLabel" name="RXPacketRateLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RX Packet Rate</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="7">
<widget class="QLineEdit" name="RXPacketRate">
<property name="maximumSize">
@ -1144,727 +1815,38 @@
</property>
</widget>
</item>
<item row="6" column="6">
<widget class="QLabel" name="RXPacketRateLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RX Packet Rate</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="2">
<spacer name="verticalSpacer">
<item row="1" column="1">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QGroupBox" name="PairingGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>RX Level</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="PairSignalStrengthLabel1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>-100dB</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QProgressBar" name="PairSignalStrengthBar1">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="minimum">
<number>-127</number>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>-127</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="format">
<string>%v dBm</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>900</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="title">
<string>Configuration</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="7">
<widget class="QComboBox" name="ComSpeed">
<property name="toolTip">
<string>Com speed in bps.</string>
</property>
</widget>
</item>
<item row="18" column="6">
<widget class="QLabel" name="FlexiIOPortLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>FlexiIO Port</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="7">
<widget class="QComboBox" name="MainPort">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Choose the function for the main port.</string>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QComboBox" name="MaxRFTxPower">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Set the maximum TX output power the modem will use (mW)
0 to disable the modem.</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="modelColumn">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QLabel" name="MainPortLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Main Port</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="18" column="7">
<widget class="QComboBox" name="FlexiIOPort"/>
</item>
<item row="0" column="6">
<widget class="QLabel" name="MaxRFTxPowerLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Max Power</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="ComSpeedLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Com Speed</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="PPMOnly">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>Only PPM packets will be transmitted and baudrate set to 9600bauds by default.</string>
</property>
<property name="text">
<string>PPM Only</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="PPM">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>PPM packets will be received by this modem.
Must be selected if Coordinator modem is configured for PPM.</string>
</property>
<property name="text">
<string>PPM</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="CoordIDLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Coordinator ID</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="customDeviceIDLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Device ID</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="CustomDeviceID">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>90</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>Enter your custom ID for this device as a hexadecimal value,
this allows device clones. Be sure only one device with this
ID transmits at the same time!
Leave blank to use autogenerated Device ID.</string>
</property>
<property name="maxLength">
<number>8</number>
</property>
<property name="frame">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>false</bool>
</property>
<property name="placeholderText">
<string>AA00FF99</string>
</property>
<property name="cursorMoveStyle">
<enum>Qt::LogicalMoveStyle</enum>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="CoordID">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>90</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>This is the coordinator ID we currently are bound to.
To manually bind to a specific coordinator, just type
or paste its device ID in this box and save.
The device must be rebooted for the binding to take place.</string>
</property>
<property name="maxLength">
<number>8</number>
</property>
<property name="cursorMoveStyle">
<enum>Qt::LogicalMoveStyle</enum>
</property>
<property name="clearButtonEnabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QCheckBox" name="OneWayLink">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="toolTip">
<string>If selected, data will only be transmitted from the coordinator to the Rx modem.</string>
</property>
<property name="text">
<string>One-Way</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="Coordinator">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>This modem will be a coordinator and other modems will bind to it.</string>
</property>
<property name="text">
<string>Coordinator</string>
</property>
</widget>
</item>
<item row="3" column="7">
<widget class="QComboBox" name="FlexiPort">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Choose the function for the flexi port.</string>
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="QLabel" name="FlexiPortLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Flexi Port</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="7">
<widget class="QComboBox" name="VCPPort">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Choose the function for the USB virtual com port.</string>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="QLabel" name="VCPPortLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>VCP Port</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="MaximumChannelLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Max Chan</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="MinimumChannelLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Min Chan</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSpinBox" name="MinimumChannel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz.</string>
</property>
<property name="maximum">
<number>250</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="MinFreq">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>430.000 (MHz)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="1" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSpinBox" name="MaximumChannel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz.</string>
</property>
<property name="maximum">
<number>250</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="MaxFreq">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>440.000 (MHz)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="5">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>

View File

@ -3,7 +3,7 @@
<description>Settings to indicate how to decode receiver input by @ref ManualControlModule.</description>
<field name="ChannelGroups" units="Channel Group" type="enum"
elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3"
options="PWM,PPM,DSM (MainPort),DSM (FlexiPort),DSM (RcvrPort),S.Bus,EX.Bus,HoTT,SRXL,GCS,OPLink,None" defaultvalue="None"/>
options="PWM,PPM,DSM (MainPort),DSM (FlexiPort),DSM (RcvrPort),S.Bus,EX.Bus,HoTT,SRXL,GCS,OPLink,OpenLRS,None" defaultvalue="None"/>
<field name="ChannelNumber" units="channel" type="uint8" defaultvalue="0"
elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3"/>
<field name="ChannelMin" units="us" type="int16" defaultvalue="1000"

View File

@ -1,7 +1,7 @@
<xml>
<object name="OPLinkReceiver" singleinstance="true" settings="false" category="System">
<description>A receiver channel group carried over the OPLink radio.</description>
<field name="Channel" units="us" type="int16" elements="8"/>
<field name="Channel" units="us" type="int16" elements="16"/>
<access gcs="readonly" flight="readwrite"/>
<telemetrygcs acked="false" updatemode="manual" period="0"/>
<telemetryflight acked="false" updatemode="periodic" period="1000"/>

View File

@ -1,10 +1,8 @@
<xml>
<object name="OPLinkSettings" singleinstance="true" settings="true" category="System">
<description>OPLink configurations options.</description>
<field name="Coordinator" units="" type="enum" elements="1" options="False,True" defaultvalue="False"/>
<field name="OneWay" units="" type="enum" elements="1" options="False,True" defaultvalue="False"/>
<field name="PPM" units="" type="enum" elements="1" options="False,True" defaultvalue="False"/>
<field name="PPMOnly" units="" type="enum" elements="1" options="False,True" defaultvalue="False"/>
<field name="Protocol" units="" type="enum" elements="1" options="Disabled,OPLinkReceiver,OPLinkCoordinator,OpenLRS" defaultvalue="Disabled"/>
<field name="LinkType" units="" type="enum" elements="1" options="Data,Control,DataAndControl" defaultvalue="Data"/>
<field name="CoordID" units="hex" type="uint32" elements="1" defaultvalue="0"/>
<field name="MainPort" units="" type="enum" elements="1" options="Disabled,Telemetry,Serial,PPM,PWM" defaultvalue="Disabled"/>
<field name="FlexiPort" units="" type="enum" elements="1" options="Disabled,Telemetry,Serial,PPM,PWM" defaultvalue="Disabled"/>
@ -15,6 +13,25 @@
<field name="MaxChannel" units="" type="uint8" elements="1" defaultvalue="250"/>
<field name="CustomDeviceID" units="hex" type="uint32" elements="1" defaultvalue="0"/>
<!-- OpenLRS options -->
<field name="Version" units="" type="uint8" elements="1" defaultvalue="0"/>
<field name="SerialBaudrate" units="bps" type="uint32" elements="1" defaultvalue="0"/>
<field name="RFFrequency" units="hz" type="uint32" elements="1" defaultvalue="0"/>
<field name="FailsafeDelay" units="ms" type="uint32" elements="1" defaultvalue="1000"/>
<field name="RSSIType" units="function" type="enum" elements="1" options="Combined,RSSI,LinkQuality" defaultvalue="Combined"/>
<!-- rf_magic === CoordID -->
<field name="RFPower" units="" type="uint8" elements="1" defaultvalue="0"/>
<field name="RFChannelSpacing" units="hz" type="uint8" elements="1" defaultvalue="0"/>
<field name="HopChannel" units="" type="uint8" elements="24" defaultvalue="0"/>
<field name="ModemParams" units="" type="uint8" elements="1" defaultvalue="0"/>
<field name="Flags" units="" type="uint8" elements="1" defaultvalue="0"/>
<!-- beacon options -->
<field name="BeaconFrequency" units="hz" type="uint32" elements="1" defaultvalue="462712500"/>
<field name="BeaconDelay" units="s" type="uint8" elements="1" defaultvalue="30"/>
<field name="BeaconPeriod" units="s" type="uint8" elements="1" defaultvalue="15"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
<telemetryflight acked="true" updatemode="onchange" period="0"/>

View File

@ -18,12 +18,12 @@
<field name="Resets" units="" type="uint8" elements="1" defaultvalue="0"/>
<field name="Timeouts" units="" type="uint8" elements="1" defaultvalue="0"/>
<field name="RSSI" units="dBm" type="int8" elements="1" defaultvalue="0"/>
<field name="LinkQuality" units="" type="uint8" elements="1" defaultvalue="0"/>
<field name="LinkQuality" units="" type="uint16" elements="1" defaultvalue="0"/>
<field name="TXRate" units="Bps" type="uint16" elements="1" defaultvalue="0"/>
<field name="RXRate" units="Bps" type="uint16" elements="1" defaultvalue="0"/>
<field name="TXSeq" units="" type="uint16" elements="1" defaultvalue="0"/>
<field name="RXSeq" units="" type="uint16" elements="1" defaultvalue="0"/>
<field name="LinkState" units="function" type="enum" elements="1" options="Disabled,Enabled,Disconnected,Connecting,Connected" defaultvalue="Disabled"/>
<field name="LinkState" units="function" type="enum" elements="1" options="Disabled,Enabled,Binding,Bound,Disconnected,Connecting,Connected" defaultvalue="Disabled"/>
<field name="PairIDs" units="hex" type="uint32" elements="4" defaultvalue="0"/>
<field name="PairSignalStrengths" units="dBm" type="int8" elements="4" defaultvalue="-127"/>
<field name="TXPacketRate" units="packet/s" type="uint16" elements="1" defaultvalue="0"/>
@ -31,7 +31,7 @@
<access gcs="readonly" flight="readwrite"/>
<telemetrygcs acked="false" updatemode="manual" period="0"/>
<telemetryflight acked="false" updatemode="throttled" period="500"/>
<telemetryflight acked="false" updatemode="periodic" period="500"/>
<logging updatemode="manual" period="0"/>
</object>
</xml>

View File

@ -2,7 +2,7 @@
<object name="ReceiverActivity" singleinstance="true" settings="false" category="System">
<description>Monitors which receiver channels have been active within the last second.</description>
<field name="ActiveGroup" units="Channel Group" type="enum" elements="1"
options="PWM,PPM,DSM (MainPort),DSM (FlexiPort),DSM (RcvrPort),S.Bus,EX.Bus,HoTT,SRXL,GCS,OPLink,None"
options="PWM,PPM,DSM (MainPort),DSM (FlexiPort),DSM (RcvrPort),S.Bus,EX.Bus,HoTT,SRXL,GCS,OPLink,OpenLRS,None"
defaultvalue="None"/>
<field name="ActiveChannel" units="channel" type="uint8" elements="1"
defaultvalue="255"/>