PKT Encoder: Add Support for libsndfile .wav output and float symbol output files compatible with packet decoder; Fix terminating byte inclusion;

README to include mentions for m17-fme and cross compatibility use;
pull/26/head
lwvmobile 2024-06-10 03:52:33 -04:00
rodzic 3bfe8ae61d
commit 1de9d711eb
5 zmienionych plików z 224 dodań i 16 usunięć

5
.gitignore vendored
Wyświetl plik

@ -5,3 +5,8 @@
/SP5WWP/m17-packet/m17-packet-decode
/SP5WWP/.vscode
*.json
*.rrc
*.wav
*.bin
*.sym
*.patch

Wyświetl plik

@ -12,6 +12,12 @@ Written in C, it has all the components described by the protocol's specificatio
There's no support for **any** encryption yet.
### Cloning
Be sure to clone with `--recursive` to pull the linked libm17 repository, otherwise, building will fail.
```
git clone https://github.com/M17-Project/M17_Implementations.git --recursive
```
### Building
First, build the shared object `libm17.so`:
```
@ -76,19 +82,91 @@ Packet encoding is available with `m17-packet-encoder`. Its input parameters are
-x - binary output (M17 baseband as a packed bitstream)
-r - raw audio output - default (single channel, signed 16-bit LE, +7168 for the +1.0 symbol, 10 samples per symbol)
-s - signed 16-bit LE symbols output
-f - float symbols output compatible with m17-packet-decode
-d - raw audio output - same as -r, but no RRC filtering (debug)
-w - libsndfile wav audio output - default (single channel, signed 16-bit LE, +7168 for the +1.0 symbol, 10 samples per symbol)
```
Input data is passed over stdin. Example command:
`echo -en "\x05Testing M17 packet mode." | ./m17-packet-encode -S N0CALL -D ALL -C 0 -n 25 -o baseband.rrc`
`echo -en "\x05Testing M17 packet mode." | ./m17-packet-encode -S N0CALL -D ALL -C 0 -n 25 -f -o baseband.sym`
`-en` parameter for `echo` suppresses the trailing newline character and enables the use of `\` within the message.
`\x05` sets the packet data content and stands for text message (as per M17 Specification document, chapter 3.2 - Packet Application).
If a WAVE file format is required for the baseband, sox can be used:
`sox -t raw -r 48000 -b 16 -c 1 -L -e signed-integer baseband.rrc baseband.wav`
Output:
This line converts .rrc to .wav. SDRangel successfully decoding a packet:
![SDRangel screen dump](https://github.com/M17-Project/M17_Implementations/assets/44336093/d2cd195c-6126-4b48-b516-36d20dced9ce)
```
DST: ALL FFFFFFFFFFFF
SRC: N0CALL 00004B13D106
Data CRC: BFEC
LSF CRC: 432A
FN:00 (full frame)
0554657374696E67204D3137207061636B6574206D6F64652E00
FN:-- (ending frame)
00BFEC0000000000000000000000000000000000000000000084
FULL: 0554657374696E67204D3137207061636B6574206D6F64652E00BFEC
SMS: Testing M17 packet mode.
```
The two characters at the end of the message are probably CRC bytes erroneously decoded by SDRangel as a part of the text message.
Decode packet created with above sample:
`cat baseband.sym | ./m17-packet-decode`
Output:
```
DST: FFFFFFFFFFFF SRC: 00004B13D106 TYPE: 0002 META: 0000000000000000000000000000 LSF_CRC_OK
Testing M17 packet mode.
```
Encode directly as wav format (skip sox):
`echo -en "\x05Testing M17 packet mode." | ./m17-packet-encode -S N0CALL -D AB1CDE -C 7 -n 25 -w -o baseband.wav`
Output:
```
DST: AB1CDE 00001F245D51
SRC: N0CALL 00004B13D106
Data CRC: BFEC
LSF CRC: F754
FN:00 (full frame)
0554657374696E67204D3137207061636B6574206D6F64652E00
FN:-- (ending frame)
00BFEC0000000000000000000000000000000000000000000084
FULL: 0554657374696E67204D3137207061636B6574206D6F64652E00BFEC
SMS: Testing M17 packet mode.
```
Decode with M17-FME:
`m17-fme -r -w baseband.wav -v 1`
Output:
```
M17 Project - Florida Man Edition
Build Version: 2024-1-g4f2c15c
Session Number: A4F5
M17 Project RF Audio Frame Demodulator.
SNDFile (.wav, .rrc) Input File: baseband.wav
Payload Verbosity: 1;
M17 LSF Frame Sync (08:57:09):
DST: AB1CDE SRC: N0CALL CAN: 7; Data Packet
LSF: 00 00 1F 24 5D 51 00 00 4B 13 D1 06 03 82 00
00 00 00 00 00 00 00 00 00 00 00 00 00 F7 54
(CRC CHK) E: F754; C: F754;
M17 PKT Frame Sync (08:57:09): CNT: 00; PBC: 00; EOT: 0;
pkt: 0554657374696E67204D3137207061636B6574206D6F64652E00
M17 PKT Frame Sync (08:57:09): CNT: 01; LST: 01; EOT: 1;
pkt: 00BFEC0000000000000000000000000000000000000000000084 Protocol: SMS;
SMS: Testing M17 packet mode.
PKT: 05 54 65 73 74 69 6E 67 20 4D 31 37 20 70 61 63 6B 65 74 20 6D 6F 64 65 2E
00 BF EC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
(CRC CHK) E: BFEC; C: BFEC;
M17 No Frame Sync (08:57:09):
```

Wyświetl plik

@ -1,10 +1,10 @@
all: m17-packet-encode m17-packet-decode
m17-packet-encode: m17-packet-encode.c
gcc -I ../../libm17 -O2 -Wall -Wextra m17-packet-encode.c -o m17-packet-encode -lm -lm17
gcc -I ../../libm17 -O2 -Wall -Wextra m17-packet-encode.c -o m17-packet-encode -lm -lm17 -lsndfile
m17-packet-decode: m17-packet-decode.c
gcc -I ../../libm17 -O2 -Wall -Wextra m17-packet-decode.c -o m17-packet-decode -lm -lm17
gcc -I ../../libm17 -O2 -Wall -Wextra m17-packet-decode.c -o m17-packet-decode -lm -lm17 -lsndfile
install: all
sudo install m17-packet-encode /usr/local/bin

Wyświetl plik

@ -207,7 +207,7 @@ int main(int argc, char* argv[])
{
uint16_t p_len=strlen((const char*)packet_data);
uint16_t p_crc=CRC_M17(packet_data, p_len+1);
//fprintf(stderr, "rx=%02X%02X calc=%04X", packet_data[p_len+1], packet_data[p_len+2], p_crc);
fprintf(stderr, "Data CRC: rx=%02X%02X calc=%04X\n ", packet_data[p_len+1], packet_data[p_len+2], p_crc);
if(p_crc==(uint16_t)packet_data[p_len+1]*256+(uint16_t)packet_data[p_len+2])
{
fprintf(stderr, "%s\n", &packet_data[1]);

Wyświetl plik

@ -3,6 +3,7 @@
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <sndfile.h>
//libm17
#include <m17.h>
@ -11,6 +12,11 @@
struct LSF lsf;
char wav_name[1024]; //name of wav file to output to
SNDFILE *wav; //sndfile wav file
SF_INFO info; //sndfile parameter struct
int len=3; //number of blocks produced via counter +3 for pre,lsf, and eot marker
uint8_t enc_bits[SYM_PER_PLD*2]; //type-2 bits, unpacked
uint8_t rf_bits[SYM_PER_PLD*2]; //type-4 bits, unpacked
@ -21,7 +27,7 @@ uint16_t num_bytes=0; //number of bytes in
uint8_t fname[128]={'\0'}; //output file
FILE* fp;
float full_packet[6912+88]; //full packet, symbols as floats - (40+40+32*40+40+40)/1000*4800
float full_packet[36*192*10]; //full packet, symbols as floats - 36 "frames" max (incl. preamble, LSF, EoT), 192 symbols each, sps=10:
//pream, LSF, 32 frames, ending frame, EOT plus RRC flushing
uint16_t pkt_sym_cnt=0; //packet symbol counter, used to fill the packet
uint8_t pkt_cnt=0; //packet frame counter (1..32) init'd at 0
@ -30,6 +36,9 @@ uint8_t full_packet_data[32*25]; //full packet data,
uint8_t out_type=0; //output file type - 0 - raw int16 filtered samples (.rrc) - default
// 1 - int16 symbol stream
// 2 - binary stream (TODO)
// 3 - simple 10x upsample no filter
// 4 - SB16-LE RRC filtered wav file
// 5 - float symbol output for m17-packet-decode
//type - 0 - preamble before LSF (standard)
//type - 1 - preamble before BERT transmission
@ -152,6 +161,18 @@ int main(int argc, char* argv[])
{
out_type=2;
}
else if(argv[i][1]=='d') //-d - raw unfiltered output to wav file
{
out_type=3;
}
else if(argv[i][1]=='w') //-w - rrc filtered output to wav file
{
out_type=4;
}
else if(argv[i][1]=='f') //-f - float symbol output
{
out_type=5;
}
else
{
fprintf(stderr, "Unknown param detected. Exiting...\n");
@ -172,6 +193,9 @@ int main(int argc, char* argv[])
//fprintf(stderr, "-x - binary output (M17 baseband as a packed bitstream),\n");
fprintf(stderr, "-r - raw audio output - default (single channel, signed 16-bit LE, +7168 for the +1.0 symbol, 10 samples per symbol),\n");
fprintf(stderr, "-s - signed 16-bit LE symbols output\n");
fprintf(stderr, "-f - float symbols output compatible with m17-packet-decode\n");
fprintf(stderr, "-d - raw audio output - same as -r, but no RRC filtering (debug)\n");
fprintf(stderr, "-w - libsndfile audio output - default (single channel, signed 16-bit LE, +7168 for the +1.0 symbol, 10 samples per symbol),\n");
return -1;
}
@ -199,6 +223,7 @@ int main(int argc, char* argv[])
fprintf(stderr, "Packet data too short. Exiting...\n");
return -1;
}
num_bytes++; //increment by one to include the terminating byte
uint16_t packet_crc=CRC_M17(full_packet_data, num_bytes);
full_packet_data[num_bytes] =packet_crc>>8;
full_packet_data[num_bytes+1]=packet_crc&0xFF;
@ -231,13 +256,13 @@ int main(int argc, char* argv[])
uint16_t lsf_crc=LSF_CRC(&lsf);
lsf.crc[0]=lsf_crc>>8;
lsf.crc[1]=lsf_crc&0xFF;
fprintf(stderr, "LSF CRC:\t%04hX\n", lsf_crc);
fprintf(stderr, "LSF CRC:\t%04hX\n", lsf_crc);
//encode LSF data
conv_encode_LSF(enc_bits, &lsf);
//fill preamble
memset((uint8_t*)full_packet, 0, sizeof(float)*(6912+88));
memset((uint8_t*)full_packet, 0.0f, 36*192*10*sizeof(float));
fill_preamble(full_packet, 0);
pkt_sym_cnt=SYM_PER_FRA;
@ -344,15 +369,36 @@ int main(int argc, char* argv[])
num_bytes=tmp; //bring back the num_bytes value
//fprintf(stderr, "DATA: %s\n", full_packet_data);
fprintf (stderr, "FULL: ");
for(uint8_t i=0; i<tmp; i++)
{
fprintf (stderr, "%02X", full_packet_data[i]);
}
fprintf(stderr, "\n");
fprintf(stderr, " SMS: %s\n", full_packet_data);
//send EOT
for(uint8_t i=0; i<SYM_PER_FRA/SYM_PER_SWD; i++) //192/8=24
fill_syncword(full_packet, &pkt_sym_cnt, EOT_MRKR);
//dump baseband to a file
fp=fopen((const char*)fname, "wb");
if (out_type == 3 || out_type == 4) //open wav file out
{
sprintf (wav_name, "%s", fname);
info.samplerate = 48000;
info.channels = 1;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
wav = sf_open (wav_name, SFM_WRITE, &info); //write only, no append
if (wav == NULL)
{
fprintf (stderr,"Error - could not open raw wav output file %s\n", wav_name);
return -1;
}
}
else //dump baseband to a file
fp=fopen((const char*)fname, "wb");
//debug mode - symbols multiplied by 7168 scaling factor
/*for(uint16_t i=0; i<pkt_sym_cnt; i++)
{
@ -402,7 +448,86 @@ int main(int argc, char* argv[])
}
}
fclose(fp);
//float symbol stream compatible with m17-packet-decode
else if(out_type==5)
{
for(uint16_t i=0; i<pkt_sym_cnt; i++)
{
float val=full_packet[i];
fwrite(&val, 4, 1, fp);
}
}
//simple 10x upsample * 7168.0f
else if (out_type == 3)
{
//array of upsample full_packet
float up[1920*35]; memset (up, 0, 1920*35*sizeof(float));
//10x upsample from full_packet to up
for (int i = 0; i < 192*len; i++)
{
for (int j = 0; j < 10; j++)
up[(i*10)+j] = full_packet[i];
}
//array of shorts for sndfile wav output
short bb[1920*35]; memset (bb, 0, 1920*35*sizeof(short));
//write dead air to sndfile wav
sf_write_short(wav, bb, 1920);
//load bb with upsample, use len to see how many we need to send
for (int i = 0; i < 1920*len; i++)
bb[i] = (short)(up[i] * 7168.0f);
//write to sndfile wav
sf_write_short(wav, bb, 1920*len);
}
//standard mode - filtered baseband (converted to wav)
else if(out_type == 4)
{
float mem[FLT_LEN];
float mac=0.0f;
memset((uint8_t*)mem, 0, FLT_LEN*sizeof(float));
for(uint16_t i=0; i<pkt_sym_cnt; i++)
{
//push new sample
mem[0]=full_packet[i]*RRC_DEV;
for(uint8_t j=0; j<10; j++)
{
mac=0.0f;
//calc the sum of products
for(uint16_t k=0; k<FLT_LEN; k++)
mac+=mem[k]*rrc_taps_10[k]*sqrtf(10.0); //temporary fix for the interpolation gain error
//shift the delay line right by 1
for(int16_t k=FLT_LEN-1; k>0; k--)
{
mem[k]=mem[k-1];
}
mem[0]=0.0f;
//write to file
short tmp[2]; tmp[0]=mac;
sf_write_short(wav, tmp, 1);
}
}
}
//close file, depending on type opened
if (out_type == 3 || out_type == 4)
{
sf_write_sync(wav);
sf_close(wav);
}
else fclose(fp);
return 0;
}