2020-06-02 19:10:11 +02:00

285 lines
7.0 KiB
C++

/*
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/>.
*/
// Compatible with CADET PRO V4 TX
#if defined(PELIKAN_A7105_INO)
#include "iface_a7105.h"
//#define PELIKAN_FORCE_ID
#define PELIKAN_LITE_FORCE_ID
#define PELIKAN_BIND_COUNT 400
#define PELIKAN_BIND_RF 0x3C
#define PELIKAN_NUM_RF_CHAN 0x1D
#define PELIKAN_PACKET_PERIOD 7980
#define PELIKAN_LITE_PACKET_PERIOD 18000
static void __attribute__((unused)) pelikan_build_packet()
{
static boolean upper=false;
packet[0] = 0x15;
if(IS_BIND_IN_PROGRESS)
{
packet[1] = 0x04; //version??
packet[2] = rx_tx_addr[0];
packet[3] = rx_tx_addr[1];
packet[4] = rx_tx_addr[2];
packet[5] = rx_tx_addr[3];
if(sub_protocol==PELIKAN_PRO)
packet[6] = 0x05; //sub version??
else //PELIKAN_LITE
packet[6] = 0x03; //sub version??
packet[7] = 0x00; //??
packet[8] = 0x55; //??
packet_length = 10;
}
else
{
//ID
packet[1] = rx_tx_addr[0];
packet[7] = rx_tx_addr[1];
packet[12] = rx_tx_addr[2];
packet[13] = rx_tx_addr[3];
//Channels
uint8_t offset=upper?4:0;
uint16_t channel=convert_channel_16b_nolimit(CH_AETR[offset++], 153, 871);
uint8_t top=(channel>>2) & 0xC0;
packet[2] = channel;
channel=convert_channel_16b_nolimit(CH_AETR[offset++], 153, 871);
top|=(channel>>4) & 0x30;
packet[3] = channel;
channel=convert_channel_16b_nolimit(CH_AETR[offset++], 153, 871);
top|=(channel>>6) & 0x0C;
packet[4] = channel;
channel=convert_channel_16b_nolimit(CH_AETR[offset], 153, 871);
top|=(channel>>8) & 0x03;
packet[5] = channel;
packet[6] = top;
//Check
crc8=0x15;
for(uint8_t i=1;i<8;i++)
crc8+=packet[i];
packet[8]=crc8;
//Low/Up channel flag
packet[9]=upper?0xAA:0x00;
upper=!upper;
//Hopping counters
if(sub_protocol==PELIKAN_LITE || ++packet_count>4)
{
packet_count=0;
if(++hopping_frequency_no>=PELIKAN_NUM_RF_CHAN)
hopping_frequency_no=0;
}
packet[10]=hopping_frequency_no;
packet[11]=packet_count;
packet_length = 15;
}
//Check
crc8=0x15;
for(uint8_t i=1; i<packet_length-1 ;i++)
crc8+=packet[i];
packet[packet_length-1]=crc8;
//Send
#ifdef DEBUG_SERIAL
if(packet[9]==0x00)
{
debug("C: %02X P(%d):",IS_BIND_IN_PROGRESS?PELIKAN_BIND_RF:hopping_frequency[hopping_frequency_no],packet_length);
for(uint8_t i=0;i<packet_length;i++)
debug(" %02X",packet[i]);
debugln("");
}
#endif
A7105_WriteData(packet_length, IS_BIND_IN_PROGRESS?PELIKAN_BIND_RF:hopping_frequency[hopping_frequency_no]);
A7105_SetPower();
}
uint16_t ReadPelikan()
{
if(phase==0)
{
#ifndef FORCE_PELIKAN_TUNING
A7105_AdjustLOBaseFreq(1);
#endif
if(IS_BIND_IN_PROGRESS)
{
bind_counter--;
if (bind_counter==0)
{
BIND_DONE;
A7105_Strobe(A7105_STANDBY);
if(sub_protocol==PELIKAN_PRO)
A7105_WriteReg(A7105_03_FIFOI,0x28);
else//PELIKAN_LITE
A7105_WriteID((rx_tx_addr[0]<<24)|(rx_tx_addr[1]<<16)|(rx_tx_addr[2]<<8)|(rx_tx_addr[3]));
}
}
#ifdef MULTI_SYNC
telemetry_set_input_sync(sub_protocol==PELIKAN_PRO?PELIKAN_PACKET_PERIOD:PELIKAN_LITE_PACKET_PERIOD);
#endif
pelikan_build_packet();
if(sub_protocol==PELIKAN_PRO || IS_BIND_IN_PROGRESS)
return PELIKAN_PACKET_PERIOD;
//PELIKAN_LITE
phase++;
return 942;
}
//PELIKAN_LITE
A7105_Strobe(A7105_TX);
phase++;
if(phase==1)
return 942;
phase=0;
return PELIKAN_LITE_PACKET_PERIOD-942-942;
}
static uint8_t pelikan_firstCh(uint8_t u, uint8_t l)
{
int16_t i;
i = u * 10 + l - 23;
do
{
if (i > 24)
i -= 24;
if (i <= 0)
return 10;
else if ((i > 0) && (i < 13))
return 10 + 12 + (i * 4);
else if ((i > 12) && (i < 24))
return 10 - 2 + ((i - 12) * 4);
}
while (i > 24);
return 0;
}
static uint8_t pelikan_adjust_value(uint8_t value, uint8_t addition, uint8_t limit)
{
uint8_t i;
do
{
i = 0;
if (value > limit) {
value -= 62;
i++;
}
if (value == 24) {
value += addition;
i++;
}
if (value == 48) {
value += addition;
i++;
}
}
while (i > 0);
return value;
}
static uint8_t pelikan_add(uint8_t pfrq,uint8_t a, uint8_t limit)
{
uint8_t nfrq;
nfrq = pfrq + a;
nfrq = pelikan_adjust_value(nfrq, a, limit);
return nfrq;
}
static void __attribute__((unused)) pelikan_init_hop()
{
#define PELIKAN_HOP_LIMIT 70
rx_tx_addr[0] = 0;
rx_tx_addr[1]+= RX_num;
uint8_t high = (rx_tx_addr[1]>>4) % 3; // 0..2
uint8_t low = rx_tx_addr[1] & 0x0F;
if(high==2)
low %= 0x04; // 0..3
else if(high)
low %= 0x0E; // 0..D
else
low %= 0x0F; // 0..E
rx_tx_addr[1] = (high<<4) + low;
uint8_t addition = (20 * high)+ (2 * low) + 8;
uint8_t first_channel = pelikan_firstCh(high, low);
first_channel = pelikan_adjust_value(first_channel, addition, PELIKAN_HOP_LIMIT);
hopping_frequency[0] = first_channel;
debug("%02X", first_channel);
for (uint8_t i = 1; i < PELIKAN_NUM_RF_CHAN; i++)
{
hopping_frequency[i] = pelikan_add(hopping_frequency[i-1], addition, PELIKAN_HOP_LIMIT);
debug(" %02X", hopping_frequency[i]);
}
debugln("");
}
#ifdef PELIKAN_FORCE_ID
const uint8_t PROGMEM pelikan_hopp[][PELIKAN_NUM_RF_CHAN] = {
{ 0x5A,0x46,0x32,0x6E,0x6C,0x58,0x44,0x42,0x40,0x6A,0x56,0x54,0x52,0x3E,0x68,0x66,0x64,0x50,0x3C,0x3A,0x38,0x62,0x4E,0x4C,0x5E,0x4A,0x36,0x5C,0x34 }
};
#endif
#ifdef PELIKAN_LITE_FORCE_ID
const uint8_t PROGMEM pelikan_lite_hopp[][PELIKAN_NUM_RF_CHAN] = {
{ 0x46,0x2A,0x3E,0x5A,0x5C,0x24,0x4E,0x32,0x54,0x26,0x2C,0x34,0x56,0x1E,0x3A,0x3C,0x50,0x4A,0x2E,0x42,0x20,0x52,0x28,0x22,0x44,0x58,0x36,0x38,0x4C }
};
#endif
uint16_t initPelikan()
{
A7105_Init();
if(IS_BIND_IN_PROGRESS || sub_protocol==PELIKAN_LITE)
A7105_WriteReg(A7105_03_FIFOI,0x10);
//ID from dump
#if defined(PELIKAN_FORCE_ID)
if(sub_protocol==PELIKAN_PRO)
{
rx_tx_addr[0]=0x0D; // hopping freq
rx_tx_addr[1]=0xF4; // hopping freq
rx_tx_addr[2]=0x50; // ID
rx_tx_addr[3]=0x18; // ID
// Fill frequency table
for(uint8_t i=0;i<PELIKAN_NUM_RF_CHAN;i++)
hopping_frequency[i]=pgm_read_byte_near(&pelikan_hopp[0][i]);
}
#elif defined(PELIKAN_LITE_FORCE_ID)
if(sub_protocol==PELIKAN_LITE)
{
rx_tx_addr[0]=0x04; // hopping freq
rx_tx_addr[1]=0x63; // hopping freq
rx_tx_addr[2]=0x60; // ID
rx_tx_addr[3]=0x18; // ID
// Fill frequency table
for(uint8_t i=0;i<PELIKAN_NUM_RF_CHAN;i++)
hopping_frequency[i]=pgm_read_byte_near(&pelikan_lite_hopp[0][i]);
}
#else
pelikan_init_hop();
#endif
if(sub_protocol==PELIKAN_LITE && IS_BIND_DONE)
A7105_WriteID((rx_tx_addr[0]<<24)|(rx_tx_addr[1]<<16)|(rx_tx_addr[2]<<8)|(rx_tx_addr[3]));
hopping_frequency_no=PELIKAN_NUM_RF_CHAN;
packet_count=5;
phase=0;
return 2400;
}
#endif