Merge remote-tracking branch 'refs/remotes/pascallanger/master' into benlye-multi-new

This commit is contained in:
Ben Lye
2017-11-26 12:45:20 +00:00
23 changed files with 1064 additions and 441 deletions

View File

@@ -0,0 +1,442 @@
/*
Protocol by Dennis Cabell, 2017
KE8FZX
To use this software, you must adhere to the license terms described below, and assume all responsibility for the use
of the software. The user is responsible for all consequences or damage that may result from using this software.
The user is responsible for ensuring that the hardware used to run this software complies with local regulations and that
any radio signal generated or received from use of this software is legal for that user to generate. The author(s) of this software
assume no liability whatsoever. The author(s) of this software is not responsible for legal or civil consequences of
using this software, including, but not limited to, any damages cause by lost control of a vehicle using this software.
If this software is copied or modified, this disclaimer must accompany all copies.
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Multiprotocol 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 Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
// The Receiver for this protocol is available at: https://github.com/soligen2010/RC_RX_CABELL_V3_FHSS
#if defined(CABELL_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define CABELL_BIND_COUNT 2000 // At least 2000 so that if TX toggles the serial bind flag then bind mode is never exited
#define CABELL_PACKET_PERIOD 3000 // Do not set too low or else next packet may not be finished transmitting before the channel is changed next time around
#define CABELL_NUM_CHANNELS 16 // The maximum number of RC channels that can be sent in one packet
#define CABELL_MIN_CHANNELS 4 // The minimum number of channels that must be included in a packet, the number of channels cannot be reduced any further than this
#define CABELL_PAYLOAD_BYTES 24 // 12 bits per value * 16 channels
#define CABELL_RADIO_CHANNELS 9 // This is 1/5 of the total number of radio channels used for FHSS
#define CABELL_RADIO_MIN_CHANNEL_NUM 3 // Channel 0 is right on the boarder of allowed frequency range, so move up to avoid bleeding over
#define CABELL_TELEMETRY_PACKET_LENGTH 4
#define CABELL_BIND_RADIO_ADDR 0xA4B7C123F7LL
#define CABELL_OPTION_MASK_CHANNEL_REDUCTION 0x0F
#define CABELL_OPTION_MASK_RECIEVER_OUTPUT_MODE 0x30
#define CABELL_OPTION_SHIFT_RECIEVER_OUTPUT_MODE 4
#define CABELL_OPTION_MASK_MAX_POWER_OVERRIDE 0x40
typedef struct
{
enum RxMode_t : uint8_t
{ // Note bit 8 is used to indicate if the packet is the first of 2 on the channel. Mask out this bit before using the enum
normal = 0,
bind = 1,
setFailSafe = 2,
normalWithTelemetry = 3,
telemetryResponse = 4,
unBind = 127
} RxMode;
uint8_t reserved = 0;
uint8_t option;
/* mask 0x0F : Channel reduction. The number of channels to not send (subtracted from the 16 max channels) at least 4 are always sent
* mask 0x30>>4 : Receiver output mode
* 0 (00) = Single PPM on individual pins for each channel
* 1 (01) = SUM PPM on channel 1 pin
* 2 (10) = Future use. Reserved for SBUS output
* 3 (11) = Unused
* mask 0x40>>6 Contains max power override flag for Multi-protocol TX module. Also sent to RX
* mask 0x80>>7 Unused
*/
uint8_t modelNum;
uint8_t checkSum_LSB;
uint8_t checkSum_MSB;
uint8_t payloadValue [CABELL_PAYLOAD_BYTES] = {0}; //12 bits per channel value, unsigned
} CABELL_RxTxPacket_t;
//-----------------------------------------------------------------------------------------
static uint8_t __attribute__((unused)) CABELL_getNextChannel (uint8_t seqArray[], uint8_t seqArraySize, uint8_t prevChannel)
{
/* Possible channels are in 5 bands, each band comprised of seqArraySize channels
* seqArray contains seqArraySize elements in the relative order in which we should progress through the band
*
* Each time the channel is changes, bands change in a way so that the next channel will be in a
* different non-adjacent band. Both the band changes and the index in seqArray is incremented.
*/
prevChannel -= CABELL_RADIO_MIN_CHANNEL_NUM; // Subtract CABELL_RADIO_MIN_CHANNEL_NUM because it was added to the return value
if(prevChannel>(seqArraySize * 5))
prevChannel=seqArraySize * 5; // Constrain the values just in case something bogus was sent in.
uint8_t currBand = prevChannel / seqArraySize;
uint8_t nextBand = (currBand + 3) % 5;
uint8_t prevChannalSeqArrayValue = prevChannel % seqArraySize;
uint8_t prevChannalSeqArrayPosition = 0;
for (int x = 0; x < seqArraySize; x++)
{ // Find the position of the previous channel in the array
if (seqArray[x] == prevChannalSeqArrayValue)
prevChannalSeqArrayPosition = x;
}
uint8_t nextChannalSeqArrayPosition = prevChannalSeqArrayPosition + 1;
if (nextChannalSeqArrayPosition >= seqArraySize)
nextChannalSeqArrayPosition = 0;
return (seqArraySize * nextBand) + seqArray[nextChannalSeqArrayPosition] + CABELL_RADIO_MIN_CHANNEL_NUM; // Add CABELL_RADIO_MIN_CHANNEL_NUM so we dont use channel 0 as it may bleed below 2.400 GHz
}
//-----------------------------------------------------------------------------------------
#if defined CABELL_HUB_TELEMETRY
static void __attribute__((unused)) CABELL_get_telemetry()
{
// calculate TX rssi based on past 250 expected telemetry packets. Cannot use full second count because telemetry_counter is not large enough
state++;
if (state > 250)
{
TX_RSSI = telemetry_counter;
telemetry_counter = 0;
state = 0;
telemetry_lost=0;
}
// Process incoming telemetry packet of it was received
if (NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // data received from model
NRF24L01_ReadPayload(packet, CABELL_TELEMETRY_PACKET_LENGTH);
if ((packet[0] & 0x7F) == CABELL_RxTxPacket_t::RxMode_t::telemetryResponse) // ignore high order bit in compare because it toggles with each packet
{
RX_RSSI = packet[1]; // Packet rate 0 to 255 where 255 is 100% packet rate
v_lipo1 = packet[2]; // Directly from analog input of receiver, but reduced to 8-bit depth (0 to 255). Scaling depends on the input to the analog pin of the receiver.
v_lipo2 = packet[3]; // Directly from analog input of receiver, but reduced to 8-bit depth (0 to 255). Scaling depends on the input to the analog pin of the receiver.
telemetry_counter++;
if(telemetry_lost==0)
telemetry_link=1;
}
}
else
{
// If no telemetry packet was received then delay by the typical telemetry packet processing time
// This is done to try to keep the sendPacket process timing more consistent. Since the SPI payload read takes some time
delayMicroseconds(50);
}
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_FlushRx();
}
#endif
//-----------------------------------------------------------------------------------------
static void __attribute__((unused)) CABELL_send_packet(uint8_t bindMode)
{
#if defined CABELL_HUB_TELEMETRY
if (!bindMode && (sub_protocol == CABELL_V3_TELEMETRY)) // check for incoming packet and switch radio back to TX mode if we were listening for telemetry
CABELL_get_telemetry();
#endif
CABELL_RxTxPacket_t TxPacket;
uint8_t channelReduction = constrain((option & CABELL_OPTION_MASK_CHANNEL_REDUCTION),0,CABELL_NUM_CHANNELS-CABELL_MIN_CHANNELS); // Max 12 - cannot reduce below 4 channels
if (bindMode)
channelReduction = 0; // Send full packet to bind as higher channels will contain bind info
uint8_t packetSize = sizeof(TxPacket) - ((((channelReduction - (channelReduction%2))/ 2)) * 3); // reduce 3 bytes per 2 channels, but not last channel if it is odd
uint8_t maxPayloadValueIndex = sizeof(TxPacket.payloadValue) - (sizeof(TxPacket) - packetSize);
if ((sub_protocol == CABELL_UNBIND) && !bindMode)
{
TxPacket.RxMode = CABELL_RxTxPacket_t::RxMode_t::unBind;
TxPacket.option = option;
}
else
{
if (sub_protocol == CABELL_SET_FAIL_SAFE && !bindMode)
TxPacket.RxMode = CABELL_RxTxPacket_t::RxMode_t::setFailSafe;
else
{
if (bindMode)
TxPacket.RxMode = CABELL_RxTxPacket_t::RxMode_t::bind;
else
{
switch (sub_protocol)
{
case CABELL_V3_TELEMETRY:
TxPacket.RxMode = CABELL_RxTxPacket_t::RxMode_t::normalWithTelemetry;
break;
default:
TxPacket.RxMode = CABELL_RxTxPacket_t::RxMode_t::normal;
break;
}
}
}
TxPacket.option = (bindMode) ? (option & (~CABELL_OPTION_MASK_CHANNEL_REDUCTION)) : option; //remove channel reduction if in bind mode
}
TxPacket.reserved = 0;
TxPacket.modelNum = RX_num;
uint16_t checkSum = TxPacket.modelNum + TxPacket.option + TxPacket.RxMode + TxPacket.reserved; // Start Calculate checksum
int adjusted_x;
int payloadIndex = 0;
uint16_t holdValue;
for (int x = 0;(x < CABELL_NUM_CHANNELS - channelReduction); x++)
{
switch (x)
{
case 0 : adjusted_x = ELEVATOR; break;
case 1 : adjusted_x = AILERON; break;
case 2 : adjusted_x = RUDDER; break;
case 3 : adjusted_x = THROTTLE; break;
default : adjusted_x = x; break;
}
holdValue = map(limit_channel_100(adjusted_x),servo_min_100,servo_max_100,1000,2000); // valid channel values are 1000 to 2000
if (bindMode)
{
switch (adjusted_x)
{
case THROTTLE : holdValue = 1000; break; // always set throttle to off when binding for safety
//tx address sent for bind
case 11 : holdValue = 1000 + rx_tx_addr[0]; break;
case 12 : holdValue = 1000 + rx_tx_addr[1]; break;
case 13 : holdValue = 1000 + rx_tx_addr[2]; break;
case 14 : holdValue = 1000 + rx_tx_addr[3]; break;
case 15 : holdValue = 1000 + rx_tx_addr[4]; break;
}
}
// use 12 bits per value
if (x % 2)
{ //output channel number is ODD
holdValue = holdValue<<4;
payloadIndex--;
}
else
holdValue &= 0x0FFF;
TxPacket.payloadValue[payloadIndex] |= (uint8_t)(holdValue & 0x00FF);
payloadIndex++;
TxPacket.payloadValue[payloadIndex] |= (uint8_t)((holdValue>>8) & 0x00FF);
payloadIndex++;
}
for(int x = 0; x < maxPayloadValueIndex ; x++)
checkSum += TxPacket.payloadValue[x]; // Finish Calculate checksum
TxPacket.checkSum_MSB = checkSum >> 8;
TxPacket.checkSum_LSB = checkSum & 0x00FF;
// Set channel for next transmission
rf_ch_num = CABELL_getNextChannel (hopping_frequency,CABELL_RADIO_CHANNELS, rf_ch_num);
NRF24L01_WriteReg(NRF24L01_05_RF_CH,rf_ch_num);
//NRF24L01_FlushTx(); //just in case things got hung up
//NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
uint8_t* p = reinterpret_cast<uint8_t*>(&TxPacket.RxMode);
*p &= 0x7F; // Make sure 8th bit is clear
*p |= (packet_count++)<<7; // This causes the 8th bit of the first byte to toggle with each xmit so consecutive payloads are not identical.
// This is a work around for a reported bug in clone NRF24L01 chips that mis-took this case for a re-transmit of the same packet.
CABELL_SetPower();
NRF24L01_WritePayload((uint8_t*)&TxPacket, packetSize);
#if defined CABELL_HUB_TELEMETRY
if (!bindMode && (sub_protocol == CABELL_V3_TELEMETRY))
{ // switch radio to rx as soon as packet is sent
// calculate transmit time based on packet size and data rate of 1MB per sec
// This is done because polling the status register during xmit caused issues.
// bits = packst_size * 8 + 73 bits overhead
// at 250 Kbs per sec, one bit is 4 uS
// then add 140 uS which is 130 uS to begin the xmit and 10 uS fudge factor
delayMicroseconds(((((unsigned long)packetSize * 8ul) + 73ul) * 4ul) + 140ul) ;
packet_period = CABELL_PACKET_PERIOD + (constrain(((int16_t)(CABELL_NUM_CHANNELS - channelReduction) - (int16_t)6 ),(int16_t)0 ,(int16_t)10 ) * (int16_t)100); // increase packet period by 100 us for each channel over 6
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); // RX mode with 16 bit CRC
}
else
#endif
packet_period = CABELL_PACKET_PERIOD; // Standard packet period when not in telemetry mode.
}
//-----------------------------------------------------------------------------------------
static void __attribute__((unused)) CABELL_getChannelSequence (uint8_t outArray[], uint8_t numChannels, uint64_t permutation)
{
/* This procedure initializes an array with the sequence progression of channels.
* This is not the actual channels itself, but the sequence base to be used within bands of
* channels.
*
* There are numChannels! permutations for arranging the channels
* one of these permutations will be calculated based on the permutation input
* permutation should be between 1 and numChannels! but the routine will constrain it
* if these bounds are exceeded. Typically the radio's unique TX ID should be used.
*
* The maximum numChannels is 20. Anything larger than this will cause the uint64_t
* variables to overflow, yielding unknown results (possibly infinite loop?). Therefor
* this routine constrains the value.
*/
uint8_t i; //iterator counts numChannels
uint64_t indexOfNextSequenceValue;
uint64_t numChannelsFactorial=1;
uint8_t sequenceValue;
numChannels = constrain(numChannels,1,20);
for (i = 1; i <= numChannels;i++)
{
numChannelsFactorial *= i; // Calculate n!
outArray[i-1] = i-1; // Initialize array with the sequence
}
permutation = (permutation % numChannelsFactorial) + 1; // permutation must be between 1 and n! or this algorithm will infinite loop
//Rearrange the array elements based on the permutation selected
for (i=0, permutation--; i<numChannels; i++ )
{
numChannelsFactorial /= ((uint64_t)numChannels)-i;
indexOfNextSequenceValue = i+(permutation/numChannelsFactorial);
permutation %= numChannelsFactorial;
//Copy the value in the selected array position
sequenceValue = outArray[indexOfNextSequenceValue];
//Shift the unused elements in the array to make room to move in the one just selected
for( ; indexOfNextSequenceValue > i; indexOfNextSequenceValue--)
outArray[indexOfNextSequenceValue] = outArray[indexOfNextSequenceValue-1];
// Copy the selected value into it's new array slot
outArray[i] = sequenceValue;
}
}
//-----------------------------------------------------------------------------------------
static void __attribute__((unused)) CABELL_setAddress()
{
uint64_t CABELL_addr;
// Serial.print("NORM ID: ");Serial.print((uint32_t)(CABELL_normal_addr>>32)); Serial.print(" ");Serial.println((uint32_t)((CABELL_normal_addr<<32)>>32));
if (IS_BIND_DONE_on)
{
CABELL_addr = (((uint64_t)rx_tx_addr[0]) << 32) +
(((uint64_t)rx_tx_addr[1]) << 24) +
(((uint64_t)rx_tx_addr[2]) << 16) +
(((uint64_t)rx_tx_addr[3]) << 8) +
(((uint64_t)rx_tx_addr[4])); // Address to use after binding
}
else
CABELL_addr = CABELL_BIND_RADIO_ADDR; // Static addr for binding
CABELL_getChannelSequence(hopping_frequency,CABELL_RADIO_CHANNELS,CABELL_addr); // Get the sequence for hopping through channels
rf_ch_num = CABELL_RADIO_MIN_CHANNEL_NUM; // Initialize the channel sequence
packet_count=0;
uint64_t CABELL_Telemetry_addr = ~CABELL_addr; // Invert bits for reading so that telemetry packets have a different address.
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, reinterpret_cast<uint8_t*>(&CABELL_Telemetry_addr), 5);
NRF24L01_WriteRegisterMulti(NRF24L01_0B_RX_ADDR_P1, reinterpret_cast<uint8_t*>(&CABELL_Telemetry_addr), 5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, reinterpret_cast<uint8_t*>(&CABELL_addr), 5);
}
//-----------------------------------------------------------------------------------------
static void __attribute__((unused)) CABELL_init()
{
NRF24L01_Initialize();
CABELL_SetPower();
NRF24L01_SetBitrate(NRF24L01_BR_250K); // slower data rate gives better range/reliability
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes
NRF24L01_SetTxRxMode(TX_EN); //Power up and 16 bit CRC
CABELL_setAddress();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01);
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20); // 32 byte packet length
NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, 0x20); // 32 byte packet length
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x5F); // no retransmits
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F); // Enable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x04); // Enable dynamic Payload Length
NRF24L01_Activate(0x73);
prev_power = NRF_POWER_0;
}
//-----------------------------------------------------------------------------------------
static void CABELL_SetPower() // This over-ride the standard Set Power to allow an flag in option to indicate max power setting
// Note that on many modules max power may actually be worse than the normal high power setting
// test and only use max if it helps the range
{
if(IS_BIND_DONE_on && !IS_RANGE_FLAG_on && ((option & CABELL_OPTION_MASK_MAX_POWER_OVERRIDE) != 0))
{ // If we are not in range or bind mode and power setting override is in effect, then set max power, else standard power logic
if(prev_power != NRF_POWER_3) // prev_power is global variable for NRF24L01; NRF_POWER_3 is max power
{
uint8_t rf_setup = NRF24L01_ReadReg(NRF24L01_06_RF_SETUP);
rf_setup = (rf_setup & 0xF9) | (NRF_POWER_3 << 1);
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, rf_setup);
prev_power=NRF_POWER_3;
}
}
else
NRF24L01_SetPower();
}
//-----------------------------------------------------------------------------------------
uint16_t CABELL_callback()
{
if (IS_BIND_DONE_on)
{
CABELL_send_packet(0); // packet_period is set/adjusted in CABELL_send_packet
return packet_period;
}
if (bind_counter == 0)
{
BIND_DONE;
CABELL_init(); // non-bind address
}
else
{
CABELL_send_packet(1);
bind_counter--;
}
return CABELL_PACKET_PERIOD;
}
//-----------------------------------------------------------------------------------------
uint16_t initCABELL(void)
{
if (IS_BIND_DONE_on)
bind_counter = 0;
else
bind_counter = CABELL_BIND_COUNT;
CABELL_init();
#if defined CABELL_HUB_TELEMETRY
init_frskyd_link_telemetry();
telemetry_lost=1; // do not send telemetry to TX right away until we have a TX_RSSI value to prevent warning message...
#endif
packet_period = CABELL_PACKET_PERIOD;
return packet_period;
}
#endif

View File

@@ -63,7 +63,7 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix()
BIND_SET_PULLUP; // set pullup
if(IS_BIND_BUTTON_on)
{
eeprom_write_byte((EE_ADDR)(30+mode_select),0x01); // Set fixed id mode for the current model
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+mode_select),0x01); // Set fixed id mode for the current model
option=1;
}
BIND_SET_OUTPUT;

View File

@@ -31,3 +31,4 @@
31,Q303,Q303,CX35,CX10D,CX10WD
32,GW008
33,DM002
34,CABELL,CAB_V3,C_TELEM,-,-,-,-,F_SAFE,UNBIND

View File

@@ -19,7 +19,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 1
#define VERSION_REVISION 6
#define VERSION_PATCH_LEVEL 25
#define VERSION_PATCH_LEVEL 30
//******************
// Protocols
//******************
@@ -59,6 +59,7 @@ enum PROTOCOLS
MODE_Q303 = 31, // =>NRF24L01
MODE_GW008 = 32, // =>NRF24L01
MODE_DM002 = 33, // =>NRF24L01
MODE_CABELL = 34, // =>NRF24L01
};
enum Flysky
@@ -196,6 +197,13 @@ enum Q303
CX10D = 2,
CX10WD = 3,
};
enum CABELL
{
CABELL_V3 = 0,
CABELL_V3_TELEMETRY = 1,
CABELL_SET_FAIL_SAFE= 6,
CABELL_UNBIND = 7,
};
#define NONE 0
#define P_HIGH 1
@@ -216,14 +224,29 @@ struct PPM_Parameters
// Telemetry
enum MultiPacketTypes {
MULTI_TELEMETRY_STATUS = 1,
MULTI_TELEMETRY_SPORT = 2,
MULTI_TELEMETRY_HUB = 3,
MULTI_TELEMETRY_DSM = 4,
MULTI_TELEMETRY_DSMBIND = 5,
MULTI_TELEMETRY_AFHDS2A = 6,
MULTI_TELEMETRY_STATUS = 1,
MULTI_TELEMETRY_SPORT = 2,
MULTI_TELEMETRY_HUB = 3,
MULTI_TELEMETRY_DSM = 4,
MULTI_TELEMETRY_DSMBIND = 5,
MULTI_TELEMETRY_AFHDS2A = 6,
MULTI_TELEMETRY_INPUTSYNC=8,
MULTI_COMMAND_CONFIG = 0x80,
MULTI_COMMAND_FAILSAFE =0x81,
};
enum FailSafeMode {
FAILSAFE_NOTSET = 0,
FAILSAFE_HOLD = 1,
FAILSAFE_CUSTOM = 2,
FAILSAFE_NOPULSES = 3,
FAILSAFE_RECEIVER = 4,
// Use during update so we can get away with only one copy of Failsafe channels
FAILSEFASE_INVALID = 0xfe
};
#define FAILSAFE_CHANNEL_HOLD 0
#define FAILSAFE_CHANNEL_NOPULSES 2047
// Macros
#define NOP() __asm__ __volatile__("nop")
@@ -298,6 +321,23 @@ enum MultiPacketTypes {
#define IS_WAIT_BIND_on ( ( protocol_flags2 & _BV(7) ) !=0 )
#define IS_WAIT_BIND_off ( ( protocol_flags2 & _BV(7) ) ==0 )
//Configuration
#define IS_TELEMTRY_INVERSION_ON (multi_config & 0x01)
#define IS_MULTI_TELEMETRY_ON (multi_config & 0x02)
#define IS_EXTRA_TELEMETRY_ON (multi_config & 0x04)
// Failsafe
#define failsafeToPPM(i) (Failsafe_data[i]* 5/8+860)
#define isNormalFailsafeChanel(i) (Failsafe_data[i] != FAILSAFE_CHANNEL_HOLD && Failsafe_data[i] != FAILSAFE_CHANNEL_NOPULSES)
//Status messages
#if defined(STM32_BOARD) && defined (SERIAL_DEBUG)
#define debug(msg, ...) {char buf[64]; sprintf(buf, msg "\r\n", ##__VA_ARGS__); for(int i=0;buf[i] !=0; i++) StatusSerial_write(buf[i]);}
#else
#define debug(...)
#undef SERIAL_DEBUG
#endif
//********************
//*** Blink timing ***
@@ -435,6 +475,14 @@ enum {
#define SPEED_57600 2
#define SPEED_125K 3
/** EEPROM Layout */
#define EEPROM_ID_OFFSET 10 // Module ID (4 bytes)
#define EEPROM_ID_VALID_OFFSET 20 // 1 byte flag that ID is valid
#define MODELMODE_EEPROM_OFFSET 30 // Autobind mode, 1 byte per model, end is 46
#define AFHDS2A_EEPROM_OFFSET 50 // RX ID, 4 byte per model id, end is 114
#define CONFIG_EEPROM_OFFSET 120 // Current configuration of the multimodule
//****************************************
//*** MULTI protocol serial definition ***
//****************************************
@@ -483,6 +531,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
Q303 31
GW008 32
DM002 33
CABELL 34
BindBit=> 0x80 1=Bind/0=No
AutoBindBit=> 0x40 1=Yes /0=No
RangeCheck=> 0x20 1=Yes /0=No
@@ -585,6 +634,11 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
CX35 1
CX10D 2
CX10WD 3
sub_protocol==CABELL
CABELL_V3 0
CABELL_V3_TELEMETRY 1
CABELL_SET_FAIL_SAFE 6
CABELL_UNBIND 7
Power value => 0x80 0=High/1=Low
Stream[3] = option_protocol;
@@ -623,7 +677,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
version of multi code, should be displayed as major.minor.revision.patchlevel
*/
/*
Multiprotocol telemetry definition for OpenTX
Multiprotocol telemetry/command definition for OpenTX
Based on #define MULTI_TELEMETRY enables OpenTX to get the multimodule status and select the correct telemetry type automatically.
Serial: 100000 Baud 8e2 (same as input)
@@ -643,6 +697,8 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
[4-xx] data
Commands from TX to multi cannot be longer than 22 bytes (RXLen -4byte header)
Type = 0x01 Multimodule Status:
[4] Flags
0x01 = Input signal detected
@@ -672,12 +728,53 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
Type 0x05 DSM bind data
data[0-16] DSM bind data
technically DSM bind data is only 10 bytes but multi send 16
like with telemtry, check length field)
technically DSM bind data is only 10 bytes but multi sends 16
like with telemtery, check length field)
Type 0x06 Flysky AFHDS2 telemetry data
length: 29
data[0] = RSSI value
data[1-28] telemetry data
Type 0x08 Input synchronisation
Informs the TX about desired rate and current delay
length: 4
data[0-1] Desired refresh rate in µs
data[2-3] Time (µs) between last serial servo input received and servo input needed (lateness), TX should adjust its
sending time to minimise this value.
data[4] Interval of this message in ms
data[5] Input delay target in 10µs
Note that there are protocols (AFHDS2A) that have a refresh rate that is smaller than the maximum achievable
refresh rate via the serial protocol, in this case, the TX should double the rate and also subract this
refresh rate from the input lag if the input lag is more than the desired refresh rate.
The remote should try to get to zero of (inputdelay+target*10).
Commands from TX to module use values > 127 for command type
Type 0x80 Module Configuration
This sent from the TX to Multi to configure inversion and multi telemetry type
length: 1
data[0] flags
0x01 Telemetry inversion (1 = inverted)
0x02 Use Multi telemetry protocol (if 0 use multi status)
0x04 Send extra telemetry (type 0x08) to allow input synchronisation
Type 0x81 Failsafe data
length: 23
data[0] Failsafe mode:
0 - Failsafe not set
1 - Failsafe hold, keep last received values
2 - Failsafe custom, use the values from the channels
3 - Failsafe nopulses, stop sending pulses from the receiver
4 - Failsafe receiver, use receiver stored values
Many of these many modes don't work with all protocols, fallback to best
available method
data[1-22] Failsafe data, encoded like normal channel data, with the expection
that 0 means hold for that channel and 2047 means no pulses
*/

View File

@@ -21,20 +21,23 @@
along with Multiprotocol. If not, see <http://www.gnu.org/licenses/>.
*/
#include <avr/pgmspace.h>
//#define DEBUG_TX
//#define USE_MY_CONFIG
#ifdef ARDUINO_AVR_XMEGA32D4
#include "MultiOrange.h"
//#define SERIAL_DEBUG // Only for STM32_BOARD on usart1
#define USE_MY_CONFIG
#ifdef __arm__// Let's automatically select the board if arm is selected
#define STM32_BOARD
#endif
#ifdef ARDUINO_AVR_XMEGA32D4
#include "MultiOrange.h"
#endif
#include "Multiprotocol.h"
//Multiprotocol module configuration file
#include "_Config.h"
// Let's automatically select the board
// if arm is selected
#ifdef __arm__
#define STM32_BOARD
#endif
//Personal config file
#if defined USE_MY_CONFIG
@@ -58,6 +61,9 @@
void ISR_COMPB();
extern "C"
{
#ifdef SERIAL_DEBUG
void __irq_usart1(void);
#endif
void __irq_usart2(void);
void __irq_usart3(void);
}
@@ -184,6 +190,11 @@ uint8_t pkt[MAX_PKT];//telemetry receiving packets
volatile uint8_t tx_head=0;
volatile uint8_t tx_tail=0;
#endif // BASH_SERIAL
#ifdef SERIAL_DEBUG
volatile uint8_t tx_debug_buff[TXBUFFER_SIZE];
volatile uint8_t tx_debug_head=0;
volatile uint8_t tx_debug_tail=0;
#endif // SERIAL_DEBUG
uint8_t v_lipo1;
uint8_t v_lipo2;
uint8_t RX_RSSI;
@@ -193,7 +204,7 @@ uint8_t pkt[MAX_PKT];//telemetry receiving packets
uint8_t telemetry_link=0;
uint8_t telemetry_counter=0;
uint8_t telemetry_lost;
#endif
#endif // TELEMETRY
// Callback
typedef uint16_t (*void_function_t) (void);//pointer to a function with no parameters which return an uint16_t integer
@@ -202,6 +213,13 @@ void_function_t remote_callback = 0;
// Init
void setup()
{
// Setup diagnostic uart before anything else
#ifdef SERIAL_DEBUG
usart1_begin(115200,SERIAL_8N1);
tx_debug_resume();
debug("Multiprotocol version: %d.%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_PATCH_LEVEL);
#endif
// General pinout
#ifdef ORANGE_TX
//XMEGA
@@ -227,14 +245,15 @@ void setup()
pinMode(CC25_CSN_pin,OUTPUT);
pinMode(NRF_CSN_pin,OUTPUT);
pinMode(CYRF_CSN_pin,OUTPUT);
pinMode(SPI_CSN_pin,OUTPUT);
pinMode(CYRF_RST_pin,OUTPUT);
pinMode(PE1_pin,OUTPUT);
pinMode(PE2_pin,OUTPUT);
pinMode(TX_INV_pin,OUTPUT);
pinMode(RX_INV_pin,OUTPUT);
#if defined TELEMETRY
pinMode(TX_INV_pin,OUTPUT);
pinMode(RX_INV_pin,OUTPUT);
#if defined INVERT_SERIAL
TX_INV_on;//activated inverter for both serial TX and RX signals
TX_INV_on; //activate inverter for both serial TX and RX signals
RX_INV_on;
#else
TX_INV_off;
@@ -287,7 +306,7 @@ void setup()
// Timer1 config
TCCR1A = 0;
TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer
// Random
random_init();
#endif
@@ -341,6 +360,7 @@ void setup()
((MODE_DIAL3_ipr & _BV(MODE_DIAL3_pin)) ? 0 : 4) +
((MODE_DIAL4_ipr & _BV(MODE_DIAL4_pin)) ? 0 : 8);
#endif
debug("Mode switch reads as %d", mode_select);
// Update LED
LED_off;
@@ -360,6 +380,8 @@ void setup()
// Read or create protocol id
MProtocol_id_master=random_id(10,false);
debug("Module Id: %lx", MProtocol_id_master);
#ifdef ENABLE_PPM
//Protocol and interrupts initialization
@@ -415,6 +437,7 @@ void setup()
#endif //ENABLE_SERIAL
}
servo_mid=servo_min_100+servo_max_100; //In fact 2* mid_value
debug("init complete");
}
// Main
@@ -539,7 +562,7 @@ uint8_t Update_All()
update_led_status();
#if defined(TELEMETRY)
#if ( !( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) ) )
if((protocol==MODE_FRSKYD) || (protocol==MODE_BAYANG) || (protocol==MODE_HUBSAN) || (protocol==MODE_AFHDS2A) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM) )
if( (protocol==MODE_FRSKYD) || (protocol==MODE_BAYANG) || (protocol==MODE_HUBSAN) || (protocol==MODE_AFHDS2A) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM) || (protocol==MODE_CABELL) )
#endif
TelemetryUpdate();
#endif
@@ -678,6 +701,18 @@ inline void tx_resume()
#endif
}
#ifdef SERIAL_DEBUG
inline void tx_debug_resume()
{
USART1_BASE->CR1 |= USART_CR1_TXEIE;
}
inline void tx_debug_pause()
{
USART1_BASE->CR1 &= ~ USART_CR1_TXEIE;
}
#endif // SERIAL_DEBUG
#ifdef STM32_BOARD
void start_timer2()
{
@@ -764,7 +799,7 @@ static void protocol_init()
#if defined(HUBSAN_A7105_INO)
case MODE_HUBSAN:
PE1_off; //antenna RF1
if(IS_BIND_BUTTON_FLAG_on) random_id(10,true); // Generate new ID if bind button is pressed.
if(IS_BIND_BUTTON_FLAG_on) random_id(EEPROM_ID_OFFSET,true); // Generate new ID if bind button is pressed.
next_callback = initHubsan();
remote_callback = ReadHubsan;
break;
@@ -820,12 +855,12 @@ static void protocol_init()
{
if(IS_BIND_BUTTON_FLAG_on)
{
eeprom_write_byte((EE_ADDR)(30+mode_select),0x00); // reset to autobind mode for the current model
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+mode_select),0x00); // reset to autobind mode for the current model
option=0;
}
else
{
option=eeprom_read_byte((EE_ADDR)(30+mode_select)); // load previous mode: autobind or fixed id
option=eeprom_read_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+mode_select)); // load previous mode: autobind or fixed id
if(option!=1) option=0; // if not fixed id mode then it should be autobind
}
}
@@ -842,12 +877,12 @@ static void protocol_init()
{
if(IS_BIND_BUTTON_FLAG_on)
{
eeprom_write_byte((EE_ADDR)(30+mode_select),0x00); // reset to autobind mode for the current model
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+mode_select),0x00); // reset to autobind mode for the current model
option=0;
}
else
{
option=eeprom_read_byte((EE_ADDR)(30+mode_select)); // load previous mode: autobind or fixed id
option=eeprom_read_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+mode_select)); // load previous mode: autobind or fixed id
if(option!=1) option=0; // if not fixed id mode then it should be autobind
}
}
@@ -988,6 +1023,12 @@ static void protocol_init()
remote_callback = DM002_callback;
break;
#endif
#if defined(CABELL_NRF24L01_INO)
case MODE_CABELL:
next_callback=initCABELL();
remote_callback = CABELL_callback;
break;
#endif
#endif
}
}
@@ -1045,6 +1086,7 @@ void update_serial_data()
protocol=(rx_ok_buff[0]==0x55?0:32) + (rx_ok_buff[1]&0x1F); //protocol no (0-63) bits 4-6 of buff[1] and bit 0 of buf[0]
sub_protocol=(rx_ok_buff[2]>>4)& 0x07; //subprotocol no (0-7) bits 4-6
RX_num=rx_ok_buff[2]& 0x0F; // rx_num bits 0---3
debug("New protocol selected: %d, sub proto %d, rxnum %d", protocol, sub_protocol, RX_num);
}
else
if( ((rx_ok_buff[1]&0x80)!=0) && ((cur_protocol[1]&0x80)==0) ) // Bind flag has been set
@@ -1064,7 +1106,7 @@ void update_serial_data()
//store current protocol values
for(uint8_t i=0;i<3;i++)
cur_protocol[i] = rx_ok_buff[i];
// decode channel values
volatile uint8_t *p=rx_ok_buff+3;
uint8_t dec=-3;
@@ -1310,7 +1352,7 @@ void pollBoot()
#if defined(TELEMETRY)
void PPM_Telemetry_serial_init()
{
if( (protocol==MODE_FRSKYD) || (protocol==MODE_HUBSAN) || (protocol==MODE_AFHDS2A) || (protocol==MODE_BAYANG) )
if( (protocol==MODE_FRSKYD) || (protocol==MODE_HUBSAN) || (protocol==MODE_AFHDS2A) || (protocol==MODE_BAYANG) || (protocol==MODE_CABELL) )
initTXSerial( SPEED_9600 ) ;
if(protocol==MODE_FRSKYX)
initTXSerial( SPEED_57600 ) ;
@@ -1357,7 +1399,7 @@ static uint32_t random_id(uint16_t address, uint8_t create_new)
{
id<<=8;
id|=eeprom_read_byte((EE_ADDR)address+i-1);
}
}
if(id!=0x2AD141A7) //ID with seed=0
return id;
}
@@ -1373,7 +1415,7 @@ static uint32_t random_id(uint16_t address, uint8_t create_new)
{
eeprom_write_byte((EE_ADDR)address+i,id);
id>>=8;
}
}
eeprom_write_byte((EE_ADDR)(address+10),0xf0);//write bind flag in eeprom.
return id;
#else

View File

@@ -209,14 +209,14 @@
#endif
#else //STM32_BOARD
#define BIND_pin PA0
#define LED_pin PA1
#define LED_pin PA1
//
#define PPM_pin PA8 //PPM 5V tolerant
#define PPM_pin PA8 //PPM 5V tolerant
//
#define S1_pin PA4 //Dial switch pins
#define S2_pin PA5
#define S1_pin PA4 //Dial switch pins
#define S2_pin PA5
#define S3_pin PA6
#define S4_pin PA7
#define S4_pin PA7
//
#define PE1_pin PB4 //PE1
#define PE2_pin PB5 //PE2
@@ -226,10 +226,11 @@
#define CYRF_RST_pin PB8 //CYRF RESET
#define A7105_CSN_pin PB9 //A7105
#define CYRF_CSN_pin PB12 //CYRF CSN
#define SPI_CSN_pin PA15
//SPI pins
#define SCK_pin PB13 //SCK
#define SDO_pin PB14 //MISO
#define SDI_pin PB15 //MOSI
#define SDI_pin PB15 //MOSI
//
#define TX_INV_pin PB3
#define RX_INV_pin PB1
@@ -240,40 +241,43 @@
#define PE2_on digitalWrite(PE2_pin,HIGH)
#define PE2_off digitalWrite(PE2_pin,LOW)
#define A7105_CSN_on digitalWrite(A7105_CSN_pin,HIGH)
#define A7105_CSN_off digitalWrite(A7105_CSN_pin,LOW)
#define A7105_CSN_on digitalWrite(A7105_CSN_pin,HIGH)
#define A7105_CSN_off digitalWrite(A7105_CSN_pin,LOW)
#define NRF_CE_on
#define NRF_CE_off
#define SCK_on digitalWrite(SCK_pin,HIGH)
#define SCK_off digitalWrite(SCK_pin,LOW)
#define SCK_on digitalWrite(SCK_pin,HIGH)
#define SCK_off digitalWrite(SCK_pin,LOW)
#define SDI_on digitalWrite(SDI_pin,HIGH)
#define SDI_off digitalWrite(SDI_pin,LOW)
#define SDI_on digitalWrite(SDI_pin,HIGH)
#define SDI_off digitalWrite(SDI_pin,LOW)
#define SDI_1 (digitalRead(SDI_pin)==HIGH)
#define SDI_0 (digitalRead(SDI_pin)==LOW)
#define SDI_1 (digitalRead(SDI_pin)==HIGH)
#define SDI_0 (digitalRead(SDI_pin)==LOW)
#define CC25_CSN_on digitalWrite(CC25_CSN_pin,HIGH)
#define CC25_CSN_off digitalWrite(CC25_CSN_pin,LOW)
#define CC25_CSN_on digitalWrite(CC25_CSN_pin,HIGH)
#define CC25_CSN_off digitalWrite(CC25_CSN_pin,LOW)
#define NRF_CSN_on digitalWrite(NRF_CSN_pin,HIGH)
#define NRF_CSN_off digitalWrite(NRF_CSN_pin,LOW)
#define NRF_CSN_on digitalWrite(NRF_CSN_pin,HIGH)
#define NRF_CSN_off digitalWrite(NRF_CSN_pin,LOW)
#define CYRF_CSN_on digitalWrite(CYRF_CSN_pin,HIGH)
#define CYRF_CSN_on digitalWrite(CYRF_CSN_pin,HIGH)
#define CYRF_CSN_off digitalWrite(CYRF_CSN_pin,LOW)
#define CYRF_RST_HI digitalWrite(CYRF_RST_pin,HIGH) //reset cyrf
#define SPI_CSN_on digitalWrite(SPI_CSN_pin,HIGH)
#define SPI_CSN_off digitalWrite(SPI_CSN_pin,LOW)
#define CYRF_RST_HI digitalWrite(CYRF_RST_pin,HIGH) //reset cyrf
#define CYRF_RST_LO digitalWrite(CYRF_RST_pin,LOW) //
#define SDO_1 (digitalRead(SDO_pin)==HIGH)
#define SDO_0 (digitalRead(SDO_pin)==LOW)
#define SDO_1 (digitalRead(SDO_pin)==HIGH)
#define SDO_0 (digitalRead(SDO_pin)==LOW)
#define TX_INV_on digitalWrite(TX_INV_pin,HIGH)
#define TX_INV_on digitalWrite(TX_INV_pin,HIGH)
#define TX_INV_off digitalWrite(TX_INV_pin,LOW)
#define RX_INV_on digitalWrite(RX_INV_pin,HIGH)
#define RX_INV_on digitalWrite(RX_INV_pin,HIGH)
#define RX_INV_off digitalWrite(RX_INV_pin,LOW)
#define LED_on digitalWrite(LED_pin,HIGH)

View File

@@ -127,25 +127,55 @@ static void __attribute__((unused)) SFHSS_calc_next_chan()
// Values grow down and to the right.
static void __attribute__((unused)) SFHSS_build_data_packet()
{
uint16_t ch1,ch2,ch3,ch4;
// command.bit0 is the packet number indicator: =0 -> SFHSS_DATA1, =1 -> SFHSS_DATA2
// command.bit1 is unknown but seems to be linked to the payload[0].bit0 but more dumps are needed: payload[0]=0x82 -> =0, payload[0]=0x81 -> =1
// command.bit2 is the failsafe transmission indicator: =0 -> normal data, =1->failsafe data
// command.bit3 is the channels indicator: =0 -> CH1-4, =1 -> CH5-8
//Coding below matches the Futaba T8J transmission scheme DATA1->CH1-4, DATA2->CH5-8, DATA1->CH5-8, DATA2->CH1-4,...
// XK, T10J and TM-FH are different with a classic DATA1->CH1-4, DATA2->CH5-8,...
//Failsafe is sent twice every couple of seconds (unknown but >5s)
uint8_t command= (phase == SFHSS_DATA1) ? 0 : 1; // Building packet for Data1 or Data2
counter+=command;
if(counter&1) command|=0x08; // Transmit lower and upper channels twice in a row
if((counter&0x3FE)==0x3FE)
{
command|=0x04; // Transmit failsafe data every 7s
counter&=0x3FF; // Reset counter
if( (counter&0x3FC) == 0x3FC )
{ // Transmit failsafe data twice every 7s
if( ((counter&1)^(command&1)) == 0 )
command|=0x04; // Failsafe
}
else
command|=0x02; // Assuming packet[0] == 0x81
uint8_t ch_offset = ((command&0x08) >> 1) + ((command&0x04)<<1); // CH1..CH8 when failsafe is off, CH9..CH16 when failsafe is on
uint16_t ch1 = convert_channel_16b_nolim(CH_AETR[ch_offset+0],2020,1020);
uint16_t ch2 = convert_channel_16b_nolim(CH_AETR[ch_offset+1],2020,1020);
uint16_t ch3 = convert_channel_16b_nolim(CH_AETR[ch_offset+2],2020,1020);
uint16_t ch4 = convert_channel_16b_nolim(CH_AETR[ch_offset+3],2020,1020);
counter&=0x3FF; // Reset failsafe counter
if(counter&1) command|=0x08; // Transmit lower and upper channels twice in a row
uint8_t ch_offset = ((command&0x08) >> 1) | ((command&0x04) << 1); // CH1..CH4 or CH5..CH8, if failsafe CH9..CH12 or CH13..CH16
ch1 = convert_channel_16b_nolim(CH_AETR[ch_offset+0],2020,1020);
ch2 = convert_channel_16b_nolim(CH_AETR[ch_offset+1],2020,1020);
ch3 = convert_channel_16b_nolim(CH_AETR[ch_offset+2],2020,1020);
ch4 = convert_channel_16b_nolim(CH_AETR[ch_offset+3],2020,1020);
if(command&0x04)
{ //Failsafe data are:
// 0 to 1023 -> no output on channel
// 1024-2047 -> hold output on channel
// 2048-4095 -> channel_output=(data&0x3FF)*5/4+880 in µs
// Notes:
// 2048-2559 -> does not look valid since it only covers the range from 1520µs to 2160µs
// 2560-3583 -> valid for any channel values from 880µs to 2160µs
// 3584-4095 -> looks to be used for the throttle channel with values ranging from 880µs to 1520µs
#ifdef SFHSS_FAILSAFE_CH9_16
ch1=((5360-ch1)<<2)/5; //((1520*2-ch1)<<2)/5+1856;
ch2=((5360-ch2)<<2)/5;
ch3=((5360-ch3)<<2)/5;
if((command&0x08)==0 && ch3<3072) // Throttle
ch3+=1024;
ch4=((5360-ch4)<<2)/5;
#else
ch1=1024;ch2=1024;ch4=1024; // All channels hold their positions
ch3=((command&0x08)==0)?3664:1024; // except throttle value set to 980µs
#endif
}
// XK [0]=0x81 [3]=0x00 [4]=0x00
// T8J [0]=0x81 [3]=0x42 [4]=0x07
@@ -154,8 +184,8 @@ static void __attribute__((unused)) SFHSS_build_data_packet()
packet[0] = 0x81; // can be 80 or 81 for Orange, only 81 for XK
packet[1] = rx_tx_addr[0];
packet[2] = rx_tx_addr[1];
packet[3] = rx_tx_addr[2]; // ID?
packet[4] = rx_tx_addr[3]; // ID?
packet[3] = 0x00; // unknown but prevents some receivers to bind if not 0
packet[4] = 0x00; // unknown but prevents some receivers to bind if not 0
packet[5] = (rf_ch_num << 3) | ((ch1 >> 9) & 0x07);
packet[6] = (ch1 >> 1);
packet[7] = (ch1 << 7) | ((ch2 >> 5) & 0x7F );
@@ -194,7 +224,7 @@ uint16_t ReadSFHSS()
/* Work cycle: 6.8ms */
#define SFHSS_PACKET_PERIOD 6800
#define SFHSS_DATA2_TIMING 1630 // original 1650
#define SFHSS_DATA2_TIMING 1625 // Adjust this value between 1600 and 1650 if your RX(s) are not operating properly
case SFHSS_DATA1:
SFHSS_build_data_packet();
SFHSS_send_packet();
@@ -225,7 +255,7 @@ static void __attribute__((unused)) SFHSS_get_tx_id()
uint8_t run_count = 0;
// add guard for bit count
fixed_id = 1 ^ (MProtocol_id & 1);
for (uint8_t i = 0; i < 32; ++i)
for (uint8_t i = 0; i < 16; ++i)
{
fixed_id = (fixed_id << 1) | (MProtocol_id & 1);
MProtocol_id >>= 1;
@@ -242,10 +272,8 @@ static void __attribute__((unused)) SFHSS_get_tx_id()
run_count = 0;
}
// fixed_id = 0xBC11;
rx_tx_addr[0] = fixed_id >> 24;
rx_tx_addr[1] = fixed_id >> 16;
rx_tx_addr[2] = fixed_id >> 8;
rx_tx_addr[3] = fixed_id >> 0;
rx_tx_addr[0] = fixed_id >> 8;
rx_tx_addr[1] = fixed_id >> 0;
}
uint16_t initSFHSS()

View File

@@ -81,7 +81,7 @@ static void __attribute__((unused)) SYMAX_read_controls()
if (Servo_AUX5)
{
flags |= SYMAX_FLAG_HEADLESS;
flags &= ~SYMAX_XTRM_RATES; // Extended rates & headless incompatible
flags &= ~SYMAX_XTRM_RATES; // Extended rates & headless incompatible
}
}
@@ -158,7 +158,7 @@ static void __attribute__((unused)) SYMAX_build_packet(uint8_t bind)
packet[6] = flags & SYMAX_FLAG_FLIP ? 0x40 : 0x00;
packet[7] = flags & SYMAX_FLAG_HEADLESS ? 0x80 : 0x00;
if (flags & SYMAX_XTRM_RATES)
{ // use trims to extend controls
{ // use trims to extend controls
packet[5] |= elevator >> 2;
packet[6] |= rudder >> 2;
packet[7] |= aileron >> 2;

View File

@@ -20,54 +20,47 @@
uint8_t RetrySequence ;
#if ( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) )
#define MULTI_TIME 500 //in ms
#define MULTI_TIME 500 //in ms
#define INPUT_SYNC_TIME 100 //in ms
#define INPUT_ADDITIONAL_DELAY 100 // in 10µs, 100 => 1000 µs
uint32_t lastMulti = 0;
#endif
#endif // MULTI_TELEMETRY/MULTI_STATUS
#if defined SPORT_TELEMETRY
#define SPORT_TIME 12000 //12ms
#define SPORT_TIME 12000 //12ms
#define FRSKY_SPORT_PACKET_SIZE 8
#define FX_BUFFERS 4
uint32_t last = 0;
uint8_t sport_counter=0;
uint8_t RxBt = 0;
uint8_t sport = 0;
#define MAX_PKTX 10
#define FX_BUFFERS 4
uint8_t pktx[MAX_PKTX];
uint8_t pktx1[FRSKY_SPORT_PACKET_SIZE*FX_BUFFERS];
uint8_t indx;
//struct t_fx_rx_packet
//{
// uint8_t validSequence ;
// uint8_t count ;
// uint8_t payload[6] ;
//} ;
uint8_t pktx1[FRSKY_SPORT_PACKET_SIZE*FX_BUFFERS];
// Store for out of sequence packet
//struct t_fx_rx_packet FrskyxRxTelemetry ;
// Store for out of sequence packet
uint8_t FrskyxRxTelemetryValidSequence ;
struct t_fx_rx_frame
{
uint8_t valid ;
uint8_t count ;
uint8_t payload[6] ;
} ;
uint8_t FrskyxRxTelemetryValidSequence ;
// Store for FrskyX telemetry
struct t_fx_rx_frame FrskyxRxFrames[4] ;
uint8_t NextFxFrameToForward ;
#endif // SPORT_TELEMETRY
struct t_fx_rx_frame
{
uint8_t valid ;
uint8_t count ;
uint8_t payload[6] ;
} ;
// Store for FrskyX telemetry
struct t_fx_rx_frame FrskyxRxFrames[4] ;
uint8_t NextFxFrameToForward ;
#endif
#if defined HUB_TELEMETRY
#define USER_MAX_BYTES 6
uint8_t prev_index;
#endif
#endif // HUB_TELEMETRY
#define START_STOP 0x7e
#define BYTESTUFF 0x7d
#define STUFF_MASK 0x20
#define START_STOP 0x7e
#define BYTESTUFF 0x7d
#define STUFF_MASK 0x20
#define MAX_PKTX 10
uint8_t pktx[MAX_PKTX];
uint8_t indx;
uint8_t frame[18];
#if ( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) )
@@ -85,30 +78,30 @@ static void multi_send_header(uint8_t type, uint8_t len)
static void multi_send_status()
{
multi_send_header(MULTI_TELEMETRY_STATUS, 5);
multi_send_header(MULTI_TELEMETRY_STATUS, 5);
// Build flags
uint8_t flags=0;
if (IS_INPUT_SIGNAL_on)
flags |= 0x01;
if (mode_select==MODE_SERIAL)
flags |= 0x02;
if (remote_callback != 0)
{
flags |= 0x04;
// Build flags
uint8_t flags=0;
if (IS_INPUT_SIGNAL_on)
flags |= 0x01;
if (mode_select==MODE_SERIAL)
flags |= 0x02;
if (remote_callback != 0)
{
flags |= 0x04;
if (IS_WAIT_BIND_on)
flags |= 0x10;
else
if (!IS_BIND_DONE_on)
flags |= 0x08;
}
Serial_write(flags);
Serial_write(flags);
// Version number example: 1.1.6.1
Serial_write(VERSION_MAJOR);
Serial_write(VERSION_MINOR);
Serial_write(VERSION_REVISION);
Serial_write(VERSION_PATCH_LEVEL);
// Version number example: 1.1.6.1
Serial_write(VERSION_MAJOR);
Serial_write(VERSION_MINOR);
Serial_write(VERSION_REVISION);
Serial_write(VERSION_PATCH_LEVEL);
}
#endif
@@ -156,9 +149,9 @@ static void multi_send_status()
#ifdef MULTI_TELEMETRY
static void multi_send_frskyhub()
{
multi_send_header(MULTI_TELEMETRY_HUB, 9);
for (uint8_t i = 0; i < 9; i++)
Serial_write(frame[i]);
multi_send_header(MULTI_TELEMETRY_HUB, 9);
for (uint8_t i = 0; i < 9; i++)
Serial_write(frame[i]);
}
#endif
@@ -169,8 +162,8 @@ void frskySendStuffed()
{
if ((frame[i] == START_STOP) || (frame[i] == BYTESTUFF))
{
Serial_write(BYTESTUFF);
frame[i] ^= STUFF_MASK;
Serial_write(BYTESTUFF);
frame[i] ^= STUFF_MASK;
}
Serial_write(frame[i]);
}
@@ -181,12 +174,8 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
{
uint8_t clen = pkt[0] + 3 ;
if(pkt[1] == rx_tx_addr[3] && pkt[2] == rx_tx_addr[2] && len == clen )
{
{
telemetry_link|=1; // Telemetry data is available
/*previous version
RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>4);
if(pktt[len-2] >=128) RSSI_dBm -= 164;
else RSSI_dBm += 130;*/
TX_RSSI = pkt[len-2];
if(TX_RSSI >=128)
TX_RSSI -= 128;
@@ -204,12 +193,8 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
{
uint8_t topBit = 0 ;
if ( telemetry_counter & 0x80 )
{
if ( ( telemetry_counter & 0x1F ) != RetrySequence )
{
topBit = 0x80 ;
}
}
telemetry_counter = ( (telemetry_counter+1)%32 ) | topBit ; // Request next telemetry frame
}
else
@@ -222,28 +207,14 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
}
}
else
{
pktt[6]=0; // Discard packet
}
//
#if defined SPORT_TELEMETRY && defined FRSKYX_CC2500_INO
telemetry_lost=0;
if (protocol==MODE_FRSKYX)
{
uint16_t lcrc = crc_x(&pkt[3], len-7 ) ;
// if ( ( sub_protocol & 2 ) == 0 )
// {
// if ( ( (lcrc >> 8) == pkt[len-4]) && ( (lcrc & 0x00FF ) == pkt[len-3]) )
// {
// lcrc = 0 ;
// }
// else
// {
// lcrc = 1 ;
// }
// }
// if ( lcrc == 0 )
if ( ( (lcrc >> 8) == pkt[len-4]) && ( (lcrc & 0x00FF ) == pkt[len-3]) )
{
// Check if in sequence
@@ -267,18 +238,12 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
{
p->count = count ;
for ( uint8_t i = 0 ; i < count ; i += 1 )
{
p->payload[i] = pkt[i+7] ;
}
}
else
{
p->count = 0 ;
}
p->valid = 1 ;
FrX_receive_seq = ( FrX_receive_seq + 1 ) & 0x03 ;
if ( FrskyxRxTelemetryValidSequence & 0x80 )
@@ -287,24 +252,16 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
FrskyxRxTelemetryValidSequence &= 0x7F ;
}
// if ( FrskyxRxTelemetry.validSequence & 0x80 )
// {
// FrX_receive_seq = ( FrskyxRxTelemetry.validSequence + 1 ) & 3 ;
// FrskyxRxTelemetry.validSequence &= 0x7F ;
// }
}
else
{
// Save and request correct packet
// struct t_fx_rx_packet *p ;
struct t_fx_rx_frame *q ;
uint8_t count ;
// pkt[4] RSSI
// pkt[5] sequence control
// pkt[6] payload count
// pkt[7-12] payload
// pkt[4] RSSI
// pkt[5] sequence control
// pkt[6] payload count
// pkt[7-12] payload
pktt[6] = 0 ; // Don't process
if ( (pkt[5] & 0x03) == ( ( FrX_receive_seq +1 ) & 3 ) )
{
@@ -319,55 +276,18 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
}
}
else
{
q->count = 0 ;
}
q->valid = 1 ;
FrskyxRxTelemetryValidSequence = 0x80 | ( pkt[5] & 0x03 ) ;
}
// p = &FrskyxRxTelemetry ;
// count = pkt[6] ;
// if ( count <= 6 )
// {
// p->count = count ;
// for ( uint8_t i = 0 ; i < count ; i += 1 )
// {
// p->payload[i] = pkt[i+7] ;
// }
// p->validSequence = 0x80 | ( pkt[5] & 0x03 ) ;
// }
FrX_receive_seq = ( FrX_receive_seq & 0x03 ) | 0x04 ; // Request re-transmission
FrX_receive_seq = ( FrX_receive_seq & 0x03 ) | 0x04 ; // Request re-transmission
}
if (((pktt[5] >> 4) & 0x0f) == 0x08)
{
FrX_send_seq = 0 ;
// FrX_receive_seq = 0x08 ;
}
}
// packet[21] = (FrX_receive_seq << 4) | FrX_send_seq ;//8 at start
// if ( FrX_send_seq != 0x08 )
// {
// FrX_send_seq = ( FrX_send_seq + 1 ) & 0x03 ;
// }
// if ((pktt[5] >> 4 & 0x0f) == 0x08)
// {
// seq_last_sent = 8;
// seq_last_rcvd = 0;
// pass=0;
// }
// else
// {
// if ((pktt[5] >> 4 & 0x03) == (seq_last_rcvd + 1) % 4)
// seq_last_rcvd = (seq_last_rcvd + 1) % 4;
// else
// pass=0;//reset if sequence wrong
// }
}
#endif
}
@@ -397,7 +317,7 @@ void frsky_link_frame()
telemetry_link |= 2 ; // Send hub if available
}
else
if (protocol==MODE_HUBSAN||protocol==MODE_AFHDS2A||protocol==MODE_BAYANG)
if (protocol==MODE_HUBSAN||protocol==MODE_AFHDS2A||protocol==MODE_BAYANG||protocol==MODE_CABELL)
{
frame[1] = v_lipo1;
frame[2] = v_lipo2;
@@ -446,7 +366,7 @@ void frsky_user_frame()
}
else
telemetry_link=0;
}
}
/*
HuB RX packets.
pkt[6]|(counter++)|00 01 02 03 04 05 06 07 08 09
@@ -514,23 +434,19 @@ pkt[6]|(counter++)|00 01 02 03 04 05 06 07 08 09
*/
const uint8_t PROGMEM Indices[] = { 0x00, 0xA1, 0x22, 0x83, 0xE4, 0x45,
0xC6, 0x67, 0x48, 0xE9, 0x6A, 0xCB,
0xAC, 0x0D, 0x8E, 0x2F, 0xD0, 0x71,
0xF2, 0x53, 0x34, 0x95, 0x16, 0xB7,
0x98, 0x39, 0xBA, 0x1B } ;
#ifdef MULTI_TELEMETRY
const uint8_t PROGMEM Indices[] = { 0x00, 0xA1, 0x22, 0x83, 0xE4, 0x45,
0xC6, 0x67, 0x48, 0xE9, 0x6A, 0xCB,
0xAC, 0x0D, 0x8E, 0x2F, 0xD0, 0x71,
0xF2, 0x53, 0x34, 0x95, 0x16, 0xB7,
0x98, 0x39, 0xBA, 0x1B } ;
void sportSend(uint8_t *p)
{
multi_send_header(MULTI_TELEMETRY_SPORT, 9);
uint16_t crc_s = 0;
uint8_t x = p[0] ;
if ( x <= 0x1B )
{
x = pgm_read_byte_near( &Indices[x] ) ;
}
Serial_write(x) ;
for (uint8_t i = 1; i < 9; i++)
{
@@ -540,8 +456,8 @@ const uint8_t PROGMEM Indices[] = { 0x00, 0xA1, 0x22, 0x83, 0xE4, 0x45,
if (i>0)
{
crc_s += p[i]; //0-1FF
crc_s += crc_s >> 8; //0-100
crc_s += p[i]; //0-1FF
crc_s += crc_s >> 8; //0-100
crc_s &= 0x00ff;
}
}
@@ -661,7 +577,7 @@ void proces_sport_data(uint8_t data)
pass = 1;
break;
}
if(data == BYTESTUFF)//if they are stuffed
if(data == BYTESTUFF) //if they are stuffed
pass=2;
else
if (indx < MAX_PKTX)
@@ -680,9 +596,7 @@ void proces_sport_data(uint8_t data)
uint8_t dest = sport * FRSKY_SPORT_PACKET_SIZE ;
uint8_t i ;
for ( i = 0 ; i < FRSKY_SPORT_PACKET_SIZE ; i += 1 )
{
pktx1[dest++] = pktx[i] ; // Triple buffer
}
sport += 1 ;//ok to send
}
// else
@@ -704,10 +618,9 @@ void TelemetryUpdate()
h = SerialControl.head ;
t = SerialControl.tail ;
if ( h >= t )
t += 192 - h ;
t += TXBUFFER_SIZE - h ;
else
t -= h ;
// if ( t < 32 )
if ( t < 64 )
{
return ;
@@ -741,9 +654,6 @@ void TelemetryUpdate()
#if defined SPORT_TELEMETRY
if (protocol==MODE_FRSKYX)
{ // FrSkyX
// struct t_fx_rx_frame *p ;
// uint8_t count ;
for(;;)
{
struct t_fx_rx_frame *p ;
@@ -763,40 +673,12 @@ void TelemetryUpdate()
}
}
// p = &FrskyxRxFrames[NextFxFrameToForward] ;
// if ( p->valid )
// {
// count = p->count ;
// for (uint8_t i=0; i < count ; i++)
// proces_sport_data(p->payload[i]) ;
// p->valid = 0 ; // Sent on
// NextFxFrameToForward = ( NextFxFrameToForward + 1 ) & 3 ;
// }
if(telemetry_link)
{
if(pktt[4] & 0x80)
RX_RSSI=pktt[4] & 0x7F ;
else
RxBt = (pktt[4]<<1) + 1 ;
// if(pktt[6] && pktt[6]<=6)
// {
// for (uint8_t i=0; i < pktt[6]; i++)
// proces_sport_data(pktt[7+i]);
// if ( FrskyxRxTelemetry.validSequence & 0x80 )
// {
// // Process out of sequence packet
// for (uint8_t i=0; i < FrskyxRxTelemetry.count ; i++)
// {
// proces_sport_data( FrskyxRxTelemetry.payload[i] ) ;
// }
//// FrX_receive_seq = ( FrskyxRxTelemetry.validSequence + 1 ) & 3 ;
// FrskyxRxTelemetry.validSequence = 0 ;
// }
// }
telemetry_link=0;
}
uint32_t now = micros();
@@ -810,7 +692,7 @@ void TelemetryUpdate()
#endif
}
}
#endif
#endif // SPORT_TELEMETRY
#if defined DSM_TELEMETRY
if(telemetry_link && protocol == MODE_DSM)
@@ -820,17 +702,17 @@ void TelemetryUpdate()
return;
}
#endif
#if defined AFHDS2A_FW_TELEMETRY
if(telemetry_link == 2 && protocol == MODE_AFHDS2A)
#if defined AFHDS2A_FW_TELEMETRY
if(telemetry_link == 2 && protocol == MODE_AFHDS2A)
{
AFHDSA_short_frame();
telemetry_link=0;
return;
}
#endif
#endif
if((telemetry_link & 1 )&& protocol != MODE_FRSKYX)
{ // FrSkyD + Hubsan + AFHDS2A + Bayang
{ // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell
frsky_link_frame();
return;
}
@@ -850,6 +732,19 @@ void TelemetryUpdate()
/**************************/
/**************************/
#ifdef SERIAL_DEBUG
void StatusSerial_write(uint8_t data)
{
uint8_t nextHead ;
nextHead = tx_debug_head + 1 ;
if ( nextHead >= TXBUFFER_SIZE )
nextHead = 0 ;
tx_debug_buff[nextHead]=data;
tx_debug_head = nextHead ;
tx_debug_resume();
}
#endif // SERIAL_DEBUG
#ifndef BASH_SERIAL
// Routines for normal serial output
void Serial_write(uint8_t data)
@@ -969,11 +864,34 @@ void TelemetryUpdate()
#endif
}
#ifdef STM32_BOARD
#if defined(SERIAL_DEBUG)
void __irq_usart1()
{ // Transmit interrupt
if(USART1_BASE->SR & USART_SR_TXE)
{
if(tx_debug_head!=tx_debug_tail)
{
if(++tx_debug_tail>=TXBUFFER_SIZE) //head
tx_debug_tail=0;
USART1_BASE->DR=tx_debug_buff[tx_debug_tail]; //clears TXE bit
}
if (tx_debug_tail == tx_debug_head)
tx_debug_pause(); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
}
}
void usart1_begin(uint32_t baud,uint32_t config )
{
usart_init(USART1);
usart_config_gpios_async(USART1,GPIOA,PIN_MAP[PA10].gpio_bit,GPIOA,PIN_MAP[PA9].gpio_bit,config);
usart_set_baud_rate(USART1, STM32_PCLK1, baud);
usart_enable(USART1);
}
#endif
void usart2_begin(uint32_t baud,uint32_t config )
{
usart_init(USART2);
usart_config_gpios_async(USART2,GPIOA,PIN_MAP[PA3].gpio_bit,GPIOA,PIN_MAP[PA2].gpio_bit,config);
usart_set_baud_rate(USART2, STM32_PCLK1, baud);//
usart_set_baud_rate(USART2, STM32_PCLK1, baud);
usart_enable(USART2);
}
void usart3_begin(uint32_t baud,uint32_t config )
@@ -1056,7 +974,9 @@ void Serial_write( uint8_t byte )
#ifdef INVERT_SERIAL
byte |= 1 ; // Start bit
#endif
uint8_t next = (SerialControl.head + 2) & 0x7f ;
uint8_t next = SerialControl.head + 2;
if(next>=TXBUFFER_SIZE)
next=0;
if ( next != SerialControl.tail )
{
SerialControl.data[SerialControl.head] = byte ;
@@ -1120,9 +1040,7 @@ ISR(TIMER0_COMPA_vect)
GPIOR1 = 3 ;
}
else
{
OCR0A += 20 ;
}
}
ISR(TIMER0_COMPB_vect)
@@ -1150,12 +1068,9 @@ ISR(TIMER0_COMPB_vect)
{
GPIOR0 = ptr->data[ptr->tail] ;
GPIOR2 = ptr->data[ptr->tail+1] ;
uint8_t nextTail ;
nextTail = ptr->tail + 2 ;
if ( nextTail > 192 )
{
uint8_t nextTail = ptr->tail + 2 ;
if ( nextTail >= TXBUFFER_SIZE )
nextTail = 0 ;
}
ptr->tail = nextTail ;
GPIOR1 = 8 ;
OCR0A = OCR0B + 40 ;
@@ -1170,44 +1085,36 @@ ISR(TIMER0_COMPB_vect)
}
}
else
{
OCR0B += 20 ;
}
}
ISR(TIMER0_OVF_vect)
{
uint8_t byte ;
if ( GPIOR1 > 2 )
{
byte = GPIOR0 ;
}
else
{
byte = GPIOR2 ;
}
if ( byte & 0x01 )
SERIAL_TX_on;
else
SERIAL_TX_off;
byte /= 2 ; // Generates shorter code than byte >>= 1
if ( GPIOR1 > 2 )
{
GPIOR0 = byte ;
}
else
{
GPIOR2 = byte ;
}
if ( --GPIOR1 == 0 )
{
// prepare next byte
{ // prepare next byte
volatile struct t_serial_bash *ptr = &SerialControl ;
if ( ptr->head != ptr->tail )
{
GPIOR0 = ptr->data[ptr->tail] ;
GPIOR2 = ptr->data[ptr->tail+1] ;
ptr->tail = ( ptr->tail + 2 ) & 0x7F ;
uint8_t nextTail = ptr->tail + 2 ;
if ( nextTail >= TXBUFFER_SIZE )
nextTail = 0 ;
ptr->tail = nextTail ;
GPIOR1 = 10 ;
}
else

View File

@@ -79,6 +79,7 @@
#undef Q303_NRF24L01_INO
#undef GW008_NRF24L01_INO
#undef DM002_NRF24L01_INO
#undef CABELL_NRF24L01_INO
#endif
//Make sure telemetry is selected correctly
@@ -87,6 +88,7 @@
#undef AFHDS2A_FW_TELEMETRY
#undef AFHDS2A_HUB_TELEMETRY
#undef BAYANG_HUB_TELEMETRY
#undef CABELL_HUB_TELEMETRY
#undef HUBSAN_HUB_TELEMETRY
#undef HUB_TELEMETRY
#undef SPORT_TELEMETRY
@@ -100,6 +102,9 @@
#if not defined(BAYANG_NRF24L01_INO)
#undef BAYANG_HUB_TELEMETRY
#endif
#if not defined(CABELL_NRF24L01_INO)
#undef CABELL_HUB_TELEMETRY
#endif
#if not defined(HUBSAN_A7105_INO)
#undef HUBSAN_HUB_TELEMETRY
#endif
@@ -116,7 +121,7 @@
#if not defined(DSM_CYRF6936_INO)
#undef DSM_TELEMETRY
#endif
#if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS)
#if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS)
#undef TELEMETRY
#undef INVERT_TELEMETRY
#endif

View File

@@ -294,7 +294,7 @@ static void __attribute__((unused)) WK_build_beacon_pkt_2801()
BIND_SET_PULLUP; // set pullup
if(IS_BIND_BUTTON_on)
{
eeprom_write_byte((EE_ADDR)(30+mode_select),0x01); // Set fixed id mode for the current model
eeprom_write_byte((EE_ADDR)(MODELMODE_EEPROM_OFFSET+mode_select),0x01); // Set fixed id mode for the current model
option=1;
}
BIND_SET_OUTPUT;

View File

@@ -139,10 +139,16 @@
//#define Q303_NRF24L01_INO
//#define GW008_NRF24L01_INO
//#define DM002_NRF24L01_INO
//#define CABELL_NRF24L01_INO
/**************************/
/*** FAILSAFE SETTINGS ***/
/**************************/
//SHFSS failsafe is by default set to all channels hold their positions except throttle forced to low (980µs)
//You can uncomment the setting below to use channels 9(1) to 16(8) instead
//#define SFHSS_FAILSAFE_CH9_16
#define AFHDS2A_FAILSAFE
#ifdef AFHDS2A_FAILSAFE
/*
@@ -208,7 +214,7 @@ const int8_t AFHDS2AFailsafe[14]= {
//#define AFHDS2A_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
//#define BAYANG_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
//#define HUBSAN_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
//#define CABELL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
/****************************/
/*** SERIAL MODE SETTINGS ***/
@@ -401,6 +407,11 @@ const PPM_Parameters PPM_prot[15]= {
NONE
MODE_DM002
NONE
MODE_CABELL
CABELL_V3
CABELL_V3_TELEMETRY
CABELL_SET_FAIL_SAFE
CABELL_UNBIND
*/
// RX_Num is used for model match. Using RX_Num values different for each receiver will prevent starting a model with the false config loaded...

24
Multiprotocol/_MyConfig.h Normal file
View File

@@ -0,0 +1,24 @@
//#define FORCE_GLOBAL_ID 0x12345678
#if not defined STM32_BOARD
// #undef AFHDS2A_A7105_INO
// #undef DEVO_CYRF6936_INO
// #undef J6PRO_CYRF6936_INO
// #undef WK2x01_CYRF6936_INO
// #undef FRSKYV_CC2500_INO
// #undef FRSKYX_CC2500_INO
// #undef KN_NRF24L01_INO
// #undef SLT_NRF24L01_INO
// #undef FY326_NRF24L01_INO
// #undef FQ777_NRF24L01_INO
// #undef ASSAN_NRF24L01_INO
// #undef HONTAI_NRF24L01_INO
// #undef Q303_NRF24L01_INO
// #undef GW008_NRF24L01_INO
// #undef DM002_NRF24L01_INO
// #undef CABELL_NRF24L01_INO
#endif