Skip to content

Instantly share code, notes, and snippets.

@markusgritsch
Last active October 3, 2018 12:36
Show Gist options
  • Save markusgritsch/a9acd69e1b0f3117fe6db060fd63e351 to your computer and use it in GitHub Desktop.
Save markusgritsch/a9acd69e1b0f3117fe6db060fd63e351 to your computer and use it in GitHub Desktop.
BoldClash-BWHOOP-B-03/Silverware/src/rx_bayang_protocol_telemetry.c -> H101-dual/H101_dual/src/rx_bayang_protocol.c
/*
The MIT License (MIT)
Copyright (c) 2016 silverx
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "binary.h"
#include "drv_spi.h"
//#include "project.h"
#include "xn297.h"
#include "drv_time.h"
#include <stdio.h>
#include "config.h"
#include "defines.h"
#include "rx_bayang.h"
#include "util.h"
#include "hardware.h"
// radio settings
// packet period in uS
#define PACKET_PERIOD 3000
#define PACKET_PERIOD_TELEMETRY 5000
// was 250 ( uS )
#define PACKET_OFFSET 0
#ifdef USE_STOCK_TX
#undef PACKET_PERIOD
#define PACKET_PERIOD 2000
#undef PACKET_OFFSET
#define PACKET_OFFSET 0
#endif
// how many times to hop ahead if no reception
#define HOPPING_NUMBER 4
#ifdef RX_BAYANG_PROTOCOL_TELEMETRY
float rx[4];
char aux[AUXNUMBER];
char lastaux[AUXNUMBER];
char auxchange[AUXNUMBER];
char lasttrim[4];
char rfchannel[4];
char rxaddress[5];
int telemetry_enabled = 0;
int rx_bind_enable = 0;
int rx_bind_load = 0;
int rxmode = 0;
int rf_chan = 0;
unsigned long autobindtime = 0;
int autobind_inhibit = 0;
int packet_period = PACKET_PERIOD;
void writeregs(uint8_t data[], uint8_t size)
{
spi_cson();
for (uint8_t i = 0; i < size; i++)
{
spi_sendbyte(data[i]);
}
spi_csoff();
}
void rx_init()
{
// always on (CH_ON) channel set 1
aux[AUXNUMBER - 2] = 1;
// always off (CH_OFF) channel set 0
aux[AUXNUMBER - 1] = 0;
#ifdef AUX1_START_ON
aux[CH_AUX1] = 1;
#endif
#ifdef RADIO_XN297L
#ifndef TX_POWER
#define TX_POWER 7
#endif
// Gauss filter amplitude - lowest
static uint8_t demodcal[2] = { 0x39 , B00000001 };
writeregs( demodcal , sizeof(demodcal) );
// powerup defaults
//static uint8_t rfcal2[7] = { 0x3a , 0x45 , 0x21 , 0xef , 0xac , 0x3a , 0x50};
//writeregs( rfcal2 , sizeof(rfcal2) );
static uint8_t rfcal2[7] = { 0x3a , 0x45 , 0x21 , 0xef , 0x2c , 0x5a , 0x50};
writeregs( rfcal2 , sizeof(rfcal2) );
static uint8_t regs_1f[6] = { 0x3f , 0x0a, 0x6d , 0x67 , 0x9c , 0x46 };
writeregs( regs_1f , sizeof(regs_1f) );
static uint8_t regs_1e[4] = { 0x3e , 0xf6 , 0x37 , 0x5d };
writeregs( regs_1e , sizeof(regs_1e) );
#define XN_TO_RX B10001111
#define XN_TO_TX B10000010
#define XN_POWER B00000001|((TX_POWER&7)<<3)
#endif
#ifdef RADIO_XN297
static uint8_t bbcal[6] = { 0x3f, 0x4c, 0x84, 0x6F, 0x9c, 0x20 };
writeregs(bbcal, sizeof(bbcal));
// new values
static uint8_t rfcal[8] =
{ 0x3e, 0xc9, 0x9a, 0xA0, 0x61, 0xbb, 0xab, 0x9c };
writeregs(rfcal, sizeof(rfcal));
// 0xa7 0x03
static uint8_t demodcal[6] =
{ 0x39, 0x0b, 0xdf, 0xc4, B00100111, B00000000 };
writeregs(demodcal, sizeof(demodcal));
#ifndef TX_POWER
#define TX_POWER 3
#endif
#define XN_TO_RX B00001111
#define XN_TO_TX B00000010
#define XN_POWER (B00000001|((TX_POWER&3)<<1))
#endif
delay(100);
// write rx address " 0 0 0 0 0 "
static uint8_t rxaddr[6] = { 0x2a , 0 , 0 , 0 , 0 , 0 };
writeregs( rxaddr , sizeof(rxaddr) );
xn_writereg(EN_AA, 0); // aa disabled
xn_writereg(EN_RXADDR, 1); // pipe 0 only
xn_writereg(RF_SETUP, XN_POWER); // power / data rate / lna
xn_writereg(RX_PW_P0, 15); // payload size
xn_writereg(SETUP_RETR, 0); // no retransmissions ( redundant?)
xn_writereg(SETUP_AW, 3); // address size (5 bytes)
xn_command(FLUSH_RX);
xn_writereg(RF_CH, 0); // bind on channel 0
#ifdef RADIO_XN297L
xn_writereg(0x1d, B00111000); // 64 bit payload , software ce
spi_cson();
spi_sendbyte(0xFD); // internal CE high command
spi_sendbyte(0); // required for above
spi_csoff();
#endif
#ifdef RADIO_XN297
xn_writereg(0x1d, B00011000); // 64 bit payload , software ce
#endif
xn_writereg(0, XN_TO_RX); // power up, crc enabled, rx mode
#ifdef RADIO_CHECK
int rxcheck = xn_readreg(0x0f); // rx address pipe 5
// should be 0xc6
extern void failloop(int);
if (rxcheck != 0xc6)
failloop(3);
#endif
if ( rx_bind_load )
{
uint8_t rxaddr_regs[6] = { 0x2a , };
for ( int i = 1 ; i < 6; i++)
{
rxaddr_regs[i] = rxaddress[i-1];
}
// write new rx address
writeregs( rxaddr_regs , sizeof(rxaddr_regs) );
rxaddr_regs[0] = 0x30; // tx register ( write ) number
// write new tx address
writeregs( rxaddr_regs , sizeof(rxaddr_regs) );
xn_writereg(0x25, rfchannel[rf_chan]); // Set channel frequency
rxmode = RX_MODE_NORMAL;
if ( telemetry_enabled ) packet_period = PACKET_PERIOD_TELEMETRY;
}
else
{
autobind_inhibit = 1;
}
}
//#define RXDEBUG
#ifdef RXDEBUG
unsigned long packettime;
int channelcount[4];
int failcount;
int skipstats[12];
int afterskip[12];
#warning "RX debug enabled"
#endif
int packetrx;
int packetpersecond;
void send_telemetry(void);
void nextchannel(void);
int loopcounter = 0;
unsigned int send_time;
int telemetry_send = 0;
int oldchan = 0;
#define TELEMETRY_TIMEOUT 10000
void beacon_sequence()
{
static int beacon_seq_state = 0;
switch (beacon_seq_state)
{
case 0:
// send data
telemetry_send = 1;
send_telemetry();
beacon_seq_state++;
break;
case 1:
// wait for data to finish transmitting
if ((xn_readreg(0x17) & B00010000))
{
xn_writereg(0, XN_TO_RX);
beacon_seq_state = 0;
telemetry_send = 0;
nextchannel();
}
else
{ // if it takes too long we get rid of it
if (gettime() - send_time > TELEMETRY_TIMEOUT)
{
xn_command(FLUSH_TX);
xn_writereg(0, XN_TO_RX);
beacon_seq_state = 0;
telemetry_send = 0;
}
}
break;
default:
beacon_seq_state = 0;
break;
}
}
extern int lowbatt;
extern float vbattfilt;
extern float vbatt_comp;
void send_telemetry()
{
int txdata[15];
for (int i = 0; i < 15; i++)
txdata[i] = i;
txdata[0] = 133;
txdata[1] = lowbatt;
int vbatt = vbattfilt * 100 + .5f;
// battery volt filtered
txdata[3] = (vbatt >> 8) & 0xff;
txdata[4] = vbatt & 0xff;
vbatt = vbatt_comp * 100 + .5f;
// battery volt compensated
txdata[5] = (vbatt >> 8) & 0xff;
txdata[6] = vbatt & 0xff;
int temp = packetpersecond / 2;
if (temp > 255)
temp = 255;
txdata[7] = temp; // rx strenght
if (lowbatt)
txdata[3] |= (1 << 3);
int sum = 0;
for (int i = 0; i < 14; i++)
{
sum += txdata[i];
}
txdata[14] = sum;
xn_command(FLUSH_TX);
xn_writereg(0, XN_TO_TX);
xn_writepayload(txdata, 15);
send_time = gettime();
return;
}
static char checkpacket()
{
int status = xn_readreg(7);
if (status & (1 << MASK_RX_DR))
{ // rx clear bit
// this is not working well
// xn_writereg( STATUS , (1<<MASK_RX_DR) );
//RX packet received
//return 1;
}
if ((status & B00001110) != B00001110)
{
// rx fifo not empty
return 2;
}
return 0;
}
int rxdata[15];
float packettodata(int *data)
{
return (((data[0] & 0x0003) * 256 + data[1]) / 1023.0 * 2.0) - 1.0;
}
static int decodepacket(void)
{
if (rxdata[0] == 165)
{
int sum = 0;
for (int i = 0; i < 14; i++)
{
sum += rxdata[i];
}
if ((sum & 0xFF) == rxdata[14])
{
rx[0] = packettodata(&rxdata[4]);
rx[1] = packettodata(&rxdata[6]);
rx[2] = packettodata(&rxdata[10]);
// throttle
rx[3] =
((rxdata[8] & 0x0003) * 256 +
rxdata[9]) / 1023.0;
#ifndef DISABLE_EXPO
rx[0] = rcexpo(rx[0], EXPO_XY);
rx[1] = rcexpo(rx[1], EXPO_XY);
rx[2] = rcexpo(rx[2], EXPO_YAW);
#endif
#ifdef USE_STOCK_TX
char trims[4];
trims[0] = rxdata[6] >> 2;
trims[1] = rxdata[4] >> 2;
for (int i = 0; i < 2; i++)
if (trims[i] != lasttrim[i])
{
aux[CH_PIT_TRIM + i] = trims[i] > lasttrim[i];
lasttrim[i] = trims[i];
}
#else
aux[CH_INV] = (rxdata[3] & 0x80) ? 1 : 0; // inverted flag
aux[CH_VID] = (rxdata[2] & 0x10) ? 1 : 0;
aux[CH_PIC] = (rxdata[2] & 0x20) ? 1 : 0;
#endif
aux[CH_TO] = (rxdata[3] & 0x20) ? 1 : 0; // take off flag
aux[CH_EMG] = (rxdata[3] & 0x04) ? 1 : 0; // emg stop flag
aux[CH_FLIP] = (rxdata[2] & 0x08) ? 1 : 0;
aux[CH_EXPERT] = (rxdata[1] == 0xfa) ? 1 : 0;
aux[CH_HEADFREE] = (rxdata[2] & 0x02) ? 1 : 0;
aux[CH_RTH] = (rxdata[2] & 0x01) ? 1 : 0; // rth channel
for (int i = 0; i < AUXNUMBER - 2; i++)
{
auxchange[i] = 0;
if (lastaux[i] != aux[i])
auxchange[i] = 1;
lastaux[i] = aux[i];
}
return 1; // valid packet
}
return 0; // sum fail
}
return 0; // first byte different
}
void nextchannel()
{
rf_chan++;
rf_chan &= 3; // same as %4
xn_writereg(0x25, rfchannel[rf_chan]);
}
unsigned long lastrxtime;
unsigned long failsafetime;
unsigned long secondtimer;
int failsafe = 0;
unsigned int skipchannel = 0;
int lastrxchan;
int timingfail = 0;
void checkrx(void)
{
int packetreceived = checkpacket();
int pass = 0;
if (packetreceived)
{
if (rxmode == RX_MODE_BIND)
{ // rx startup , bind mode
xn_readpayload(rxdata, 15);
if (rxdata[0] == 0xa4 || rxdata[0] == 0xa3)
{ // bind packet
if (rxdata[0] == 0xa3)
{
telemetry_enabled = 1;
packet_period = PACKET_PERIOD_TELEMETRY;
}
rfchannel[0] = rxdata[6];
rfchannel[1] = rxdata[7];
rfchannel[2] = rxdata[8];
rfchannel[3] = rxdata[9];
uint8_t rxaddr_regs[6] = { 0x2a , };
for ( int i = 1 ; i < 6; i++)
{
rxaddr_regs[i] = rxdata[i];
rxaddress[i-1] = rxdata[i];
}
// write new rx address
writeregs( rxaddr_regs , sizeof(rxaddr_regs) );
rxaddr_regs[0] = 0x30; // tx register ( write ) number
// write new tx address
writeregs( rxaddr_regs , sizeof(rxaddr_regs) );
xn_writereg(0x25, rfchannel[rf_chan]); // Set channel frequency
rxmode = RX_MODE_NORMAL;
#ifdef SERIAL
printf(" BIND \n");
#endif
}
}
else
{ // normal mode
#ifdef RXDEBUG
channelcount[rf_chan]++;
packettime = gettime() - lastrxtime;
if (skipchannel && !timingfail)
afterskip[skipchannel]++;
if (timingfail)
afterskip[0]++;
#endif
unsigned long temptime = gettime();
xn_readpayload(rxdata, 15);
pass = decodepacket();
if (pass)
{
packetrx++;
if (telemetry_enabled)
beacon_sequence();
skipchannel = 0;
timingfail = 0;
lastrxchan = rf_chan;
lastrxtime = temptime;
failsafetime = temptime;
failsafe = 0;
if (!telemetry_send)
nextchannel();
}
else
{
#ifdef RXDEBUG
failcount++;
#endif
}
} // end normal rx mode
} // end packet received
// finish sending if already started
if (telemetry_send)
beacon_sequence();
unsigned long time = gettime();
if (time - lastrxtime > (HOPPING_NUMBER * packet_period + 1000)
&& rxmode != RX_MODE_BIND)
{
// channel with no reception
lastrxtime = time;
// set channel to last with reception
if (!timingfail)
rf_chan = lastrxchan;
// advance to next channel
nextchannel();
// set flag to discard packet timing
timingfail = 1;
}
if (!timingfail && !telemetry_send && skipchannel < HOPPING_NUMBER + 1
&& rxmode != RX_MODE_BIND)
{
unsigned int temp = time - lastrxtime;
if (temp > 1000
&& (temp - (PACKET_OFFSET)) / ((int) packet_period) >=
(skipchannel + 1))
{
nextchannel();
#ifdef RXDEBUG
skipstats[skipchannel]++;
#endif
skipchannel++;
}
}
if (time - failsafetime > FAILSAFETIME)
{ // failsafe
failsafe = 1;
rx[0] = 0;
rx[1] = 0;
rx[2] = 0;
rx[3] = 0;
}
if ( !failsafe) autobind_inhibit = 1;
else if ( !autobind_inhibit && time - autobindtime > 15000000 )
{
autobind_inhibit = 1;
rxmode = RX_MODE_BIND;
static uint8_t rxaddr[6] = { 0x2a , 0 , 0 , 0 , 0 , 0 };
writeregs( rxaddr , sizeof(rxaddr) );
xn_writereg(RF_CH, 0); // bind on channel 0
}
if (gettime() - secondtimer > 1000000)
{
packetpersecond = packetrx;
packetrx = 0;
secondtimer = gettime();
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment