/////////////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2019-2021 Edouard Griffiths, F4EXB // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation as version 3 of the License, or // // (at your option) any later version. // // // // This program is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY; without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License V3 for more details. // // // // You should have received a copy of the GNU General Public License // // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////////// #ifndef LEANSDR_SOFTWORD_H #define LEANSDR_SOFTWORD_H namespace leansdr { // This file implements options for SOFTBYTE in s2_frame_receiver // (representation of bytes after deinterleaving). // Also used as SOFTWORD in ldpc_engine // (representation of packed SOFTBITs). // Interface for ldpc_engine: // SOFTBIT softword_get(const SOFTWORD &p, int b) // SOFTBIT softwords_xor(const SOFTWORD p1[], const SOFTWORD p2[], int b) // void softword_zero(SOFTWORD *p, int b) // void softwords_set(SOFTWORD p[], int b) // void softwords_flip(SOFTWORD p[], int b) // HARD SOFTWORD / SOFTBYTE typedef uint8_t hard_sb; // Bit 7 is transmitted first. inline bool softword_get(const hard_sb &p, int b) { return p & (1 << (7 - b)); } inline void softword_set(hard_sb *p, int b, bool v) { hard_sb mask = 1 << (7 - b); *p = ((*p) & ~mask) | (v << (7 - b)); } inline void softword_clear(hard_sb *p) { *p = 0; } inline bool softword_weight(const bool &l) { (void) l; return true; } inline void softbit_set(bool *p, bool v) { *p = v; } inline bool softbit_harden(bool b) { return b; } inline uint8_t softbyte_harden(const hard_sb &b) { return b; } inline bool softbit_xor(bool x, bool y) { return x ^ y; } inline void softbit_clear(bool *p) { *p = false; } inline bool softwords_xor(const hard_sb p1[], const hard_sb p2[], int b) { return (p1[b / 8] ^ p2[b / 8]) & (1 << (7 - (b & 7))); } inline void softword_zero(hard_sb *p) { *p = 0; } inline void softwords_set(hard_sb p[], int b) { p[b / 8] |= 1 << (7 - (b & 7)); } inline void softword_write(hard_sb &p, int b, bool v) { hard_sb mask = 1 << (7 - b); p = (p & ~mask) | (hard_sb)v << (7 - b); } inline void softwords_write(hard_sb p[], int b, bool v) { softword_write(p[b / 8], b & 7, v); } inline void softwords_flip(hard_sb p[], int b) { p[b / 8] ^= 1 << (7 - (b & 7)); } uint8_t *softbytes_harden(hard_sb p[], int nbytes, uint8_t storage[]) { (void) nbytes; (void) storage; return p; } // LLR SOFTWORD struct llr_sb { llr_t bits[8]; // bits[0] is transmitted first. }; float prob(llr_t l) { return (127.0 + l) / 254; } llr_t llr(float p) { int r = -127 + 254 * p; if (r < -127) { r = -127; } if (r > 127) { r = 127; } return r; } inline llr_t llr_xor(llr_t lx, llr_t ly) { float px = prob(lx), py = prob(ly); return llr(px * (1 - py) + (1 - px) * py); } inline llr_t softword_get(const llr_sb &p, int b) { return p.bits[b]; } // Special case to avoid computing b/8*8+b%7. Assumes llr_sb[] packed. inline llr_t softwords_get(const llr_sb p[], int b) { return p[0].bits[b]; // Beyond bounds on purpose } inline void softword_set(llr_sb *p, int b, llr_t v) { p->bits[b] = v; } inline void softword_clear(llr_sb *p) { memset(p->bits, 0, sizeof(p->bits)); } // inline llr_t softwords_get(const llr_sb p[], int b) { // return softword_get(p[b/8], b&7); // } inline llr_t softword_weight(llr_t l) { return abs(l); } inline void softbit_set(llr_t *p, bool v) { *p = v ? -127 : 127; } inline bool softbit_harden(llr_t l) { return (l < 0); } inline uint8_t softbyte_harden(const llr_sb &b) { // Without conditional jumps uint8_t r = (((b.bits[0] & 128) >> 0) | ((b.bits[1] & 128) >> 1) | ((b.bits[2] & 128) >> 2) | ((b.bits[3] & 128) >> 3) | ((b.bits[4] & 128) >> 4) | ((b.bits[5] & 128) >> 5) | ((b.bits[6] & 128) >> 6) | ((b.bits[7] & 128) >> 7)); return r; } inline llr_t softbit_xor(llr_t x, llr_t y) { return llr_xor(x, y); } inline void softbit_clear(llr_t *p) { *p = -127; } inline llr_t softwords_xor(const llr_sb p1[], const llr_sb p2[], int b) { return llr_xor(p1[b / 8].bits[b & 7], p2[b / 8].bits[b & 7]); } inline void softword_zero(llr_sb *p) { memset(p, -127, sizeof(*p)); } inline void softwords_set(llr_sb p[], int b) { p[b / 8].bits[b & 7] = 127; } inline void softword_write(llr_sb &p, int b, llr_t v) { p.bits[b] = v; } inline void softwords_write(llr_sb p[], int b, llr_t v) { softword_write(p[b / 8], b & 7, v); } inline void softwords_flip(llr_sb p[], int b) { llr_t *l = &p[b / 8].bits[b & 7]; *l = -*l; } uint8_t *softbytes_harden(llr_sb p[], int nbytes, uint8_t storage[]) { for (uint8_t *q = storage; nbytes--; ++p, ++q) { *q = softbyte_harden(*p); } return storage; } // Generic wrappers template inline SOFTBIT softwords_get(const SOFTBYTE p[], int b) { return softword_get(p[b / 8], b & 7); } template inline void softwords_set(SOFTBYTE p[], int b, SOFTBIT v) { softword_set(&p[b / 8], b & 7, v); } template inline SOFTBIT softwords_weight(const SOFTBYTE p[], int b) { return softword_weight(softwords_get(p, b)); } } // namespace leansdr #endif // LEANSDR_SOFTWORD_H