Files
vt1200/harness/udpstream/frame_parse.c
T

112 lines
3.2 KiB
C

/*
* frame_parse.c -- receive-side frame check for the VT1200 video stream.
*
* fp_parse() answers one question: is the block of bytes the transport just
* delivered a complete, uncorrupted frame of the format frame.py writes? It
* checks, in this order, the length bound, the magic and version, and finally
* the CRC -- the CRC is the expensive part, so a truncated or foreign frame is
* rejected before it is computed.
*
* The CRC is CCITT-FALSE (polynomial 0x1021, initial value 0xFFFF, no input or
* output reflection, no final xor), the same one frame.py implements with a
* 256-entry table. It covers header bytes 0..11 followed by the payload; the
* stored crc16 at offset 12 is never part of its own input.
*
* This file is compiled twice: by the 1987 TI C compiler inside the payload
* build (build-stream.sh stages it as FRMPSR.C) and by the host cc for
* tests/test_frame_parse.c. So it is K&R C -- no prototypes in definitions,
* no declarations after statements, no '//', no 'const' -- and it must not
* assume a 32-bit int beyond the fields it masks.
*/
#include "frmpsr.h"
/*
* One byte through the CRC, bit by bit. frame.py builds a table from the
* identical loop; that is the whole reason this is written the long way, so
* the two can be compared line for line.
*/
static unsigned int fp_crc_byte(crc, byte)
unsigned int crc;
unsigned int byte;
{
int i;
crc = (crc ^ ((byte & 0xFF) << 8)) & 0xFFFF;
for (i = 0; i < 8; i++) {
if (crc & 0x8000) {
crc = ((crc << 1) ^ 0x1021) & 0xFFFF;
} else {
crc = (crc << 1) & 0xFFFF;
}
}
return crc;
}
/* Fold len bytes at buf into crc. */
static unsigned int fp_crc_add(crc, buf, len)
unsigned int crc;
unsigned char *buf;
unsigned int len;
{
unsigned int i;
for (i = 0; i < len; i++) {
crc = fp_crc_byte(crc, buf[i]);
}
return crc;
}
/*
* int fp_parse(unsigned char *buf, unsigned int len, fp_header *out)
*
* See frame_parse.h for the contract. A NULL buffer or header is a rejection
* rather than a crash: the payload calls this with a pointer it published
* itself, and a zero there means "no slot yet".
*/
int fp_parse(buf, len, out)
unsigned char *buf;
unsigned int len;
fp_header *out;
{
unsigned int plen, stored, crc;
if (buf == 0 || out == 0) {
return 0;
}
if (len < FP_HEADER_SIZE) {
return 0;
}
if (buf[0] != FP_MAGIC0 || buf[1] != FP_MAGIC1) {
return 0;
}
if (buf[2] != FP_VERSION) {
return 0;
}
plen = (unsigned int) buf[6] | ((unsigned int) buf[7] << 8);
/*
* Subtracting rather than adding: plen can be 0xFFFF, and
* FP_HEADER_SIZE + plen would still fit a 32-bit unsigned int but not a
* 16-bit one. len is known to be at least FP_HEADER_SIZE here.
*/
if (len - FP_HEADER_SIZE < plen) {
return 0;
}
stored = ((unsigned int) buf[FP_CRC_OFF + 1] << 8)
| (unsigned int) buf[FP_CRC_OFF];
crc = fp_crc_add(0xFFFF, buf, FP_PREFIX_SIZE);
crc = fp_crc_add(crc, buf + FP_HEADER_SIZE, plen);
if (crc != stored) {
return 0;
}
out->kind = (unsigned int) buf[3];
out->frame_no = (unsigned int) buf[4] | ((unsigned int) buf[5] << 8);
out->payload_len = plen;
out->rows = (unsigned int) buf[8];
out->stretch = (unsigned int) buf[9];
out->payload_off = FP_HEADER_SIZE;
return 1;
}