From 056fb067a01c89fd9d66901b80868f1e0e35d909 Mon Sep 17 00:00:00 2001 From: Sven Steudte Date: Wed, 6 Sep 2017 22:03:56 +0200 Subject: [PATCH] Implemented grouped APRS packet transmission properly Fixed packet losses (incomplete) --- tracker/software/drivers/ov5640.c | 2 - tracker/software/drivers/pac1720.c | 2 +- tracker/software/protocols/aprs/aprs.c | 47 ++++++++++++++++++++++-- tracker/software/protocols/aprs/aprs.h | 7 +++- tracker/software/protocols/aprs/ax25.c | 6 ++- tracker/software/protocols/aprs/ax25.h | 1 + tracker/software/radio.c | 44 +++++----------------- tracker/software/threads/image.c | 51 +++++++++++++++++--------- tracker/software/threads/log.c | 2 +- 9 files changed, 99 insertions(+), 63 deletions(-) diff --git a/tracker/software/drivers/ov5640.c b/tracker/software/drivers/ov5640.c index 4707b25..ead359b 100644 --- a/tracker/software/drivers/ov5640.c +++ b/tracker/software/drivers/ov5640.c @@ -820,9 +820,7 @@ bool OV5640_Snapshot2RAM(void) do { TRACE_INFO("CAM > Capture image"); - lockRadio(); // Lock radio because SPI and pseudo DCMI use the same DMA status = OV5640_Capture(); - unlockRadio(); // Unlock radio TRACE_INFO("CAM > Capture finished"); ov5640_conf->size_sampled = ov5640_conf->ram_size - 1; diff --git a/tracker/software/drivers/pac1720.c b/tracker/software/drivers/pac1720.c index 62e9aeb..ad34742 100644 --- a/tracker/software/drivers/pac1720.c +++ b/tracker/software/drivers/pac1720.c @@ -153,6 +153,6 @@ void pac1720_init(void) I2C_write8(PAC1720_ADDRESS, PAC1720_V_SOURCE_SAMP_CONFIG, 0xFF); //TRACE_INFO("PAC > Init PAC1720 continuous measurement"); - //chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(512), "PAC1720", NORMALPRIO, pac1720_thd, NULL); + chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(512), "PAC1720", NORMALPRIO, pac1720_thd, NULL); } diff --git a/tracker/software/protocols/aprs/aprs.c b/tracker/software/protocols/aprs/aprs.c index de617d8..ec00f58 100644 --- a/tracker/software/protocols/aprs/aprs.c +++ b/tracker/software/protocols/aprs/aprs.c @@ -47,6 +47,7 @@ uint32_t aprs_encode_position(uint8_t* message, mod_t mod, const aprs_conf_t *co packet.max_size = 512; // TODO: replace 512 with real size packet.mod = mod; + ax25_init(&packet); ax25_send_header(&packet, config->callsign, config->ssid, config->path, config->preamble); ax25_send_byte(&packet, '/'); // Report w/ timestamp, no APRS messaging. $ = NMEA raw data @@ -169,7 +170,7 @@ uint32_t aprs_encode_position(uint8_t* message, mod_t mod, const aprs_conf_t *co /** * Transmit custom experimental packet */ -uint32_t aprs_encode_experimental(char packetType, uint8_t* message, mod_t mod, const aprs_conf_t *config, uint8_t *data, size_t size, bool noPreamble) +uint32_t aprs_encode_experimental(char packetType, uint8_t* message, mod_t mod, const aprs_conf_t *config, uint8_t *data, size_t size) { ax25_t packet; packet.data = message; @@ -177,7 +178,8 @@ uint32_t aprs_encode_experimental(char packetType, uint8_t* message, mod_t mod, packet.mod = mod; // Encode APRS header - ax25_send_header(&packet, config->callsign, config->ssid, config->path, noPreamble ? 0 : config->preamble); + ax25_init(&packet); + ax25_send_header(&packet, config->callsign, config->ssid, config->path, config->preamble); ax25_send_string(&packet, "{{"); ax25_send_byte(&packet, packetType); @@ -185,7 +187,7 @@ uint32_t aprs_encode_experimental(char packetType, uint8_t* message, mod_t mod, for(uint16_t i=0; idata = message; + packet->max_size = 8192; // TODO: replace 8192 with real size + packet->mod = mod; + + // Encode APRS header + ax25_init(packet); +} +uint32_t aprs_encode_data_encodePacket(ax25_t* packet, char packetType, const aprs_conf_t *config, uint8_t *data, size_t size) +{ + // Encode header + ax25_send_header(packet, config->callsign, config->ssid, config->path, packet->size > 0 ? 0 : config->preamble); + ax25_send_string(packet, "{{"); + ax25_send_byte(packet, packetType); + + // Encode message + for(uint16_t i=0; isize; +} +uint32_t aprs_encode_data_finalize(ax25_t* packet) +{ + scramble(packet); + nrzi_encode(packet); + return packet->size; +} + /** * Transmit message packet */ @@ -205,6 +242,7 @@ uint32_t aprs_encode_message(uint8_t* message, mod_t mod, const aprs_conf_t *con // Encode APRS header char temp[10]; + ax25_init(&packet); ax25_send_header(&packet, config->callsign, config->ssid, config->path, config->preamble); ax25_send_byte(&packet, ':'); @@ -218,7 +256,7 @@ uint32_t aprs_encode_message(uint8_t* message, mod_t mod, const aprs_conf_t *con chsnprintf(temp, sizeof(temp), "%d", ++msg_id); ax25_send_string(&packet, temp); - // Send footer + // Encode footer ax25_send_footer(&packet); scramble(&packet); nrzi_encode(&packet); @@ -237,6 +275,7 @@ uint32_t aprs_encode_telemetry_configuration(uint8_t* message, mod_t mod, const packet.max_size = 512; // TODO: replace 512 with real size packet.mod = mod; + ax25_init(&packet); ax25_send_header(&packet, config->callsign, config->ssid, config->path, config->preamble); // Header ax25_send_byte(&packet, ':'); // Message flag diff --git a/tracker/software/protocols/aprs/aprs.h b/tracker/software/protocols/aprs/aprs.h index 4e508c1..c6ff7ec 100644 --- a/tracker/software/protocols/aprs/aprs.h +++ b/tracker/software/protocols/aprs/aprs.h @@ -21,6 +21,7 @@ #include "config.h" #include "si4464.h" #include "tracking.h" +#include "ax25.h" #define GSP_FIX_OLD 0x0 #define GSP_FIX_CURRENT 0x1 @@ -51,7 +52,11 @@ uint32_t aprs_encode_position(uint8_t* message, mod_t mod, const aprs_conf_t *config, trackPoint_t *trackPoint); uint32_t aprs_encode_telemetry_configuration(uint8_t* message, mod_t mod, const aprs_conf_t *config, const telemetry_conf_t type); uint32_t aprs_encode_message(uint8_t* message, mod_t mod, const aprs_conf_t *config, const char *receiver, const char *text); -uint32_t aprs_encode_experimental(char packetType, uint8_t* message, mod_t mod, const aprs_conf_t *config, uint8_t *data, size_t size, bool noPreamble); +uint32_t aprs_encode_experimental(char packetType, uint8_t* message, mod_t mod, const aprs_conf_t *config, uint8_t *data, size_t size); + +void aprs_encode_data_init(ax25_t* packet, uint8_t* message, mod_t mod); +uint32_t aprs_encode_data_encodePacket(ax25_t* packet, char packetType, const aprs_conf_t *config, uint8_t *data, size_t size); +uint32_t aprs_encode_data_finalize(ax25_t* packet); #endif diff --git a/tracker/software/protocols/aprs/ax25.c b/tracker/software/protocols/aprs/ax25.c index feedcfa..96347ff 100644 --- a/tracker/software/protocols/aprs/ax25.c +++ b/tracker/software/protocols/aprs/ax25.c @@ -113,11 +113,15 @@ void ax25_send_string(ax25_t *packet, const char *string) } } +void ax25_init(ax25_t *packet) +{ + packet->size = 0; +} + void ax25_send_header(ax25_t *packet, const char *callsign, uint8_t ssid, const char *path, uint16_t preamble) { uint8_t i, j; uint8_t tmp[8]; - packet->size = 0; packet->ones_in_a_row = 0; packet->crc = 0xffff; diff --git a/tracker/software/protocols/aprs/ax25.h b/tracker/software/protocols/aprs/ax25.h index ac5ec80..ba753d4 100644 --- a/tracker/software/protocols/aprs/ax25.h +++ b/tracker/software/protocols/aprs/ax25.h @@ -36,6 +36,7 @@ typedef struct { mod_t mod; // Modulation type (MOD_AFSK or MOD_2GFSK) } ax25_t; +void ax25_init(ax25_t *packet); void ax25_send_header(ax25_t *packet, const char *callsign, uint8_t ssid, const char *path, uint16_t preamble); void ax25_send_path(ax25_t *packet, const char *callsign, uint8_t ssid, bool last); void ax25_send_byte(ax25_t *packet, char byte); diff --git a/tracker/software/radio.c b/tracker/software/radio.c index 1a755d7..64defa4 100644 --- a/tracker/software/radio.c +++ b/tracker/software/radio.c @@ -80,21 +80,8 @@ void init2GFSK(radioMSG_t *msg) { active_mod = MOD_2GFSK; } -thread_reference_t feeder_ref = NULL; thread_t *feeder_thd = NULL; -/* - * Radio GPIO1 interrupt - */ -CH_IRQ_HANDLER(VectorE0) { - CH_IRQ_PROLOGUE(); - - chThdResumeS(&feeder_ref, MSG_OK); - - EXTI->PR |= EXTI_PR_PR12; - CH_IRQ_EPILOGUE(); -} - /* * TODO: I'd suggest re-working the FIFO handler system. * Will give it some thought. @@ -112,19 +99,11 @@ THD_FUNCTION(si_fifo_feeder_thd, arg) // Initial FIFO fill Si4464_writeFIFO(tim_msg.msg, c); - // Initialize interrupt - chSysLock(); - SYSCFG->EXTICR[3] |= SYSCFG_EXTICR4_EXTI12_PC; - EXTI->IMR |= EXTI_IMR_MR12; // Activate interrupt for chan12 (=>PC12) - EXTI->RTSR |= EXTI_RTSR_TR12; // Listen on rising edge - EXTI->PR |= EXTI_PR_PR12; // Clear any pending interrupt - nvicEnableVector(EXTI15_10_IRQn, 1); // Enable interrupt - chSysUnlock(); - // Transmit + // Start transmission radioTune(tim_msg.freq, 0, tim_msg.power, all); while(c < all) { // Do while bytes not written into FIFO completely - chThdSuspendS(&feeder_ref); // Suspend until interrupt resumes it + //chThdSuspendS(&feeder_ref); // Suspend until interrupt resumes it // Determine free memory in Si4464-FIFO uint8_t more = Si4464_freeFIFO(); @@ -132,14 +111,14 @@ THD_FUNCTION(si_fifo_feeder_thd, arg) if((more = all-c) == 0) // Calculate remainder to send break; // End if nothing left } - //TRACE_DEBUG("fed %db %d<%d", more, c, all); Si4464_writeFIFO(&tim_msg.msg[c], more); // Write into FIFO c += more; + chThdSleepMilliseconds(20); } - nvicDisableVector(EXTI15_10_IRQn); // Disable interrupt - + // Shutdown radio (and wait for Si4464 to finish transmission) shutdownRadio(); + chThdExit(MSG_OK); } @@ -147,8 +126,6 @@ void send2GFSK(radioMSG_t *msg) { // Copy data memcpy(&tim_msg, msg, sizeof(radioMSG_t)); - if(feeder_thd != NULL) // No waiting on first use - chThdWait(feeder_thd); // Start/re-start FIFO feeder feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_thd, NULL); @@ -313,10 +290,7 @@ void shutdownRadio(void) { // Wait for PH to finish transmission for 2GFSK while(active_mod == MOD_2GFSK && Si4464_getState() == SI4464_STATE_TX) - { - TRACE_DEBUG("Waiting for Si4464 (state=%d, free=%d)", Si4464_getState(), Si4464_freeFIFO()); chThdSleepMilliseconds(5); - } Si4464_shutdown(); active_mod = MOD_NOT_SET; @@ -376,12 +350,11 @@ uint32_t getAPRSRegionFrequency(void) { */ bool transmitOnRadio(radioMSG_t *msg, bool shutdown) { - (void)shutdown; + (void)shutdown; if(inRadioBand(msg->freq)) // Frequency in radio radio band { if(inRadioBand(msg->freq)) // Frequency in radio radio band { - lockRadio(); // Lock radio TRACE_INFO( "RAD > Transmit %d.%03d MHz, Pwr %d, %s, %d bits", @@ -462,8 +435,9 @@ void lockRadio(void) { chMtxLock(&radio_mtx); - while(active_mod != MOD_NOT_SET && Si4464_getState() == SI4464_STATE_TX) - chThdSleepMilliseconds(1); + // Wait for old feeder thread to terminate + if(feeder_thd != NULL) // No waiting on first use + chThdWait(feeder_thd); } void unlockRadio(void) diff --git a/tracker/software/threads/image.c b/tracker/software/threads/image.c index 87eb3d4..ac009f1 100644 --- a/tracker/software/threads/image.c +++ b/tracker/software/threads/image.c @@ -273,7 +273,7 @@ const uint8_t noCameraFound[] = { 0xBD, 0xC0, 0x20, 0x00, 0x01, 0xFF, 0xD9 }; -static uint8_t gimage_id = 0; // Global image ID (for all image threads) +static uint8_t gimage_id = 5; // Global image ID (for all image threads) mutex_t camera_mtx; void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, uint8_t image_id, bool redudantTx) @@ -297,6 +297,17 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, msg.freq = getFrequency(&conf->frequency); msg.power = conf->power; + //image_id = 0; // FIXME temporary + + ax25_t ax25_handle; + if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) + { + msg.mod = conf->protocol == PROT_APRS_AFSK ? MOD_AFSK : MOD_2GFSK; + msg.afsk_conf = &(conf->afsk_conf); + msg.gfsk_conf = &(conf->gfsk_conf); + aprs_encode_data_init(&ax25_handle, msg.msg, msg.mod); + } + while(true) { conf->wdg_timeout = chVTGetSystemTimeX() + S2ST(600); // TODO: Implement more sophisticated method @@ -309,8 +320,9 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, if(r <= 0) { - if(msg.bin_len > 0) transmitOnRadio(&msg, false); // Empty buffer TRACE_ERROR("SSDV > Premature end of file"); + if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) msg.bin_len = aprs_encode_data_finalize(&ax25_handle); + if(msg.bin_len > 0) transmitOnRadio(&msg, false); // Empty buffer break; } ssdv_enc_feed(&ssdv, b, r); @@ -318,37 +330,34 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, if(c == SSDV_EOI) { - if(msg.bin_len > 0) transmitOnRadio(&msg, false); // Empty buffer TRACE_INFO("SSDV > ssdv_enc_get_packet said EOI"); + if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) msg.bin_len = aprs_encode_data_finalize(&ax25_handle); + if(msg.bin_len > 0) transmitOnRadio(&msg, false); // Empty buffer break; } else if(c != SSDV_OK) { - if(msg.bin_len > 0) transmitOnRadio(&msg, false); // Empty buffer TRACE_ERROR("SSDV > ssdv_enc_get_packet failed: %i", c); + if(conf->protocol == PROT_APRS_2GFSK || conf->protocol == PROT_APRS_AFSK) msg.bin_len = aprs_encode_data_finalize(&ax25_handle); + if(msg.bin_len > 0) transmitOnRadio(&msg, false); // Empty buffer return; } switch(conf->protocol) { case PROT_APRS_2GFSK: case PROT_APRS_AFSK: - msg.mod = conf->protocol == PROT_APRS_AFSK ? MOD_AFSK : MOD_2GFSK; - msg.afsk_conf = &(conf->afsk_conf); - msg.gfsk_conf = &(conf->gfsk_conf); - - // Deleting buffer - for(uint16_t t=0; t<256; t++) - pkt_base91[t] = 0; - // Encode packet TRACE_INFO("IMG > Encode APRS/SSDV packet"); base91_encode(&pkt[1], pkt_base91, sizeof(pkt)-37); // Sync byte, CRC and FEC of SSDV not transmitted - msg.bin_len += 8 + aprs_encode_experimental('I', &msg.msg[msg.bin_len/8+1], msg.mod, &conf->aprs_conf, pkt_base91, strlen((char*)pkt_base91), msg.bin_len > 0); + msg.bin_len = aprs_encode_data_encodePacket(&ax25_handle, 'I', &conf->aprs_conf, pkt_base91, strlen((char*)pkt_base91)); if(redudantTx) - msg.bin_len += 8 + aprs_encode_experimental('I', &msg.msg[msg.bin_len/8+1], msg.mod, &conf->aprs_conf, pkt_base91, strlen((char*)pkt_base91), false); + msg.bin_len = aprs_encode_data_encodePacket(&ax25_handle, 'I', &conf->aprs_conf, pkt_base91, strlen((char*)pkt_base91)); // Transmit - if(msg.bin_len >= 58000 || conf->packet_spacing) { // Transmit if buffer is full or if single packet transmission activation (packet_spacing != 0) + if(msg.bin_len >= 58000 || conf->packet_spacing) // Transmit if buffer is full or if single packet transmission activation (packet_spacing != 0) + { + msg.bin_len = aprs_encode_data_finalize(&ax25_handle); transmitOnRadio(&msg, false); msg.bin_len = 0; + chThdSleepMilliseconds(7500); // FIXME: Throttle it for my poor TH-D72. Has to be removed later. } break; @@ -400,10 +409,13 @@ THD_FUNCTION(imgThread, arg) { uint32_t image_len = 0; uint8_t *image; - // Lock camera + // Lock camera FIXME: Removed for testing TRACE_INFO("IMG > Lock camera"); chMtxLock(&camera_mtx); TRACE_INFO("IMG > Locked camera"); + //TRACE_INFO("IMG > Lock radio"); + //lockRadio(); // Lock radio because SPI and pseudo DCMI use the same DMA + //TRACE_INFO("IMG > Locked radio"); uint8_t tries; bool status = false; @@ -472,7 +484,10 @@ THD_FUNCTION(imgThread, arg) { } - // Unlock camera + // Unlock camera FIXME: Removed for testing + //TRACE_INFO("IMG > Unlock radio"); + //unlockRadio(); // Unlock radio + //TRACE_INFO("IMG > Unlocked radio"); TRACE_INFO("IMG > Unlock camera"); chMtxUnlock(&camera_mtx); TRACE_INFO("IMG > Unlocked camera"); @@ -502,7 +517,7 @@ void start_image_thread(module_conf_t *conf) if(conf->init_delay) chThdSleepMilliseconds(conf->init_delay); TRACE_INFO("IMG > Startup image thread"); chsnprintf(conf->name, sizeof(conf->name), "IMG"); - thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(50*1024), "IMG", NORMALPRIO, imgThread, conf); + thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(100*1024), "IMG", NORMALPRIO, imgThread, conf); if(!th) { // Print startup error, do not start watchdog for this thread TRACE_ERROR("IMG > Could not startup thread (not enough memory available)"); diff --git a/tracker/software/threads/log.c b/tracker/software/threads/log.c index cfdab8e..7d06e55 100644 --- a/tracker/software/threads/log.c +++ b/tracker/software/threads/log.c @@ -178,7 +178,7 @@ THD_FUNCTION(logThread, arg) msg.gfsk_conf = &(conf->gfsk_conf); base91_encode((uint8_t*)pkt, pkt_base91, sizeof(pkt)); // Encode base 91 - msg.bin_len = aprs_encode_experimental('L', msg.msg, msg.mod, &conf->aprs_conf, pkt_base91, strlen((char*)pkt_base91), false); // Encode APRS + msg.bin_len = aprs_encode_experimental('L', msg.msg, msg.mod, &conf->aprs_conf, pkt_base91, strlen((char*)pkt_base91)); // Encode APRS transmitOnRadio(&msg, true); // Transmit packet break;