diff --git a/opera/opera.c b/opera/opera.c index 3338c9c..d0785a3 100644 --- a/opera/opera.c +++ b/opera/opera.c @@ -1,80 +1,515 @@ -#include -#include -#include +//****************************************************************************** +// OPERA_Coding_Test.cpp : Defines the entry point for the console application. +// +// Purpose : Algorithm testing by a laptop computer before implementation +// into PIC micro processor. +// +// Usage: "OPERA_Coding_Test [? | d | s] ["callsign"]"; +// where : s = help, d = debug and s = sample"; +// +// Version 1.0.4, 2015/11/29: Modified print format +// Version 1.0.3, 2015/11/13: Delete an additional start bit for decoder +// Version 1.0.2, 2015/11/11: Add Visual C++ directives +// Version 1.0.1, 2015/11/10: Changed help message +// Version 1.0.0, 2015/11/07: Initial Release +// +// Copyright(C) 2015 F4GCB +// Partial copyright (C)2015 7L1RLL +// Partial copyright (C)2017 F5OEO Add output format to Rpitx RFA Mode +// -char* itoa(unsigned long val, int n, char* buf, int radix) +// Acknowledgement : +// 1)Portion of this OPERA is derived from the work of EA5HVK. +// 2)All functions of this program are a copy of JUMA-TX500/136 +// Transmitter Controller which written by F4GCB. +//****************************************************************************** + +//#include "stdafx.h" +//#include +//#include +#include "stdio.h" +#include "string.h" +#include +#include + #include + #include +#include "stdint.h" +#include "math.h" + +//#define __VCpp__ TRUE + +// Grobal Variables + +int FileFreqTiming; +// Test program using SNDFILE +// see http://www.mega-nerd.com/libsndfile/api.html for API + +void WriteTone(double Frequency,uint32_t Timing) { - char c[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - int i = 0; - while (n-i) { - unsigned long d = (unsigned long)pow(radix, n-i-1); - buf[i++] = c[val/d]; - val = val%d; - } - buf[i] = '\0'; - return buf; + typedef struct { + double Frequency; + uint32_t WaitForThisSample; + } samplerf_t; + samplerf_t RfSample; + + RfSample.Frequency=Frequency; + RfSample.WaitForThisSample=Timing; //en 100 de nanosecond + //printf("Freq =%f Timing=%d\n",RfSample.Frequency,RfSample.WaitForThisSample); + if (write(FileFreqTiming,&RfSample,sizeof(samplerf_t)) != sizeof(samplerf_t)) { + fprintf(stderr, "Unable to write sample\n"); + } + } -int crc16op(char* msg, int n) +static const short int pseudo_sequence[51] = { + 1,1,1,0,0,0,0,1,0,1, 0,1,0,1,1,1,1,1,1,0, 0,1,1,0,1,1,0,1,0,0, 0,0,0,0,0,1,1,0,0,1, + 0,0,0,1,0,1,0,1,0,1, 1 +}; +static short int walsh_matrix[8][7] = { + {0,0,0,0,0,0,0},{1,0,1,0,1,0,1},{0,1,1,0,0,1,1},{1,1,0,0,1,1,0}, + {0,0,0,1,1,1,1},{1,0,1,1,0,1,0},{0,1,1,1,1,0,0},{1,1,0,1,0,0,1} +}; +static short int symbol[239]; +char call[7], call_coded[45], vector[52]; +short int vector_to_tx[51]; +short int symbol_interleaving[119], symbol_coding[119]; +short int DEBUG = 0; +const char sampleCall[7] = "AA1AA"; + +// Declaration of functions + +void genn_opera(float mode); +void generate_call(char call[7], char call_coded[45]); +void add_crc16(char call_coded[45], char vector[52]); +void scramble(char vector[52], short int symbol_coding[119]); +void Walsh_Hammered_code(short int symbol_coding[119], short int vector_to_tx[51]); +void interleave(short int vector_to_tx[51], short int symbol_interleaving[119]); +void ManchesterEncode(short int symbol_interleaving[119], short int symbol[239]); +char chr_norm_opera(char bc); + +void print_short_int(const char caption[], short int code[239], int length); +void print_str(const char caption[250], char code[52]); +void strcpy_w(char s1[52], char s2[52], int length); +void strcat_w(char s1[52], char s2[52], int lenS1, int lenS2); +void encodepitx(short int *code, int length,float Nop); + +#ifdef __VCpp__ +//********************************** +// main forVisual C++ +int _tmain(int argc, _TCHAR* argv[]) +//********************************** { - int i,j,crc=0; // crc-16 (0x8005 poly, flip in and out, 2 zero bytes in tail) of msg[0..n-1] - for(i=0;i!=n+2;i++){ + _tsetlocale(LC_ALL, _T("")); //Change Unicode to OS-Default locale +#else + int main(int argc, char* argv[]) +//********************************** + { +#endif + int i = 0; + char s1 = 0x00, s2[7] = ""; + + + switch (argc) + { + case 1 : // Help required + case 2 : // Help required + case 3 : // Help required + { + printf("Usage : %s CALLSIGN OperaMode[0.5,1,2,4,8} file.rfa \n", argv[0]); + + return 0; + } + case 4: // 3 arguments + { + s1 = (char)argv[1][0]; + + // range check + if (!((argv[1][0] >= '0' && argv[1][0] <= '9') || (argv[1][0] >= 'A' && argv[1][0] <= 'Z') || + (argv[1][0] >= 'a' && argv[1][0] <= 'z'))) + { + printf("%s\n","Callsign must be began with an alphan/numeric character"); + + return 0; + } + DEBUG = 0; i = 0; + while (argv[1][i] != 0 && i < 7) + { + call[i] = argv[1][i]; call[++i] = 0x00; + } + + float Mode=atof(argv[2]); + + FileFreqTiming = open( argv[3], O_WRONLY|O_CREAT, 0644); + genn_opera(Mode); + return 0; + + } + + default: + { + printf("Usage : %s CALLSIGN OperaMode[0.5,1,2,4,8} file.rfa \n", argv[0]); + break; + } + } // end of switch argc + return 0; +} // end of _tmain + +//******************* +void genn_opera(float mode) +//******************* +{ + printf("\nGenerate Op%.1f Callsign = %s\n",mode,call); + + generate_call(call, call_coded); + if (DEBUG) + print_str("call_coded =", call_coded); + + add_crc16(call_coded, vector); + + if (DEBUG) + print_str("crc16 vector =", vector); + + scramble(vector, vector_to_tx); + if (DEBUG) + print_short_int("vector_to_tx =", vector_to_tx, 44); + + Walsh_Hammered_code(vector_to_tx, symbol_coding); + if (DEBUG) + print_short_int("symbol_coding =", symbol_coding, 119); + + interleave(symbol_coding, symbol_interleaving); + if (DEBUG) + print_short_int("symbol_interleaving =", symbol_interleaving, 119); + + ManchesterEncode(symbol_interleaving, symbol); + //print_short_int("symbol =", symbol, 239); + encodepitx(symbol,239,mode); + +} // genn_opera + +//**************************************************** +// Normalize characters space S..Z 0..9 in order 0..36 +char chr_norm_opera(char bc) +//**************************************************** +{ + char cc = 0; + + if (bc >= '0' && bc <= '9') cc = bc - '0' + 27; + if (bc >= 'A' && bc <= 'Z') cc = bc - 'A' + 1; + if (bc >= 'a' && bc <= 'z') cc = bc - 'a' + 1; + if (bc == ' ') cc = 0; + + return (cc); +} // enf of chr_norm_opera + +//********************************************** +void generate_call(char *call, char *call_coded) +//********************************************** +{ + int i; + unsigned long code_sum; + + //the thired character must always be a number + if (chr_norm_opera(call[2]) < 27) + { + for (i=5; i> 0; i--) call[i] = call[i-1]; + call[0]=' '; + } + + // the call must always have 6 characters + for (i=strlen(call); i < 6; i++) + call[i] = ' '; + call[6] = 0x00; + + if (DEBUG) printf("NormalizedCall=%s\n", call); + code_sum = chr_norm_opera(call[0]); + code_sum = code_sum * 36 + chr_norm_opera(call[1]) - 1; + code_sum = code_sum * 10 + chr_norm_opera(call[2]) - 27; + code_sum = code_sum * 27 + chr_norm_opera(call[3]); + code_sum = code_sum * 27 + chr_norm_opera(call[4]); + code_sum = code_sum * 27 + chr_norm_opera(call[5]); + + if (DEBUG) printf("code_sum=%Lu\n", code_sum); + + // merge coded callsign ino a string + call_coded[28] = 0x00; + call_coded[27] = (short int) ((code_sum & 0x01) + 0x30); + for (i = 26; i >= 0; i--) + { + code_sum = code_sum >> 1; + call_coded[i] = (short int)((code_sum & 0x01) + 0x30); + } +} // end of pack_callsign + +//*************************************************** +void generate_crc(char *datas, char *crc, int length) +//*************************************************** +{ + unsigned int i, j, k; + char buffer[52]; //strlen(datas)]; + short int wcrc[16] = {0}, byte1 = 0, byte2 = 0; + +#ifdef __VCpp__ + strcpy_s(buffer, 52, datas);// strcpy(buffer, datas); +#else + strcpy(buffer, datas);// strcpy(buffer, datas); +#endif + if (DEBUG) + print_str("buffer_crc = ", buffer); + + for (i = 0; i < strlen(datas); i++) + { + for (j = 0; j < 8; j++) + { + if (j > 0) buffer[i] = buffer[i] >> 1; + byte1 = buffer[i] & 0x01; + byte2 = byte1 ^ wcrc[0]; + wcrc[0] = byte2 ^ wcrc[1]; + for (k = 1; k < 13; k++) + wcrc[k] = wcrc[k+1]; + wcrc[13] = byte2 ^ wcrc[14]; + wcrc[14] = wcrc[15]; + wcrc[15] = byte2; + } + } + + + // if msb byte crc = 0 then value at 27 + byte2 = 0; + for (i = 0; i < 8; i++) +#ifdef __VCpp__ // add for Visual C++ by 7L1RLL 11/07/2015 + byte2 = byte2 + (short) wcrc[i] * pow((double)2.0, (int)i); +#else + byte2 = byte2 + wcrc[i] * pow(2, i); +#endif + if (byte2 == 0) byte2 =27; + + // if lsb byte crc = 0 then value at 43 + byte1 = 0; + for (i = 8; i < 16; i++) +#ifdef __VCpp__ + byte1 = byte1 + (short) (wcrc[i] * (double)pow(2.0, (int)i - 8)); // add cast by 7L1RLL +#else + byte1 = byte1 + (wcrc[i] * pow(2, i - 8)); +#endif + if (byte1 == 0) byte1 = 43; + if (DEBUG) printf("byte1 = %x, byte2 = %x\n", byte1, byte2); + + // merge crc into a string + for (i = 0; i < 8; i++) + { + if (i > 0) byte2 = byte2 >> 1; + wcrc[7 - i] = byte2 & 0x01; + + if ( i > 0) byte1 = byte1 >> 1; + wcrc[15 - i] = byte1 & 0x01; + } + if (length > 16) length = 16; + for (i = 16 - length; i < 16; i++) + crc[i - (16 - length)] = wcrc[i] + 0x30; + crc[length] = 0x00; +} // end of genarate_crc + +//********************************************* +void add_crc16(char * call_coded, char *vector) +//********************************************* +{ // input: |28 bits|, output : |51 bits| + char crc1[17] = "", crc2[4] = ""; + +#ifdef __VCpp__ // for wide character compiler + char temp[52] = ""; + + _tsetlocale(LC_ALL, _T("")); //Change Unicode to OS-Default locale + + if (DEBUG) + print_str("call_coded in add CRC16 =", call_coded); + strcpy_w(temp, call_coded, 28); // 28 bit + if (DEBUG) + print_str("temp in add CRC16=", temp); + generate_crc(call_coded, crc1, 16); + if (DEBUG) + print_str("crc1 =", crc1); + strcat_w(temp, crc1, 28, 16); // 28 + 16 = 44 + generate_crc( temp, crc2, 3); + if (DEBUG) + print_str("crc2 =", crc2); +#else // PIC C compiler using ASCII +// char crc1[17] = "", crc2[4] = ""; + generate_crc(call_coded, crc1, 16); + if (DEBUG) printf("crc1 =%s\n", crc1); + generate_crc(strcat(call_coded, crc1), crc2, 3); + if (DEBUG) printf("crc2 =%s\n", crc2); +#endif + // |4 bits sync| + |28 bits call| + |19 bit crc| +#ifdef __VCpp__ + strcpy_w(vector, "0000", 4); // 4 + strcat_w(vector, temp, 4, 44); // 4 + 44 = 48 + strcat_w(vector, crc2, 48, 3); // 48 + 3 = 51 +#else // not VC++ ex : PIC + strcpy(vector, "0000"); // 4 + strcat(vector, call_coded); // 4 + 44 = 48 + strcat(vector, crc2); // 48 + 3 = 51 +#endif +} // end of add_crc16 + +//************************************************** +void scramble(char *vector, short int *vector_to_tx) +//************************************************** +{ // encoding |51 bits| + int i=0; + + for (i = 0; i < 51; i++) + { + vector_to_tx[i] = vector[i] & 0x01; + // convert ASCII to binary + vector_to_tx[i] = vector_to_tx[i] ^ pseudo_sequence[i]; + } +} // end of scrambling + +//************************************************************************* +void Walsh_Hammered_code(short int *vector_to_tx, short int *symbol_coding) +//************************************************************************* +{ // order 8 walsh matrix codification : |119 bits| + int data = 0, idx = 0, i = 0, j = 0; + + for (i = 0; i < 51; i += 3) + { + data = 0; + for (j = 0; j < 3; j++) + data = data + (vector_to_tx[i + j] << (2 - j)); + for (j = 0; j < 7; j++) + { + symbol_coding[idx] = walsh_matrix[data][j]; + idx++; + } + } +} //end of Walsh_Hammered_code + +//*********************************************************************** +void interleave(short int *symbol_coding, short int *symbol_interleaving) +//*********************************************************************** +{ // interleaving : |119 bits| + int idx = 0, i = 0, j = 0; + + idx = 0; + for (i = 0; i < 7; i++) + { + for (j = i; j < 119; j += 7) + { + symbol_interleaving[idx]= symbol_coding[j]; + idx++; + } + } +} // end of interleave + +//********************************************************************** +void ManchesterEncode(short int *symbol_interleaving, short int *symbol) +//********************************************************************** +{ // manchester codification : |11| + |238 bits| - |1 bit| modified by 7L1RLL 11/07/2015 + int idx = 0; + int i = 0, j = 0; + + symbol[0] = 1; + for (i = 0; i < 119; i++) + { + if (symbol_interleaving[i] == 0) + { + symbol[idx + 1] = 1; + symbol[idx + 2] = 0; + } + else + { + symbol[idx + 1] = 0; + symbol[idx + 2] = 1; + } + idx += 2; + } +} // end of Manchester_encode + +//*************** +void print_help() +//*************** +{ + printf("%s\n","Usage : OPERA_Coding_Test [? | s | [d \"callsign\"]]"); + printf("%s\n"," Normal : OPERA_Coding_Test \"callsign\""); + printf("%s\n"," Help : OPERA_Coding_Test ?"); + printf("%s\n"," Sample : OPERA_Coding_Test s"); + printf("%s\n"," Debug : OPERA_Coding_Test d \"callsign\""); + printf("%s\n"," Callsign format shall be like \"AA1AAA\". "); + printf("%s\n"," Third character mast be a numeric character(0..9)."); +} // end of help + +//******************************************************************** +void print_short_int(const char *caption, short int *code, int length) +//******************************************************************** +{ // This is service function for debugging + int i = 0; + + printf("%s\n", caption); + for (i = 0; i < length; i++) + { + printf("%d", code[i]); + if (((i+1) % 4) == 0) printf(" "); + if (((i+1) % 40) == 0) printf("\n"); + } + printf("\n"); +} // end fo print_short_int + + +void encodepitx(short int *code, int length,float Nop) +{ + int i = 0; + int j=0; + /*and each of the +239 symbols are transmitted by keying the transmitter as CW on and off with a symbol +rate of 0.256*n s/symbol, where n is the integer of operation mode OPn that corresponds +with the Opera frequency recommendation: */ + //WriteTone(1*32767,1e6*(256*Nop)); + WriteTone(1*32767,1e6*(256*Nop)); + for (i = 0; i < length-1; i++) + { + //for(j=0;j<1000;j++) + WriteTone(code[i]*32767,1e6*(256*Nop)); //AM + //WriteTone(code[i]*100000,1e6*(256*Nop)); //FM + } +} + + +//******************************************************************** +void print_str(const char * caption, char * code) +//******************************************************************** +{ // This is a service function for debugging + int i = 0; + + printf("%s\n", caption); + for (i = 0; i < strlen(code); i++) + { + printf("%c", code[i]); + if (((i + 1) % 4) == 0) printf(" "); + if (((i + 1) % 40) == 0) printf("\n"); + } + printf("\n"); +} // end fo print_str +//******************************************************* +void strcpy_w(char * s1, char * s2, int length) +//******************************************************* +{ + int i; + + for (i = 0; i < length; i++) + s1[i] = s2[i]; + s1[length] = 0x00; +} // end of strcpy_w + +//**************************************************************** +void strcat_w(char * s1, char * s2, int lenS1, int lenS2) +//**************************************************************** +{ + int i; - for(j=0;j!=8;j++) - crc = crc&1 ? (crc>>1) ^ 0xa001 : crc>>1; - } - // replace, swap and store crc in msg[32..48] - crc = crc&0xff00 ? ( crc&0x00ff ? crc : 0x001b|(crc&0xff00) ) : 0x2b00|(crc&0x00ff); - crc = ((crc&0x00ff)<<8); // amp="amp" crc="crc" xff00="xff00">>8); - return crc; -} + for (i = 0; i < lenS2; i++) + s1[i + lenS1] = s2[i]; + s1[lenS1 + lenS2]= 0x00; -int main(int argc, const char* argv[]){ - if(argc != 2){ - printf("usage: opera [callsign]\n"); - return 0; - } - const char* call = argv[1]; - char msg[239]; - int i,j; - - char c[]=" "; //align last prefix digit at c[2] and fill gaps with blanks - int aligned = isdigit(call[2]); - strncpy(aligned ? c : &c[1], call, aligned ? 6 : 5); - //strupr(c); To implement : for now warning, should be in CAPITAL - - unsigned long n1=(c[0]>='0'&&c[0]<='9'?c[0]-'0'+27:c[0]==' '?0:c[0]-'A'+1); // packing call e.g. " K1JT ", "AA1AA " into n1 - n1=36*n1+(c[1]>='0'&&c[1]<='9'?c[1]-'0'+26:c[1]-'A'); - n1=10*n1+c[2]-'0'; - n1=27*n1+(c[3]==' '?0:c[3]-'A'+1); - n1=27*n1+(c[4]==' '?0:c[4]-'A'+1); - n1=27*n1+(c[5]==' '?0:c[5]-'A'+1); - itoa(n1, 28, &msg[4], 2); //msg[4..32] = binary representation n1 in ASCII - itoa(crc16op(&msg[4], 28), 16, &msg[32], 2); //store bin-crc of msg[4..31] in msg[32..47] - itoa(crc16op(&msg[4], 28+16) & 0x07, 3, &msg[48], 2); //store bin-crc of msg[4..47] in msg[48..51] - msg[0]=msg[1]=msg[2]=msg[3]='0'; //unused bits msg[0-3] - - const char* prn_vec = "111000010101011111100110110100000001100100010101011"; - for(i=0; i!=51; i++) //scramble - msg[i] = ((msg[i]-'0') ^ (prn_vec[i]-'0')) +'0'; - - const char* wh[] = {"0000000", "1010101", "0110011", "1100110", "0001111", "1011010", "0111100", "1101001"}; - for(i=(51/3)-1; i>=0; i--){ // Walsh-Hadamard encoding to msg[0..118] - char b = (msg[i*3+0]-'0')*4+(msg[i*3+1]-'0')*2+(msg[i*3+2]-'0')*1; - for(j=0; j!=7;j++) - msg[i*7+j] = wh[b][j]; - } - - for(i=0; i!=7; i++) // interleave 7x17 to msg[121..240] - for(j=0; j!=17; j++) - msg[121+j+17*i] = msg[i+7*j]; - - for(i=0; i!=119; i++){ // Manchester encoding to msg[2..120] - msg[2*i+1+2] = msg[121+i]; - msg[2*i+0+2] = (msg[2*i+1+2] == '0') + '0'; - } - msg[0] = msg[1] ='1'; // head - msg[239] = '\0'; // tail - - printf("message=%s symbols=%s\n", c, msg); -} +} // end of strcat_w() +//************** End of Program ********************************