Exportable version of WizziLab's modem driver.
src/modem_ref.cpp
- Committer:
- Jeej
- Date:
- 2021-09-07
- Revision:
- 61:820395fc5572
- Parent:
- 60:08efaaca0e83
- Child:
- 62:75d819d68e5f
File content as of revision 61:820395fc5572:
#include "mbed.h" #include "WizziDebug.h" #include "modem_ref.h" #include "kal_crypto.h" #include "kal_codec.h" #include "d7a_1x_fs.h" #if 0 #define REF_PRINT(...) PRINT(__VA_ARGS__) #define URC_PRINT(...) PRINT(__VA_ARGS__) #else #define REF_PRINT(...); #define URC_PRINT(...); #endif typedef struct { action_callback_t* cb; alp_payload_t** alp_rsp; } modem_ref_user_t; typedef struct { fx_serial_send_t* send; modem_ref_callbacks_t* cb; modem_lwan_callbacks_t* lwan_cb; modem_ref_user_t user[MAX_USER_NB]; u8 state; } modem_ref_ctx_t; static modem_ref_ctx_t g_modem; #define STATE_OPEN 0xab #define STATE_CLOSED 0 // Flows #define WC_FLOWID_CMD 0x10 #define WC_FLOWID_ALP 0x20 #define WC_FLOWID_SYS 0x30 // Sub-Flows #define WC_FLOW_ALP_CMD 0x20 #define WC_FLOW_ALP_RESP 0x21 #define WC_FLOW_ALP_UNS 0x22 #define WC_FLOW_SYS_RST 0x30 #define WC_FLOW_SYS_PING 0x34 #define WC_FLOW_SYS_PONG 0x35 #define WC_FLOW_SYS_CFG 0x36 #define WC_FLOW_SYS_XON 0x39 #define WC_FLOW_SYS_XOFF 0x3a #define WC_FLOW_SYS_XACK 0x3b // Misc CMD... #define WM_BOOT 0x81 #define PKT_MAX_SIZE 255 static void serial_send(WizziComPacketType type, alp_payload_t* alp) { u8 buf[PKT_MAX_SIZE]; //PRINT("<--\n"); //alp_payload_print(alp); u32 len = alp_payload_to_buf(alp, buf, 0, PKT_MAX_SIZE); ASSERT(g_modem.send != NULL, "NULL send function!\r\n"); g_modem.send(type, buf, len); alp_payload_free(alp); } static void _call_fs_user_cb(alp_payload_t* alp, int id, u32 action) { alp_parsed_chunk_t r; u8* p = alp->d; if (NULL == alp) { return; } alp_parse_chunk(&p, &r); switch (r.type) { case ALP_OPCODE_TAG: id = r.meta.tag.id; REF_PRINT("ACT %d: TAG[%d] ID:%d ERR:%d EOP:%d\n", action, id, r.meta.tag.err, r.meta.tag.eop); break; case ALP_OPCODE_F_RD_DATA: REF_PRINT("ACT %d: F_RD_DATA[%d] @%d %d bytes\n", action, r.meta.f_data.fid, r.meta.f_data.offset, r.meta.f_data.length); if (g_modem.cb->read) { g_modem.cb->read(action, r.meta.f_data.fid, r.meta.f_data.offset, r.meta.f_data.length, id); } break; case ALP_OPCODE_F_WR_DATA: REF_PRINT("ACT %d: F_WR_DATA[%d] @%d %d bytes\n", action, r.meta.f_data.fid, r.meta.f_data.offset, r.meta.f_data.length); if (g_modem.cb->write) { g_modem.cb->write(action, r.meta.f_data.fid, r.data, r.meta.f_data.offset, r.meta.f_data.length, id); } break; case ALP_OPCODE_F_RD_PROP: REF_PRINT("ACT %d: F_RD_PROP[%d]\n", action, r.meta.f_data.fid); if (g_modem.cb->read_fprop) { g_modem.cb->read_fprop(action, r.meta.f_data.fid, id); } break; case ALP_OPCODE_F_DELETE: REF_PRINT("ACT %d: F_DELETE[%d]\n", action, r.meta.f_data.fid); if (g_modem.cb->remove) { g_modem.cb->remove(action, r.meta.f_data.fid, id); } break; case ALP_OPCODE_F_FLUSH: REF_PRINT("ACT %d: F_FLUSH[%d]\n", action, r.meta.f_data.fid); if (g_modem.cb->flush) { g_modem.cb->flush(action, r.meta.f_data.fid, id); } break; default: ASSERT(false, "ASSERT: Unsupported ALP File Operation: %d\n", r.type); break; } ASSERT(id >= 0, "ASSERT: Wrong id %d\n", id); _call_fs_user_cb(alp->next, id, ++action); } static void call_fs_user_cb(alp_payload_t* alp) { _call_fs_user_cb(alp, -1, 0); } static void _call_urc_user_cb(alp_payload_t* alp, u32 action) { alp_parsed_chunk_t r; u8* p = alp->d; if (NULL == alp) { return; } alp_parse_chunk(&p, &r); switch (r.type) { case ALP_OPCODE_RSP_URC: if (ALP_URC_TYPE_LQUAL == r.meta.urc.type) { REF_PRINT("ACT %d: RSP_URC: LQUAL[%d] %d\n", action, r.meta.urc.ifid, r.meta.urc.per); if (g_modem.cb->lqual) { g_modem.cb->lqual(r.meta.urc.ifid, r.meta.urc.per); } } else if (ALP_URC_TYPE_LDOWN == r.meta.urc.type) { REF_PRINT("ACT %d: RSP_URC: LDOWN[%d]\n", action, r.meta.urc.ifid); if (g_modem.cb->ldown) { g_modem.cb->ldown(r.meta.urc.ifid); } } else if (ALP_URC_TYPE_BUSY == r.meta.urc.type) { REF_PRINT("ACT %d: RSP_URC: BUSY[%d]\n", action, r.meta.urc.ifid); if (g_modem.cb->busy) { g_modem.cb->busy(r.meta.urc.ifid); } } else if (ALP_URC_TYPE_ITF_BUSY == r.meta.urc.type) { REF_PRINT("ACT %d: RSP_URC: ITF_BUSY[%d] for %d seconds\n", action, r.meta.urc.ifid, r.meta.urc.per); if (FID_LWAN_ITF == r.meta.urc.ifid) { if (g_modem.lwan_cb) { if (MAX_U32 == r.meta.urc.per) { if (g_modem.lwan_cb->join_failed) { g_modem.lwan_cb->join_failed(); } } else if (0 == r.meta.urc.per) { if (g_modem.lwan_cb->packet_sent) { g_modem.lwan_cb->packet_sent(); } } else { if (g_modem.lwan_cb->itf_busy) { g_modem.lwan_cb->itf_busy(r.meta.urc.per); } } } } else { if (g_modem.cb->itf_busy) { g_modem.cb->itf_busy(r.meta.urc.ifid, r.meta.urc.per); } } } else { ASSERT(false, "ASSERT: Unsupported ALP URC: %d\n", r.meta.urc.type); } break; default: // This could be anything // Let user deal with the payload if (g_modem.cb->udata) { g_modem.cb->udata(alp); } break; } _call_urc_user_cb(alp->next, ++action); } static void call_urc_user_cb(alp_payload_t* alp) { _call_urc_user_cb(alp, 0); } void modem_ref_input(u8 flowid, u8* payload, u8 size) { int rem =size; u8* p = payload; alp_parsed_chunk_t r; int id = -1; s8 err = ALP_ERR_NONE; u8 eop; u32 parsed; alp_payload_t* alp; REF_PRINT("input 0x%x/%d Bytes\n", flowid, size); switch (flowid) { case WC_FLOW_ALP_UNS: case WC_FLOW_ALP_CMD: // pre-parse payload alp = alp_payload_parse(p, size); //PRINT("-->\n"); //alp_payload_print(alp); if (ALP_OPCODE_TAG == (alp->d[0] & 0x3F)) { // Payload starts with a tag, this must be a FS command call_fs_user_cb(alp); } else { // else this is a 'real' URC (or ISTATUS if enabled on modem) call_urc_user_cb(alp); } alp_payload_free(alp); break; case WC_FLOW_ALP_RESP: // pre-parse payload alp = alp_payload_parse(p, size); //PRINT("-->\n"); //alp_payload_print(alp); p = alp->d; alp_parse_chunk(&p, &r); // This should always be a TAG'ed response as we tag our requests ASSERT((r.type == ALP_OPCODE_RSP_TAG), "ASSERT: expecting RESP_TAG got 0x%02X\n", r.type); id = r.meta.tag.id; eop = r.meta.tag.eop; if (g_modem.user[id].cb == NULL) { PRINT("WARNING: NULL Callback for ID %d\n", id); alp_payload_print(alp); alp_payload_free(alp); break; } //ASSERT(g_modem.user[id].cb != NULL, "ASSERT: NULL Callback for ID %d\n", id); if (g_modem.user[id].alp_rsp) { // Give the remaining of the payload to the user to deal with *(g_modem.user[id].alp_rsp) = alp_payload_append(*(g_modem.user[id].alp_rsp), alp); } else { // Discard payload alp_payload_free(alp); } if(eop) { // This is mainly for debug, catch old pointers //g_modem.user[id].data = NULL; //g_modem.user[id].istatus= NULL; REF_PRINT("EOP\n"); } // User Callback g_modem.user[id].cb(eop, err, id); break; case WC_FLOW_SYS_RST: // 'Software' reset request if (g_modem.cb->reset) { g_modem.cb->reset(); } break; case WC_FLOWID_CMD: if (*p == WM_BOOT) { uint16_t nb_boot; u8 cause; p++; cause = p[0]; nb_boot = HAL_TO_U16(p[3], p[2]); if (g_modem.cb->boot) { g_modem.cb->boot(cause, nb_boot); } } else { REF_PRINT("Unsupported CMD :0x%x\n", *p); } break; default: REF_PRINT("Unsupported WC Flowid:0x%x / %d Bytes\n", flowid, size); break; } } static u32 modem_ref_add_root_permission(u8* p, u8* root_key, u8* action, u32 action_size) { u8 hash[32]; // Calculate hash on action kal_sha256_init(); kal_sha256_update(action, action_size); kal_sha256_update(root_key, D7A_FS_ROOT_KEY_SIZE); kal_sha256_final(hash); // Prepend Permission-request... ALP_ACTION_PERM_REQ(p, false, ALP_PERM_REQ_ROOT, ALP_WIZZILAB_AUTH_PROTOCOL_ID); // ... and hash memcpy(p, hash, ALP_ACTION_PERM_REQ_TOKEN_SIZE); return ALP_ACTION_PERM_REQ_OFFSET; } int modem_ref_get_id(action_callback_t* cb) { int i; // Use rolling ids static u8 rolling; for(i = 0; i < MAX_USER_NB; i++) { int id = (i + rolling) % MAX_USER_NB; if (g_modem.user[id].cb == NULL) { g_modem.user[id].cb = cb; rolling++; //PRINT("Get ID:%d/0x%08x\n", id, cb); return id; } } ASSERT(i < MAX_USER_NB, "ASSERT: out of users\n"); return -1; } int modem_ref_free_id(u8 id) { if (id < MAX_USER_NB) { g_modem.user[id].cb = NULL; //PRINT("Free ID:%d\n", id); return id; } return -1; } void modem_ref_open(fx_serial_send_t* send, modem_ref_callbacks_t* callbacks) { if (g_modem.state != STATE_OPEN) { g_modem.send = send; g_modem.cb = callbacks; memset(g_modem.user, 0, (MAX_USER_NB * sizeof(modem_ref_user_t))); REF_PRINT("Open Modem - Max users:%d\n", MAX_USER_NB); g_modem.state = STATE_OPEN; } } void modem_ref_close(void) { if (g_modem.state == STATE_OPEN) { g_modem.state = STATE_CLOSED; } } void modem_ref_reset(void) { serial_send(WizziComPacketSysReset, NULL); } void modem_ref_set_lwan_cb(modem_lwan_callbacks_t* callbacks) { g_modem.lwan_cb = callbacks; } void modem_ref_set_boot_cb(fx_boot_t* boot_cb) { g_modem.cb->boot = boot_cb; } void modem_ref_alp(void* itf, alp_payload_t* alp_user, alp_payload_t** alp_rsp, int id) { alp_payload_t* alp = NULL; if (alp_rsp) { // Expecting a response // Make sure pointer value is NULL *alp_rsp = NULL; } // response pointer g_modem.user[id].alp_rsp = alp_rsp; // Always a tag alp = alp_payload_tag(alp, id); // Forward on itf if any if (itf) { alp = alp_payload_forward(alp, itf); // NOP action to get istats on ACKs alp = alp_payload_nop(alp, false); } // Add user payload alp = alp_payload_append(alp, alp_user); // Send to modem serial_send(WizziComPacketAlpUns, alp); } static void _modem_ref_rsp(alp_payload_t* alp_user, u8 err, int id) { alp_payload_t* alp = NULL; // response pointer g_modem.user[id].alp_rsp = NULL; // Always a tag alp = alp_payload_rsp_tag(alp, id, true, err); // Add user payload alp = alp_payload_append(alp, alp_user); // Send to modem serial_send(WizziComPacketAlpResp, alp); } void modem_ref_respond(u8 action, s8 status, int id) { alp_payload_t* alp = NULL; alp = alp_payload_rsp_status(alp, action, status); _modem_ref_rsp(alp, (status < ALP_ERR_NONE)? true: false, id); } void modem_ref_respond_fprop(u8 fid, alp_file_header_t* hdr, int id) { alp_payload_t* alp = NULL; alp = alp_payload_rsp_fprop(alp, fid, hdr); _modem_ref_rsp(alp, false, id); } void modem_ref_respond_read(u8 fid, void* data, u32 offset, u32 length, int id) { alp_payload_t* alp = NULL; alp = alp_payload_rsp_f_data(alp, fid, data, offset, length); _modem_ref_rsp(alp, false, id); }