kopia lustrzana https://github.com/dl9rdz/rdz_ttgo_sonde
partial ims100 support
rodzic
f407cbb544
commit
e1498f6bbc
|
@ -162,6 +162,8 @@ void setupChannelList() {
|
|||
}
|
||||
else if (space[1] == 'M') {
|
||||
type = STYPE_M10;
|
||||
} else if (space[1] == 'I') {
|
||||
type = STYPE_IMS100;
|
||||
}
|
||||
else continue;
|
||||
int active = space[3] == '+' ? 1 : 0;
|
||||
|
@ -235,7 +237,7 @@ const char *handleQRGPost(AsyncWebServerRequest *request) {
|
|||
const char *tstr = tstring.c_str();
|
||||
const char *sstr = sstring.c_str();
|
||||
Serial.printf("Processing a=%s, f=%s, t=%s, site=%s\n", active ? "YES" : "NO", fstr, tstr, sstr);
|
||||
char typech = (tstr[2] == '4' ? '4' : tstr[2] == '9' ? 'R' : tstr[0] == 'M' ? 'M' : tstr[3]); // a bit ugly
|
||||
char typech = (tstr[2] == '4' ? '4' : tstr[2] == '9' ? 'R' : tstr[0] == 'M' ? 'M' : tstr[0] == 'i' ? 'I' : tstr[3]); // a bit ugly
|
||||
file.printf("%3.3f %c %c %s\n", atof(fstr), typech, active ? '+' : '-', sstr);
|
||||
}
|
||||
file.close();
|
||||
|
@ -1525,7 +1527,7 @@ void loopDecoder() {
|
|||
Serial.println("");
|
||||
}
|
||||
// wifi (axudp) or bluetooth (bttnc) active => send packet
|
||||
if ((res & 0xff) == 0 && (connected || tncclient.connected() )) {
|
||||
if (((res & 0xff) == 0 )&& (connected || tncclient.connected() )) {
|
||||
//Send a packet with position information
|
||||
// first check if ID and position lat+lonis ok
|
||||
SondeInfo *s = &sonde.sondeList[rxtask.receiveSonde];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const char *version_name = "rdzTTGOsonde";
|
||||
const char *version_id = "devel20191110";
|
||||
const char *version_id = "ims20191116";
|
||||
const int SPIFFS_MAJOR=2;
|
||||
const int SPIFFS_MINOR=1;
|
||||
|
|
|
@ -26,7 +26,7 @@ extern bool axp192_found;
|
|||
|
||||
SPIClass spiDisp(HSPI);
|
||||
|
||||
const char *sondeTypeStr[NSondeTypes] = { "DFM6", "DFM9", "RS41", "RS92", "M10" };
|
||||
const char *sondeTypeStr[NSondeTypes] = { "DFM6", "DFM9", "RS41", "RS92", "M10", "i100" };
|
||||
|
||||
byte myIP_tiles[8*11];
|
||||
static uint8_t ap_tile[8]={0x00,0x04,0x22,0x92, 0x92, 0x22, 0x04, 0x00};
|
||||
|
|
|
@ -0,0 +1,541 @@
|
|||
|
||||
/* IMS100 decoder functions */
|
||||
#include "IMS100.h"
|
||||
#include "SX1278FSK.h"
|
||||
#include "rsc.h"
|
||||
#include "Sonde.h"
|
||||
#include <SPIFFS.h>
|
||||
|
||||
// well...
|
||||
//#include "rs92gps.h"
|
||||
|
||||
#define IMS100_DEBUG 1
|
||||
|
||||
#if IMS100_DEBUG
|
||||
#define IMS100_DBG(x) x
|
||||
#else
|
||||
#define IMS100_DBG(x)
|
||||
#endif
|
||||
|
||||
static uint16_t MON[]={0,0,31,59,90,120,151,181,212,243,273,304,334};
|
||||
|
||||
static byte data2[80];
|
||||
static byte data1[80];
|
||||
static byte *dataptr=data1;
|
||||
|
||||
static uint8_t rxbitc;
|
||||
static uint16_t rxbyte;
|
||||
static int rxp=0;
|
||||
static int haveNewFrame = 0;
|
||||
static int lastFrame = 0;
|
||||
static int headerDetected = 0;
|
||||
|
||||
#include "bch_ecc.c"
|
||||
|
||||
static boolean initialized;
|
||||
int IMS100::setup(float frequency)
|
||||
{
|
||||
#if IMS100_DEBUG
|
||||
Serial.println("Setup sx1278 for IMS100 sonde");
|
||||
#endif
|
||||
if(!initialized) {
|
||||
rs_init_BCH64();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if(sx1278.ON()!=0) {
|
||||
IMS100_DBG(Serial.println("Setting SX1278 power on FAILED"));
|
||||
return 1;
|
||||
}
|
||||
if(sx1278.setFSK()!=0) {
|
||||
IMS100_DBG(Serial.println("Setting FSJ mode FAILED"));
|
||||
return 1;
|
||||
}
|
||||
if(sx1278.setBitrate(2400)!=0) {
|
||||
IMS100_DBG(Serial.println("Setting bitrate 9600bit/s FAILED"));
|
||||
return 1;
|
||||
}
|
||||
#if IMS100_DEBUG
|
||||
float br = sx1278.getBitrate();
|
||||
Serial.print("Exact bitrate is ");
|
||||
Serial.println(br);
|
||||
#endif
|
||||
if(sx1278.setAFCBandwidth(sonde.config.rs92.rxbw)!=0) {
|
||||
IMS100_DBG(Serial.printf("Setting AFC bandwidth %d Hz FAILED", sonde.config.rs92.rxbw));
|
||||
return 1;
|
||||
}
|
||||
if(sx1278.setRxBandwidth(sonde.config.rs92.rxbw)!=0) {
|
||||
IMS100_DBG(Serial.printf("Setting RX bandwidth to %d Hz FAILED", sonde.config.rs92.rxbw));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Enable auto-AFC, auto-AGC, RX Trigger by preamble
|
||||
if(sx1278.setRxConf(0x1E)!=0) {
|
||||
IMS100_DBG(Serial.println("Setting RX Config FAILED"));
|
||||
return 1;
|
||||
}
|
||||
// Set autostart_RX to 01, preamble 0, SYNC detect==on, syncsize=3 (==4 byte
|
||||
//char header[] = "0110.0101 0110.0110 1010.0101 1010.1010";
|
||||
|
||||
//const char *SYNC="\x10\xB6\xCA\x11\x22\x96\x12\xF8";
|
||||
//const char *SYNC="\x08\x6D\x53\x88\x44\x69\x48\x1F";
|
||||
// was 0x57
|
||||
//const char *SYNC="\x99\x9A";
|
||||
#if 1
|
||||
// version 1, working with continuous RX
|
||||
const char *SYNC="\x55\x55";
|
||||
if(sx1278.setSyncConf(0x70, 2, (const uint8_t *)SYNC)!=0) {
|
||||
IMS100_DBG(Serial.println("Setting SYNC Config FAILED"));
|
||||
return 1;
|
||||
}
|
||||
//if(sx1278.setPreambleDetect(0xA8)!=0) {
|
||||
if(sx1278.setPreambleDetect(0x9F)!=0) {
|
||||
IMS100_DBG(Serial.println("Setting PreambleDetect FAILED"));
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Packet config 1: fixed len, no mancecer, no crc, no address filter
|
||||
// Packet config 2: packet mode, no home ctrl, no beackn, msb(packetlen)=0)
|
||||
if(sx1278.setPacketConfig(0x08, 0x40)!=0) {
|
||||
IMS100_DBG(Serial.println("Setting Packet config FAILED"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
Serial.print("IMS100: setting RX frequency to ");
|
||||
Serial.println(frequency);
|
||||
int res = sx1278.setFrequency(frequency);
|
||||
// enable RX
|
||||
sx1278.setPayloadLength(0); // infinite for now...
|
||||
//sx1278.setPayloadLength(292);
|
||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||
|
||||
#if IMS100_DEBUG
|
||||
IMS100_DBG(Serial.println("Setting SX1278 config for IMS100 finished\n"); Serial.println());
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int IMS100::setFrequency(float frequency) {
|
||||
Serial.print("IMS100: setting RX frequency to ");
|
||||
Serial.println(frequency);
|
||||
int res = sx1278.setFrequency(frequency);
|
||||
// enable RX
|
||||
sx1278.setPayloadLength(0); // infinite for now...
|
||||
|
||||
sx1278.writeRegister(REG_OP_MODE, FSK_RX_MODE);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
uint32_t IMS100::bits2val(const uint8_t *bits, int len) {
|
||||
uint32_t val = 0;
|
||||
for (int j = 0; j < len; j++) {
|
||||
val |= (bits[j] << (len-1-j));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
IMS100::IMS100() {
|
||||
}
|
||||
|
||||
#define IMS100_FRAMELEN (75)
|
||||
|
||||
#define IMS100_CRCPOS 99
|
||||
|
||||
void IMS100::printRaw(uint8_t *data, int len)
|
||||
{
|
||||
char buf[3];
|
||||
int i;
|
||||
for(i=0; i<len; i++) {
|
||||
snprintf(buf, 3, "%02X ", data[i]);
|
||||
Serial.print(buf);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
static int update_checkIMS100(int c, uint8_t b) {
|
||||
int c0, c1, t, t6, t7, s;
|
||||
c1 = c & 0xFF;
|
||||
// B
|
||||
b = (b >> 1) | ((b & 1) << 7);
|
||||
b ^= (b >> 2) & 0xFF;
|
||||
// A1
|
||||
t6 = ( c & 1) ^ ((c >> 2) & 1) ^ ((c >> 4) & 1);
|
||||
t7 = ((c >> 1) & 1) ^ ((c >> 3) & 1) ^ ((c >> 5) & 1);
|
||||
t = (c & 0x3F) | (t6 << 6) | (t7 << 7);
|
||||
// A2
|
||||
s = (c >> 7) & 0xFF;
|
||||
s ^= (s >> 2) & 0xFF;
|
||||
c0 = b ^ t ^ s;
|
||||
return ((c1 << 8) | c0) & 0xFFFF;
|
||||
}
|
||||
static bool checkIMS100crc(uint8_t *msg) {
|
||||
int i, cs, cs1;
|
||||
cs = 0;
|
||||
for (i = 0; i < IMS100_CRCPOS; i++) {
|
||||
cs = update_checkIMS100(cs, msg[i]);
|
||||
}
|
||||
cs = cs & 0xFFFF;
|
||||
cs1 = (msg[IMS100_CRCPOS] << 8) | msg[IMS100_CRCPOS+1];
|
||||
return (cs1 == cs);
|
||||
}
|
||||
|
||||
typedef uint32_t SET256[8];
|
||||
static SET256 sondeudp_VARSET = {0x03BBBBF0UL,0x80600000UL,0x06A001A0UL,
|
||||
0x0000001CUL,0x00000000UL,0x00000000UL,0x00000000UL,
|
||||
0x00000000UL};
|
||||
// VARSET=SET256{4..9,11..13,15..17,19..21,23..25,53..54,63,69,71,72,85,87,89,90,98..100};
|
||||
|
||||
static uint8_t fixcnt[IMS100_FRAMELEN];
|
||||
static uint8_t fixbytes[IMS100_FRAMELEN];
|
||||
|
||||
static int32_t getint32(uint8_t *data) {
|
||||
return (int32_t)( data[3]|(data[2]<<8)|(data[1]<<16)|(data[0]<<24) );
|
||||
}
|
||||
static int16_t getint16(uint8_t *data) {
|
||||
return (int16_t)(data[1]|((uint16_t)data[0]<<8));
|
||||
}
|
||||
|
||||
static char dez(uint8_t nr) {
|
||||
nr = nr%10;
|
||||
return '0'+nr;
|
||||
}
|
||||
static char hex(uint8_t nr) {
|
||||
nr = nr&0x0f;
|
||||
if(nr<10) return '0'+nr;
|
||||
else return 'A'+nr-10;
|
||||
}
|
||||
const static float DEGMUL = 1.0/0xB60B60;
|
||||
#define VMUL 0.005
|
||||
#ifndef PI
|
||||
#define PI (3.1415926535897932384626433832795)
|
||||
#endif
|
||||
#define RAD (PI/180)
|
||||
|
||||
// 6*2 block first subframe, 6*2 blocks second subframe
|
||||
uint16_t getw16(uint8_t *data, int index) {
|
||||
int bytepos;
|
||||
if(index<12) bytepos = 3 + 2*index;
|
||||
else bytepos = 27 + 3 + 2*(index-12);
|
||||
return ( data[bytepos]<<8 ) | data[bytepos+1];
|
||||
}
|
||||
|
||||
// ret: 1=frame ok; 2=frame with errors; 0=ignored frame (m10dop-alternativ)
|
||||
int IMS100::decodeframeIMS100(uint8_t *data) {
|
||||
int repairstep = 16;
|
||||
int repl = 0;
|
||||
bool crcok;
|
||||
printRaw(data, 75);
|
||||
uint8_t outdata[80];
|
||||
int outpos=0;
|
||||
|
||||
// do error correction, based on RS's bch decoder
|
||||
uint8_t cw[64], err_pos[4], err_val[4];
|
||||
int8_t errcnt[12];
|
||||
int bitpos = 0; // 24 bit header
|
||||
for(int subframe = 0; subframe<2; subframe++) {
|
||||
outdata[outpos++] = data[(bitpos/8)];
|
||||
outdata[outpos++] = data[(bitpos/8)+1];
|
||||
outdata[outpos++] = data[(bitpos/8)+2];
|
||||
bitpos += 24;
|
||||
for(int block=0; block<6; block++) {
|
||||
// create codeword for decoder
|
||||
for (int j = 46; j < 63; j++) cw[j] = 0;
|
||||
for (int j = 0; j<46; j++) {
|
||||
cw[45-j] = ( data[ (bitpos+j)>>3 ] >> (7 - ((bitpos+j)&7)) ) & 1;
|
||||
}
|
||||
errcnt[block+6*subframe] = rs_decode_bch_gf2t2(cw, err_pos, err_val);
|
||||
// TODO: Check for uncorrectable errors
|
||||
|
||||
outdata[outpos] = outdata[outpos+1] = 0;
|
||||
for(int j=0; j<16; j++) { outdata[outpos + (j>>3)] |= (cw[45-j]<<(7 - (j&7))); }
|
||||
outpos += 2;
|
||||
outdata[outpos] = outdata[outpos+1] = 0;
|
||||
for(int j=0; j<16; j++) { outdata[outpos + (j>>3)] |= (cw[45-17-j]<<(7 - (j&7))); }
|
||||
outpos += 2;
|
||||
bitpos += 46;
|
||||
}
|
||||
}
|
||||
Serial.print("errcount: ");
|
||||
for(int i=0; i<12; i++) { Serial.print(errcnt[i]); Serial.print(" "); } Serial.println(".");
|
||||
printRaw(outdata, 54);
|
||||
|
||||
// decoding...
|
||||
uint16_t gps_chk_sum = 0;
|
||||
for(int j= 10; j<12; j++) gps_chk_sum += getw16(outdata, j);
|
||||
if(outdata[0x12]!=0xC1) { Serial.println("Warning: Typs is not ims100 (0xC1)"); }
|
||||
uint16_t counter = (outdata[3]<<8) | outdata[4];
|
||||
Serial.printf(" [%d] ", counter);
|
||||
uint32_t val = (outdata[7]<<8) | (outdata[8]) | (outdata[9]<<24) | (outdata[10]<<16);
|
||||
if( (counter&15)==0 && errcnt[1]>=0 ) {
|
||||
uint32_t sn = *(float *)(&val);
|
||||
Serial.printf(" sn:%x ", sn);
|
||||
snprintf(sonde.si()->ser, 12, "%d", sn);
|
||||
snprintf(sonde.si()->id, 10, "IMS%06x", sn);
|
||||
sonde.si()->validID = true;
|
||||
}
|
||||
if( (counter&63)==15 ) Serial.printf(" freq:%x / %f ",val,400e3+(*(float *)&val)*100);
|
||||
uint16_t ms;
|
||||
uint8_t hr, mi;
|
||||
if( (counter&1)==0 ) {
|
||||
ms = (outdata[0x17]<<8) | outdata[0x18];
|
||||
hr = outdata[0x19];
|
||||
mi = outdata[0x1A];
|
||||
Serial.printf(" %02d:%02d:%06.3f ", hr, mi, 0.001 * ms);
|
||||
}
|
||||
for(int j=0; j<11; j++) gps_chk_sum += getw16(outdata, j+12);
|
||||
boolean gps_err = gps_chk_sum != getw16(outdata, 11+12);
|
||||
Serial.printf("GPS checksum ok: %s %d vs %d\n",gps_err?"NO":"yes",gps_chk_sum, getw16(outdata, 11+12));
|
||||
if((counter&1)==0) {
|
||||
uint16_t dat2 = (outdata[27+3]<<8) | (outdata[27+4]);
|
||||
int y = 2000+(dat2%10)+10;
|
||||
int m = (dat2/10)%100;
|
||||
int d = dat2/1000;
|
||||
Serial.printf(" (%04d-%02d-%02d) ", y, m, d);
|
||||
// time
|
||||
int tt = (y-1970)*365 + (y-1969)/4; // days since 1970
|
||||
if(m<=12) { tt += MON[m]; if((y%4)==0 && m>2) tt++; }
|
||||
tt = (tt+d-1)*(60*60*24) + hr*3600 + mi*60 + ms/1000;
|
||||
sonde.si()->time = tt;
|
||||
sonde.si()->frame = counter;
|
||||
sonde.si()->validTime = 1;
|
||||
if(!gps_err) {
|
||||
int32_t lat = (outdata[30+2]<<24) | (outdata[30+3]<<16) | (outdata[30+4]<<8) | outdata[30+5];
|
||||
int32_t lon = (outdata[30+6]<<24) | (outdata[30+7]<<16) | (outdata[30+8]<<8) | outdata[30+9];
|
||||
int32_t alt = (outdata[30+10]<<16) | (outdata[30+11]<<8) | (outdata[30+12]);
|
||||
int32_t latdeg = lat / 1e6;
|
||||
int32_t londeg = lon / 1e6;
|
||||
float la = latdeg + ((double)lat/1.0e6-latdeg)*100/60.0;
|
||||
float lo = londeg + ((double)lon/1.0e6-londeg)*100/60.0;
|
||||
float al = alt/1.0e2;
|
||||
Serial.printf(" lat: %.5f(%d) lon: %.5f(%d) alt: %.2f ", la, lat, lo, lon, al);
|
||||
sonde.si()->lat = la;
|
||||
sonde.si()->lon = lo;
|
||||
sonde.si()->alt = al;
|
||||
sonde.si()->vs = 0; // not in data?
|
||||
uint16_t vd = (outdata[30+18]<<8) | (outdata[30+19]);
|
||||
uint16_t vh = (outdata[30+20]<<8) | (outdata[30+21]);
|
||||
sonde.si()->hs = vh / 1.94384e2;
|
||||
sonde.si()->dir = vd / 1.0e2;
|
||||
sonde.si()->validPos = 0x37;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t rxdata;
|
||||
static bool rxsearching=true;
|
||||
|
||||
// search for
|
||||
// //101001100110011010011010011001100110100110101010100110101001
|
||||
// //1010011001100110100110100110 0110.0110 1001.1010 1010.1001 1010.1001 => 0x669AA9A9
|
||||
|
||||
// for now, search just for 0x04 => 1010101010110101
|
||||
//uint32_t testhead = 0b10101010101101010010101100110100;
|
||||
uint32_t head[]={0b10101010101101010010101100110100, ~0b10101010101101010010101100110100, 0x396c6420, 0x207a6472};
|
||||
// 600 bit => 75 byte, for now twice as this is before diff. decoding
|
||||
void IMS100::processIMS100data(uint8_t dt)
|
||||
{
|
||||
for(int i=0; i<8; i++) {
|
||||
uint8_t d = (dt&0x80)?1:0;
|
||||
dt <<= 1;
|
||||
rxdata = (rxdata<<1) | d;
|
||||
//
|
||||
if(rxsearching) {
|
||||
if( rxdata == head[0] || rxdata == head[1] ) {
|
||||
rxsearching = false;
|
||||
rxbitc = 0;
|
||||
rxp = 0;
|
||||
dataptr[0] = 0x04;
|
||||
dataptr[1] = 0x9D;
|
||||
rxp = 2;
|
||||
#if 1
|
||||
int rssi=sx1278.getRSSI();
|
||||
int fei=sx1278.getFEI();
|
||||
int afc=sx1278.getAFC();
|
||||
Serial.print("Test: RSSI="); Serial.print(rssi);
|
||||
Serial.print(" FEI="); Serial.print(fei);
|
||||
Serial.print(" AFC="); Serial.println(afc);
|
||||
sonde.si()->rssi = rssi;
|
||||
sonde.si()->afc = afc;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
rxbitc = (rxbitc+1)%16;
|
||||
if(rxbitc&1) continue;
|
||||
rxbyte = (rxbyte<<1) | ( (rxdata&1)^((rxdata>>1)&1)^1 );
|
||||
if(rxbitc == 0) { // got 8 data bit
|
||||
//Serial.printf("%03x ",rxbyte);
|
||||
dataptr[rxp++] = rxbyte&0xff; // (rxbyte>>1)&0xff;
|
||||
#if 0
|
||||
if(rxp==7 && dataptr[6] != 0x65) {
|
||||
Serial.printf("wrong start: %02x\n",dataptr[6]);
|
||||
rxsearching = true;
|
||||
}
|
||||
#endif
|
||||
if(rxp>=IMS100_FRAMELEN) {
|
||||
rxsearching = true;
|
||||
haveNewFrame = decodeframeIMS100(dataptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int IMS100::receive() {
|
||||
for(int i=0; i<2; i++) { // two 500ms frames
|
||||
unsigned long t0 = millis();
|
||||
Serial.printf("IMS100::receive() start at %ld\n",t0);
|
||||
while( millis() - t0 < 1000 ) {
|
||||
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||
if ( bitRead(value, 7) ) {
|
||||
Serial.println("FIFO full");
|
||||
}
|
||||
if ( bitRead(value, 4) ) {
|
||||
Serial.println("FIFO overflow");
|
||||
}
|
||||
if ( bitRead(value, 2) == 1 ) {
|
||||
Serial.println("FIFO: ready()");
|
||||
sx1278.clearIRQFlags();
|
||||
}
|
||||
if(bitRead(value, 6) == 0) { // while FIFO not empty
|
||||
byte data = sx1278.readRegister(REG_FIFO);
|
||||
//Serial.printf("%02x",data);
|
||||
processIMS100data(data);
|
||||
value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||
} else {
|
||||
if(headerDetected) {
|
||||
t0 = millis(); // restart timer... don't time out if header detected...
|
||||
headerDetected = 0;
|
||||
}
|
||||
if(haveNewFrame) {
|
||||
Serial.printf("IMS100::receive(): new frame complete after %ldms\n", millis()-t0);
|
||||
printRaw(dataptr, IMS100_FRAMELEN);
|
||||
int retval = haveNewFrame==1 ? RX_OK: RX_ERROR;
|
||||
haveNewFrame = 0;
|
||||
if(i==0) continue;
|
||||
// TODO: consider return value of both frames??
|
||||
return retval;
|
||||
}
|
||||
delay(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
Serial.printf("IMS100::receive() timed out\n");
|
||||
return RX_TIMEOUT; // TODO RX_OK;
|
||||
}
|
||||
|
||||
#define IMS100MAXLEN (240)
|
||||
int IMS100::waitRXcomplete() {
|
||||
// called after complete...
|
||||
#if 0
|
||||
Serial.printf("decoding frame %d\n", lastFrame);
|
||||
print_frame(lastFrame==1?data1:data2, 240);
|
||||
SondeInfo *si = sonde.sondeList+rxtask.receiveSonde;
|
||||
si->lat = gpx.lat;
|
||||
si->lon = gpx.lon;
|
||||
si->alt = gpx.alt;
|
||||
si->vs = gpx.vU;
|
||||
si->hs = gpx.vH;
|
||||
si->dir = gpx.vD;
|
||||
si->validPos = 0x3f;
|
||||
memcpy(si->id, gpx.id, 9);
|
||||
si->validID = true;
|
||||
|
||||
int res=0;
|
||||
uint32_t t0 = millis();
|
||||
while( rxtask.receiveResult == 0xFFFF && millis()-t0 < 2000) { delay(20); }
|
||||
|
||||
if( rxtask.receiveResult<0 || rxtask.receiveResult==RX_TIMEOUT) {
|
||||
res = RX_TIMEOUT;
|
||||
} else if ( rxtask.receiveResult==0) {
|
||||
res = RX_OK;
|
||||
} else {
|
||||
res = RX_ERROR;
|
||||
}
|
||||
rxtask.receiveResult = 0xFFFF;
|
||||
Serial.printf("IMS100::waitRXcomplete returning %d (%s)\n", res, RXstr[res]);
|
||||
return res;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int oldwaitRXcomplete() {
|
||||
Serial.println("IMS100: receive frame...\n");
|
||||
sx1278receiveData = true;
|
||||
delay(6000); // done in other task....
|
||||
//sx1278receiveData = false;
|
||||
#if 0
|
||||
//sx1278.setPayloadLength(518-8); // Expect 320-8 bytes or 518-8 bytes (8 byte header)
|
||||
//sx1278.setPayloadLength(0); // infinite for now...
|
||||
|
||||
////// test code for continuous reception
|
||||
// sx1278.receive(); /// active FSK RX mode -- already done above...
|
||||
uint8_t value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||
unsigned long previous = millis();
|
||||
|
||||
byte ready=0;
|
||||
uint32_t wait = 8000;
|
||||
// while not yet done or FIFO not yet empty
|
||||
// bit 6: FIFO Empty
|
||||
// bit 2 payload ready
|
||||
int by=0;
|
||||
while( (!ready || bitRead(value,6)==0) && (millis() - previous < wait) )
|
||||
{
|
||||
if( bitRead(value, 7) ) { Serial.println("FIFO full"); }
|
||||
if( bitRead(value, 4) ) { Serial.println("FIFO overflow"); }
|
||||
if( bitRead(value,2)==1 ) ready=1;
|
||||
if( bitRead(value, 6) == 0 ) { // FIFO not empty
|
||||
byte data = sx1278.readRegister(REG_FIFO);
|
||||
process8N1data(data);
|
||||
by++;
|
||||
#if 0
|
||||
if(di==1) {
|
||||
int rssi=getRSSI();
|
||||
int fei=getFEI();
|
||||
int afc=getAFC();
|
||||
Serial.print("Test: RSSI="); Serial.println(rssi);
|
||||
Serial.print("Test: FEI="); Serial.println(fei);
|
||||
Serial.print("Test: AFC="); Serial.println(afc);
|
||||
sonde.si()->rssi = rssi;
|
||||
sonde.si()->afc = afc;
|
||||
}
|
||||
if(di>520) {
|
||||
// TODO
|
||||
Serial.println("TOO MUCH DATA");
|
||||
break;
|
||||
}
|
||||
previous = millis(); // reset timeout after receiving data
|
||||
#endif
|
||||
}
|
||||
value = sx1278.readRegister(REG_IRQ_FLAGS2);
|
||||
}
|
||||
Serial.printf("processed %d bytes before end/timeout\n", by);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/////
|
||||
#if 0
|
||||
int e = sx1278.receivePacketTimeout(1000, data+8);
|
||||
if(e) { Serial.println("TIMEOUT"); return RX_TIMEOUT; } //if timeout... return 1
|
||||
|
||||
printRaw(data, IMS100MAXLEN);
|
||||
//for(int i=0; i<IMS100MAXLEN; i++) { data[i] = reverse(data[i]); }
|
||||
//printRaw(data, MAXLEN);
|
||||
//for(int i=0; i<IMS100MAXLEN; i++) { data[i] = data[i] ^ scramble[i&0x3F]; }
|
||||
//printRaw(data, MAXLEN);
|
||||
//int res = decode41(data, IMS100MAXLEN);
|
||||
#endif
|
||||
int res=0;
|
||||
return res==0 ? RX_OK : RX_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
IMS100 ims100 = IMS100();
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* IMS100.h
|
||||
* Functions for decoding Meteomodem IMS100 sondes with SX127x chips
|
||||
* Copyright (C) 2019 Hansi Reiser, dl9rdz
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef IMS100_h
|
||||
#define IMS100_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <Arduino.h>
|
||||
#ifndef inttypes_h
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
struct CONTEXTR9 {
|
||||
char calibdata[512];
|
||||
uint32_t calibok;
|
||||
char mesok;
|
||||
char posok;
|
||||
char framesent;
|
||||
double lat;
|
||||
double lon;
|
||||
double heig;
|
||||
double speed;
|
||||
double dir;
|
||||
double climb;
|
||||
double lastlat;
|
||||
double laslong;
|
||||
double lastalt;
|
||||
double lastspeed;
|
||||
double lastdir;
|
||||
double lastclb;
|
||||
float hrmsc;
|
||||
float vrmsc;
|
||||
double hp;
|
||||
double hyg;
|
||||
double temp;
|
||||
double ozontemp;
|
||||
double ozon;
|
||||
uint32_t goodsats;
|
||||
uint32_t timems;
|
||||
uint32_t framenum;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Main class */
|
||||
class IMS100
|
||||
{
|
||||
private:
|
||||
void printRaw(uint8_t *data, int len);
|
||||
void processIMS100data(uint8_t data);
|
||||
int decodeframeIMS100(uint8_t *data);
|
||||
#if 0
|
||||
void stobyte92(uint8_t byte);
|
||||
void dogps(const uint8_t *sf, int sf_len,
|
||||
struct CONTEXTR9 * cont, uint32_t * timems,
|
||||
uint32_t * gpstime);
|
||||
uint32_t bits2val(const uint8_t *bits, int len);
|
||||
int bitsToBytes(uint8_t *bits, uint8_t *bytes, int len);
|
||||
int decode92(byte *data, int maxlen);
|
||||
|
||||
uint8_t hamming_conf[ 7*8]; // 7*8=56
|
||||
uint8_t hamming_dat1[13*8]; // 13*8=104
|
||||
uint8_t hamming_dat2[13*8];
|
||||
|
||||
uint8_t block_conf[ 7*4]; // 7*4=28
|
||||
uint8_t block_dat1[13*4]; // 13*4=52
|
||||
uint8_t block_dat2[13*4];
|
||||
|
||||
uint8_t H[4][8] = // extended Hamming(8,4) particy check matrix
|
||||
{{ 0, 1, 1, 1, 1, 0, 0, 0},
|
||||
{ 1, 0, 1, 1, 0, 1, 0, 0},
|
||||
{ 1, 1, 0, 1, 0, 0, 1, 0},
|
||||
{ 1, 1, 1, 0, 0, 0, 0, 1}};
|
||||
uint8_t He[8] = { 0x7, 0xB, 0xD, 0xE, 0x8, 0x4, 0x2, 0x1}; // Spalten von H:
|
||||
// 1-bit-error-Syndrome
|
||||
boolean initialized = false;
|
||||
#endif
|
||||
|
||||
public:
|
||||
IMS100();
|
||||
int setup(float frequency);
|
||||
int receive();
|
||||
int waitRXcomplete();
|
||||
|
||||
//int use_ecc = 1;
|
||||
};
|
||||
|
||||
extern IMS100 ims100;
|
||||
|
||||
#endif
|
|
@ -6,6 +6,7 @@
|
|||
#include "RS92.h"
|
||||
#include "DFM.h"
|
||||
#include "M10.h"
|
||||
#include "IMS100.h"
|
||||
#include "SX1278FSK.h"
|
||||
#include "Display.h"
|
||||
#include <Wire.h>
|
||||
|
@ -385,6 +386,9 @@ void Sonde::setup() {
|
|||
case STYPE_M10:
|
||||
m10.setup( sondeList[rxtask.currentSonde].freq * 1000000);
|
||||
break;
|
||||
case STYPE_IMS100:
|
||||
ims100.setup( sondeList[rxtask.currentSonde].freq * 1000000);
|
||||
break;
|
||||
}
|
||||
// debug
|
||||
float afcbw = sx1278.getAFCBandwidth();
|
||||
|
@ -404,13 +408,16 @@ void Sonde::receive() {
|
|||
case STYPE_RS92:
|
||||
res = rs92.receive();
|
||||
break;
|
||||
case STYPE_M10:
|
||||
res = m10.receive();
|
||||
break;
|
||||
case STYPE_DFM06:
|
||||
case STYPE_DFM09:
|
||||
res = dfm.receive();
|
||||
break;
|
||||
case STYPE_M10:
|
||||
res = m10.receive();
|
||||
break;
|
||||
case STYPE_IMS100:
|
||||
res = ims100.receive();
|
||||
break;
|
||||
}
|
||||
|
||||
// state information for RX_TIMER / NORX_TIMER events
|
||||
|
@ -488,13 +495,16 @@ rxloop:
|
|||
case STYPE_RS92:
|
||||
rs92.waitRXcomplete();
|
||||
break;
|
||||
case STYPE_M10:
|
||||
m10.waitRXcomplete();
|
||||
break;
|
||||
case STYPE_DFM06:
|
||||
case STYPE_DFM09:
|
||||
dfm.waitRXcomplete();
|
||||
break;
|
||||
case STYPE_M10:
|
||||
m10.waitRXcomplete();
|
||||
break;
|
||||
case STYPE_IMS100:
|
||||
ims100.waitRXcomplete();
|
||||
break;
|
||||
}
|
||||
memmove(sonde.si()->rxStat+1, sonde.si()->rxStat, 17);
|
||||
sonde.si()->rxStat[0] = res;
|
||||
|
|
|
@ -46,8 +46,8 @@ extern const char *RXstr[];
|
|||
// 01000000 => goto sonde -1
|
||||
// 01000001 => goto sonde +1
|
||||
|
||||
#define NSondeTypes 5
|
||||
enum SondeType { STYPE_DFM06, STYPE_DFM09, STYPE_RS41, STYPE_RS92, STYPE_M10 };
|
||||
#define NSondeTypes 6
|
||||
enum SondeType { STYPE_DFM06, STYPE_DFM09, STYPE_RS41, STYPE_RS92, STYPE_M10, STYPE_IMS100 };
|
||||
extern const char *sondeTypeStr[NSondeTypes];
|
||||
|
||||
typedef struct st_sondeinfo {
|
||||
|
|
|
@ -0,0 +1,805 @@
|
|||
/* SPDX-License-Identifier: GPL-3.0
|
||||
*
|
||||
* BCH / Reed-Solomon
|
||||
* encoder()
|
||||
* decoder() (Euklid. Alg.)
|
||||
*
|
||||
*
|
||||
* based on https://github.com/rs1729/RS/blob/master/meisei/meisei_ims.c
|
||||
* author: zilog80
|
||||
*
|
||||
|
||||
Meisei:
|
||||
bin.BCH(63, 51), t=2
|
||||
g(X) = (X^6+X+1)(X^6+X^4+X^2+X+1)
|
||||
g(a) = 0 fuer a = alpha^1,...,alpha^4
|
||||
Es koennen 2 Fehler korrigiert werden; diese koennen auch direkt mit
|
||||
L(x) = 1 + L1 x + L2 x^2, L1=L1(S1), L2=L2(S1,S3)
|
||||
gefunden werden. Problem: 3 Fehler und mehr erkennen.
|
||||
Auch bei 3 Fehlern ist deg(Lambda)=2 und Lambda hat auch 2 Loesungen.
|
||||
Meisei-Bloecke sind auf 46 bit gekuerzt und enthalten 2 parity bits.
|
||||
-> Wenn decodierte Bloecke bits in Position 46-63 schalten oder
|
||||
einer der parity-checks fehlschlaegt, dann Block nicht korrigierbar.
|
||||
Es werden
|
||||
- 54% der 3-Fehler-Bloecke erkannt
|
||||
- 39% der 3-Fehler-Bloecke werden durch Position/Parity erkannt
|
||||
- 7% der 3-Fehler-Bloecke werden falsch korrigiert
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
//
|
||||
// --- bch_ecc.h ---
|
||||
//
|
||||
|
||||
typedef unsigned char ui8_t;
|
||||
typedef unsigned int ui32_t;
|
||||
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef uint8_t ui8_t;
|
||||
typedef uint32_t ui32_t;
|
||||
|
||||
|
||||
int rs_init_BCH64(void);
|
||||
int rs_decode_bch_gf2t2(ui8_t cw[], ui8_t *err_pos, ui8_t *err_val);
|
||||
|
||||
// ---
|
||||
|
||||
|
||||
#define MAX_DEG 63 // max N-1
|
||||
|
||||
|
||||
typedef struct {
|
||||
ui32_t f;
|
||||
ui32_t ord;
|
||||
ui8_t alpha;
|
||||
} GF_t;
|
||||
|
||||
static GF_t GF/*64BCH*/ = { 0x43, // BCH-GF(2^6): X^6 + X + 1 : 0x43
|
||||
64, // 2^6
|
||||
0x02 }; // generator: alpha = X
|
||||
|
||||
typedef struct {
|
||||
ui8_t N;
|
||||
ui8_t t;
|
||||
ui8_t R; // RS: R=2t, BCH: R<=mt
|
||||
ui8_t K; // K=N-R
|
||||
ui8_t b;
|
||||
ui8_t p; ui8_t ip; // p*ip = 1 mod N
|
||||
ui8_t g[MAX_DEG+1]; // ohne g[] eventuell als init_return
|
||||
} RS_t;
|
||||
|
||||
|
||||
static RS_t RS/*BCH64*/ = { 63, 2, 12, 51, 1, 1, 1, {114, 101, 97, 108, 108, 121, 32, 40, 99, 41, 32, 100, 108, 57, 114, 100, 122, 32, 71, 80, 76, 32, 108, 105, 99, 101, 110, 115, 101, 0}};
|
||||
|
||||
static ui8_t exp_a[256],
|
||||
log_a[256];
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static
|
||||
int GF_deg(ui32_t p) {
|
||||
ui32_t d = 31;
|
||||
if (p == 0) return -1; /* deg(0) = -infty */
|
||||
else {
|
||||
while (d && !(p & (1<<d))) d--; /* d<32, 1L = 1 */
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
static
|
||||
ui8_t GF2m_mul(ui8_t a, ui8_t b) {
|
||||
ui32_t aa = a;
|
||||
ui8_t ab = 0;
|
||||
int i, m = GF_deg(b);
|
||||
|
||||
if (b & 1) ab = a;
|
||||
|
||||
for (i = 0; i < m; i++) {
|
||||
aa = (aa << 1); // a = a * X
|
||||
if (GF_deg(aa) == GF_deg(GF.f))
|
||||
aa ^= GF.f; // a = a - GF.f
|
||||
b >>= 1;
|
||||
if (b & 1) ab ^= (ui8_t)aa; /* b_{i+1} > 0 ? */
|
||||
}
|
||||
return ab;
|
||||
}
|
||||
|
||||
static
|
||||
int GF_genTab(GF_t gf, ui8_t expa[], ui8_t loga[]) {
|
||||
int i, j;
|
||||
ui8_t b;
|
||||
|
||||
// GF.f = f;
|
||||
// GF.ord = 1 << GF_deg(GF.f);
|
||||
|
||||
b = 0x01;
|
||||
for (i = 0; i < gf.ord; i++) {
|
||||
expa[i] = b; // b_i = a^i
|
||||
b = GF2m_mul(gf.alpha, b);
|
||||
}
|
||||
|
||||
loga[0] = -00; // log(0) = -inf
|
||||
for (i = 1; i < gf.ord; i++) {
|
||||
b = 0x01; j = 0;
|
||||
while (b != i) {
|
||||
b = GF2m_mul(gf.alpha, b);
|
||||
j++;
|
||||
if (j > gf.ord-1) {
|
||||
return -1; // a not primitive
|
||||
}
|
||||
} // j = log_a(i)
|
||||
loga[i] = j;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static ui8_t GF_mul(ui8_t p, ui8_t q) {
|
||||
ui32_t x;
|
||||
if ((p == 0) || (q == 0)) return 0;
|
||||
x = (ui32_t)log_a[p] + log_a[q];
|
||||
return exp_a[x % (GF.ord-1)]; // a^(ord-1) = 1
|
||||
}
|
||||
|
||||
static ui8_t GF_inv(ui8_t p) {
|
||||
if (p == 0) return 0; // DIV_BY_ZERO
|
||||
return exp_a[GF.ord-1-log_a[p]]; // a^(ord-1) = 1
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* p(x) = p[0] + p[1]x + ... + p[N-1]x^(N-1)
|
||||
*/
|
||||
|
||||
static
|
||||
ui8_t poly_eval(ui8_t poly[], ui8_t x) {
|
||||
int n;
|
||||
ui8_t xn, y;
|
||||
|
||||
y = poly[0];
|
||||
if (x != 0) {
|
||||
for (n = 1; n < GF.ord-1; n++) {
|
||||
xn = exp_a[(n*log_a[x]) % (GF.ord-1)];
|
||||
y ^= GF_mul(poly[n], xn);
|
||||
}
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
static
|
||||
ui8_t poly_evalH(ui8_t poly[], ui8_t x) {
|
||||
int n;
|
||||
ui8_t y;
|
||||
y = poly[GF.ord-1];
|
||||
for (n = GF.ord-2; n >= 0; n--) {
|
||||
y = GF_mul(y, x) ^ poly[n];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int poly_deg(ui8_t p[]) {
|
||||
int n = MAX_DEG;
|
||||
while (p[n] == 0 && n > 0) n--;
|
||||
if (p[n] == 0) n--; // deg(0) = -inf
|
||||
return n;
|
||||
}
|
||||
|
||||
static
|
||||
int poly_divmod(ui8_t p[], ui8_t q[], ui8_t *d, ui8_t *r) {
|
||||
int deg_p, deg_q; // p(x) = q(x)d(x) + r(x)
|
||||
int i; // deg(r) < deg(q)
|
||||
ui8_t c;
|
||||
|
||||
deg_p = poly_deg(p);
|
||||
deg_q = poly_deg(q);
|
||||
|
||||
if (deg_q < 0) return -1; // q=0: DIV_BY_ZERO
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) d[i] = 0;
|
||||
for (i = 0; i <= MAX_DEG; i++) r[i] = 0;
|
||||
|
||||
|
||||
c = GF_mul( p[deg_p], GF_inv(q[deg_q]));
|
||||
|
||||
if (deg_q == 0) {
|
||||
for (i = 0; i <= deg_p; i++) d[i] = GF_mul(p[i], c);
|
||||
for (i = 0; i <= MAX_DEG; i++) r[i] = 0;
|
||||
}
|
||||
else if (deg_p < 0) { // p=0
|
||||
for (i = 0; i <= MAX_DEG; i++) {
|
||||
d[i] = 0;
|
||||
r[i] = 0;
|
||||
}
|
||||
}
|
||||
else if (deg_p < deg_q) {
|
||||
for (i = 0; i <= MAX_DEG; i++) d[i] = 0;
|
||||
for (i = 0; i <= deg_p; i++) r[i] = p[i]; // r(x)=p(x), deg(r)<deg(q)
|
||||
for (i = deg_p+1; i <= MAX_DEG; i++) r[i] = 0;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i <= deg_p; i++) r[i] = p[i];
|
||||
while (deg_p >= deg_q) {
|
||||
d[deg_p-deg_q] = c;
|
||||
for (i = 0; i <= deg_q; i++) {
|
||||
r[deg_p-i] ^= GF_mul( q[deg_q-i], c);
|
||||
}
|
||||
while (r[deg_p] == 0 && deg_p > 0) deg_p--;
|
||||
if (r[deg_p] == 0) deg_p--;
|
||||
if (deg_p >= 0) c = GF_mul( r[deg_p], GF_inv(q[deg_q]));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int poly_add(ui8_t a[], ui8_t b[], ui8_t *sum) {
|
||||
int i;
|
||||
ui8_t c[MAX_DEG+1];
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) {
|
||||
c[i] = a[i] ^ b[i];
|
||||
}
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { sum[i] = c[i]; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int poly_mul(ui8_t a[], ui8_t b[], ui8_t *ab) {
|
||||
int i, j;
|
||||
ui8_t c[MAX_DEG+1];
|
||||
|
||||
if (poly_deg(a)+poly_deg(b) > MAX_DEG) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { c[i] = 0; }
|
||||
|
||||
for (i = 0; i <= poly_deg(a); i++) {
|
||||
for (j = 0; j <= poly_deg(b); j++) {
|
||||
c[i+j] ^= GF_mul(a[i], b[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { ab[i] = c[i]; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int polyGF_eggT(int deg, ui8_t a[], ui8_t b[], // in
|
||||
ui8_t *u, ui8_t *v, ui8_t *ggt // out
|
||||
) {
|
||||
// deg = 0:
|
||||
// a(x)u(x)+b(x)v(x) = ggt(x)
|
||||
// RS:
|
||||
// deg=t, a(x)=S(x), b(x)=x^2t
|
||||
|
||||
int i;
|
||||
ui8_t r0[MAX_DEG+1], r1[MAX_DEG+1], r2[MAX_DEG+1],
|
||||
s0[MAX_DEG+1], s1[MAX_DEG+1], s2[MAX_DEG+1],
|
||||
t0[MAX_DEG+1], t1[MAX_DEG+1], t2[MAX_DEG+1],
|
||||
quo[MAX_DEG+1];
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { u[i] = 0; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { v[i] = 0; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { ggt[i] = 0; }
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { r0[i] = a[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { r1[i] = b[i]; }
|
||||
s0[0] = 1; for (i = 1; i <= MAX_DEG; i++) { s0[i] = 0; } // s0 = 1
|
||||
s1[0] = 0; for (i = 1; i <= MAX_DEG; i++) { s1[i] = 0; } // s1 = 0
|
||||
t0[0] = 0; for (i = 1; i <= MAX_DEG; i++) { t0[i] = 0; } // t0 = 0
|
||||
t1[0] = 1; for (i = 1; i <= MAX_DEG; i++) { t1[i] = 0; } // t1 = 1
|
||||
for (i = 0; i <= MAX_DEG; i++) { r2[i] = 0; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { s2[i] = 0; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { t2[i] = 0; }
|
||||
|
||||
while ( poly_deg(r1) >= deg ) {
|
||||
poly_divmod(r0, r1, quo, r2);
|
||||
for (i = 0; i <= MAX_DEG; i++) { r0[i] = r1[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { r1[i] = r2[i]; }
|
||||
poly_mul(quo, s1, s2);
|
||||
poly_add(s0, s2, s2);
|
||||
for (i = 0; i <= MAX_DEG; i++) { s0[i] = s1[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { s1[i] = s2[i]; }
|
||||
poly_mul(quo, t1, t2);
|
||||
poly_add(t0, t2, t2);
|
||||
for (i = 0; i <= MAX_DEG; i++) { t0[i] = t1[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { t1[i] = t2[i]; }
|
||||
}
|
||||
|
||||
if (deg > 0) {
|
||||
for (i = 0; i <= MAX_DEG; i++) { ggt[i] = r1[i]; } // deg=0: r0
|
||||
for (i = 0; i <= MAX_DEG; i++) { u[i] = s1[i]; } // deg=0: s0
|
||||
for (i = 0; i <= MAX_DEG; i++) { v[i] = t1[i]; }
|
||||
}
|
||||
else {
|
||||
for (i = 0; i <= MAX_DEG; i++) { ggt[i] = r0[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { u[i] = s0[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { v[i] = t0[i]; }
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int polyGF_lfsr(int deg, int x2t, ui8_t S[],
|
||||
ui8_t *Lambda, ui8_t *Omega ) {
|
||||
// BCH/RS/LFSR: deg=t+e/2, e=#erasures
|
||||
// S(x)Lambda(x) = Omega(x) mod x^2t
|
||||
int i;
|
||||
ui8_t r0[MAX_DEG+1], r1[MAX_DEG+1], r2[MAX_DEG+1],
|
||||
s0[MAX_DEG+1], s1[MAX_DEG+1], s2[MAX_DEG+1],
|
||||
quo[MAX_DEG+1];
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { Lambda[i] = 0; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { Omega[i] = 0; }
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { r0[i] = S[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { r1[i] = 0; } r1[x2t] = 1; //x^2t
|
||||
s0[0] = 1; for (i = 1; i <= MAX_DEG; i++) { s0[i] = 0; }
|
||||
s1[0] = 0; for (i = 1; i <= MAX_DEG; i++) { s1[i] = 0; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { r2[i] = 0; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { s2[i] = 0; }
|
||||
|
||||
while ( poly_deg(r1) >= deg ) { // deg=t+e/2
|
||||
poly_divmod(r0, r1, quo, r2);
|
||||
for (i = 0; i <= MAX_DEG; i++) { r0[i] = r1[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { r1[i] = r2[i]; }
|
||||
|
||||
poly_mul(quo, s1, s2);
|
||||
poly_add(s0, s2, s2);
|
||||
for (i = 0; i <= MAX_DEG; i++) { s0[i] = s1[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { s1[i] = s2[i]; }
|
||||
}
|
||||
|
||||
// deg > 0:
|
||||
for (i = 0; i <= MAX_DEG; i++) { Omega[i] = r1[i]; }
|
||||
for (i = 0; i <= MAX_DEG; i++) { Lambda[i] = s1[i]; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int poly_D(ui8_t a[], ui8_t *Da) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { Da[i] = 0; } // unten werden nicht immer
|
||||
// alle Koeffizienten gesetzt
|
||||
for (i = 1; i <= poly_deg(a); i++) {
|
||||
if (i % 2) Da[i-1] = a[i]; // GF(2^n): b+b=0
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
ui8_t forney(ui8_t x, ui8_t Omega[], ui8_t Lambda[]) {
|
||||
ui8_t DLam[MAX_DEG+1];
|
||||
ui8_t w, z, Y; // x=X^(-1), Y = x^(b-1) * Omega(x)/Lambda'(x)
|
||||
// Y = X^(1-b) * Omega(X^(-1))/Lambda'(X^(-1))
|
||||
poly_D(Lambda, DLam);
|
||||
w = poly_eval(Omega, x);
|
||||
z = poly_eval(DLam, x); if (z == 0) { return -00; }
|
||||
Y = GF_mul(w, GF_inv(z));
|
||||
if (RS.b == 0) Y = GF_mul(GF_inv(x), Y);
|
||||
else if (RS.b > 1) {
|
||||
ui8_t xb1 = exp_a[((RS.b-1)*log_a[x]) % (GF.ord-1)];
|
||||
Y = GF_mul(xb1, Y);
|
||||
}
|
||||
|
||||
return Y;
|
||||
}
|
||||
|
||||
static
|
||||
int era_sigma(int n, ui8_t era_pos[], ui8_t *sigma) {
|
||||
int i;
|
||||
ui8_t Xa[MAX_DEG+1], sig[MAX_DEG+1];
|
||||
ui8_t a_i;
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) sig[i] = 0;
|
||||
for (i = 0; i <= MAX_DEG; i++) Xa[i] = 0;
|
||||
|
||||
// sigma(X)=(1 - alpha^j1 X)...(1 - alpha^jn X)
|
||||
// j_{i+1} = era_pos[i]
|
||||
sig[0] = 1;
|
||||
Xa[0] = 1;
|
||||
for (i = 0; i < n; i++) { // n <= 2*RS.t
|
||||
a_i = exp_a[(RS.p*era_pos[i]) % (GF.ord-1)];
|
||||
Xa[1] = a_i; // Xalp[0..1]: (1-alpha^(j_)X)
|
||||
poly_mul(sig, Xa, sig);
|
||||
}
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) sigma[i] = sig[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int syndromes(ui8_t cw[], ui8_t *S) {
|
||||
int i, errors = 0;
|
||||
ui8_t a_i;
|
||||
|
||||
// syndromes: e_j=S((alpha^p)^(b+i)) (wie in g(X))
|
||||
for (i = 0; i < 2*RS.t; i++) {
|
||||
a_i = exp_a[(RS.p*(RS.b+i)) % (GF.ord-1)]; // (alpha^p)^(b+i)
|
||||
S[i] = poly_eval(cw, a_i);
|
||||
if (S[i]) errors = 1;
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static
|
||||
int prn_GFpoly(ui32_t p) {
|
||||
int i, s;
|
||||
s = 0;
|
||||
if (p == 0) Serial.println("0");
|
||||
else {
|
||||
if (p != (p & 0x1FF)) Serial.println(" (& 0x1FF) ");
|
||||
for (i=8; i>1; i--) {
|
||||
if ( (p>>i) & 1 ) {
|
||||
if (s) Serial.println(" + ");
|
||||
Serial.printf("X^%d", i);
|
||||
s = 1;
|
||||
}
|
||||
}
|
||||
if ( (p>>1) & 1 ) {
|
||||
if (s) Serial.printf(" + ");
|
||||
Serial.printf("X");
|
||||
s = 1;
|
||||
}
|
||||
if ( p & 1 ) {
|
||||
if (s) Serial.printf(" + ");
|
||||
Serial.printf("1");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static
|
||||
void prn_table(void) {
|
||||
int i;
|
||||
|
||||
Serial.printf("F2[X] mod ");
|
||||
prn_GFpoly(GF.f);
|
||||
Serial.printf(" : 0x%X\n", GF.f);
|
||||
Serial.printf("\n");
|
||||
|
||||
Serial.printf("a^n[%d] = {\n", GF.ord);
|
||||
Serial.printf(" ");
|
||||
for (i=0; i<GF.ord; i++) {
|
||||
Serial.printf(" 0x");
|
||||
Serial.printf("%02X", exp_a[i]);
|
||||
if (i<GF.ord-1) Serial.printf(","); else printf("}");
|
||||
if (i%16 == 15) Serial.printf("\n ");
|
||||
}
|
||||
Serial.printf("\n");
|
||||
|
||||
Serial.printf("log_a(n)[%d] = {\n", GF.ord);
|
||||
Serial.printf(" ");
|
||||
Serial.printf(" -oo ,"); // log(0)
|
||||
for (i=1; i<GF.ord; i++) {
|
||||
Serial.printf(" 0x");
|
||||
Serial.printf("%02X", log_a[i]);
|
||||
if (i<GF.ord-1) Serial.printf(","); else printf("}");
|
||||
if (i%16 == 15) Serial.printf("\n ");
|
||||
}
|
||||
Serial.printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
int rs_init_RS255() {
|
||||
int i, check_gen;
|
||||
ui8_t Xalp[MAX_DEG+1];
|
||||
|
||||
GF = GF256RS;
|
||||
check_gen = GF_genTab( GF, exp_a, log_a);
|
||||
|
||||
RS = RS256; // N=255, t=12, b=0, p=1
|
||||
for (i = 0; i <= MAX_DEG; i++) RS.g[i] = 0;
|
||||
for (i = 0; i <= MAX_DEG; i++) Xalp[i] = 0;
|
||||
|
||||
// g(X)=(X-alpha^b)...(X-alpha^(b+2t-1)), b=0
|
||||
RS.g[0] = 0x01;
|
||||
Xalp[1] = 0x01; // X
|
||||
for (i = 0; i < 2*RS.t; i++) {
|
||||
Xalp[0] = exp_a[(RS.b+i) % (GF.ord-1)]; // Xalp[0..1]: X - alpha^(b+i)
|
||||
poly_mul(RS.g, Xalp, RS.g);
|
||||
}
|
||||
|
||||
return check_gen;
|
||||
}
|
||||
|
||||
int rs_init_RS255ccsds() {
|
||||
int i, check_gen;
|
||||
ui8_t Xalp[MAX_DEG+1];
|
||||
|
||||
GF = GF256RSccsds;
|
||||
check_gen = GF_genTab( GF, exp_a, log_a);
|
||||
|
||||
RS = RS256ccsds; // N=255, t=16, b=112, p=11
|
||||
for (i = 0; i <= MAX_DEG; i++) RS.g[i] = 0;
|
||||
for (i = 0; i <= MAX_DEG; i++) Xalp[i] = 0;
|
||||
|
||||
// beta=alpha^p primitive root of g(X)
|
||||
// beta^ip=alpha // N=255, p=11 -> ip=116
|
||||
for (i = 1; i < GF.ord-1; i++) {
|
||||
if ( (RS.p * i) % (GF.ord-1) == 1 ) {
|
||||
RS.ip = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// g(X)=(X-(alpha^p)^b)...(X-(alpha^p)^(b+2t-1)), b=112
|
||||
RS.g[0] = 0x01;
|
||||
Xalp[1] = 0x01; // X
|
||||
for (i = 0; i < 2*RS.t; i++) {
|
||||
Xalp[0] = exp_a[(RS.p*(RS.b+i)) % (GF.ord-1)]; // Xalp[0..1]: X - (alpha^p)^(b+i)
|
||||
poly_mul(RS.g, Xalp, RS.g);
|
||||
}
|
||||
/*
|
||||
RS.g[ 0] = RS.g[32] = exp_a[0];
|
||||
RS.g[ 1] = RS.g[31] = exp_a[249];
|
||||
RS.g[ 2] = RS.g[30] = exp_a[59];
|
||||
RS.g[ 3] = RS.g[29] = exp_a[66];
|
||||
RS.g[ 4] = RS.g[28] = exp_a[4];
|
||||
RS.g[ 5] = RS.g[27] = exp_a[43];
|
||||
RS.g[ 6] = RS.g[26] = exp_a[126];
|
||||
RS.g[ 7] = RS.g[25] = exp_a[251];
|
||||
RS.g[ 8] = RS.g[24] = exp_a[97];
|
||||
RS.g[ 9] = RS.g[23] = exp_a[30];
|
||||
RS.g[10] = RS.g[22] = exp_a[3];
|
||||
RS.g[11] = RS.g[21] = exp_a[213];
|
||||
RS.g[12] = RS.g[20] = exp_a[50];
|
||||
RS.g[13] = RS.g[19] = exp_a[66];
|
||||
RS.g[14] = RS.g[18] = exp_a[170];
|
||||
RS.g[15] = RS.g[17] = exp_a[5];
|
||||
RS.g[16] = exp_a[24];
|
||||
*/
|
||||
return check_gen;
|
||||
}
|
||||
#endif
|
||||
|
||||
int rs_init_BCH64() {
|
||||
int i, check_gen;
|
||||
|
||||
//GF = GF64BCH;
|
||||
check_gen = GF_genTab( GF, exp_a, log_a);
|
||||
|
||||
//RS = BCH64; // N=63, t=2, b=1
|
||||
for (i = 0; i <= MAX_DEG; i++) RS.g[i] = 0;
|
||||
|
||||
// g(X)=X^12+X^10+X^8+X^5+X^4+X^3+1
|
||||
// =(X^6+X+1)(X^6+X^4+X^2+X+1)
|
||||
RS.g[0] = RS.g[3] = RS.g[4] = RS.g[5] = RS.g[8] = RS.g[10] = RS.g[12] = 1;
|
||||
|
||||
return check_gen;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int rs_init_RS15ccsds() {
|
||||
int i, check_gen;
|
||||
ui8_t Xalp[MAX_DEG+1];
|
||||
|
||||
GF = GF16RS;
|
||||
check_gen = GF_genTab( GF, exp_a, log_a);
|
||||
|
||||
//RS = RS16_0; // N=15, t=3, b=0, p=1
|
||||
RS = RS16ccsds; // N=15, t=2, b=6, p=1
|
||||
for (i = 0; i <= MAX_DEG; i++) RS.g[i] = 0;
|
||||
for (i = 0; i <= MAX_DEG; i++) Xalp[i] = 0;
|
||||
|
||||
// g(X)=(X-alpha^b)...(X-alpha^(b+2t-1))
|
||||
RS.g[0] = 0x01;
|
||||
Xalp[1] = 0x01; // X
|
||||
for (i = 0; i < 2*RS.t; i++) {
|
||||
Xalp[0] = exp_a[(RS.b+i) % (GF.ord-1)]; // Xalp[0..1]: X - alpha^(b+i)
|
||||
poly_mul(RS.g, Xalp, RS.g);
|
||||
}
|
||||
|
||||
return check_gen;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
int rs_encode(ui8_t cw[]) {
|
||||
int j;
|
||||
ui8_t __cw[MAX_DEG+1],
|
||||
parity[MAX_DEG+1],
|
||||
d[MAX_DEG+1];
|
||||
for (j = 0; j <= MAX_DEG; j++) parity[j] = 0;
|
||||
for (j = 0; j <= MAX_DEG; j++) __cw[j] = 0;
|
||||
for (j = RS.R; j < RS.N; j++) __cw[j] = cw[j];
|
||||
poly_divmod(__cw, RS.g, d, parity);
|
||||
//if (poly_deg(parity) >= RS.R) return -1;
|
||||
for (j = 0; j < RS.R; j++) cw[j] = parity[j];
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// 2*Errors + Erasure <= 2*t
|
||||
int rs_decode_ErrEra(ui8_t cw[], int nera, ui8_t era_pos[],
|
||||
ui8_t *err_pos, ui8_t *err_val) {
|
||||
ui8_t x, gamma;
|
||||
ui8_t S[MAX_DEG+1],
|
||||
Lambda[MAX_DEG+1],
|
||||
Omega[MAX_DEG+1],
|
||||
sigma[MAX_DEG+1],
|
||||
sigLam[MAX_DEG+1];
|
||||
int deg_sigLam, deg_Lambda, deg_Omega;
|
||||
int i, nerr, errera = 0;
|
||||
|
||||
if (nera > 2*RS.t) { return -4; }
|
||||
|
||||
for (i = 0; i < 2*RS.t; i++) { err_pos[i] = 0; }
|
||||
for (i = 0; i < 2*RS.t; i++) { err_val[i] = 0; }
|
||||
|
||||
// IF: erasures set 0
|
||||
// for (i = 0; i < nera; i++) cw[era_pos[i]] = 0x00; // erasures
|
||||
// THEN: restore cw[era_pos[i]], if errera < 0
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { S[i] = 0; }
|
||||
errera = syndromes(cw, S);
|
||||
// wenn S(x)=0 , dann poly_divmod(cw, RS.g, d, rem): rem=0
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { sigma[i] = 0; }
|
||||
sigma[0] = 1;
|
||||
|
||||
|
||||
if (nera > 0) {
|
||||
era_sigma(nera, era_pos, sigma);
|
||||
poly_mul(sigma, S, S);
|
||||
for (i = 2*RS.t; i <= MAX_DEG; i++) S[i] = 0; // S = sig*S mod x^2t
|
||||
}
|
||||
|
||||
if (errera)
|
||||
{
|
||||
polyGF_lfsr(RS.t+nera/2, 2*RS.t, S, Lambda, Omega);
|
||||
|
||||
deg_Lambda = poly_deg(Lambda);
|
||||
deg_Omega = poly_deg(Omega);
|
||||
if (deg_Omega >= deg_Lambda + nera) {
|
||||
errera = -3;
|
||||
return errera;
|
||||
}
|
||||
gamma = Lambda[0];
|
||||
if (gamma) {
|
||||
for (i = deg_Lambda; i >= 0; i--) Lambda[i] = GF_mul(Lambda[i], GF_inv(gamma));
|
||||
for (i = deg_Omega ; i >= 0; i--) Omega[i] = GF_mul( Omega[i], GF_inv(gamma));
|
||||
poly_mul(sigma, Lambda, sigLam);
|
||||
deg_sigLam = poly_deg(sigLam);
|
||||
}
|
||||
else {
|
||||
errera = -2;
|
||||
return errera;
|
||||
}
|
||||
|
||||
nerr = 0; // Errors + Erasures (erasure-pos bereits bekannt)
|
||||
for (i = 1; i < GF.ord ; i++) { // Lambda(0)=1
|
||||
x = (ui8_t)i; // roll-over
|
||||
if (poly_eval(sigLam, x) == 0) { // Lambda(x)=0 fuer x in erasures[] moeglich
|
||||
// error location index
|
||||
ui8_t x1 = GF_inv(x);
|
||||
err_pos[nerr] = (log_a[x1]*RS.ip) % (GF.ord-1);
|
||||
// error value; bin-BCH: err_val=1
|
||||
err_val[nerr] = forney(x, Omega, sigLam);
|
||||
//err_val[nerr] == 0, wenn era_val[pos]=0, d.h. cw[pos] schon korrekt
|
||||
nerr++;
|
||||
}
|
||||
if (nerr >= deg_sigLam) break;
|
||||
}
|
||||
|
||||
// 2*Errors + Erasure <= 2*t
|
||||
if (nerr < deg_sigLam) errera = -1; // uncorrectable errors
|
||||
else {
|
||||
errera = nerr;
|
||||
for (i = 0; i < errera; i++) cw[err_pos[i]] ^= err_val[i];
|
||||
}
|
||||
}
|
||||
|
||||
return errera;
|
||||
}
|
||||
|
||||
// Errors <= t
|
||||
int rs_decode(ui8_t cw[], ui8_t *err_pos, ui8_t *err_val) {
|
||||
ui8_t tmp[1] = {0};
|
||||
return rs_decode_ErrEra(cw, 0, tmp, err_pos, err_val);
|
||||
}
|
||||
#endif
|
||||
|
||||
int rs_decode_bch_gf2t2(ui8_t cw[], ui8_t *err_pos, ui8_t *err_val) {
|
||||
// binary 2-error correcting BCH
|
||||
|
||||
ui8_t x, gamma,
|
||||
S[MAX_DEG+1],
|
||||
L[MAX_DEG+1], L2,
|
||||
Lambda[MAX_DEG+1],
|
||||
Omega[MAX_DEG+1];
|
||||
int i, n, errors = 0;
|
||||
|
||||
|
||||
for (i = 0; i < RS.t; i++) { err_pos[i] = 0; }
|
||||
for (i = 0; i < RS.t; i++) { err_val[i] = 0; }
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { S[i] = 0; }
|
||||
errors = syndromes(cw, S);
|
||||
// wenn S(x)=0 , dann poly_divmod(cw, RS.g, d, rem): rem=0
|
||||
|
||||
if (errors) {
|
||||
polyGF_lfsr(RS.t, 2*RS.t, S, Lambda, Omega);
|
||||
gamma = Lambda[0];
|
||||
if (gamma) {
|
||||
for (i = poly_deg(Lambda); i >= 0; i--) Lambda[i] = GF_mul(Lambda[i], GF_inv(gamma));
|
||||
for (i = poly_deg(Omega) ; i >= 0; i--) Omega[i] = GF_mul( Omega[i], GF_inv(gamma));
|
||||
}
|
||||
else {
|
||||
errors = -2;
|
||||
return errors;
|
||||
}
|
||||
|
||||
// GF(2)-BCH, t=2:
|
||||
// S1 = S[0]
|
||||
// S1^2 = S2 , S2^2 = S4
|
||||
// L(x) = 1 + L1 x + L2 x^2 (1-2 errors)
|
||||
// L1 = S1 , L2 = (S3 + S1^3)/S1
|
||||
if ( RS.t == 2 ) {
|
||||
|
||||
for (i = 0; i <= MAX_DEG; i++) { L[i] = 0; }
|
||||
L[0] = 1;
|
||||
L[1] = S[0];
|
||||
L2 = GF_mul(S[0], S[0]); L2 = GF_mul(L2, S[0]); L2 ^= S[2];
|
||||
L2 = GF_mul(L2, GF_inv(S[0]));
|
||||
L[2] = L2;
|
||||
|
||||
if (S[1] != GF_mul(S[0],S[0]) || S[3] != GF_mul(S[1],S[1])) {
|
||||
errors = -2;
|
||||
return errors;
|
||||
}
|
||||
if (L[1] != Lambda[1] || L[2] != Lambda[2] ) {
|
||||
errors = -2;
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
n = 0;
|
||||
for (i = 1; i < GF.ord ; i++) { // Lambda(0)=1
|
||||
x = (ui8_t)i; // roll-over
|
||||
if (poly_eval(Lambda, x) == 0) {
|
||||
// error location index
|
||||
err_pos[n] = log_a[GF_inv(x)];
|
||||
// error value; bin-BCH: err_val=1
|
||||
err_val[n] = 1; // = forney(x, Omega, Lambda);
|
||||
n++;
|
||||
}
|
||||
if (n >= poly_deg(Lambda)) break;
|
||||
}
|
||||
|
||||
if (n < poly_deg(Lambda)) errors = -1; // uncorrectable errors
|
||||
else {
|
||||
errors = n;
|
||||
for (i = 0; i < errors; i++) cw[err_pos[i]] ^= err_val[i];
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
Ładowanie…
Reference in New Issue