esp32-ogn-tracker/main/adsl.h

413 wiersze
21 KiB
C++

#ifndef __ADSL_H__
#define __ADSL_H__
#include <stdlib.h>
#include <math.h>
// #include <string.h>
// #include "radiodemod.h"
// #include "intmath.h"
#include "ognconv.h"
#include "bitcount.h"
// #include "format.h"
// #include "crc1021.h"
class ADSL_Packet
{ public:
const static uint8_t TxBytes = 27; // including SYNC, Length, actual packet content (1+20 bytes) and 3-byte CRC
const static uint8_t SYNC1 = 0x72; // two SYNC bytes - Lemgth byte can be considered the 3rd SYNC byte as it is fixed
const static uint8_t SYNC2 = 0x4B;
uint8_t SYNC[2]; // two bytes for correct alignment: can contain the last two SYNC bytes
uint8_t Length; // [bytes] packet length = 24 = 0x18 (excluding length but including the 24-bit CRC)
uint8_t Version; // Version[4]/Sigmature[1]/Key[2]/Reserved[1]
union
{ uint32_t Word[5]; // this part to be scrambled/encrypted, is aligned to 32-bit
struct // this is aligned to 32-bit
{ uint8_t Type; // 2=iConspicuity, bit #7 = Unicast
uint8_t Address [4]; // Address[30]/Reserved[1]/RelayForward[1] (not aligned to 32-bit !)
union
{ uint8_t Meta [2]; // Time[6]/Cat[5]/Emerg[3]/FlightState[2]
struct
{ uint8_t TimeStamp :6; // [0.25sec]
uint8_t FlightState :2; // 0=unknown, 1=ground, 2=airborne
uint8_t AcftCat :5; // 1=light, 2=small-heavy, 3=heli, 4=glider, 5=baloon/airship, 6=para/hang-glider, 7=skydiver,
uint8_t Emergency :3; // 1=OK
} ;
} ;
uint8_t Position[11]; // Lat[24]/Lon[24]/Speed[8]/Alt[14]/Climb[9]/Track[9]
union
{ uint8_t Integrity[2]; // SourceInteg[2]/DesignAssurance[2]/NavigationIntegrity[4]/NorizAccuracy[3]/VertAccuracy[2]/ValocityAccuracy[2]/Reserved[1]
struct
{ uint8_t SourceIntegrity:2; // 3=1e-7/h, 2=1e-5/h, 1=1e-3/h
uint8_t DesignAssurance:2; // 3=B, 2=C, 1=D
uint8_t NavigIntegrity :4; // 12=7.5m, 11=25m, 10=75m
uint8_t HorizAccuracy :3; // 7=3m, 6=10m, 5=30m
uint8_t VertAccuracy :2; // 3=15m, 2=45m, 1=150m
uint8_t VelAccuracy :2; // 3=1m/s 2=3m/s 3=10m/s
uint8_t Reserved :1; //
} ;
} ;
} ;
} ;
uint8_t CRC[3]; // 24-bit (is aligned to 32-bit)
// --------------------------------------------------------------------------------------------------------
public:
void Init(void)
{ SYNC[0]=SYNC1; SYNC[1]=SYNC2;
Length=TxBytes-3; Version=0x00;
for(int Idx=0; Idx<5; Idx++)
Word[Idx]=0;
Type=0x02; }
void Print(void) const
{ printf(" v%02X %4.1fs: %02X:%06X [%+09.5f,%+010.5f]deg %dm %+4.1fm/s %05.1fdeg %3.1fm/s\n",
Version, 0.25*TimeStamp, getAddrTable(), getAddress(), FNTtoFloat(getLat()), FNTtoFloat(getLon()),
getAlt(), 0.125*getClimb(), (45.0/0x40)*getTrack(), 0.25*getSpeed()); }
int Print(char *Out) const
{ return sprintf(Out, "%02X:%06X %4.1fs [%+09.5f,%+010.5f]deg %dm %+4.1fm/s %05.1fdeg %3.1fm/s",
getAddrTable(), getAddress(), 0.25*TimeStamp, FNTtoFloat(getLat()), FNTtoFloat(getLon()),
getAlt(), 0.125*getClimb(), (45.0/0x40)*getTrack(), 0.25*getSpeed()); }
/*
uint32_t getAddress(void) const { return get3bytes(Address); }
uint8_t getAddrTable(void) const { return Address[3]&0x3F; }
void setAddress(uint32_t Addr) { set3bytes(Address, Addr); }
void setAddrTable(uint8_t Table) { Address[3] = (Address[3]&0xC0) | Table; }
*/
uint8_t getRelay(void) const { return Address[3]&0x80; }
void setRelay(uint8_t Relay) { Address[3] = (Address[3]&0x7F) | (Relay<<7); }
static uint32_t get3bytes(const uint8_t *Byte) { int32_t Word=Byte[2]; Word<<=8; Word|=Byte[1]; Word<<=8; Word|=Byte[0]; return Word; }
static void set3bytes(uint8_t *Byte, uint32_t Word) { Byte[0]=Word; Byte[1]=Word>>8; Byte[2]=Word>>16; }
static uint32_t get4bytes(const uint8_t *Byte)
{ uint32_t A = Byte[0];
uint32_t B = Byte[1];
uint32_t C = Byte[2];
uint32_t D = Byte[3];
return A | (B<<8) | (C<<16) | (D<<24); }
// { uint32_t Word =Byte[3]; Word<<=8;
// Word|=Byte[2]; Word<<=8;
// Word|=Byte[1]; Word<<=8;
// Word|=Byte[0];
// return Word; }
static void set4bytes(uint8_t *Byte, uint32_t Word) { Byte[0]=Word; Byte[1]=Word>>8; Byte[2]=Word>>16; Byte[3]=Word>>24; }
uint32_t getAddress(void) const
{ uint32_t Addr = get4bytes(Address); return (Addr>>6)&0x00FFFFFF; }
void setAddress(uint32_t NewAddr)
{ uint32_t Addr = get4bytes(Address);
Addr = (Addr&0xC000003F) | (NewAddr<<6);
set4bytes(Address, Addr); }
uint8_t getAddrTable(void) const { return Address[0]&0x3F; }
void setAddrTable(uint8_t Table) { Address[0] = (Address[0]&0xC0) | Table; }
uint8_t getAddrTypeOGN(void) const
{ uint8_t Table=getAddrTable();
if(Table==0x05) return 1; // ICAO
if(Table==0x06) return 2; // FLARM
if(Table==0x07) return 3; // OGN
if(Table==0x08) return 2; // FANET => FLARM ?
return 0; }
void setAddrTypeOGN(uint8_t AddrType)
{ if(AddrType==0) setAddrTable(0);
else setAddrTable(AddrType+4); }
void setAcftTypeOGN(uint8_t AcftType) // set OGN aircraft-type
{ const uint8_t Map[16] = { 0, 4, 1, 3, // unknown, glider, tow-plane, helicopter
8, 1, 7, 7, // sky-diver, drop plane, hang-glider, para-glider
1, 2, 0, 5, // motor airplane, jet, UFO, balloon
5,11, 0, 0 } ; // airship, UAV, ground vehicle, static object
if(AcftType<16) AcftCat=Map[AcftType];
else AcftCat=0; }
uint8_t getAcftTypeOGN(void) const // get OGN aircraft-type
{ const uint8_t Map[32] = { 0, 8, 9, 3, 1,12, 2, 7,
4,13, 3,13,13,13, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 } ;
return Map[AcftCat]; }
// --------------------------------------------------------------------------------------------------------
uint32_t getTime(uint16_t &msTime, uint32_t RefTime, int FwdMargin=3) const
{ msTime=250*(TimeStamp&3);
if(TimeStamp>=60) return 0;
int Sec=RefTime%15;
int DiffSec=(TimeStamp>>2)-Sec;
if(DiffSec>FwdMargin) DiffSec-=15;
else if(DiffSec<=(-15+FwdMargin)) DiffSec+=15;
return RefTime+DiffSec; } // get out the correct position timestamp
uint8_t getHorAccur(void) const
{ const uint8_t Map[8] = { 63, 63, 63, 63, 63, 30, 10, 3 } ;
return Map[HorizAccuracy]; }
void setHorAccur(uint8_t Prec)
{ if(Prec<= 3) HorizAccuracy=7;
else if(Prec<=10) HorizAccuracy=6;
else if(Prec<=30) HorizAccuracy=5;
else HorizAccuracy=4;
VelAccuracy = HorizAccuracy-4; }
uint8_t getVerAccur(void) const // [m] vertical accuracy
{ const uint8_t Map[8] = { 63, 63, 45, 15 } ;
return Map[VertAccuracy]; }
void setVerAccur(uint8_t Prec)
{ if(Prec<=15) HorizAccuracy=3;
else if(Prec<=45) HorizAccuracy=2;
else HorizAccuracy=1; }
static int32_t FNTtoOGN(int32_t Coord) { return ((int64_t)Coord*27000219 +(1<<28))>>29; } // [FANET cordic] => [0.0001/60 deg]
static int32_t OGNtoFNT(int32_t Coord) { return ((int64_t)Coord*83399317 +(1<<21))>>22; } // [0.0001/60 deg] => [FANET cordic]
static int32_t FNTtoUBX(int32_t Coord) { return ((int64_t)Coord*900007296+(1<<29))>>30; } // [FANET-cordic ] => [1e-7 deg]
static int32_t UBXtoFNT(int32_t Coord) { return ((int64_t)Coord*5003959 +(1<<21))>>22; } // [1e-7 deg] => [FANET cordic]
static float FNTtoFloat(int32_t Coord) // convert from FANET cordic units to float degrees
{ const float Conv = 90.0007295677/0x40000000; // FANET cordic conversion factor (not exactly cordic)
return Conv*Coord; }
int32_t getLatOGN(void) const { return FNTtoOGN(getLat()); }
int32_t getLonOGN(void) const { return FNTtoOGN(getLon()); }
int32_t getLatUBX(void) const { return FNTtoUBX(getLat()); }
int32_t getLonUBX(void) const { return FNTtoUBX(getLon()); }
int32_t getLat(void) const { int32_t Lat=get3bytes(Position ); Lat<<=8; Lat>>=1; return Lat; } // FANET-cordic
int32_t getLon(void) const { int32_t Lon=get3bytes(Position+3); Lon<<=8; return Lon; } // FANET-cordic
void setLatOGN(int32_t Lat) { setLat(OGNtoFNT(Lat)); }
void setLonOGN(int32_t Lon) { setLon(OGNtoFNT(Lon)); }
void setLat(int32_t Lat) { Lat = (Lat+0x40)>>7; set3bytes(Position , Lat); } // FANET-cordic
void setLon(int32_t Lon) { Lon = (Lon+0x80)>>8; set3bytes(Position+3, Lon); } // FANET-cordic
uint16_t getSpeed(void) const { return UnsVRdecode<uint16_t,6>(Position[6]); } // [0.25 m/s]
void setSpeed(uint16_t Speed) { Position[6] = UnsVRencode<uint16_t,6>(Speed); } // [0.25 m/s]
int32_t getAlt(void) const // [m]
{ int32_t Word=Position[8]&0x3F; Word<<=8; Word|=Position[7];
return UnsVRdecode<int32_t,12>(Word)-316; }
void setAlt(int32_t Alt)
{ Alt+=316; if(Alt<0) Alt=0;
int32_t Word=UnsVRencode<uint32_t,12>(Alt);
Position[7]=Word;
Position[8] = (Position[8]&0xC0) | (Word>>8); }
int16_t getClimbWord(void) const //
{ int16_t Word=Position[9]&0x7F; Word<<=2; Word|=Position[8]>>6; return Word; }
int16_t getClimb(void) const // [0.125 m/s]
{ return SignVRdecode<int16_t,6>(getClimbWord()); }
void setClimb(int16_t Climb) // [0.125 m/s]
{ setClimbWord(SignVRencode<int16_t,6>(Climb)); }
void setClimbWord(int16_t Word)
{ Position[8] = (Position[8]&0x3F) | ((Word&0x03)<<6);
Position[9] = (Position[9]&0x80) | (Word>>2); }
bool hasClimb(void) { return getClimbWord()!=0x100; } // climb-rate present or absent
void clrClimb(void) { setClimbWord(0x100); } // declare climb-rate as absent
uint16_t getTrack(void) const // 9-bit cordic
{ int16_t Word=Position[10]; Word<<=1; Word|=Position[9]>>7; return Word; }
void setTrack(int16_t Word)
{ Position[9] = (Position[9]&0x7F) | ((Word&0x01)<<7);
Position[10] = Word>>1; }
// --------------------------------------------------------------------------------------------------------
// calculate distance vector [LatDist, LonDist] from a given reference [RefLat, Reflon]
int calcDistanceVectorOGN(int32_t &LatDist, int32_t &LonDist, int32_t RefLat, int32_t RefLon, uint16_t LatCos=3000, int32_t MaxDist=0x7FFF)
{ LatDist = ((getLatOGN()-RefLat)*1517+0x1000)>>13; // convert from 1/600000deg to meters (40000000m = 360deg) => x 5/27 = 1517/(1<<13)
if(abs(LatDist)>MaxDist) return -1;
LonDist = ((getLonOGN()-RefLon)*1517+0x1000)>>13;
if(abs(LonDist)>(4*MaxDist)) return -1;
LonDist = (LonDist*LatCos+0x800)>>12;
if(abs(LonDist)>MaxDist) return -1;
return 1; }
// sets position [Lat, Lon] according to given distance vector [LatDist, LonDist] from a reference point [RefLat, RefLon]
void setDistanceVectorOGN(int32_t LatDist, int32_t LonDist, int32_t RefLat, int32_t RefLon, uint16_t LatCos=3000)
{ setLatOGN(RefLat+(LatDist*27)/5);
LonDist = (LonDist<<12)/LatCos; // LonDist/=cosine(Latitude)
setLonOGN(RefLon+(LonDist*27)/5); }
// --------------------------------------------------------------------------------------------------------
void Scramble(void)
{ XXTEA_Encrypt_Key0(Word, 5, 6); }
void Descramble(void)
{ XXTEA_Decrypt_Key0(Word, 5, 6); }
// --------------------------------------------------------------------------------------------------------
static uint32_t PolyPass(uint32_t CRC, uint8_t Byte) // pass a single byte through the CRC polynomial
{ const uint32_t Poly = 0xFFFA0480;
CRC |= Byte;
for(uint8_t Bit=0; Bit<8; Bit++)
{ if(CRC&0x80000000) CRC ^= Poly;
CRC<<=1; }
return CRC; }
static uint32_t checkPI(const uint8_t *Byte, uint8_t Bytes) // run over data bytes and the three CRC bytes
{ uint32_t CRC = 0;
for(uint8_t Idx=0; Idx<Bytes; Idx++)
{ CRC = PolyPass(CRC, Byte[Idx]); }
return CRC>>8; } // should be all zero for a correct packet
static uint32_t calcPI(const uint8_t *Byte, uint8_t Bytes) // calculate PI for the given packet data excluding the three CRC bytes
{ uint32_t CRC = 0;
for(uint8_t Idx=0; Idx<Bytes; Idx++)
{ CRC = PolyPass(CRC, Byte[Idx]); }
CRC=PolyPass(CRC, 0); CRC=PolyPass(CRC, 0); CRC=PolyPass(CRC, 0);
return CRC>>8; } //
void setCRC(void)
{ uint32_t Word = calcPI((const uint8_t *)&Version, TxBytes-6);
CRC[0]=Word>>16; CRC[1]=Word>>8; CRC[2]=Word; }
uint32_t checkCRC(void) const
{ return checkPI((const uint8_t *)&Version, TxBytes-3); }
static int Correct(uint8_t *PktData, uint8_t *PktErr, const int MaxBadBits=6) // correct the manchester-decoded packet with dead/weak bits marked
{ const int Bytes=TxBytes-3;
uint32_t CRC = checkPI(PktData, Bytes); if(CRC==0) return 0;
uint8_t ErrBit=FindCRCsyndrome(CRC);
if(ErrBit!=0xFF) { FlipBit(PktData, ErrBit); return 1; }
uint8_t BadBitIdx[MaxBadBits]; // bad bit index
uint8_t BadBitMask[MaxBadBits]; // bad bit mask
uint32_t Syndrome[MaxBadBits]; // bad bit mask
uint8_t BadBits=0; // count the bad bits
for(uint8_t ByteIdx=0; ByteIdx<Bytes; ByteIdx++) // loop over bytes
{ uint8_t Byte=PktErr[ByteIdx];
uint8_t Mask=0x80;
for(uint8_t BitIdx=0; BitIdx<8; BitIdx++) // loop over bits
{ if(Byte&Mask)
{ if(BadBits<MaxBadBits)
{ BadBitIdx[BadBits]=ByteIdx; // store the bad bit index
BadBitMask[BadBits]=Mask;
Syndrome[BadBits]=CRCsyndrome(ByteIdx*8+BitIdx); }
BadBits++;
}
Mask>>=1;
}
if(BadBits>MaxBadBits) break;
}
if(BadBits>MaxBadBits) return -1; // return failure when too many bad bits
uint8_t Loops = 1<<BadBits; uint8_t PrevGrayIdx=0;
for(uint8_t Idx=1; Idx<Loops; Idx++) // loop through all combination of bad bit flips
{ uint8_t GrayIdx= Idx ^ (Idx>>1); // use Gray code to change flip just one bit at a time
uint8_t BitExp = GrayIdx^PrevGrayIdx;
uint8_t Bit=0; while(BitExp>>=1) Bit++;
PktData[BadBitIdx[Bit]]^=BadBitMask[Bit];
CRC^=Syndrome[Bit]; if(CRC==0) return Count1s(GrayIdx);
uint8_t ErrBit=FindCRCsyndrome(CRC);
if(ErrBit!=0xFF)
{ FlipBit(PktData, ErrBit);
return Count1s(GrayIdx)+1; }
PrevGrayIdx=GrayIdx; }
return -1; }
static void FlipBit(uint8_t *Byte, int BitIdx)
{ int ByteIdx=BitIdx>>3;
BitIdx&=7; BitIdx=7-BitIdx;
uint8_t Mask=1; Mask<<=BitIdx;
Byte[ByteIdx]^=Mask; }
static uint32_t CRCsyndrome(uint8_t Bit)
{ const uint16_t PacketBytes = TxBytes-3;
const uint16_t PacketBits = PacketBytes*8;
const uint32_t Syndrome[PacketBits] = {
0x7ABEE1, 0xC2A574, 0x6152BA, 0x30A95D, 0xE7AEAA, 0x73D755, 0xC611AE, 0x6308D7,
0xCE7E6F, 0x98C533, 0xB3989D, 0xA6364A, 0x531B25, 0xD67796, 0x6B3BCB, 0xCA67E1,
0x9AC9F4, 0x4D64FA, 0x26B27D, 0xECA33A, 0x76519D, 0xC4D2CA, 0x626965, 0xCECEB6,
0x67675B, 0xCC49A9, 0x99DED0, 0x4CEF68, 0x2677B4, 0x133BDA, 0x099DED, 0xFB34F2,
0x7D9A79, 0xC13738, 0x609B9C, 0x304DCE, 0x1826E7, 0xF3E977, 0x860EBF, 0xBCFD5B,
0xA184A9, 0xAF3850, 0x579C28, 0x2BCE14, 0x15E70A, 0x0AF385, 0xFA83C6, 0x7D41E3,
0xC15AF5, 0x9F577E, 0x4FABBF, 0xD82FDB, 0x93EDE9, 0xB60CF0, 0x5B0678, 0x2D833C,
0x16C19E, 0x0B60CF, 0xFA4A63, 0x82DF35, 0xBE959E, 0x5F4ACF, 0xD05F63, 0x97D5B5,
0xB410DE, 0x5A086F, 0xD2FE33, 0x96851D, 0xB4B88A, 0x5A5C45, 0xD2D426, 0x696A13,
0xCB4F0D, 0x9A5D82, 0x4D2EC1, 0xD96D64, 0x6CB6B2, 0x365B59, 0xE4D7A8, 0x726BD4,
0x3935EA, 0x1C9AF5, 0xF1B77E, 0x78DBBF, 0xC397DB, 0x9E31E9, 0xB0E2F0, 0x587178,
0x2C38BC, 0x161C5E, 0x0B0E2F, 0xFA7D13, 0x82C48D, 0xBE9842, 0x5F4C21, 0xD05C14,
0x682E0A, 0x341705, 0xE5F186, 0x72F8C3, 0xC68665, 0x9CB936, 0x4E5C9B, 0xD8D449,
0x939020, 0x49C810, 0x24E408, 0x127204, 0x093902, 0x049C81, 0xFDB444, 0x7EDA22,
0x3F6D11, 0xE04C8C, 0x702646, 0x381323, 0xE3F395, 0x8E03CE, 0x4701E7, 0xDC7AF7,
0x91C77F, 0xB719BB, 0xA476D9, 0xADC168, 0x56E0B4, 0x2B705A, 0x15B82D, 0xF52612,
0x7A9309, 0xC2B380, 0x6159C0, 0x30ACE0, 0x185670, 0x0C2B38, 0x06159C, 0x030ACE,
0x018567, 0xFF38B7, 0x80665F, 0xBFC92B, 0xA01E91, 0xAFF54C, 0x57FAA6, 0x2BFD53,
0xEA04AD, 0x8AF852, 0x457C29, 0xDD4410, 0x6EA208, 0x375104, 0x1BA882, 0x0DD441,
0xF91024, 0x7C8812, 0x3E4409, 0xE0D800, 0x706C00, 0x383600, 0x1C1B00, 0x0E0D80,
0x0706C0, 0x038360, 0x01C1B0, 0x00E0D8, 0x00706C, 0x003836, 0x001C1B, 0xFFF409,
0x800000, 0x400000, 0x200000, 0x100000, 0x080000, 0x040000, 0x020000, 0x010000,
0x008000, 0x004000, 0x002000, 0x001000, 0x000800, 0x000400, 0x000200, 0x000100,
0x000080, 0x000040, 0x000020, 0x000010, 0x000008, 0x000004, 0x000002, 0x000001 } ;
return Syndrome[Bit]; }
static uint8_t FindCRCsyndrome(uint32_t Syndr) // quick search for a single-bit CRC syndrome
{ const uint16_t PacketBytes = TxBytes-3;
const uint16_t PacketBits = PacketBytes*8;
const uint32_t Syndrome[PacketBits] = {
0x000001BF, 0x000002BE, 0x000004BD, 0x000008BC, 0x000010BB, 0x000020BA, 0x000040B9, 0x000080B8,
0x000100B7, 0x000200B6, 0x000400B5, 0x000800B4, 0x001000B3, 0x001C1BA6, 0x002000B2, 0x003836A5,
0x004000B1, 0x00706CA4, 0x008000B0, 0x00E0D8A3, 0x010000AF, 0x01856788, 0x01C1B0A2, 0x020000AE,
0x030ACE87, 0x038360A1, 0x040000AD, 0x049C816D, 0x06159C86, 0x0706C0A0, 0x080000AC, 0x0939026C,
0x099DED1E, 0x0AF3852D, 0x0B0E2F5A, 0x0B60CF39, 0x0C2B3885, 0x0DD44197, 0x0E0D809F, 0x100000AB,
0x1272046B, 0x133BDA1D, 0x15B82D7E, 0x15E70A2C, 0x161C5E59, 0x16C19E38, 0x1826E724, 0x18567084,
0x1BA88296, 0x1C1B009E, 0x1C9AF551, 0x200000AA, 0x24E4086A, 0x2677B41C, 0x26B27D12, 0x2B705A7D,
0x2BCE142B, 0x2BFD538F, 0x2C38BC58, 0x2D833C37, 0x304DCE23, 0x30A95D03, 0x30ACE083, 0x34170561,
0x365B594D, 0x37510495, 0x38132373, 0x3836009D, 0x3935EA50, 0x3E44099A, 0x3F6D1170, 0x400000A9,
0x457C2992, 0x4701E776, 0x49C81069, 0x4CEF681B, 0x4D2EC14A, 0x4D64FA11, 0x4E5C9B66, 0x4FABBF32,
0x531B250C, 0x56E0B47C, 0x579C282A, 0x57FAA68E, 0x58717857, 0x5A086F41, 0x5A5C4545, 0x5B067836,
0x5F4ACF3D, 0x5F4C215E, 0x609B9C22, 0x6152BA02, 0x6159C082, 0x62696516, 0x6308D707, 0x67675B18,
0x682E0A60, 0x696A1347, 0x6B3BCB0E, 0x6CB6B24C, 0x6EA20894, 0x70264672, 0x706C009C, 0x726BD44F,
0x72F8C363, 0x73D75505, 0x76519D14, 0x78DBBF53, 0x7A930980, 0x7ABEE100, 0x7C881299, 0x7D41E32F,
0x7D9A7920, 0x7EDA226F, 0x800000A8, 0x80665F8A, 0x82C48D5C, 0x82DF353B, 0x860EBF26, 0x8AF85291,
0x8E03CE75, 0x91C77F78, 0x93902068, 0x93EDE934, 0x96851D43, 0x97D5B53F, 0x98C53309, 0x99DED01A,
0x9A5D8249, 0x9AC9F410, 0x9CB93665, 0x9E31E955, 0x9F577E31, 0xA01E918C, 0xA184A928, 0xA476D97A,
0xA6364A0B, 0xADC1687B, 0xAF385029, 0xAFF54C8D, 0xB0E2F056, 0xB3989D0A, 0xB410DE40, 0xB4B88A44,
0xB60CF035, 0xB719BB79, 0xBCFD5B27, 0xBE959E3C, 0xBE98425D, 0xBFC92B8B, 0xC1373821, 0xC15AF530,
0xC2A57401, 0xC2B38081, 0xC397DB54, 0xC4D2CA15, 0xC611AE06, 0xC6866564, 0xCA67E10F, 0xCB4F0D48,
0xCC49A919, 0xCE7E6F08, 0xCECEB617, 0xD05C145F, 0xD05F633E, 0xD2D42646, 0xD2FE3342, 0xD677960D,
0xD82FDB33, 0xD8D44967, 0xD96D644B, 0xDC7AF777, 0xDD441093, 0xE04C8C71, 0xE0D8009B, 0xE3F39574,
0xE4D7A84E, 0xE5F18662, 0xE7AEAA04, 0xEA04AD90, 0xECA33A13, 0xF1B77E52, 0xF3E97725, 0xF526127F,
0xF9102498, 0xFA4A633A, 0xFA7D135B, 0xFA83C62E, 0xFB34F21F, 0xFDB4446E, 0xFF38B789, 0xFFF409A7 } ;
uint16_t Bot=0;
uint16_t Top=PacketBits;
uint32_t MidSyndr=0;
for( ; ; )
{ uint16_t Mid=(Bot+Top)>>1;
MidSyndr = Syndrome[Mid]>>8;
if(Syndr==MidSyndr) return (uint8_t)Syndrome[Mid];
if(Mid==Bot) break;
if(Syndr< MidSyndr) Top=Mid;
else Bot=Mid; }
return 0xFF; }
} __attribute__((packed));
class ADSL_RxPacket: public ADSL_Packet
{ public:
uint32_t sTime; // [ s] reception time
uint16_t msTime; // [ms]
int8_t RSSI; // [dBm]
uint8_t BitErr; // number of bit errors
public:
void setTime(double RxTime) { sTime=floor(RxTime); msTime=floor(1000.0*(RxTime-sTime)); }
double getTime(void) const { return (double)sTime+0.001*msTime; }
uint32_t SlotTime(void) const { uint32_t Slot=sTime; if(msTime<=300) Slot--; return Slot; }
};
#endif // __ADSL_H__