/* -*- c++ -*- */ /* * Copyright 2023 jmfriedt. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "m17_coder_impl.h" #include #include #include #include #include "../M17_Implementations/SP5WWP/inc/m17.h" #include "../M17_Implementations/SP5WWP/m17-coder/golay.h" #include "../M17_Implementations/SP5WWP/m17-coder/crc.h" namespace gr { namespace m17 { struct LSF { uint8_t dst[6]; uint8_t src[6]; uint8_t type[2]; uint8_t meta[112/8]; uint8_t crc[2]; } lsf; void send_Preamble(const uint8_t type,float *out, int *counterout, float samp_rate) { float symb; if(type) //pre-BERT { // for(uint16_t i=0; i<(int)(40e-3*samp_rate)/2; i++) //40ms * 4800 = 192 TODO JMF for(uint16_t i=0; i<(int)(192/2); i++) //40ms * 4800 = 192 { symb=-3.0; // write(STDOUT_FILENO, (uint8_t*)&symb, sizeof(float)); out[*counterout]=symb; *counterout=(*counterout)+1; symb=+3.0; // write(STDOUT_FILENO, (uint8_t*)&symb, sizeof(float)); out[*counterout]=symb; *counterout=(*counterout)+1; } } else //pre-LSF { // for(uint16_t i=0; i<(int)(40e-3*samp_rate)/2; i++) //40ms * 4800 = 192 TODO JMF for(uint16_t i=0; i<(int)(192/2); i++) //40ms * 4800 = 192 { symb=+3.0; // write(STDOUT_FILENO, (uint8_t*)&symb, sizeof(float)); out[*counterout]=symb; *counterout=(*counterout)+1; symb=-3.0; // write(STDOUT_FILENO, (uint8_t*)&symb, sizeof(float)); out[*counterout]=symb; *counterout=(*counterout)+1; } } } void send_Syncword(const uint16_t sword, float *out, int *counterout) { float symb; for(uint8_t i=0; i<16; i+=2) { symb=symbol_map[(sword>>(14-i))&3]; // write(STDOUT_FILENO, (uint8_t*)&symb, sizeof(float)); out[*counterout]=symb; *counterout=(*counterout)+1; } } //out - unpacked bits //in - packed raw bits //fn - frame number void conv_Encode_Frame(uint8_t* out, uint8_t* in, uint16_t fn) { uint8_t pp_len = sizeof(P_2); uint8_t p=0; //puncturing pattern index uint16_t pb=0; //pushed punctured bits uint8_t ud[144+4+4]; //unpacked data memset(ud, 0, 144+4+4); //unpack frame number for(uint8_t i=0; i<16; i++) { ud[4+i]=(fn>>(15-i))&1; } //unpack data for(uint8_t i=0; i<16; i++) { for(uint8_t j=0; j<8; j++) { ud[4+16+i*8+j]=(in[i]>>(7-j))&1; } } //encode for(uint8_t i=0; i<144+4; i++) { uint8_t G1=(ud[i+4] +ud[i+1]+ud[i+0])%2; uint8_t G2=(ud[i+4]+ud[i+3]+ud[i+2] +ud[i+0])%2; //printf("%d%d", G1, G2); if(P_2[p]) { out[pb]=G1; pb++; } p++; p%=pp_len; if(P_2[p]) { out[pb]=G2; pb++; } p++; p%=pp_len; } //printf("pb=%d\n", pb); } //out - unpacked bits //in - packed raw bits (LSF struct) void conv_Encode_LSF(uint8_t* out, struct LSF *in) { uint8_t pp_len = sizeof(P_1); uint8_t p=0; //puncturing pattern index uint16_t pb=0; //pushed punctured bits uint8_t ud[240+4+4]; //unpacked data memset(ud, 0, 240+4+4); //unpack DST for(uint8_t i=0; i<8; i++) { ud[4+i] =((in->dst[0])>>(7-i))&1; ud[4+i+8] =((in->dst[1])>>(7-i))&1; ud[4+i+16]=((in->dst[2])>>(7-i))&1; ud[4+i+24]=((in->dst[3])>>(7-i))&1; ud[4+i+32]=((in->dst[4])>>(7-i))&1; ud[4+i+40]=((in->dst[5])>>(7-i))&1; } //unpack SRC for(uint8_t i=0; i<8; i++) { ud[4+i+48]=((in->src[0])>>(7-i))&1; ud[4+i+56]=((in->src[1])>>(7-i))&1; ud[4+i+64]=((in->src[2])>>(7-i))&1; ud[4+i+72]=((in->src[3])>>(7-i))&1; ud[4+i+80]=((in->src[4])>>(7-i))&1; ud[4+i+88]=((in->src[5])>>(7-i))&1; } //unpack TYPE for(uint8_t i=0; i<8; i++) { ud[4+i+96] =((in->type[0])>>(7-i))&1; ud[4+i+104]=((in->type[1])>>(7-i))&1; } //unpack META for(uint8_t i=0; i<8; i++) { ud[4+i+112]=((in->meta[0])>>(7-i))&1; ud[4+i+120]=((in->meta[1])>>(7-i))&1; ud[4+i+128]=((in->meta[2])>>(7-i))&1; ud[4+i+136]=((in->meta[3])>>(7-i))&1; ud[4+i+144]=((in->meta[4])>>(7-i))&1; ud[4+i+152]=((in->meta[5])>>(7-i))&1; ud[4+i+160]=((in->meta[6])>>(7-i))&1; ud[4+i+168]=((in->meta[7])>>(7-i))&1; ud[4+i+176]=((in->meta[8])>>(7-i))&1; ud[4+i+184]=((in->meta[9])>>(7-i))&1; ud[4+i+192]=((in->meta[10])>>(7-i))&1; ud[4+i+200]=((in->meta[11])>>(7-i))&1; ud[4+i+208]=((in->meta[12])>>(7-i))&1; ud[4+i+216]=((in->meta[13])>>(7-i))&1; } //unpack CRC for(uint8_t i=0; i<8; i++) { ud[4+i+224]=((in->crc[0])>>(7-i))&1; ud[4+i+232]=((in->crc[1])>>(7-i))&1; } //encode for(uint8_t i=0; i<240+4; i++) { uint8_t G1=(ud[i+4] +ud[i+1]+ud[i+0])%2; uint8_t G2=(ud[i+4]+ud[i+3]+ud[i+2] +ud[i+0])%2; //printf("%d%d", G1, G2); if(P_1[p]) { out[pb]=G1; pb++; } p++; p%=pp_len; if(P_1[p]) { out[pb]=G2; pb++; } p++; p%=pp_len; } //printf("pb=%d\n", pb); } uint16_t LSF_CRC(struct LSF *in) { uint8_t d[28]; memcpy(&d[0], in->dst, 6); memcpy(&d[6], in->src, 6); memcpy(&d[12], in->type, 2); memcpy(&d[14], in->meta, 14); return CRC_M17(d, 28); } m17_coder::sptr m17_coder::make(std::string src_id,std::string dst_id,short type,std::string meta, float samp_rate,bool debug) { return gnuradio::get_initial_sptr (new m17_coder_impl(src_id,dst_id,type,meta,samp_rate,debug)); } /* * The private constructor */ m17_coder_impl::m17_coder_impl(std::string src_id,std::string dst_id,short type,std::string meta, float samp_rate, bool debug) : gr::block("m17_coder", gr::io_signature::make(1, 1, sizeof(char)), gr::io_signature::make(1, 1, sizeof(float))) ,_meta(meta), _samp_rate(samp_rate), _debug(debug) { set_meta(meta); set_src_id(src_id); set_dst_id(dst_id); set_samp_rate(samp_rate); set_type(type); set_debug(debug); uint16_t ccrc=LSF_CRC(&lsf); lsf.crc[0]=ccrc>>8; lsf.crc[1]=ccrc&0xFF; _got_lsf=0; //have we filled the LSF struct yet? _fn=0; //16-bit Frame Number (for the stream mode) } void m17_coder_impl::set_samp_rate(float samp_rate) {_samp_rate=samp_rate; printf("New sampling rate: %f\n",_samp_rate); } void m17_coder_impl::set_debug(bool debug) {_debug=debug; if (_debug==true) printf("true\n"); else printf("Debug false\n"); } void m17_coder_impl::set_src_id(std::string src_id) {for (int i=0;i<6;i++) {_src_id[i]=0;} sscanf(src_id.c_str(), "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", &_src_id[0], &_src_id[1], &_src_id[2], &_src_id[3],&_src_id[4],&_src_id[5]); for (int i=0;i<6;i++) {lsf.src[i]=_src_id[i];} printf("new SRC ID: %hhu %hhu %hhu %hhu %hhu %hhu\n",_src_id[0],_src_id[1],_src_id[2],_src_id[3],_src_id[4],_src_id[5]);fflush(stdout); } void m17_coder_impl::set_dst_id(std::string dst_id) {for (int i=0;i<6;i++) {_dst_id[i]=0;} sscanf(dst_id.c_str(), "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", &_dst_id[0], &_dst_id[1], &_dst_id[2], &_dst_id[3],&_dst_id[4],&_dst_id[5]); for (int i=0;i<6;i++) {lsf.dst[i]=_dst_id[i];} printf("new DST ID: %hhu %hhu %hhu %hhu %hhu %hhu\n",_dst_id[0],_dst_id[1],_dst_id[2],_dst_id[3],_dst_id[4],_dst_id[5]);fflush(stdout); } void m17_coder_impl::set_meta(std::string meta) {int length; printf("new meta: %s\n",meta.c_str());fflush(stdout); _meta=meta; if (meta.length()<14) length=meta.length(); else length=14; for (int i=0;i>8; printf("new type: %hhd %hhd\n",lsf.type[1],lsf.type[0]);fflush(stdout); } /* * Our virtual destructor. */ m17_coder_impl::~m17_coder_impl() { } void m17_coder_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) { ninput_items_required[0] = noutput_items/24; // TODO JMF (if 16 inputs -> 384 outputs) } int m17_coder_impl::general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { const char *in = (const char *) input_items[0]; float *out = (float *) output_items[0]; int countin=0; int countout=0; uint8_t enc_bits[SYM_PER_PLD*2]; //type-2 bits, unpacked uint8_t rf_bits[SYM_PER_PLD*2]; //type-4 bits, unpacked uint8_t lich[6]; //48 bits packed raw, unencoded LICH uint8_t lich_encoded[12]; //96 bits packed, encoded LICH uint8_t data[16]; //raw payload, packed bits uint8_t lich_cnt=0; //0..5 LICH counter, derived from the Frame Number do { if (countin+16<=noutput_items) {if(_got_lsf) //stream frames { //we could discard the data we already have // for (int i=0;i<6;i++) {lsf.dst[i]=in[countin];countin++;} // for (int i=0;i<6;i++) {lsf.src[i]=in[countin];countin++;} // for (int i=0;i<2;i++) {lsf.type[i]=in[countin];countin++;} // for (int i=0;i<14;i++) {lsf.meta[i]=in[countin];countin++;} for (int i=0;i<16;i++) {data[i]=in[countin];countin++;} //send stream frame syncword send_Syncword(SYNC_STR,out,&countout); //derive the LICH_CNT from the Frame Number lich_cnt=_fn%6; //extract LICH from the whole LSF switch(lich_cnt) { case 0: lich[0]=lsf.dst[0]; lich[1]=lsf.dst[1]; lich[2]=lsf.dst[2]; lich[3]=lsf.dst[3]; lich[4]=lsf.dst[4]; break; case 1: lich[0]=lsf.dst[5]; lich[1]=lsf.src[0]; lich[2]=lsf.src[1]; lich[3]=lsf.src[2]; lich[4]=lsf.src[3]; break; case 2: lich[0]=lsf.src[4]; lich[1]=lsf.src[5]; lich[2]=lsf.type[0]; lich[3]=lsf.type[1]; lich[4]=lsf.meta[0]; break; case 3: lich[0]=lsf.meta[1]; lich[1]=lsf.meta[2]; lich[2]=lsf.meta[3]; lich[3]=lsf.meta[4]; lich[4]=lsf.meta[5]; break; case 4: lich[0]=lsf.meta[6]; lich[1]=lsf.meta[7]; lich[2]=lsf.meta[8]; lich[3]=lsf.meta[9]; lich[4]=lsf.meta[10]; break; case 5: lich[0]=lsf.meta[11]; lich[1]=lsf.meta[12]; lich[2]=lsf.meta[13]; lich[3]=lsf.crc[0]; lich[4]=lsf.crc[1]; break; default: ; break; } lich[5]=lich_cnt<<5; //encode the LICH uint32_t val; val=golay24_encode((lich[0]<<4)|(lich[1]>>4)); lich_encoded[0]=(val>>16)&0xFF; lich_encoded[1]=(val>>8)&0xFF; lich_encoded[2]=(val>>0)&0xFF; val=golay24_encode(((lich[1]&0x0F)<<8)|lich[2]); lich_encoded[3]=(val>>16)&0xFF; lich_encoded[4]=(val>>8)&0xFF; lich_encoded[5]=(val>>0)&0xFF; val=golay24_encode((lich[3]<<4)|(lich[4]>>4)); lich_encoded[6]=(val>>16)&0xFF; lich_encoded[7]=(val>>8)&0xFF; lich_encoded[8]=(val>>0)&0xFF; val=golay24_encode(((lich[4]&0x0F)<<8)|lich[5]); lich_encoded[9]=(val>>16)&0xFF; lich_encoded[10]=(val>>8)&0xFF; lich_encoded[11]=(val>>0)&0xFF; //unpack LICH (12 bytes) memset(enc_bits, 0, SYM_PER_PLD*2); for(uint8_t i=0; i<12; i++) { for(uint8_t j=0; j<8; j++) enc_bits[i*8+j]=(lich_encoded[i]>>(7-j))&1; } //encode the rest of the frame conv_Encode_Frame(&enc_bits[96], data, _fn); //reorder bits for(uint16_t i=0; i>(7-(i%8)))&1) //flip bit if '1' { if(rf_bits[i]) rf_bits[i]=0; else rf_bits[i]=1; } } float s; for(uint16_t i=0; i>8; // lsf.crc[1]=ccrc&0xFF; _got_lsf=1; printf("got_lsf=1\n"); //encode LSF data conv_Encode_LSF(enc_bits, &lsf); //send out the preamble and LSF send_Preamble(0,out,&countout,_samp_rate); //0 - LSF preamble, as opposed to 1 - BERT preamble //send LSF syncword send_Syncword(SYNC_LSF,out,&countout); //reorder bits for(uint16_t i=0; i>(7-(i%8)))&1) //flip bit if '1' { if(rf_bits[i]) rf_bits[i]=0; else rf_bits[i]=1; } } float s; for(uint16_t i=0; i