From e1498f6bbceec3d152634750d7058a42f821495f Mon Sep 17 00:00:00 2001 From: "Hansi, dl9rdz" Date: Mon, 18 Nov 2019 12:46:00 +0100 Subject: [PATCH] partial ims100 support --- RX_FSK/RX_FSK.ino | 6 +- RX_FSK/version.h | 2 +- libraries/SondeLib/Display.cpp | 2 +- libraries/SondeLib/IMS100.cpp | 541 ++++++++++++++++++++++ libraries/SondeLib/IMS100.h | 96 ++++ libraries/SondeLib/Sonde.cpp | 22 +- libraries/SondeLib/Sonde.h | 4 +- libraries/SondeLib/bch_ecc.c | 805 +++++++++++++++++++++++++++++++++ 8 files changed, 1466 insertions(+), 12 deletions(-) create mode 100644 libraries/SondeLib/IMS100.cpp create mode 100644 libraries/SondeLib/IMS100.h create mode 100644 libraries/SondeLib/bch_ecc.c diff --git a/RX_FSK/RX_FSK.ino b/RX_FSK/RX_FSK.ino index 20f884e..3072c0d 100644 --- a/RX_FSK/RX_FSK.ino +++ b/RX_FSK/RX_FSK.ino @@ -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]; diff --git a/RX_FSK/version.h b/RX_FSK/version.h index 57983e1..0b727fb 100644 --- a/RX_FSK/version.h +++ b/RX_FSK/version.h @@ -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; diff --git a/libraries/SondeLib/Display.cpp b/libraries/SondeLib/Display.cpp index 9ca61d4..b804abe 100644 --- a/libraries/SondeLib/Display.cpp +++ b/libraries/SondeLib/Display.cpp @@ -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}; diff --git a/libraries/SondeLib/IMS100.cpp b/libraries/SondeLib/IMS100.cpp new file mode 100644 index 0000000..9027b76 --- /dev/null +++ b/libraries/SondeLib/IMS100.cpp @@ -0,0 +1,541 @@ + +/* IMS100 decoder functions */ +#include "IMS100.h" +#include "SX1278FSK.h" +#include "rsc.h" +#include "Sonde.h" +#include + +// 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> 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 +#include +#include +#ifndef inttypes_h + #include +#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 diff --git a/libraries/SondeLib/Sonde.cpp b/libraries/SondeLib/Sonde.cpp index 65656b9..5d03cf5 100644 --- a/libraries/SondeLib/Sonde.cpp +++ b/libraries/SondeLib/Sonde.cpp @@ -6,6 +6,7 @@ #include "RS92.h" #include "DFM.h" #include "M10.h" +#include "IMS100.h" #include "SX1278FSK.h" #include "Display.h" #include @@ -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; diff --git a/libraries/SondeLib/Sonde.h b/libraries/SondeLib/Sonde.h index fba462b..0e05256 100644 --- a/libraries/SondeLib/Sonde.h +++ b/libraries/SondeLib/Sonde.h @@ -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 { diff --git a/libraries/SondeLib/bch_ecc.c b/libraries/SondeLib/bch_ecc.c new file mode 100644 index 0000000..b1190d0 --- /dev/null +++ b/libraries/SondeLib/bch_ecc.c @@ -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 + +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<>= 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) { + 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 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; +} +