horusdemodlib/src/drs232.c

236 wiersze
6.8 KiB
C

/*---------------------------------------------------------------------------*\
FILE........: drs232.c
AUTHOR......: David Rowe
DATE CREATED: March 2016
Looks for a unique word in series of bits. When found, deframes a RS232
encoded frame of bytes. Used for high bit rate Horus SSTV reception.
Frame format:
16 bytes 0x55 - 0xabcdef01 UW - 256 bytes of payload - 2 bytes CRC
Each byte is encoded as a 10 bit RS232 serial word:
0 LSB .... MSB 1
Building:
$ gcc drs232.c -o drs232 -Wall
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2016 David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. 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 for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
/* states -----------------------------------------------*/
#define LOOK_FOR_UW 0
#define COLLECT_PACKET 1
/* packet parameters */
#define UW_BYTES 4
#define UW_BITS 40
#define UW_ALLOWED_ERRORS 5
#define BYTES_PER_PACKET 256
#define CRC_BYTES 2
#define BITS_PER_BYTE 10
#define UNPACKED_PACKET_BYTES ((UW_BYTES+BYTES_PER_PACKET+CRC_BYTES)*BITS_PER_BYTE)
/* UW pattern we look for, including start/stop bits */
uint8_t uw[] = {
/* 0xb 0xa */
0, 1, 1, 0, 1, 0, 1, 0, 1, 1,
/* 0xd 0xc */
0, 1, 0, 1, 1, 0, 0, 1, 1, 1,
/* 0xf 0xe */
0, 1, 1, 1, 1, 0, 1, 1, 1, 1,
/* 0x1 0x0 */
0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
};
// from http://stackoverflow.com/questions/10564491/function-to-calculate-a-crc16-checksum
unsigned short gen_crc16(unsigned char* data_p, int length){
unsigned char x;
unsigned short crc = 0xFFFF;
while (length--){
x = crc >> 8 ^ *data_p++;
x ^= x>>4;
crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x <<5)) ^ ((unsigned short)x);
}
return crc;
}
int main(int argc, char *argv[]) {
FILE *fin, *fout;
int state, next_state, i, j, k, ind, score, bits_read;
char bit;
uint8_t unpacked_packet[UNPACKED_PACKET_BYTES];
uint8_t packet[BYTES_PER_PACKET+CRC_BYTES];
uint8_t abyte;
uint16_t tx_checksum, rx_checksum;
int verbose, packet_errors, packets;
if (argc < 3) {
fprintf(stderr, "usage: drs232 InputOneBitPerChar OutputPackets [-v[v]]\n");
exit(1);
}
if (strcmp(argv[1], "-") == 0) fin = stdin;
else if ( (fin = fopen(argv[1],"rb")) == NULL ) {
fprintf(stderr, "Error opening input file: %s: %s.\n",
argv[1], strerror(errno));
exit(1);
}
if (strcmp(argv[2], "-") == 0) fout = stdout;
else if ( (fout = fopen(argv[2],"wb")) == NULL ) {
fprintf(stderr, "Error opening output file: %s: %s.\n",
argv[2], strerror(errno));
exit(1);
}
verbose = 0;
if (argc > 3) {
if (strcmp(argv[3], "-v") == 0) {
verbose = 1;
}
if (strcmp(argv[3], "-vv") == 0) {
verbose = 2;
}
}
state = LOOK_FOR_UW;
for(i=0; i<UNPACKED_PACKET_BYTES; i++)
unpacked_packet[i] = 0;
bits_read = 0;
packet_errors = packets = 0;
while(fread(&bit, sizeof(char), 1, fin) == 1) {
bits_read++;
next_state = state;
if (state == LOOK_FOR_UW) {
/* put latest input bit into sliding buffer */
for(i=0; i<UW_BITS-1; i++) {
unpacked_packet[i] = unpacked_packet[i+1];
}
unpacked_packet[i] = bit;
/* lets see if it matches the UW */
score = 0;
for(i=0; i<UW_BITS; i++) {
score += (unpacked_packet[i] == uw[i]);
/* if (i == BITS_PER_BYTE)
printf(" ");
printf("%1d", unpacked_packet[i]); */
}
//printf("\n");
//fprintf(stderr,"UW score: %d\n", score);
if (score > (UW_BITS-UW_ALLOWED_ERRORS)) {
if (verbose == 2) {
fprintf(stderr,"UW found!\n");
}
ind = UW_BITS;
next_state = COLLECT_PACKET;
}
}
if (state == COLLECT_PACKET) {
unpacked_packet[ind++] = bit;
if (ind == UNPACKED_PACKET_BYTES) {
/* OK we have enough bits, remove RS232 sync bits and pack */
for(i=UW_BITS,k=0; i<UNPACKED_PACKET_BYTES; i+=BITS_PER_BYTE,k++) {
//for(j=0; j<BITS_PER_BYTE; j++)
// printf("%1d", unpacked_packet[i+j]);
//printf("\n");
abyte = 0;
for(j=0; j<8; j++) {
abyte |= unpacked_packet[i+j+1] << j;
}
packet[k] = abyte;
//printf("k:%d 0x%02x\n", k, packet[k]);
//if (k == 4)
// exit(0);
}
/* output if CRC check is OK */
rx_checksum = gen_crc16(packet, BYTES_PER_PACKET);
tx_checksum = packet[BYTES_PER_PACKET] + (packet[BYTES_PER_PACKET+1] << 8);
if (verbose == 2) {
fprintf(stderr, "k=%d bytes after UW tx_checksum: 0x%02x rx_checksum: 0x%02x\n",
k, tx_checksum, rx_checksum);
}
packets++;
if (rx_checksum == tx_checksum) {
fwrite(packet, sizeof(char), BYTES_PER_PACKET, fout);
}
else
packet_errors++;
if (verbose) {
fprintf(stderr, "packets: %d packet_errors: %d PER: %4.3f\n",
packets, packet_errors,
(float)packet_errors/packets);
}
next_state = LOOK_FOR_UW;
}
}
//if (bits_read == (16*10 + UNPACKED_PACKET_BYTES))
// exit(0);
state = next_state;
}
fclose(fin);
fclose(fout);
fprintf(stderr, "packets: %d packet_errors: %d PER: %4.3f\n", packets, packet_errors,
(float)packet_errors/packets);
return 0;
}