#include #include #include "datalink.h" #include "sampling.h" #include "timeout.h" // The buffer is big enough for 256 data bytes - 4*64 // number of 32-bit vars in the chunk #define CHUNK_LEN_32 64 // chunk size for bulk transfer - 64 floats #define CHUNK_LEN (CHUNK_LEN_32*4) static bool acquire_pending = false; static uint16_t acquire_session; static ETSTimer prSampleAbortTimer; static void FLASH_FN prSampleAbortTimerCb(void *arg) { warn("Sampling aborted due to timeout."); acquire_pending = false; // free the data obj if not NULL sbmp_ep_free_listener_obj(dlnk_ep, acquire_session); // release the slot sbmp_ep_remove_listener(dlnk_ep, acquire_session); } 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) { bool suc = false; dbg("Received msg in session %d, dg type %d", dg->session, dg->type); DataReadState *state = *obj; // allocate the state struct if (state == NULL) { state = malloc(sizeof(DataReadState)); *obj = state; } PayloadParser pp; switch (dg->type) { case DG_BULK_OFFER:// Data ready notification info("--- Data offered for bulk transfer ---"); // data is ready to be read pp = pp_start(dg->payload, dg->length); state->pos = 0; state->total = pp_u32(&pp); dbg("Total bytes: %d", state->total); retry_until_timeout(10, sbmp_bulk_request(ep, state->pos, CHUNK_LEN, dg->session)); break; case DG_BULK_DATA: // data received info("--- Received a chunk ---"); // Process the received data pp = pp_start(dg->payload, dg->length); for (int i = 0; i < dg->length/4; i++) { float f = pp_float(&pp); dbg("Rx %.2f", f); } // and ask for more state->pos += dg->length; if (state->pos >= state->total) { dbg("Transfer is complete."); // transfer complete // make sure the peer has freed the buffer // (may be waiting for us if we wanted to re-read something) retry_until_timeout(10, sbmp_bulk_abort(ep, dg->session)); goto cleanup; } else { // read next part retry_until_timeout(10, sbmp_bulk_request(ep, state->pos, CHUNK_LEN, dg->session)); } break; case DG_BULK_ABORT: // Peer resets the readout // this is unlikely warn("Bulk transfer aborted by peer."); goto cleanup; } return; cleanup: // free the obj free(state); // remove the listener sbmp_ep_remove_listener(ep, dg->session); } static bool FLASH_FN meas_request_data(uint16_t count) { info("Requesting data capture - %d samples.", count); if (acquire_pending) { error("Acquire request already in progress."); return false; } if (sbmp_ep_handshake_status(dlnk_ep) != SBMP_HSK_SUCCESS) { error("Hsk status not SUCCESS, can't request data."); return false; } // start the abort timer - timeout os_timer_disarm(&prSampleAbortTimer); os_timer_setfn(&prSampleAbortTimer, prSampleAbortTimerCb, NULL); os_timer_arm(&prSampleAbortTimer, 5000, 0); // 5 seconds, no repeat // start a message uint16_t sesn; bool suc = sbmp_ep_start_message(dlnk_ep, DG_REQUEST_CAPTURE, sizeof(uint16_t), &sesn); if (!suc) goto fail; // register the session listener suc = sbmp_ep_add_listener(dlnk_ep, sesn, request_data_sesn_listener, NULL); if (!suc) goto fail; // request N values sbmp_ep_send_u16(dlnk_ep, count); dbg("Request sent, session nr %d", sesn); acquire_session = sesn; return true; fail: os_timer_disarm(&prSampleAbortTimer); return false; } // ------ C G I --------- int FLASH_FN cgiReadSamples(HttpdConnData *connData) { char buff[128]; if (connData->conn == NULL) { //Connection aborted. Clean up. return HTTPD_CGI_DONE; } uint16_t count = 1; int len = httpdFindArg(connData->getArgs, "n", buff, sizeof(buff)); if (len != -1) { count = (uint16_t)atoi(buff); } dbg("User wants %d samples.", count); meas_request_data(count); httpdStartResponse(connData, 200); httpdHeader(connData, "Content-Type", "text/plain"); httpdEndHeaders(connData); // body httpdSend(connData, "OK.", -1); return HTTPD_CGI_DONE; }