2020-12-05 19:12:11 +01:00
/*
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/>.
*/
2020-12-13 23:15:43 +01:00
#if defined(WFLY2_A7105_INO)
2020-12-05 19:12:11 +01:00
#include "iface_a7105.h"
2020-12-13 23:15:43 +01:00
//#define WFLY2_FORCE_ID
2020-12-05 19:12:11 +01:00
2020-12-13 23:15:43 +01:00
//WFLY2 constants & variables
2020-12-15 23:58:56 +01:00
#define WFLY2_BIND_COUNT 2777 // abort bind after 10sec
2020-12-13 23:15:43 +01:00
#define WFLY2_PACKET_SIZE 32
2020-12-05 19:12:11 +01:00
2020-12-10 16:51:55 +01:00
enum {
2020-12-13 23:15:43 +01:00
WFLY2_DATA ,
WFLY2_PLL_TX ,
WFLY2_RX ,
2020-12-10 16:51:55 +01:00
};
2020-12-13 23:15:43 +01:00
static void __attribute__ (( unused )) WFLY2_build_packet ()
2020-12-10 16:51:55 +01:00
{
static uint16_t pseudo = 0 ;
2020-12-15 23:58:56 +01:00
//End bind
if ( IS_BIND_IN_PROGRESS && bind_counter )
{
bind_counter -- ;
if ( bind_counter == 0 )
{
BIND_DONE ;
A7105_WriteID ( MProtocol_id );
rf_ch_num = 0 ;
}
}
2020-12-10 16:51:55 +01:00
2020-12-15 23:58:56 +01:00
memset ( packet , 0x00 , WFLY2_PACKET_SIZE );
if ( IS_BIND_IN_PROGRESS )
2020-12-10 16:51:55 +01:00
{
2020-12-15 23:58:56 +01:00
//Header
packet [ 0 ] = 0x0F ; // Bind packet
//ID
packet [ 1 ] = rx_tx_addr [ 3 ];
packet [ 2 ] = rx_tx_addr [ 2 ];
packet [ 3 ] = rx_tx_addr [ 1 ];
//packet[4] = 0x00; // Should be rx_tx_addr[0]&0x0F but bind is already using 0x00 so ....
//Unknown
packet [ 5 ] = 0x01 ;
//Freq
rf_ch_num = ( hopping_frequency_no << 1 ) + 0x08 ;
packet [ 6 ] = rf_ch_num ;
hopping_frequency_no ++ ;
if ( hopping_frequency_no > 0x17 ) hopping_frequency_no = 0x00 ;
//Unknown bytes 7..31
2020-12-10 16:51:55 +01:00
}
else
{
2020-12-15 23:58:56 +01:00
//Pseudo
uint16_t high_bit = ( pseudo & 0x8000 ) ^ 0x8000 ; // toggle 0x8000 every other line
pseudo <<= 1 ; // *2
if ( ( pseudo & 0x8000 ) || pseudo == 0 ) pseudo ^= 0x8A87 ; // Randomisation, pseudo==0 is a guess but would give the start value seen on the dump when P[2]P[1]=0 at init and will prevent a lock up
pseudo |= high_bit ; // include toggle
packet [ 1 ] = pseudo ;
packet [ 2 ] = pseudo >> 8 ;
//RF channel
int8_t prev = rf_ch_num & 0x1F ;
rf_ch_num = ( pseudo ^ ( pseudo >> 7 ));
rf_ch_num = (( rf_ch_num >> 1 ) & 0x08 ) | ( rf_ch_num & 0x47 );
rf_ch_num = (( rf_ch_num >> 2 ) & 0x10 ) | ( rf_ch_num & 0x1F );
rf_ch_num ^= rx_tx_addr [ 3 ] & 0x1F ;
if ( abs (( int8_t ) rf_ch_num - prev ) <= 9 )
{
if ( high_bit )
rf_ch_num |= 0x20 ;
}
else
if ( ! high_bit )
rf_ch_num |= 0x20 ;
//Partial ID
packet [ 3 ] = rx_tx_addr [ 3 ];
packet [ 4 ] = rx_tx_addr [ 2 ] & 0x03 ;
2020-12-16 18:40:46 +01:00
//Header
if ( prev_option != option )
{ //Set the RX PPM/WBUS on change
packet [ 0 ] = 0x05 ; //PPM/WBUS packet
packet [ 5 ] = 0x01 ;
if ( option )
packet [ 6 ] = 0x01 ; // PPM
2020-12-20 12:05:43 +01:00
else
packet [ 6 ] = 0x00 ; // WBUS
2020-12-16 18:40:46 +01:00
prev_option = option ;
}
else
{ //Normal or Failsafe packets
uint8_t offset = 0 ;
//packet[0] = 0x00; // Normal packet
#ifdef FAILSAFE_ENABLE
2021-01-29 15:41:47 +01:00
#define WFLY2_NUM_FS_PKTS 2 //the original TX sends 4 but that's not needed...
if ( IS_FAILSAFE_VALUES_on && packet_sent >= WFLY2_NUM_FS_PKTS ) //Failsafe packet arrived from radio
packet_sent = 0 ; // send FS config packets
if ( packet_sent < WFLY2_NUM_FS_PKTS )
{ // Send failsafe packets
packet [ 0 ] = 0x01 ; //Failsafe packet
packet [ 5 ] = 0x08 | packet_sent ;
/*if(packet_sent > 1) // needed when more than 2 FS packets are sent
{
packet[5] |= 0x50; // all channels in failsafe
packet[6] = 0x55; // all channels in failsafe
}
else*/
{
uint8_t val = 0 ;
for ( uint8_t i = 0 ; i < 6 ; i ++ )
{
val >>= 2 ;
if ( Failsafe_data [ i + packet_sent * 6 ] == FAILSAFE_CHANNEL_NOPULSES ) //no pulse value = 2
val |= 0x80 ;
else if ( Failsafe_data [ i + packet_sent * 6 ] != FAILSAFE_CHANNEL_HOLD ) //hold value = 0
val |= 0x40 ; //fs value = 1
//debug("ch%d=%04X, val=%02X | ",i+1+packet_sent*6, Failsafe_data[i+packet_sent*6],val);
if ( i == 1 )
packet [ 5 ] |= val ;
}
packet [ 6 ] = val ;
}
2020-12-16 18:40:46 +01:00
offset = 2 ;
2021-01-29 15:41:47 +01:00
packet_sent ++ ;
//debugln("5=%02X, 6=%02X", packet[5], packet[6]);
2020-12-16 18:40:46 +01:00
}
#endif
//10 channels -100%=0x2C1...0%=0x800...+100%=0xD3F
for ( uint8_t i = 0 ; i < 5 ; i ++ )
{
uint16_t temp = convert_channel_16b_nolimit ( i * 2 , 0x2C1 , 0xD3F , IS_FAILSAFE_VALUES_on );
packet [ 5 + offset + i * 3 ] = temp & 0xFF ; // low byte
packet [ 7 + offset + i * 3 ] = ( temp >> 8 ) & 0x0F ; // high byte
temp = convert_channel_16b_nolimit ( i * 2 + 1 , 0x2C1 , 0xD3F , IS_FAILSAFE_VALUES_on );
packet [ 6 + offset + i * 3 ] = temp & 0xFF ; // low byte
packet [ 7 + offset + i * 3 ] |= ( temp >> 4 ) & 0xF0 ; // high byte
}
#ifdef FAILSAFE_ENABLE
2021-01-29 15:41:47 +01:00
if ( packet_sent >= WFLY2_NUM_FS_PKTS )
FAILSAFE_VALUES_off ;
2020-12-16 18:40:46 +01:00
#endif
2021-01-29 15:41:47 +01:00
//Unknown bytes 20+offset..31
2020-12-15 23:58:56 +01:00
}
2020-12-10 16:51:55 +01:00
}
//Debug
#if 0
debug("ch=%02X,%02X P=",rf_ch_num,(rf_ch_num<<1)+0x10);
2020-12-13 23:15:43 +01:00
for(uint8_t i=0; i<WFLY2_PACKET_SIZE; i++)
2020-12-10 16:51:55 +01:00
debug("%02X ", packet[i]);
debugln("");
#endif
}
2020-12-13 23:15:43 +01:00
#ifdef WFLY2_HUB_TELEMETRY
static void __attribute__ (( unused )) WFLY2_Send_Telemetry ()
2020-12-11 10:40:00 +01:00
{
//Incoming packet values
2020-12-15 23:58:56 +01:00
v_lipo1 = packet [ 3 ] << 1 ; // RX_batt *10 in V
2020-12-11 10:57:14 +01:00
v_lipo2 = packet [ 5 ] << 1 ; // Ext_batt*10 in V
2020-12-11 10:40:00 +01:00
RX_RSSI = ( 255 - packet [ 7 ]) >> 1 ; // Looks to be the RX RSSI value direct from A7105
// Read TX RSSI
TX_RSSI = 255 - A7105_ReadReg ( A7105_1D_RSSI_THOLD );
telemetry_counter ++ ; // LQI counter
telemetry_link = 1 ;
if ( telemetry_lost )
{
telemetry_lost = 0 ;
packet_count = 100 ;
telemetry_counter = 100 ;
}
}
#endif
2020-12-15 09:51:11 +01:00
#define WFLY2_PACKET_PERIOD 3600 //3600
2020-12-13 23:15:43 +01:00
#define WFLY2_BUFFER_TIME 1500 //1500
#define WFLY2_WRITE_TIME 800 //942
2020-12-10 16:51:55 +01:00
2021-02-09 18:23:33 +01:00
uint16_t WFLY2_callback ()
2020-12-05 19:12:11 +01:00
{
2020-12-10 16:51:55 +01:00
uint16_t start ;
2020-12-15 23:58:56 +01:00
uint8_t status ;
2020-12-11 10:40:00 +01:00
2020-12-13 23:15:43 +01:00
#ifndef FORCE_WFLY2_TUNING
2020-12-05 19:12:11 +01:00
A7105_AdjustLOBaseFreq ( 1 );
#endif
2020-12-10 16:51:55 +01:00
switch ( phase )
2020-12-05 19:12:11 +01:00
{
2020-12-13 23:15:43 +01:00
case WFLY2_DATA :
2020-12-10 16:51:55 +01:00
#ifdef MULTI_SYNC
2020-12-13 23:15:43 +01:00
telemetry_set_input_sync ( WFLY2_PACKET_PERIOD );
2020-12-10 16:51:55 +01:00
#endif
2020-12-11 10:40:00 +01:00
//Build data packet
2020-12-13 23:15:43 +01:00
WFLY2_build_packet ();
2020-12-10 16:51:55 +01:00
2020-12-11 10:40:00 +01:00
//Fill the TX buffer without sending
2020-12-13 23:15:43 +01:00
A7105_WriteData ( WFLY2_PACKET_SIZE , 0 );
2020-12-10 16:51:55 +01:00
2020-12-13 23:15:43 +01:00
#ifdef WFLY2_HUB_TELEMETRY
2020-12-11 10:40:00 +01:00
//LQI calculation
packet_count ++ ;
if ( packet_count >= 100 )
{
packet_count = 0 ;
TX_LQI = telemetry_counter ;
if ( telemetry_counter == 0 )
telemetry_lost = 1 ;
telemetry_counter = 0 ;
}
#endif
2020-12-13 23:15:43 +01:00
phase ++ ; // WFLY2_PLL_TX
return WFLY2_BUFFER_TIME ;
2020-12-11 10:40:00 +01:00
2020-12-13 23:15:43 +01:00
case WFLY2_PLL_TX :
2020-12-15 23:58:56 +01:00
//Check RX status
status = A7105_ReadReg ( A7105_00_MODE );
//debugln("S:%02X", status);
2020-12-11 10:40:00 +01:00
//PLL
2020-12-10 16:51:55 +01:00
A7105_Strobe ( A7105_PLL );
2020-12-11 10:40:00 +01:00
2020-12-15 23:58:56 +01:00
//Read incoming packet even if bad/not present to not change too much the TX timing, might want to reorg the code...
A7105_ReadData ( WFLY2_PACKET_SIZE );
2020-12-11 10:40:00 +01:00
2020-12-15 23:58:56 +01:00
//Read telemetry
if (( status & 0x21 ) == 0 )
{ // Packet received and CRC OK
//Debug
2021-01-29 15:41:47 +01:00
#if 0
2020-12-15 23:58:56 +01:00
debug("T:");
for(uint8_t i=0; i<WFLY2_PACKET_SIZE-20; i++) // Can't send the full telemetry at full speed
debug(" %02X", packet[i]);
debugln("");
#endif
if ( IS_BIND_IN_PROGRESS )
{
if ( packet [ 0 ] == 0x0F && packet [ 1 ] == rx_tx_addr [ 3 ] && packet [ 2 ] == rx_tx_addr [ 2 ] && packet [ 3 ] == rx_tx_addr [ 1 ] && packet [ 4 ] == 0x00 )
{
bind_counter = 1 ; // End bind
debugln ( "Bind done" );
//packet[5..7] contains the RXID
}
2020-12-11 10:40:00 +01:00
}
2020-12-15 23:58:56 +01:00
#ifdef WFLY2_HUB_TELEMETRY
else
if ( packet [ 0 ] == 0 && packet [ 1 ] == rx_tx_addr [ 3 ] && packet [ 2 ] == ( rx_tx_addr [ 2 ] & 0x03 ))
{ //Packet match the ID
WFLY2_Send_Telemetry (); // Packet looks good do send telem to the radio
}
#endif
}
2020-12-11 10:40:00 +01:00
//Change RF channel
A7105_WriteReg ( A7105_0F_PLL_I , ( rf_ch_num << 1 ) + 0x10 );
//Switch to TX
2020-12-05 19:12:11 +01:00
A7105_SetPower ();
2020-12-10 16:51:55 +01:00
A7105_SetTxRxMode ( TX_EN );
A7105_Strobe ( A7105_TX );
2020-12-11 10:40:00 +01:00
2020-12-13 23:15:43 +01:00
phase ++ ; // WFLY2_RX
return WFLY2_WRITE_TIME ;
2020-12-11 10:40:00 +01:00
2020-12-13 23:15:43 +01:00
case WFLY2_RX :
2020-12-10 16:51:55 +01:00
//Wait for TX completion
start = micros ();
while (( uint16_t )(( uint16_t ) micros () - start ) < 700 ) // Wait max 700µs
if ( ! ( A7105_ReadReg ( A7105_00_MODE ) & 0x01 ))
break ;
2020-12-11 10:40:00 +01:00
//Switch to RX
2020-12-10 16:51:55 +01:00
A7105_SetTxRxMode ( RX_EN );
A7105_Strobe ( A7105_RX );
2020-12-11 10:40:00 +01:00
2020-12-13 23:15:43 +01:00
phase = WFLY2_DATA ;
return WFLY2_PACKET_PERIOD - WFLY2_WRITE_TIME - WFLY2_BUFFER_TIME ;
2020-12-05 19:12:11 +01:00
}
2020-12-13 23:15:43 +01:00
return WFLY2_PACKET_PERIOD ; // never reached, please the compiler
2020-12-05 19:12:11 +01:00
}
2021-02-09 18:23:33 +01:00
void WFLY2_init ()
2020-12-05 19:12:11 +01:00
{
A7105_Init ();
2020-12-13 23:15:43 +01:00
#ifdef WFLY2_FORCE_ID
2020-12-11 13:55:50 +01:00
MProtocol_id = 0x50002313 ; //Richard
//MProtocol_id = 0x50000223; //Pascal
2020-12-05 19:12:11 +01:00
#endif
2020-12-11 13:55:50 +01:00
MProtocol_id &= 0x00FFFFFF ; // Since the bind ID starts with 50, let's keep only the last 3 bytes of the ID
2020-12-10 16:51:55 +01:00
MProtocol_id |= 0x50000000 ; // As recommended on the A7105 datasheet
set_rx_tx_addr ( MProtocol_id ); // Update the ID
2020-12-15 23:58:56 +01:00
if ( IS_BIND_IN_PROGRESS )
A7105_WriteID ( 0x50FFFFFE ); // Bind ID
else
A7105_WriteID ( MProtocol_id );
2020-12-10 16:51:55 +01:00
hopping_frequency_no = 0 ;
rf_ch_num = 0 ;
2020-12-15 23:58:56 +01:00
bind_counter = WFLY2_BIND_COUNT ;
2021-01-29 15:41:47 +01:00
packet_sent = 255 ;
2020-12-15 23:58:56 +01:00
phase = WFLY2_DATA ;
2020-12-13 23:15:43 +01:00
#ifdef WFLY2_HUB_TELEMETRY
2020-12-11 10:40:00 +01:00
packet_count = 0 ;
telemetry_lost = 1 ;
#endif
2020-12-05 19:12:11 +01:00
}
#endif