Opera for rpitx

dev
F5OEO 2017-05-03 09:07:33 +00:00
rodzic d1144e3e07
commit 26675b5bf1
1 zmienionych plików z 508 dodań i 73 usunięć

Wyświetl plik

@ -1,80 +1,515 @@
#include <math.h>
#include <stdio.h>
#include <string.h>
//******************************************************************************
// 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 <locale.h>
//#include <tchar.h>
#include "stdio.h"
#include "string.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#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 ********************************