diff --git a/html_build.sh b/.web-build_do.sh
similarity index 71%
rename from html_build.sh
rename to .web-build_do.sh
index fe92b25..f43daa7 100755
--- a/html_build.sh
+++ b/.web-build_do.sh
@@ -21,5 +21,5 @@ find "$BLDDIR" -name "*.map" -delete
mkdir -p "$BLDDIR/pages"
-php "$SRCDIR/home.php" > "$BLDDIR/pages/home.tpl.html"
-php "$SRCDIR/wifi.php" > "$BLDDIR/pages/wifi.tpl.html"
+php "$SRCDIR/home.php" > "$BLDDIR/pages/home.tpl"
+php "$SRCDIR/wifi.php" > "$BLDDIR/pages/wifi.tpl"
diff --git a/esp_meas.pro b/esp_meas.pro
index f425de1..609a182 100644
--- a/esp_meas.pro
+++ b/esp_meas.pro
@@ -135,7 +135,6 @@ HEADERS += \
sbmp/library/payload_parser.h \
user/sampling.h \
user/page_home.h \
- user/timeout.h \
user/sbmp_config.h \
sbmp/library/sbmp_config.example.h \
user/ftoa.h \
diff --git a/esp_meas.pro.user b/esp_meas.pro.user
index dec474b..d12ab14 100644
--- a/esp_meas.pro.user
+++ b/esp_meas.pro.user
@@ -1,6 +1,6 @@
-
+
EnvironmentId
diff --git a/flash.sh b/flash.sh
new file mode 100755
index 0000000..d465ea2
--- /dev/null
+++ b/flash.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+xterm -title "ESP html build" -e "source $HOME/.bashrc && make flash -B -j4"
diff --git a/html/json/samples.tpl.json b/html/json/samples.tpl
similarity index 100%
rename from html/json/samples.tpl.json
rename to html/json/samples.tpl
diff --git a/html/pages/home.tpl.html b/html/pages/home.tpl
similarity index 100%
rename from html/pages/home.tpl.html
rename to html/pages/home.tpl
diff --git a/html/pages/wifi.tpl.html b/html/pages/wifi.tpl
similarity index 100%
rename from html/pages/wifi.tpl.html
rename to html/pages/wifi.tpl
diff --git a/libesphttpd/Makefile b/libesphttpd/Makefile
index cc2bc3b..1c77b19 100644
--- a/libesphttpd/Makefile
+++ b/libesphttpd/Makefile
@@ -169,7 +169,7 @@ ifeq ("$(COMPRESS_W_YUI)","yes")
$(Q) for file in `find html_compressed -type f -name "*.js"`; do $(YUI-COMPRESSOR) --type js $$file -o $$file; done
$(Q) for file in `find html_compressed -type f -name "*.css"`; do $(YUI-COMPRESSOR) --type css $$file -o $$file; done
ifeq ("$(COMPRESS_W_HTMLMINIFIER)","yes")
- $(Q) for file in `find html_compressed -type f -name "*.html" -o -name "*.htm" -o -name "*.tpl"`; do $(HTML-MINIFIER) $$file -o $$file; done
+ $(Q) for file in `find html_compressed/pages -type f -name "*.html" -o -name "*.htm" -o -name "*.tpl"`; do $(HTML-MINIFIER) $$file -o $$file; done
endif
$(Q) awk "BEGIN {printf \"YUI compression ratio was: %.2f%%\\n\", (`du -b -s html_compressed/ | sed 's/\([0-9]*\).*/\1/'`/`du -b -s ../html/ | sed 's/\([0-9]*\).*/\1/'`)*100}"
# mkespfsimage will compress html, css, svg and js files with gzip by default if enabled
diff --git a/user/cgi.c b/user/cgi.c
index c7e92bd..791b433 100644
--- a/user/cgi.c
+++ b/user/cgi.c
@@ -17,6 +17,8 @@ flash as a binary. Also handles the hit counter on the main page.
#include "cgi.h"
#include "uptime.h"
#include "datalink.h"
+#include "sampling.h"
+#include "serial.h"
// -------------------------------------------------------------------------------
@@ -24,8 +26,8 @@ flash as a binary. Also handles the hit counter on the main page.
// Read multiple samples from the ADC as JSON
typedef struct {
- uint32_t total_count;
- uint32_t done_count;
+ uint16_t total_count;
+ uint16_t done_count;
bool success;
} tplReadSamplesJSON_state;
@@ -57,9 +59,10 @@ int FLASH_FN tplReadSamplesJSON(HttpdConnData *connData, char *token, void **arg
}
st->total_count = count;
st->done_count = 0;
- st->success = true;
+ st->success = true; // success true by default
- // TODO Start the capture
+ // REQUEST THE DATA
+ meas_request_data(st->total_count);
}
// the "success" field is after the data,
@@ -67,34 +70,52 @@ int FLASH_FN tplReadSamplesJSON(HttpdConnData *connData, char *token, void **arg
if (strcmp(token, "values") == 0) {
- if (st->done_count == 0) {
- dbg("Delay to simulate readout...");
- // 1000 ms delay
- for(int i=0;i<1000;i++) {
- os_delay_us(1000);
- }
+ // Wait for a chunk
+
+ uint8_t *chunk = NULL;
+ uint16_t chunk_len = 0;
+
+ // 5 secs or 500 ms
+ for (int i = 0; i < (st->done_count == 0 ? 5000*100: 500*100); i++) {
+ uart_poll();
+ if (meas_chunk_ready()) break;
+ os_delay_us(10); // 1 ms
+ system_soft_wdt_feed();
}
+ chunk = meas_get_chunk(&chunk_len);
- // TODO wait for data to be received
- // on error, terminate and proceed to the "success" field.
+ if (!chunk) {
+ // abort, proceed to the next field.
+ meas_close();
+ st->success = false;
+ return HTTPD_CGI_DONE;
+ }
- u32 chunk = MIN(10, st->total_count - st->done_count); // chunks of 10
+ PayloadParser pp = pp_start(chunk, chunk_len);
// chunk of data...
- for (u32 i = 0; i < chunk; i++, st->done_count++) {
+ for (; pp.ptr < pp.len; st->done_count++) {
// preceding comma if not the first number
if (st->done_count > 0) {
httpdSend(connData, ", ", 2);
}
- // one number
- os_sprintf(buff20, "%lu", os_random());
+ uint32_t samp = pp_u32(&pp);
+
+ // print the number
+ os_sprintf(buff20, "%d", samp);
httpdSend(connData, buff20, -1);
}
// wait for more in this substitution
- if (st->done_count < st->total_count)
+ if (st->done_count < st->total_count) {
+ meas_request_next_chunk();
return HTTPD_CGI_MORE; // more numbers to come
+ } else {
+ // we're done
+ meas_close();
+ return HTTPD_CGI_DONE;
+ }
} else if (strcmp(token, "success") == 0) {
// success status
diff --git a/user/routes.c b/user/routes.c
index e6a94f0..840865e 100644
--- a/user/routes.c
+++ b/user/routes.c
@@ -35,13 +35,10 @@ static int FLASH_FN myPassFn(HttpdConnData *connData, int no, char *user, int us
HttpdBuiltInUrl builtInUrls[] = {
ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp8266.nonet"), // redirect func for the captive portal
- ROUTE_TPL_FILE("/", tplHome, "/pages/home.tpl.html"),
-
- ROUTE_CGI("/acquire.cgi", cgiReadSamples),
-
+ ROUTE_TPL_FILE("/", tplHome, "/pages/home.tpl"),
// API for measurements
- ROUTE_TPL_FILE("/meas/samples.json", tplReadSamplesJSON, "/json/samples.tpl.json"),
+ ROUTE_TPL_FILE("/api/raw.json", tplReadSamplesJSON, "/json/samples.tpl"),
#if WIFI_PROTECT
@@ -49,7 +46,7 @@ HttpdBuiltInUrl builtInUrls[] = {
#endif
ROUTE_REDIRECT("/wifi/", "/wifi"),
- ROUTE_TPL_FILE("/wifi", tplWlan, "/pages/wifi.tpl.html"),
+ ROUTE_TPL_FILE("/wifi", tplWlan, "/pages/wifi.tpl"),
ROUTE_CGI("/wifi/scan.cgi", cgiWiFiScan),
ROUTE_CGI("/wifi/connect.cgi", cgiWiFiConnect),
diff --git a/user/sampling.c b/user/sampling.c
index 16384ea..541e68f 100644
--- a/user/sampling.c
+++ b/user/sampling.c
@@ -3,116 +3,167 @@
#include "datalink.h"
#include "sampling.h"
-#include "timeout.h"
// The buffer is big enough for 256 data bytes - 4*64
// chunk size for bulk transfer (must be multiple of 4 - length of uint32 / float)
-// NOTE: If too large, strange errors occur (problem with the UART FIFO at high speed)
+// NOTE: If too large, strange errors can occur (problem with the underlying UART FIFO at high speed)
+// the FIFO has 128 bytes, and should accomodate ideally the whole frame.
#define CHUNK_LEN 100
-static volatile bool acquire_pending = false;
-static volatile uint16_t acquire_session;
+// Only one readout can happen at a time.
+static struct {
+ bool pending; /*!< Flag that data is currently being read */
+ uint16_t sesn; /*!< SBMP session of the readout sequence */
+ bool chunk_ready; /*!< Chunk was received and is ready for reading */
+ 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 */
+
+ // the readout state
+ uint32_t pos;
+ uint32_t total;
+ ETSTimer abortTimer;
+} rd;
-static ETSTimer prSampleAbortTimer;
-static void FLASH_FN prSampleAbortTimerCb(void *arg)
+// --- timeout ---
+
+static void FLASH_FN abortTimerCb(void *arg)
{
+ (void)arg;
warn("Sampling aborted due to timeout.");
// try to abort the readout
- sbmp_bulk_abort(dlnk_ep, acquire_session);
+ sbmp_bulk_abort(dlnk_ep, rd.sesn);
// free the data obj if not NULL
- sbmp_ep_free_listener_obj(dlnk_ep, acquire_session);
+ sbmp_ep_free_listener_obj(dlnk_ep, rd.sesn);
// release the slot
- sbmp_ep_remove_listener(dlnk_ep, acquire_session);
- acquire_pending = false;
-}
+ sbmp_ep_remove_listener(dlnk_ep, rd.sesn);
+ // invalidate the chunk buffer and indicate that a new readout can start
+ rd.pending = false;
+}
-static void setReadoutTmeoTimer(int ms)
+static void FLASH_FN setReadoutTmeoTimer(int ms)
{
- dbg("Set read timeout %d", ms);
- os_timer_disarm(&prSampleAbortTimer);
- os_timer_setfn(&prSampleAbortTimer, prSampleAbortTimerCb, NULL);
- os_timer_arm(&prSampleAbortTimer, ms, 0);
+// 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 stopReadoutTmeoTimer(void)
+static void FLASH_FN stopReadoutTmeoTimer(void)
{
- dbg("Stop read timeout");
- os_timer_disarm(&prSampleAbortTimer);
+// dbg("Stop read timeout");
+ os_timer_disarm(&rd.abortTimer);
}
+// -------------
-typedef struct {
- uint32_t pos;
- uint32_t total;
-} DataReadState;
-static void FLASH_FN request_data_sesn_listener(SBMP_Endpoint *ep, SBMP_Datagram *dg, void **obj)
+
+/** request next chunk */
+void FLASH_FN meas_request_next_chunk(void)
{
- dbg("Received msg in session %d, dg type %d", dg->session, dg->type);
+ if (!rd.pending) return;
+ rd.chunk_ready = false; // invalidate the current chunk, so waiting for chunk is possible.
+ sbmp_bulk_request(dlnk_ep, rd.pos, CHUNK_LEN, rd.sesn);
+}
- DataReadState *readState = *obj;
+/** Check if chunk ready to be read */
+bool FLASH_FN meas_chunk_ready(void)
+{
+ return rd.pending && rd.chunk_ready;
+}
- // allocate the state struct
- if (readState == NULL) {
- readState = malloc(sizeof(DataReadState));
- *obj = readState;
+/**
+ * @brief Get received chunk. NULL if none.
+ *
+ * The array is valid until next chunk is requested.
+ * Chunk length in bytes is stored in the argument.
+ */
+uint8_t FLASH_FN *meas_get_chunk(uint16_t *chunk_len)
+{
+ if (!rd.pending) {
+ warn("Meas not pending, cant get chunk");
+ return NULL;
+ }
+ if (!rd.chunk_ready) {
+ warn("Rx chunk not ready");
+ return NULL;
}
+ *chunk_len = rd.received_chunk_size;
+ return rd.received_chunk;
+}
+
+/** Check if this was the last chunk */
+bool FLASH_FN meas_is_last_chunk(void)
+{
+ return rd.pos >= rd.total;
+}
+
+/** Terminate the readout. */
+void FLASH_FN meas_close(void)
+{
+ sbmp_ep_remove_listener(dlnk_ep, rd.sesn);
+ stopReadoutTmeoTimer();
+ rd.pending = false;
+
+ info("Transfer closed.");
+}
+
+
+static void FLASH_FN request_data_sesn_listener(SBMP_Endpoint *ep, SBMP_Datagram *dg, void **obj)
+{
+ (void)obj;
+
+// dbg("Received msg in session %d, dg type %d", dg->session, dg->type);
+
PayloadParser pp;
switch (dg->type) {
case DG_BULK_OFFER:// Data ready notification
stopReadoutTmeoTimer();
- info("--- Data offered for bulk transfer ---");
+// info("--- Peer offers data for bulk transfer ---");
// data is ready to be read
pp = pp_start(dg->payload, dg->length);
- readState->pos = 0;
- readState->total = pp_u32(&pp);
+ rd.pos = 0;
+ rd.total = pp_u32(&pp);
- dbg("Total bytes: %d", readState->total);
-
- // we choose to request the data immediately
+// dbg("Total bytes avail: %d", rd.total);
+ // renew the timeout
setReadoutTmeoTimer(1000);
- sbmp_bulk_request(ep, readState->pos, CHUNK_LEN, dg->session);
+
+ // request first chunk
+ sbmp_bulk_request(ep, rd.pos, CHUNK_LEN, dg->session);
break;
case DG_BULK_DATA: // data received
stopReadoutTmeoTimer();
- info("--- Received a chunk, length %d ---", dg->length);
+// info("--- Received a chunk, length %d ---", dg->length);
// Process the received data
- pp = pp_start(dg->payload, dg->length);
- while(pp.ptr < pp.len) {
- uint32_t x = pp_u32(&pp);
- printf("%d,", x);
- }
- printf("\n");
+ memcpy(rd.received_chunk, dg->payload, dg->length);
+ rd.chunk_ready = true;
+ rd.received_chunk_size = dg->length;
- // and ask for more
- readState->pos += dg->length;
+ // move the pointer for next request
+ rd.pos += dg->length;
- if (readState->pos >= readState->total) {
- dbg("Transfer is complete.");
- // transfer complete
+ setReadoutTmeoTimer(1000); // timeout to retrieve the data & ask for more
- // make sure the peer has freed the buffer
- // (may be waiting for us if we wanted to re-read something)
+ if (rd.pos >= rd.total) {
+ info("Transfer is complete.");
+ // transfer complete
+ // ask peer to release the buffer & go idle
sbmp_bulk_abort(ep, dg->session);
- goto cleanup;
- } else {
- // read next part
- setReadoutTmeoTimer(1000);
- sbmp_bulk_request(ep, readState->pos, CHUNK_LEN, dg->session);
}
break;
@@ -125,24 +176,18 @@ static void FLASH_FN request_data_sesn_listener(SBMP_Endpoint *ep, SBMP_Datagram
return;
cleanup:
- // free the obj
- free(readState);
// remove the listener
- sbmp_ep_remove_listener(ep, dg->session);
- stopReadoutTmeoTimer();
- acquire_pending = false;
-
- // In case the error was in SBMP (bad state)
+ meas_close();
}
-static bool FLASH_FN meas_request_data(uint16_t count)
+bool FLASH_FN meas_request_data(uint16_t count)
{
bool suc = false;
info("Requesting data capture - %d samples.", count);
- if (acquire_pending) {
+ if (rd.pending) {
error("Acquire request already in progress.");
return false;
}
@@ -152,7 +197,10 @@ static bool FLASH_FN meas_request_data(uint16_t count)
return false;
}
- acquire_pending = true;
+ rd.chunk_ready = false;
+ rd.pos = 0;
+ rd.total = 0;
+ rd.pending = true;
// start the abort timer - timeout
setReadoutTmeoTimer(6000);
@@ -170,7 +218,7 @@ static bool FLASH_FN meas_request_data(uint16_t count)
goto fail;
}
- acquire_session = sesn;
+ rd.sesn = sesn;
// request N values
sbmp_ep_send_u16(dlnk_ep, count);
@@ -181,7 +229,7 @@ static bool FLASH_FN meas_request_data(uint16_t count)
fail:
stopReadoutTmeoTimer();
- acquire_pending = false;
+ rd.pending = false;
return false;
}
@@ -189,7 +237,7 @@ fail:
// ------ C G I ---------
-
+/*
int FLASH_FN cgiReadSamples(HttpdConnData *connData)
{
char buff[128];
@@ -218,3 +266,4 @@ int FLASH_FN cgiReadSamples(HttpdConnData *connData)
return HTTPD_CGI_DONE;
}
+*/
diff --git a/user/sampling.h b/user/sampling.h
index 47c58ba..9407c58 100644
--- a/user/sampling.h
+++ b/user/sampling.h
@@ -4,7 +4,41 @@
#include
#include
-// temporary func to nread samples
-int cgiReadSamples(HttpdConnData *connData);
+/**
+ * Reading procedure
+ * -----------------
+ *
+ * 1. meas_request_data(count)
+ * 2. wait for meas_chunk_ready() == true
+ * 3. meas_get_chunk() to read the chunk last received
+ * 4. if meas_is_last_chunk(), call meas_close() and DONE.
+ * 5. meas_request_next_chunk() to get more data, goto 2
+ *
+ * Waiting should have a timeout, if data not received, return error status to client.
+ */
+
+/** Request data from the sampling module. Count - number of samples. */
+bool meas_request_data(uint16_t count); // TODO specify what kind of data - currently direct samples.
+
+/** request next chunk */
+void meas_request_next_chunk(void);
+
+/** Check if chunk ready to be read */
+bool meas_chunk_ready(void);
+
+/**
+ * @brief Get received chunk. NULL if none.
+ *
+ * The array is valid until next chunk is requested.
+ * Chunk length in bytes is stored in the argument.
+ */
+uint8_t *meas_get_chunk(uint16_t *chunk_len);
+
+/** Check if this was the last chunk */
+bool meas_is_last_chunk(void);
+
+/** Terminate the readout. */
+void meas_close(void);
+
#endif // SAMPLING_H
diff --git a/user/serial.c b/user/serial.c
index ea660e8..9f2f17e 100644
--- a/user/serial.c
+++ b/user/serial.c
@@ -17,7 +17,7 @@
static void uart0_rx_intr_handler(void *para);
static void uart_recvTask(os_event_t *events);
-#define uart_recvTaskPrio 0
+#define uart_recvTaskPrio 1
#define uart_recvTaskQueueLen 10
static os_event_t uart_recvTaskQueue[uart_recvTaskQueueLen];
@@ -123,18 +123,21 @@ void uart_rx_intr_enable(uint8 uart_no)
#define UART_GetRxFifoCount(uart_no) ((READ_PERI_REG(UART_STATUS((uart_no))) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT)
-static void FLASH_FN uart_recvTask(os_event_t *events)
+void FLASH_FN uart_poll(void)
{
- if (events->sig == 0) {
- uint8 fifo_len = UART_GetRxFifoCount(UART0);
+ uint8 fifo_len = UART_GetRxFifoCount(UART0);
+
+ for (uint8 idx = 0; idx < fifo_len; idx++) {
+ uint8 d_tmp = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
+ datalink_receive(d_tmp);
+ }
+}
- // read from the FIFO & print back
- for (uint8 idx = 0; idx < fifo_len; idx++) {
- uint8 d_tmp = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
- //UART_WriteChar(UART0, d_tmp, 0);
- datalink_receive(d_tmp);
- }
+static void FLASH_FN uart_recvTask(os_event_t *events)
+{
+ if (events->sig == 0) {
+ uart_poll();
// clear irq flags
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
diff --git a/user/serial.h b/user/serial.h
index 90b9419..b3e4dc5 100644
--- a/user/serial.h
+++ b/user/serial.h
@@ -3,6 +3,10 @@
#include
+/** Init the uarts */
void serialInit();
+/** poll uart while waiting for something */
+void uart_poll(void);
+
#endif
diff --git a/user/timeout.h b/user/timeout.h
deleted file mode 100644
index ecaebb0..0000000
--- a/user/timeout.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef TIMEOUT_H
-#define TIMEOUT_H
-
-#include
-
-#define until_timeout(to_ms) for(uint32_t _utmeo = system_get_time(); system_get_time() - _utmeo < ((to_ms)*1000);)
-
-/** Retry a call until a timeout. Variable 'suc' is set to the return value. Must be defined. */
-#define retry_TO(to_ms, call) \
- until_timeout(to_ms) { \
- suc = call; \
- if (suc) break; \
- }
-
-#endif // TIMEOUT_H
diff --git a/web-build.sh b/web-build.sh
new file mode 100755
index 0000000..8917b48
--- /dev/null
+++ b/web-build.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+xterm -title "ESP html build" -e "source $HOME/.bashrc && ./.web-build_do.sh"
diff --git a/html_serve.sh b/web-serve.sh
similarity index 100%
rename from html_serve.sh
rename to web-serve.sh