From 565a5f35eb3a83d005ac8b04a06bb972c9ecac65 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Mon, 14 Apr 2014 21:03:22 +0200 Subject: [PATCH] Compression tested over the air --- Modem/compression/heatshrink_encoder.c | 2 +- Modem/config.h | 4 +- Modem/hardware.c | 2 +- Modem/main.c | 124 ++----------------------- Modem/protocol/mp1.c | 114 +++++++++++++++++++++-- Modem/protocol/mp1.h | 13 +++ buildrev.h | 2 +- 7 files changed, 134 insertions(+), 127 deletions(-) diff --git a/Modem/compression/heatshrink_encoder.c b/Modem/compression/heatshrink_encoder.c index 6772c8a..54d6e79 100644 --- a/Modem/compression/heatshrink_encoder.c +++ b/Modem/compression/heatshrink_encoder.c @@ -92,7 +92,7 @@ heatshrink_encoder *heatshrink_encoder_alloc(uint8_t window_sz2, * will be scanned for useful backreferences. */ size_t buf_sz = (2 << window_sz2); - kprintf("Trying to allocate: %d\n", buf_sz); + //kprintf("Trying to allocate: %d\n", buf_sz); heatshrink_encoder *hse = HEATSHRINK_MALLOC(sizeof(*hse) + buf_sz); if (hse == NULL) { return NULL; } hse->window_sz2 = window_sz2; diff --git a/Modem/config.h b/Modem/config.h index 35ff42e..56c07c5 100644 --- a/Modem/config.h +++ b/Modem/config.h @@ -11,7 +11,7 @@ #define CONFIG_AFSK_RXTIMEOUT 0 // How long a read operation from the modem // will wait for data before timing out. -#define CONFIG_AFSK_PREAMBLE_LEN 10UL // The length of the packet preamble in milliseconds -#define CONFIG_AFSK_TRAILER_LEN 2UL // The length of the packet tail in milliseconds +#define CONFIG_AFSK_PREAMBLE_LEN 250UL // The length of the packet preamble in milliseconds +#define CONFIG_AFSK_TRAILER_LEN 20UL // The length of the packet tail in milliseconds #endif \ No newline at end of file diff --git a/Modem/hardware.c b/Modem/hardware.c index 1102b85..9714e37 100644 --- a/Modem/hardware.c +++ b/Modem/hardware.c @@ -19,7 +19,7 @@ static Afsk *modem; // M1 correction = 9500 // M2 correction = 40000 -#define FREQUENCY_CORRECTION 9500 +#define FREQUENCY_CORRECTION 40000 // This function initializes the ADC and configures // it the way we need. diff --git a/Modem/main.c b/Modem/main.c index 5e349ac..14a46dd 100644 --- a/Modem/main.c +++ b/Modem/main.c @@ -15,8 +15,6 @@ #include "afsk.h" // Header for AFSK modem #include "protocol/mp1.h" // Header for MP.1 protocol -#include "compression/heatshrink_encoder.h" -#include "compression/heatshrink_decoder.h" ////////////////////////////////////////////////////// // A few definitions // @@ -31,7 +29,7 @@ static Serial ser; // Declare a serial interface struct #define TEST_TX false // Whether we should send test packets // periodically, plus what to send: -#define TEST_PACKET "Test MP1 AFSK Packet. Test123." +#define TEST_PACKET "Packet received. This is an ACK." #define TEST_TX_INTERVAL 10000L @@ -41,114 +39,6 @@ static int serialLen = 0; // Counter for counting length of data from seri static bool sertx = false; // Flag signifying whether it's time to send data // Received on the serial port. -static uint8_t compressedData[MP1_MAX_FRAME_LENGTH]; -static uint8_t decompressedData[MP1_MAX_FRAME_LENGTH]; - - -static int freeRam () { - extern int __heap_start, *__brkval; - int v; - return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); -} - -static size_t compress(uint8_t *input, size_t length) { - heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 4); - if (hse == NULL) { - kprintf("Could not allocate encoder"); - return 0; - } - - size_t written = 0; - size_t sunk = 0; - heatshrink_encoder_sink(hse, input, length, &sunk); - int status = heatshrink_encoder_finish(hse); - - if (sunk < length) { - kprintf("Not all data was sunk into encoder\n"); - heatshrink_encoder_free(hse); - return 0; - } else { - kprintf("Bytes sunk into HSE: %d\n", length); - if (status == HSER_FINISH_MORE) { - heatshrink_encoder_poll(hse, compressedData, MP1_MAX_FRAME_LENGTH, &written); - kprintf("Bytes written into buffer: %d\n", written); - } else { - kprintf("All input data was sunk, but encoder doesn't have any data for us."); - } - } - - heatshrink_encoder_free(hse); - return written; -} - -static size_t decompress(uint8_t *input, size_t length) { - heatshrink_decoder *hsd = heatshrink_decoder_alloc(MP1_MAX_FRAME_LENGTH, 8, 4); - if (hsd == NULL) { - kprintf("Could not allocate decoder"); - return 0; - } - - kprintf("\nDecoder allocated. Free RAM: %d bytes\n", freeRam()); - - size_t written = 0; - size_t sunk = 0; - heatshrink_decoder_sink(hsd, input, length, &sunk); - int status = heatshrink_decoder_finish(hsd); - - if (sunk < length) { - kprintf("Not all data was sunk into decoder\n"); - heatshrink_decoder_free(hsd); - return 0; - } else { - kprintf("Bytes sunk into HSD: %d\n", length); - if (status == HSER_FINISH_MORE) { - heatshrink_decoder_poll(hsd, decompressedData, MP1_MAX_FRAME_LENGTH, &written); - kprintf("Bytes written into decompression buffer: %d\n", written); - } else { - kprintf("All input data was sunk, but the decoder doesn't have any data for us."); - } - } - - heatshrink_decoder_free(hsd); - return written; -} - -static void hseTest() { - kprintf("\nFree RAM: %d bytes\n", freeRam()); - size_t compressed_size = compress(serialBuffer, serialLen); - size_t decompressed_size = decompress(compressedData, compressed_size); - kprintf("\n-------------------\nInput size: %d\nCompressed size: %d\nDecompressed size: %d\n", serialLen, compressed_size, decompressed_size); - - // heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 4); - // kprintf("\nFree RAM: %d bytes\n", freeRam()); - - // size_t out_sz = 50; - // uint8_t out_buf[out_sz]; - // size_t written = 0; - // kprintf("\nFree RAM: %d bytes\n", freeRam()); - - // size_t length = serialLen; - - // heatshrink_encoder_sink(hse, serialBuffer, serialLen, &length); - - - - // int returnv = heatshrink_encoder_finish(hse); - // kprintf("Encoder finish returned: %d\n", returnv); - - // if (length < serialLen) { - // kprintf("Not all data was sunk into encoder\n"); - // } else { - // // All data delivered - // kprintf("Bytes sunk into HSE: %d\n", length); - - // heatshrink_encoder_poll(hse, out_buf, out_sz, &written); - - // kprintf("2: Bytes written into buffer: %d\n", written); - // } - - // heatshrink_encoder_free(hse); -} ////////////////////////////////////////////////////// // And here comes the actual program :) // @@ -159,6 +49,13 @@ static void hseTest() { // Right now it just prints the packet to the serial port. static void mp1Callback(struct MP1Packet *packet) { kfile_printf(&ser.fd, "%.*s\n", packet->dataLength, packet->data); + + // if (false) { + // // strcmp(packet->data, "OZ7TMD") + // timer_delay(300); + // mp1Send(&mp1, TEST_PACKET, sizeof(TEST_PACKET)); + // } + //kprintf("%.*s\n", packet->dataLength, packet->data); } @@ -230,9 +127,8 @@ int main(void) // If we should, pass the buffer to the protocol's // send function. - hseTest(); - // mp1Send(&mp1, serialBuffer, serialLen); - + mp1Send(&mp1, serialBuffer, serialLen); + // Reset the transmission flag and length counter sertx = false; serialLen = 0; diff --git a/Modem/protocol/mp1.c b/Modem/protocol/mp1.c index 39c39b8..b2ef8ff 100644 --- a/Modem/protocol/mp1.c +++ b/Modem/protocol/mp1.c @@ -3,10 +3,14 @@ #include #include +#include "compression/heatshrink_encoder.h" +#include "compression/heatshrink_decoder.h" + // FIXME: Describe these static uint8_t lastByte = 0x00; static bool sendParityBlock = false; + // FIXME: Describe this INLINE bool BIT(uint8_t byte, int n) { return ((byte & BV(n-1))>>(n-1)); } static uint8_t mp1ParityBlock(uint8_t first, uint8_t other) { @@ -39,13 +43,21 @@ static void mp1Decode(MP1 *mp1) { // If header indicates a padded packet, remove // padding - if (header & 0x01) { + if (header & MP1_HEADER_PADDED) { buffer++; } // Set the payload length of the packet to the counted // length minus 1, so we remove the checksum packet.dataLength = mp1->packetLength - 2 - (header & 0x01); + + // Check if we have received a compressed packet + if (header & MP1_HEADER_COMPRESSION) { + size_t decompressedSize = decompress(buffer, packet.dataLength); + packet.dataLength = decompressedSize; + memcpy(buffer, compressionBuffer, decompressedSize); + } + packet.data = buffer; // If a callback have been specified, let's @@ -219,19 +231,37 @@ void mp1Send(MP1 *mp1, const void *_buffer, size_t length) { // Transmit the HDLC_FLAG to signify start of TX kfile_putc(HDLC_FLAG, mp1->modem); + bool packetCompression = false; + size_t compressedSize = compress(buffer, length); + if (compressedSize != 0 && compressedSize < length) { + //kprintf("Using compression\n"); + // Compression saved us some space, we'll + // send the paket compressed + packetCompression = true; + memcpy(buffer, compressionBuffer, compressedSize); + length = compressedSize; + } else { + // We are not going to use compression + } + // Write header and possibly padding // Remember we also write a header and // a checksum. This ensures that we will // always end our packet with a checksum // and a parity byte. + + uint8_t header = 0xf0; + if (packetCompression) header ^= MP1_HEADER_COMPRESSION; + if (length % 2 != 0) { - mp1->checksum_out = mp1->checksum_out ^ 0xf1; - mp1Putbyte(mp1, 0xf1); - mp1->checksum_out = mp1->checksum_out ^ 0x55; - mp1Putbyte(mp1, 0x55); + header ^= MP1_HEADER_PADDED; + mp1->checksum_out = mp1->checksum_out ^ header; + mp1Putbyte(mp1, header); + mp1->checksum_out = mp1->checksum_out ^ MP1_PADDING; + mp1Putbyte(mp1, MP1_PADDING); } else { - mp1->checksum_out = mp1->checksum_out ^ 0xf0; - mp1Putbyte(mp1, 0xf0); + mp1->checksum_out = mp1->checksum_out ^ header; + mp1Putbyte(mp1, header); } // Continously increment the pointer address @@ -256,4 +286,72 @@ void mp1Init(MP1 *mp1, KFile *modem, mp1_callback_t callback) { // a callback for when a packet has been decoded mp1->modem = modem; mp1->callback = callback; -} \ No newline at end of file +} + +int freeRam(void) { + extern int __heap_start, *__brkval; + int v; + return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +} + +size_t compress(uint8_t *input, size_t length) { + heatshrink_encoder *hse = heatshrink_encoder_alloc(8, 4); + if (hse == NULL) { + //kprintf("Could not allocate encoder\n"); + return 0; + } + + size_t written = 0; + size_t sunk = 0; + heatshrink_encoder_sink(hse, input, length, &sunk); + int status = heatshrink_encoder_finish(hse); + + if (sunk < length) { + //kprintf("Not all data was sunk into encoder\n"); + heatshrink_encoder_free(hse); + return 0; + } else { + //kprintf("Bytes sunk into HSE: %d\n", length); + if (status == HSER_FINISH_MORE) { + heatshrink_encoder_poll(hse, compressionBuffer, MP1_MAX_FRAME_LENGTH, &written); + //kprintf("Bytes written into buffer: %d\n", written); + } else { + //kprintf("All input data was sunk, but encoder doesn't have any data for us."); + } + } + + heatshrink_encoder_free(hse); + return written; +} + +size_t decompress(uint8_t *input, size_t length) { + heatshrink_decoder *hsd = heatshrink_decoder_alloc(MP1_MAX_FRAME_LENGTH, 8, 4); + if (hsd == NULL) { + //kprintf("Could not allocate decoder\n"); + return 0; + } + + //kprintf("\nDecoder allocated. Free RAM: %d bytes\n", freeRam()); + + size_t written = 0; + size_t sunk = 0; + heatshrink_decoder_sink(hsd, input, length, &sunk); + int status = heatshrink_decoder_finish(hsd); + + if (sunk < length) { + //kprintf("Not all data was sunk into decoder\n"); + heatshrink_decoder_free(hsd); + return 0; + } else { + //kprintf("Bytes sunk into HSD: %d\n", length); + if (status == HSER_FINISH_MORE) { + heatshrink_decoder_poll(hsd, compressionBuffer, MP1_MAX_FRAME_LENGTH, &written); + //kprintf("Bytes written into decompression buffer: %d\n", written); + } else { + //kprintf("All input data was sunk, but the decoder doesn't have any data for us."); + } + } + + heatshrink_decoder_free(hsd); + return written; +} diff --git a/Modem/protocol/mp1.h b/Modem/protocol/mp1.h index 2f842b0..1c29ce3 100644 --- a/Modem/protocol/mp1.h +++ b/Modem/protocol/mp1.h @@ -14,6 +14,15 @@ #define HDLC_RESET 0x7F #define AX25_ESC 0x1B +// Some further definitions FIXME: +#define MP1_PADDING 0x55 +#define MP1_HEADER_PADDED 0x01 +#define MP1_HEADER_COMPRESSION 0x02 + +// FIXME: describe +//static uint8_t compressedData[MP1_MAX_FRAME_LENGTH-0]; +static uint8_t compressionBuffer[MP1_MAX_FRAME_LENGTH+10]; + // Just a forward declaration that this struct exists struct MP1Packet; @@ -48,4 +57,8 @@ void mp1Read(MP1 *mp1, int byte); void mp1Poll(MP1 *mp1); void mp1Send(MP1 *mp1, const void *_buffer, size_t length); +int freeRam(void); +size_t compress(uint8_t *input, size_t length); +size_t decompress(uint8_t *input, size_t length); + #endif \ No newline at end of file diff --git a/buildrev.h b/buildrev.h index 900630e..c9c7547 100644 --- a/buildrev.h +++ b/buildrev.h @@ -1,2 +1,2 @@ -#define VERS_BUILD 994 +#define VERS_BUILD 1070 #define VERS_HOST "vixen"