version bump & improved reliability with retries

master
Ondřej Hruška 8 years ago
parent 8d4ebe71fb
commit 09aa63e5a0
  1. 2
      user/fw_version.h
  2. 17
      user/page_waveform.c
  3. 106
      user/sampling.c
  4. 2
      user/sampling.h

@ -1,6 +1,6 @@
#ifndef FW_VERSION_H #ifndef FW_VERSION_H
#define FW_VERSION_H #define FW_VERSION_H
#define FIRMWARE_VERSION "0.1.2" #define FIRMWARE_VERSION "0.1.3"
#endif // FW_VERSION_H #endif // FW_VERSION_H

@ -101,23 +101,14 @@ static int FLASH_FN tplSamplesJSON(MEAS_FORMAT fmt, HttpdConnData *connData, cha
// 10 secs or 100 ms - longer wait for intial data. // 10 secs or 100 ms - longer wait for intial data.
int timeout = (st->done_count == 0 ? (int)meas_estimate_duration(st->total_count, st->freq): SAMP_RD_TMEO_TOTAL); if (!meas_wait_for_chunk()) {
dbg("Chunk read total timeout = %d ms", timeout); // meas session was already closed.
for (int i = 0; i < timeout*100; i++) {
uart_poll();
if (meas_chunk_ready() || meas_is_closed()) break; // We have some data! --- or transaction aborted by peer :(
os_delay_us(10);
system_soft_wdt_feed(); // Feed the dog, or it'll bite.
}
chunk = meas_get_chunk(&chunk_len);
if (chunk == NULL) {
// abort, proceed to the next field.
meas_close();
st->success = false; st->success = false;
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
chunk = meas_get_chunk(&chunk_len);
PayloadParser pp = pp_start(chunk, chunk_len); PayloadParser pp = pp_start(chunk, chunk_len);
// chunk of data... // chunk of data...

@ -3,6 +3,7 @@
#include "datalink.h" #include "datalink.h"
#include "sampling.h" #include "sampling.h"
#include "serial.h"
// The buffer is big enough for 256 data bytes - 4*64 // The buffer is big enough for 256 data bytes - 4*64
@ -11,8 +12,6 @@
// the FIFO has 128 bytes, and should accomodate ideally the whole frame. // the FIFO has 128 bytes, and should accomodate ideally the whole frame.
#define CHUNK_LEN 100 #define CHUNK_LEN 100
static void setReadoutTmeoTimer(int ms);
// Only one readout can happen at a time. // Only one readout can happen at a time.
@ -24,11 +23,10 @@ static struct {
uint8_t received_chunk[CHUNK_LEN]; /*!< Copy of the latest received chunk of data */ uint8_t received_chunk[CHUNK_LEN]; /*!< Copy of the latest received chunk of data */
uint16_t received_chunk_size; /*!< Size of the chunk in latest_chunk_copy */ uint16_t received_chunk_size; /*!< Size of the chunk in latest_chunk_copy */
// the readout state uint32_t est_sampling_time; /*!< Estimated time in millis before data is captured and readout starts */
uint8_t retry_count;
uint32_t pos; uint32_t pos;
uint32_t total; uint32_t total;
ETSTimer abortTimer;
MEAS_FORMAT format; /*!< Requested data format */ MEAS_FORMAT format; /*!< Requested data format */
@ -42,67 +40,65 @@ bool FLASH_FN meas_is_closed(void)
return !rd.pending; return !rd.pending;
} }
uint32_t FLASH_FN meas_estimate_duration(uint32_t count, uint32_t freq) uint32_t FLASH_FN meas_estimate_duration(uint32_t count, uint32_t freq)
{ {
return (uint32_t)((count*1000.0f) / freq) + SAMP_RD_TMEO_TOTAL; return (uint32_t)((count*1000.0f) / freq) + SAMP_RD_TMEO;
} }
/** Wait for one chunk, with possible retries */
bool FLASH_FN meas_wait_for_chunk(void)
{
for (int retry_count = 0; retry_count < SAMP_RD_RETRY_COUNT; retry_count++) {
uint32_t timeout = (rd.waiting_for_measure ? rd.est_sampling_time: SAMP_RD_TMEO);
// dbg("Chunk read total timeout = %d ms", timeout);
// --- timeout --- for (uint32_t i = 0; i < timeout*100; i++) {
uart_poll(); // can stop measure & start first chunk, if rx offer
static void FLASH_FN abortTimerCb(void *arg) // check for closed connection - aborted by peer?
{ if (meas_is_closed()) {
(void)arg; error("Session closed by peer, readout failed.");
return false; // assume already cleaned up
}
if (rd.waiting_for_measure) { if (meas_chunk_ready()) {
error("Sampling aborted due to timeout."); // yay!!
return true;
}
// try to abort the readout os_delay_us(10);
sbmp_bulk_abort(dlnk_ep, rd.sesn); system_soft_wdt_feed(); // Feed the dog, or it'll bite.
}
// release resources and stop // Data still not Rx
meas_close(); if (rd.waiting_for_measure) {
} else {
warn("Data chunk not rx in time");
// data chunk not received in time (may be lost ?) // only one try in this case
if (rd.retry_count < SAMP_RD_RETRY_COUNT) { error("Sampling aborted due to timeout (no data offered)");
rd.retry_count++; sbmp_bulk_abort(dlnk_ep, rd.sesn); // send abort msg
meas_close(); // close
return false;
dbg("Requesting again (try %d of %d).", rd.retry_count, SAMP_RD_RETRY_COUNT);
setReadoutTmeoTimer(SAMP_RD_TMEO); // re-start the timer
sbmp_bulk_request(dlnk_ep, rd.pos, CHUNK_LEN, rd.sesn);
} else { } else {
error("Retry count exhausted!"); warn("Data chunk not rx in time.");
meas_close(); dbg("Requesting again (try %d of %d).", retry_count+1, SAMP_RD_RETRY_COUNT);
sbmp_bulk_request(dlnk_ep, rd.pos, CHUNK_LEN, rd.sesn);
} }
} }
}
static void FLASH_FN setReadoutTmeoTimer(int ms)
{
// dbg("Set read timeout %d", ms);
os_timer_disarm(&rd.abortTimer);
os_timer_setfn(&rd.abortTimer, abortTimerCb, NULL);
os_timer_arm(&rd.abortTimer, ms, 0);
}
static void FLASH_FN stopReadoutTmeoTimer(void) error("Retry count exhausted!");
{ sbmp_bulk_abort(dlnk_ep, rd.sesn);
// dbg("Stop read timeout"); meas_close();
os_timer_disarm(&rd.abortTimer); return false;
} }
// -------------
/** request next chunk */ /** request next chunk */
void FLASH_FN meas_request_next_chunk(void) void FLASH_FN meas_request_next_chunk(void)
{ {
if (!rd.pending) return; if (!rd.pending) return;
rd.chunk_ready = false; // invalidate the current chunk, so waiting for chunk is possible. rd.chunk_ready = false; // invalidate the current chunk, so waiting for chunk is possible.
rd.retry_count = 0; // reset retry counter
sbmp_bulk_request(dlnk_ep, rd.pos, CHUNK_LEN, rd.sesn); sbmp_bulk_request(dlnk_ep, rd.pos, CHUNK_LEN, rd.sesn);
} }
@ -112,8 +108,6 @@ bool FLASH_FN meas_chunk_ready(void)
return rd.pending && rd.chunk_ready; return rd.pending && rd.chunk_ready;
} }
/** /**
* @brief Get received chunk. NULL if none. * @brief Get received chunk. NULL if none.
* *
@ -147,7 +141,6 @@ void FLASH_FN meas_close(void)
if (!rd.pending) return; // ignore this call if (!rd.pending) return; // ignore this call
sbmp_ep_remove_listener(dlnk_ep, rd.sesn); sbmp_ep_remove_listener(dlnk_ep, rd.sesn);
stopReadoutTmeoTimer();
rd.pending = false; rd.pending = false;
info("Transfer closed."); info("Transfer closed.");
@ -167,8 +160,6 @@ static void FLASH_FN request_data_sesn_listener(SBMP_Endpoint *ep, SBMP_Datagram
PayloadParser pp; PayloadParser pp;
switch (dg->type) { switch (dg->type) {
case DG_BULK_OFFER:// Data ready notification case DG_BULK_OFFER:// Data ready notification
stopReadoutTmeoTimer();
// data is ready to be read // data is ready to be read
pp = pp_start(dg->payload, dg->length); pp = pp_start(dg->payload, dg->length);
@ -185,31 +176,24 @@ static void FLASH_FN request_data_sesn_listener(SBMP_Endpoint *ep, SBMP_Datagram
// --- user data end --- // --- user data end ---
if (rd.format == FFT) { if (rd.format == FFT) {
// TODO read extra FFT stats // TODO read extra FFT stats ??
} }
// renew the timeout info("Offered %d bytes of data, starting readout.", rd.total);
setReadoutTmeoTimer(SAMP_RD_TMEO);
// request first chunk // request first chunk
rd.retry_count = 0;
sbmp_bulk_request(ep, rd.pos, CHUNK_LEN, dg->session); sbmp_bulk_request(ep, rd.pos, CHUNK_LEN, dg->session);
break; break;
case DG_BULK_DATA: // data received case DG_BULK_DATA: // data received
stopReadoutTmeoTimer();
// Process the received data // Process the received data
memcpy(rd.received_chunk, dg->payload, dg->length); memcpy(rd.received_chunk, dg->payload, dg->length);
rd.chunk_ready = true; rd.chunk_ready = true;
rd.received_chunk_size = dg->length; rd.received_chunk_size = dg->length;
rd.retry_count = 0;
// move the pointer for next request // move the pointer for next request
rd.pos += dg->length; rd.pos += dg->length;
setReadoutTmeoTimer(SAMP_RD_TMEO); // timeout to retrieve the data & ask for more
// --- Now we wait for the CGI func to retrieve the chunk and send it to the browser. --- // --- Now we wait for the CGI func to retrieve the chunk and send it to the browser. ---
if (rd.pos >= rd.total) { if (rd.pos >= rd.total) {
@ -257,11 +241,9 @@ bool FLASH_FN meas_request_data(MEAS_FORMAT format, uint16_t count, uint32_t fre
rd.total = 0; rd.total = 0;
rd.pending = true; rd.pending = true;
rd.format = format; rd.format = format;
rd.retry_count = 0;
memset(&rd.stats, 0, sizeof(MeasStats)); // clear the stats obj memset(&rd.stats, 0, sizeof(MeasStats)); // clear the stats obj
// start the abort timer - timeout rd.est_sampling_time = meas_estimate_duration(count, freq);
setReadoutTmeoTimer((int)meas_estimate_duration(count, freq));
// start a message // start a message
uint16_t sesn = 0; uint16_t sesn = 0;
@ -290,7 +272,7 @@ bool FLASH_FN meas_request_data(MEAS_FORMAT format, uint16_t count, uint32_t fre
return true; return true;
fail: fail:
stopReadoutTmeoTimer(); rd.waiting_for_measure = false;
rd.pending = false; rd.pending = false;
return false; return false;
} }

@ -69,5 +69,7 @@ bool meas_is_last_chunk(void);
/** Terminate the readout. */ /** Terminate the readout. */
void meas_close(void); void meas_close(void);
/** Wait for one chunk, with possible retries. True = chunk ready, false = failed. */
bool meas_wait_for_chunk(void);
#endif // SAMPLING_H #endif // SAMPLING_H

Loading…
Cancel
Save