without warning at positive error codes.
Fork of d7a_1x by
src/d7a_alp.cpp
- Committer:
- trond
- Date:
- 2017-03-28
- Revision:
- 90:eaf980532613
- Parent:
- 88:dcebea09aac7
File content as of revision 90:eaf980532613:
#include "mbed.h" #include "rtos.h" #include "dbg.h" #include "d7a.h" #include "d7a_com.h" #include "d7a_common.h" #include "d7a_fs.h" #include "d7a_modem.h" #include "d7a_sys.h" #include "d7a_alp.h" #include "sha.h" #include "d7a_typedefs.h" #if 1 #define ALP_DPRINT(...) DPRINT(__VA_ARGS__) #define ALP_DPRINT_DATA(...) DPRINT_DATA(__VA_ARGS__) #define ALP_FPRINT(...) FPRINT(__VA_ARGS__) #else #define ALP_DPRINT(...); #define ALP_DPRINT_DATA(...); #define ALP_FPRINT(...); #endif #define ALP_CMD_MAX_LENGHT (256) #define MAX_RESPONSES (32) static uint8_t g_alp_tag; static uint8_t g_alp_root_key_size; static uint8_t g_alp_buffer[ALP_CMD_MAX_LENGHT]; static UnsolicitedMsgFunction g_alp_uns_msg; static OS_Queue<d7a_com_rx_msg_t, 8> g_alp_pkt_queue; static OS_Queue<d7a_com_rx_msg_t, 8> g_alp_pl_queue; static OS_Thread g_alp_thread(osPriorityHigh, 512, NULL); void d7a_alp_thread(); d7a_errors_t d7a_alp_open(UnsolicitedMsgFunction uns_msg) { ALP_FPRINT("\r\n"); g_alp_uns_msg = uns_msg; g_alp_root_key_size = D7A_ROOT_KEY_SIZE; osStatus err = g_alp_thread.start(d7a_alp_thread); ASSERT(err == osOK, "Failed to start d7a_alp_thread (err: %d)\r\n", err); return D7A_ERR_NONE; } d7a_errors_t d7a_alp_close(void) { ALP_FPRINT("\r\n"); g_alp_thread.terminate(); return D7A_ERR_NONE; } void d7a_alp_new_pkt(d7a_com_rx_msg_t* pkt) { ALP_FPRINT("\r\n"); ASSERT(g_alp_pkt_queue.put(pkt) == osOK, "ALP queue full!\r\n"); } static void d7a_alp_new_pl(d7a_com_rx_msg_t* pl) { ALP_FPRINT("\r\n"); ASSERT(g_alp_pl_queue.put(pl) == osOK, "ALP PL queue full!\r\n"); } static d7a_com_rx_msg_t* d7a_alp_wait_pkt(uint32_t millisec) { ALP_FPRINT("\r\n"); osEvent evt = g_alp_pkt_queue.get(millisec); return (evt.status == osEventMessage)? (d7a_com_rx_msg_t*)evt.value.p : NULL; } static d7a_com_rx_msg_t* d7a_alp_wait_pl(uint32_t millisec) { ALP_FPRINT("\r\n"); osEvent evt = g_alp_pl_queue.get(millisec); return (evt.status == osEventMessage)? (d7a_com_rx_msg_t*)evt.value.p : NULL; } static uint32_t d7a_ctf_to_ti(d7a_ctf_t ctf) { return ((1 << (2*ctf.bf.exp)) * ctf.bf.mant); } static uint32_t d7a_alp_encode_length(uint8_t* p, uint32_t len) { if (len <= 0x3F) { *p++ = len; return 1; } else if (len <= 0x3FFF) { *p++ = 0x40 + (uint8_t)(len >> 8); *p++ = (uint8_t)(len & 0xFF); return 2; } else if (len <= 0x3FFFFF) { *p++ = 0x80 + (uint8_t) (len >> 16); *p++ = (uint8_t)((len >> 8) & 0xFF); *p++ = (uint8_t) (len & 0xFF); return 3; } else { *p++ = 0xC0 + (uint8_t) (len >> 24); *p++ = (uint8_t)((len >> 16) & 0xFF); *p++ = (uint8_t)((len >> 8) & 0xFF); *p++ = (uint8_t) (len & 0xFF); return 4; } } static uint32_t alp_decode_length(uint8_t* p, uint32_t* len) { uint32_t tmp = 0; switch ((*p) & 0xC0) { case 0xC0: // 0xCx xx xx xx tmp = (*p++ & 0x3F) << 24; tmp += *p++ << 16; tmp += *p++ << 8; tmp += *p++ << 0; *len = tmp; return 4; case 0x80: // 0x8x xx xx : 16384 <= Len <4194303 tmp = (*p++ & 0x3F) << 16; tmp += *p++ << 8; if (tmp == 0) { // 0x8000 ActP special ActP code // Do not fetch the extra byte tmp = 2; } else { tmp += *p++ << 0; } *len = tmp; return 3; case 0x40: // 0x4x xx : 64 <= Len < 16383 tmp = (*p++ & 0x3F) << 8; tmp += *p++ << 0; if (tmp == 0) { // 0x4000 ActP special ActP code tmp = 1; } *len = tmp; return 2; case 0: // Len <63 tmp = (*p++ & 0x3F) << 0; *len = tmp; return 1; } return 0; } static uint32_t d7a_alp_add(uint8_t* p, const uint8_t* data, uint32_t len) { memcpy(p, data, len); return len; } void d7a_alp_free_msg(d7a_msg_t* msg) { ALP_FPRINT("\r\n"); if (msg->data) { FREE(msg->data); } FREE(msg); } static d7a_msg_t* d7a_alp_new_msg(void) { ALP_FPRINT("\r\n"); d7a_msg_t* msg = (d7a_msg_t*)MALLOC(sizeof(d7a_msg_t)); memset(msg, 0, sizeof(d7a_msg_t)); msg->err = D7A_ERR_NONE; return msg; } static d7a_alp_rsp_t* d7a_alp_parse_pl(d7a_com_rx_msg_t* pkt) { ALP_FPRINT("\r\n"); if (pkt == NULL) { return NULL; } uint8_t* p = pkt->buffer; uint8_t* t = p; uint8_t len = pkt->blen; d7a_alp_rsp_t* rsp = (d7a_alp_rsp_t*)MALLOC(sizeof(d7a_alp_rsp_t)); rsp->tag = NO_TAG; rsp->eop = false; rsp->msg = d7a_alp_new_msg(); while ((p - t) < len) { uint8_t ctrl = *p++; switch (ctrl & 0x3F) { case ALP_OPCODE_RSP_STATUS: if (ctrl & ALP_OPCODE_INDIRECT) { // ITF Type uint8_t type = *p++; // Length uint32_t length; p += alp_decode_length(p, &length); // Data d7a_sp_res_t* res = (d7a_sp_res_t*)p; p += length; // Fill corresponding fields rsp->msg->lb = res->lb; // Get Link Budget rsp->msg->rxlev = res->rxlev; // Get RXLEV memcpy(rsp->msg->id, res->addressee.id, D7A_UID_LEN); // Get UID ALP_DPRINT("ALP RSP ISTATUS type:%02X lb: %3d ", type, rsp->msg->lb); ALP_DPRINT_DATA("UID:", "%02X", rsp->msg->id, D7A_UID_LEN, "\r\n"); } else { uint8_t aid = *p++; // Action ID rsp->msg->err = *p++; // Status ALP_DPRINT("ALP RSP STATUS aid:%d Status:%d\r\n", aid, rsp->msg->err); } break; case ALP_OPCODE_RSP_TAG: rsp->eop = !!(ctrl & ALP_CTRL_EOP); rsp->tag = *p++; // TAG ALP_DPRINT("ALP RSP TAG %d EOP %d\r\n", rsp->tag, rsp->eop); break; case ALP_OPCODE_RSP_F_DATA: uint8_t fid; uint32_t offset; uint32_t length; fid = *p++; // File ID p += alp_decode_length(p, &offset); // offset p += alp_decode_length(p, &length); // length rsp->msg->data = (d7a_data_t*)MALLOC(sizeof(d7a_data_t) - 1 + length); rsp->msg->data->fid = fid; rsp->msg->data->offset = offset; rsp->msg->data->length = length; p += d7a_alp_add(rsp->msg->data->buf, p, length); ALP_DPRINT("ALP RSP F_DATA f:%d o:%d s:%d\r\n", fid, offset, length); //ALP_DPRINT_DATA("DATA: ", "%02X ", (uint8_t*)rsp->data, rsp->data_len, "\r\n"); break; default: WARNING(false, "ALP Untreated OP %d\r\n", ctrl); break; } } ASSERT((p - t) == len, "Payload wrong size: %d expected %d\r\n", (p - t), len); return rsp; } static uint32_t d7a_alp_tag(uint8_t* p, bool eop) { uint8_t* t = p; *p++ = ALP_OPCODE_TAG + ((eop)? ALP_CTRL_EOP : 0); *p++ = ++g_alp_tag; return (uint32_t)(p - t); } static uint32_t d7a_alp_forward_action(uint8_t* p, d7a_itf_t* itf, bool resp) { uint8_t* t = p; uint32_t itf_size = sizeof(d7a_itf_t); switch (itf->cfg.addressee.ctrl.bf.idf) { case D7A_ID_NBID: itf_size -= 7; break; case D7A_ID_NOID: itf_size -= 8; break; case D7A_ID_UID: break; case D7A_ID_VID: itf_size -= 4; break; default: break; } *p++ = ALP_OPCODE_FORWARD + ((resp)? ALP_CTRL_RESP : 0); p += d7a_alp_add(p, (uint8_t*)itf, itf_size); return (uint32_t)(p - t); } static uint32_t d7a_alp_write_action(uint8_t* p, const uint8_t file_id, const uint32_t offset, const uint32_t size, const uint8_t* const buf, bool resp) { uint8_t* t = p; *p++ = ALP_OPCODE_F_WR_DATA + ((resp)? ALP_CTRL_RESP : 0); *p++ = file_id; p += d7a_alp_encode_length(p, offset); p += d7a_alp_encode_length(p, size); p += d7a_alp_add(p, buf, size); return (uint32_t)(p - t); } static uint32_t d7a_alp_read_action(uint8_t* p, const uint8_t file_id, const uint32_t offset, const uint32_t size, bool resp) { uint8_t* t = p; *p++ = ALP_OPCODE_F_RD_DATA + ((resp)? ALP_CTRL_RESP : 0); *p++ = file_id; p += d7a_alp_encode_length(p, offset); p += d7a_alp_encode_length(p, size); return (uint32_t)(p - t); } static uint32_t d7a_alp_perm_request_action(uint8_t* p, uint8_t* req, uint32_t req_size, const uint8_t* root_key, bool resp) { uint8_t* t = p; uint8_t hash[32]; *p++ = ALP_OPCODE_PERM_REQ + ((resp)? ALP_CTRL_RESP : 0); *p++ = 1; // ROOT request *p++ = 42; // Auth protocol ID sha256_init(); sha256_update(req, req_size); sha256_update((uint8_t*)root_key, g_alp_root_key_size); sha256_final(hash); //PRINT_DATA("Req : ", "%02X ", (uint8_t*)req, req_size, "\r\n"); //PRINT_DATA("Key : ", "%d ", (uint8_t*)root_key, g_alp_root_key_size, "\r\n"); //PRINT_DATA("Token: ", "%02X", hash, D7A_AUTH_PROTOCOLE_TOKEN_SIZE, "\r\n"); p += d7a_alp_add(p, hash, D7A_AUTH_PROTOCOLE_TOKEN_SIZE); return (uint32_t)(p - t); } static uint32_t d7a_alp_flush_action(uint8_t* p, uint8_t fid, bool resp) { uint8_t* t = p; *p++ = ALP_OPCODE_F_FLUSH + ((resp)? ALP_CTRL_RESP : 0); *p++ = fid; return (uint32_t)(p - t); } static void d7a_alp_construct_resp(d7a_msg_t** ret, uint8_t current_tag) { ALP_FPRINT("\r\n"); int i = 0; d7a_alp_rsp_t* pl = NULL; d7a_com_rx_msg_t* pkt = NULL; int32_t time; Timer timeout; timeout.start(); // Parse responses do { time = D7A_ALP_RESP_TO - timeout.read_ms(); if (time < 0) time = 0; pkt = d7a_alp_wait_pl(time); if (pkt == NULL) { ret[i] = d7a_alp_new_msg(); ret[i]->err = D7A_ERR_CMD_TO; break; } pl = d7a_alp_parse_pl(pkt); // Check TAG if (pl->tag == NO_TAG) { WARNING(false, "No tag in payload expected %d\r\n", current_tag); FREE(pkt); d7a_alp_free_msg(pl->msg); FREE(pl); ret[i] = d7a_alp_new_msg(); ret[i]->err = D7A_ERR_UNKNOWN; break; } if (pl->tag != current_tag) { WARNING(false, "Ingnoring tag %d expecting %d\r\n", pl->tag, current_tag); d7a_alp_free_msg(pl->msg); FREE(pl); d7a_alp_new_pl(pkt); continue; } FREE(pkt); // Check for END OF PAYLOAD if (pl->eop) { ALP_DPRINT("EOP\r\n"); // If tag only if (!pl->msg->data && !pl->msg->lb && i != 0) { // Ignore response d7a_alp_free_msg(pl->msg); } else { ALP_DPRINT("last response (err %d)\r\n", pl->msg->err); ret[i] = pl->msg; } FREE(pl); break; } // Wait for new msg else { ALP_DPRINT("next response (err %d)\r\n", pl->msg->err); if (i > MAX_RESPONSES) { WARNING(false, "Too much responses! max: %d\r\n", MAX_RESPONSES); FREE(pl->msg); } else { ret[i] = pl->msg; i++; } FREE(pl); } } while (1); } static uint32_t d7a_alp_construct_itf(uint8_t* p, d7a_addressee_t* addressee, uint8_t retry, bool resp) { bool broadcast = false; if (addressee) { if (addressee->ctrl.bf.idf == D7A_ID_NBID || addressee->ctrl.bf.idf == D7A_ID_NOID) { broadcast = true; } // Construct interface d7a_itf_t itf = { // Dash7 interface .type = 0xD7, // Switch response type if broadcast .cfg.qos.bf.resp = (broadcast)? D7A_RESP_ALL : D7A_RESP_ANY, .cfg.qos.bf.retry = retry, .cfg.qos.bf.record = 0, .cfg.qos.bf.stop_on_err = 0, .cfg.to.byte = 0, .cfg.te.byte = 0, }; memcpy(&itf.cfg.addressee, addressee, sizeof(d7a_addressee_t)); // Forward action return d7a_alp_forward_action(p, &itf, true); } return 0; } d7a_msg_t** d7a_alp_init_ret(void) { d7a_msg_t** ret = (d7a_msg_t**)MALLOC(sizeof(d7a_msg_t*) * (MAX_RESPONSES + 1)); for (uint32_t i = 0; i < (MAX_RESPONSES + 1); i++) { ret[i] = NULL; } return ret; } d7a_msg_t** d7a_alp_write_file(const uint8_t file_id, const uint32_t offset, const uint32_t size, const uint8_t* const buf, const uint8_t* root_key, d7a_addressee_t* addressee, uint8_t retry, bool resp) { ALP_FPRINT("\r\n"); // Get command buffer uint8_t* p = &g_alp_buffer[0]; // Save initial position of the command buffer uint8_t* t = p; uint8_t current_tag; d7a_msg_t** ret = NULL; // malloc and init pointer array ret = d7a_alp_init_ret(); // Tag action p += d7a_alp_tag(p, true); // Eventual forward p += d7a_alp_construct_itf(p, addressee, retry, resp); // get tag current_tag = g_alp_tag; // Ask for root permissions if (root_key) { uint8_t req[100]; uint8_t req_size = d7a_alp_write_action(req, file_id, offset, size, buf, resp); p += d7a_alp_perm_request_action(p, req, req_size, root_key, false); } // Write action p += d7a_alp_write_action(p, file_id, offset, size, buf, resp); // Send command d7a_com_dump(&g_alp_buffer[0], (uint8_t)(p - t), KAL_COM_FLOW_AT_CMD); // Parse responses d7a_alp_construct_resp(ret, current_tag); return ret; } d7a_msg_t** d7a_alp_read_file(const uint8_t file_id, const uint32_t offset, const uint32_t size, const uint8_t* root_key, d7a_addressee_t* addressee, uint8_t retry) { ALP_FPRINT("\r\n"); // Get command buffer uint8_t* p = &g_alp_buffer[0]; // Save initial position of the command buffer uint8_t* t = p; uint8_t current_tag; d7a_msg_t** ret = NULL; // malloc and init pointer array ret = d7a_alp_init_ret(); // Tag action p += d7a_alp_tag(p, true); // Eventual forward p += d7a_alp_construct_itf(p, addressee, retry, true); // get tag current_tag = g_alp_tag; // Ask for root permissions if (root_key) { uint8_t req[100]; uint8_t req_size = d7a_alp_read_action(req, file_id, offset, size, true); p += d7a_alp_perm_request_action(p, req, req_size, root_key, false); } // Read action p += d7a_alp_read_action(p, file_id, offset, size, true); // Send command d7a_com_dump(&g_alp_buffer[0], (uint8_t)(p - t), KAL_COM_FLOW_AT_CMD); // Parse responses d7a_alp_construct_resp(ret, current_tag); return ret; } d7a_msg_t** d7a_alp_flush_file(const uint8_t file_id, const uint8_t* root_key, d7a_addressee_t* addressee, uint8_t retry, bool resp) { ALP_FPRINT("\r\n"); // Get command buffer uint8_t* p = &g_alp_buffer[0]; // Save initial position of the command buffer uint8_t* t = p; uint8_t current_tag; d7a_msg_t** ret = NULL; // malloc and init pointer array ret = d7a_alp_init_ret(); // Tag action p += d7a_alp_tag(p, true); // Eventual forward p += d7a_alp_construct_itf(p, addressee, retry, resp); // get tag current_tag = g_alp_tag; // Ask for root permissions if (root_key) { uint8_t req[100]; uint8_t req_size = d7a_alp_flush_action(req, file_id, resp); p += d7a_alp_perm_request_action(p, req, req_size, root_key, false); } // Flush action p += d7a_alp_flush_action(p, file_id, resp); // Send command d7a_com_dump(&g_alp_buffer[0], (uint8_t)(p - t), KAL_COM_FLOW_AT_CMD); // Parse responses d7a_alp_construct_resp(ret, current_tag); return ret; } void d7a_alp_set_root_key_size(uint8_t size) { g_alp_root_key_size = size; } void d7a_alp_thread() { ALP_FPRINT("(id:0x%08x)\r\n", osThreadGetId()); d7a_com_rx_msg_t* pkt; while (true) { pkt = d7a_alp_wait_pkt(); ASSERT(pkt != NULL, "ALP NULL pkt\r\n"); switch(pkt->id) { case KAL_COM_FLOW_AT_RESP: ALP_DPRINT("KAL_COM_FLOW_AT_RESP\r\n"); d7a_alp_new_pl(pkt); break; case KAL_COM_FLOW_AT_UNS: ALP_DPRINT("KAL_COM_FLOW_AT_UNS\r\n"); if (g_alp_uns_msg) { d7a_msg_t** uns = (d7a_msg_t**)MALLOC(sizeof(d7a_msg_t*) * 2); d7a_alp_rsp_t* pl = d7a_alp_parse_pl(pkt); uns[0] = pl->msg; uns[1] = NULL; FREE(pl); // Callback g_alp_uns_msg(uns); } FREE(pkt); break; default: EPRINT("ALP Unknown Flow ID 0x%02X\r\n", pkt->id); FREE(pkt); break; } } }