Exportable version of WizziLab's modem driver.
src/modem_ref.cpp
- Committer:
- Jeej
- Date:
- 2018-01-31
- Revision:
- 24:3d8dd1d6e3de
- Parent:
- 23:5553f9541759
- Child:
- 25:14c01b9fc04d
File content as of revision 24:3d8dd1d6e3de:
#include "mbed.h" #include "WizziDebug.h" #include "modem_ref.h" #include "kal_crypto.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; u8* data; u8* istatus; } modem_user_t; typedef struct { u8* data; u8 type; u8 length; } modem_istatus_t; typedef struct { fx_serial_send_t* send; modem_callbacks_t* cb; modem_user_t user[MAX_USER_NB]; modem_istatus_t istatus; u8 state; u8 tx_sequ; } modem_ctx_t; static modem_ctx_t g_modem; #define STATE_OPEN 0xab #define STATE_CLOSED 0 #define ROOT_KEY_SIZE 16 #define SERIAL_SEND(_flow,_data,_size) do { \ ASSERT(_size<256, "SERIAL_SEND too big for serial protocol (%d/%dmax)", _size, 255);\ u8 wch[WC_HEADER_SIZE] = {WC_SYNC_BYTE_0,WC_SYNC_BYTE_1,_size,g_modem.tx_sequ++,_flow};\ g_modem.send(wch,WC_HEADER_SIZE,_data,_size);\ }while(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 protected void modem_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; REF_PRINT("input 0x%x/%d Bytes\n",flowid,size); switch (flowid) { case WC_FLOW_ALP_UNS: case WC_FLOW_ALP_CMD: rem -= alp_parse_chunk(&p, &r); //PRINT_DATA("", "%02X", p, rem, "\n"); // This should always be a TAG'ed request in case of FS access... if (r.type == ALP_OPCODE_TAG) { id = r.meta.tag.id; while(rem>0) { // Parse File Operation rem -= alp_parse_chunk(&p, &r);; REF_PRINT("ALP OP[%d] rem %d\n", r.type, rem); switch (r.type) { case ALP_OPCODE_F_RD_DATA: ASSERT((ALP_ACTION_RSP_TAG_SIZE + ALP_ACTION_RSP_F_DATA_SIZE_MAX(r.meta.f_data.length)) < 256, "F_RD_DATA too big for serial protocol (%d/%dmax)", r.meta.f_data.length, 255 - (ALP_ACTION_RSP_TAG_SIZE + ALP_ACTION_RSP_F_DATA_SIZE_MAX(0))); g_modem.cb->read(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("ALP_OPCODE_F_WR_DATA[%d] %d %d %d\n", id, r.meta.f_data.fid, r.meta.f_data.offset, r.meta.f_data.length); g_modem.cb->write(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: g_modem.cb->read_fprop(r.meta.f_data.fid,id); break; case ALP_OPCODE_F_DELETE: g_modem.cb->remove(r.meta.f_data.fid,id); break; case ALP_OPCODE_F_FLUSH: g_modem.cb->flush(r.meta.f_data.fid,id); break; default: ASSERT(false,"ASSERT: Unsupported ALP File Operation: %d\n",r.type); break; } REF_PRINT("ALP Parsing done. rem %d\n", rem); } REF_PRINT("ALP Packet done.\n"); } else { // ... or a 'real' URC (or ISTATUS if enabled on modem) g_modem.istatus = (modem_istatus_t){0}; do { switch (r.type) { case ALP_OPCODE_RSP_ISTATUS: // ISTATUS can come either alone or together with ALP_OPCODE_RSP_F_DATA // but there should be only one per payload, moreover it will come first URC_PRINT("Got ISTATUS[%x] %d Bytes\n",r.meta.itf.type,r.meta.itf.length); g_modem.istatus.type = r.meta.itf.type; g_modem.istatus.length = r.meta.itf.length; g_modem.istatus.data = r.data; if (0)// (!rem) // TODO : do we really want this ? { g_modem.cb->udata( 0, NULL, 0, 0, g_modem.istatus.type, g_modem.istatus.length, g_modem.istatus.data); } break; case ALP_OPCODE_RSP_F_DATA: // RSP_F_DATA can come either alone or together with ISTATUS g_modem.cb->udata( r.meta.f_data.fid, r.data, r.meta.f_data.offset, r.meta.f_data.length, g_modem.istatus.type, g_modem.istatus.length, g_modem.istatus.data); break; case ALP_OPCODE_RSP_URC: if (r.meta.urc.type == ALP_URC_TYPE_LQUAL) g_modem.cb->lqual(r.meta.urc.ifid,r.meta.urc.per); else if (r.meta.urc.type == ALP_URC_TYPE_LQUAL) g_modem.cb->ldown(r.meta.urc.ifid); else ASSERT(false,"ASSERT: Unsupported ALP URC: %d\n",r.meta.urc.type); break; default: ASSERT(false,"ASSERT: Unsupported ALP URC: %d\n",r.type); break; } int tem = alp_parse_chunk(&p, &r); if (!tem) { break; } rem -= tem; } while (rem>=0); } break; case WC_FLOW_ALP_RESP: // This should always be a TAG'ed response as we tag our requests rem -= alp_parse_chunk(&p, &r); ASSERT((r.type == ALP_OPCODE_RSP_TAG),"ASSERT: expecting RESP_TAG got %d\n",r.type); id = r.meta.tag.id; eop = r.meta.tag.eop; ASSERT(g_modem.user[id].cb != NULL,"ASSERT: NULL Callback for ID %d\n",id); // Empty response if (rem <= 0) { // TODO: still no info on error... REF_PRINT("ERROR\n"); err = r.meta.tag.err ? ALP_ERR_UNKNOWN : ALP_ERR_NONE; g_modem.user[id].cb(eop,err,id); return; } // Actual response(s) while(rem>0) { rem -= alp_parse_chunk(&p, &r); switch (r.type) { case ALP_OPCODE_RSP_TAG: REF_PRINT("RSP_TAG[%d]\n", r.meta.tag.id); break; case ALP_OPCODE_RSP_F_DATA: REF_PRINT("RSP_F_DATA[%d]\n", r.meta.f_data.length); ASSERT(g_modem.user[id].data != NULL,"ASSERT: NULL Data Buffer for RD on ID %d\n",id); memcpy(g_modem.user[id].data,r.data,r.meta.f_data.length); break; case ALP_OPCODE_RSP_F_PROP: REF_PRINT("RSP_F_PROP[%d]\n", r.meta.f_data.length); ASSERT(g_modem.user[id].data != NULL,"ASSERT: NULL Data Buffer for RD on ID %d\n",id); memcpy(g_modem.user[id].data,r.data,r.meta.f_data.length); break; case ALP_OPCODE_RSP_STATUS: REF_PRINT("RSP_STATUS[%d]\n", r.meta.status.code); err = r.meta.status.code; break; case ALP_OPCODE_RSP_ISTATUS: REF_PRINT("RSP_ISTATUS[%d]\n", r.meta.itf.length); ASSERT(g_modem.user[id].istatus != NULL,"ASSERT: NULL ISTAT Buffer for RD on ID %d\n",id); memcpy(g_modem.user[id].istatus,r.data,r.meta.itf.length); break; default: ASSERT(false,"ASSERT: Unsupported ALP Response: %d\n",r.type); break; } } 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 g_modem.cb->reset(); break; case WC_FLOWID_CMD: if (*p == WM_BOOT) { u16 nb_boot; u8 cause; p++; cause = p[0]; nb_boot = HAL_TO_U16(p[3],p[2]); 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; } } private u32 modem_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, ROOT_KEY_SIZE); kal_sha256_final(hash); // Prepend Permission-request... ALP_ACTION_PERM_REQ(p, false, ALP_PERM_REQ_ROOT); // ... and hash memcpy(p, hash, ALP_WIZZILAB_AUTH_PROTOCOL_TOKEN_SIZE); return ALP_ACTION_PERM_REQ_OFFSET; } public int modem_get_id(action_callback_t* cb) { int i; for(i=0;i<MAX_USER_NB;i++) { if (g_modem.user[i].cb == NULL) { g_modem.user[i].cb = cb; //REF_PRINT("Get ID:%d/0x%08x\n",i,cb); return i; } } ASSERT(i < MAX_USER_NB,"ASSERT: out of users\n"); return -1; } public int modem_free_id(u8 id) { if (id < MAX_USER_NB) { g_modem.user[id].cb = NULL; g_modem.user[id].data = NULL; g_modem.user[id].istatus= NULL; //REF_PRINT("Free ID:%d\n",id); return id; } return -1; } public void modem_open(fx_serial_send_t* send,modem_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_user_t))); REF_PRINT("Open Modem - Max users:%d\n",MAX_USER_NB); g_modem.state = STATE_OPEN; } } public void modem_close(void) { if (g_modem.state == STATE_OPEN) { g_modem.state = STATE_CLOSED; } } public void modem_reset(void) { SERIAL_SEND(WC_FLOW_SYS_RST,NULL,0); } public void modem_read_file(u8 fid, void *data, u32 offset, u32 length, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_F_RD_DATA_SIZE_MAX]; u8* p = tmp; REF_PRINT("RD[%d]@%d %d Bytes\n",fid,offset,length); g_modem.user[id].data = (u8*)data; ALP_ACTION_TAG(p,id,true); ALP_ACTION_F_RD_DATA(p,true,fid,offset,length); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); } public void modem_read_fprop(u8 fid, alp_file_header_t* data, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_F_RD_PROP_SIZE]; u8* p = tmp; REF_PRINT("RD PROPS[%d]\n",fid); g_modem.user[id].data = (u8*)data; ALP_ACTION_TAG(p,id,true); ALP_ACTION_F_RD_PROP(p,true,fid); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); } public void modem_read_fprop_root(u8 fid, alp_file_header_t* data, u8* root_key, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_SIZE(ALP_ACTION_F_RD_PROP_SIZE)]; u8* p = tmp; u8* lastp; REF_PRINT("RD PROPS (ROOT)[%d]\n",fid); ASSERT(root_key != NULL, "Missing ROOT KEY\n"); g_modem.user[id].data = (u8*)data; ALP_ACTION_TAG(p, id, true); // Actual Operation will take place after PERM_REQ p = &tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_OFFSET]; ALP_ACTION_F_RD_PROP(p,true,fid); lastp = p; modem_add_root_permission(&tmp[ALP_ACTION_TAG_SIZE], root_key, &tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_OFFSET], ALP_ACTION_F_RD_PROP_SIZE); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(lastp-tmp)); } public void modem_write_fprop(u8 fid, alp_file_header_t* data, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_F_WR_PROP_SIZE_MAX]; u8* p = tmp; DPRINT(L_API, "WR PROPS[%d]\n",fid); ALP_ACTION_TAG(p,id,true); ALP_ACTION_F_WR_PROP(p,true,fid,0,sizeof(alp_file_header_t),data); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); } public void modem_write_fprop_root(u8 fid, alp_file_header_t* data, u8* root_key, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_SIZE(ALP_ACTION_F_WR_PROP_SIZE_MAX)]; u8* p = tmp; u8* lastp; DPRINT(L_API, "WR PROPS (ROOT)[%d]\n",fid); ASSERT(root_key != NULL, "Missing ROOT KEY\n"); ALP_ACTION_TAG(p, id, true); // Actual Operation will take place after PERM_REQ p = &tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_OFFSET]; ALP_ACTION_F_WR_PROP(p,true,fid,0,sizeof(alp_file_header_t),data); lastp = p; modem_add_root_permission(&tmp[ALP_ACTION_TAG_SIZE], root_key, &tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_OFFSET], ALP_ACTION_F_WR_PROP_SIZE_MAX); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(lastp-tmp)); } public void modem_write_file(u8 fid, void *data, u32 offset, u32 length, u8 id) { ALLOC_BUFFER(u8,tmp,(ALP_ACTION_TAG_SIZE + ALP_ACTION_F_WR_DATA_SIZE_MAX(length))); u8* p = tmp; REF_PRINT("WR[%d]@%d %d Bytes\n",fid,offset,length); ALP_ACTION_TAG(p,id,true); ALP_ACTION_F_WR_DATA(p,true,fid,offset,length,data); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); DEALLOC_BUFFER(tmp); } public void modem_write_file_root(u8 fid, void *data, u32 offset, u32 length, u8* root_key, u8 id) { ALLOC_BUFFER(u8,tmp,(ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_SIZE(ALP_ACTION_F_WR_DATA_SIZE_MAX(length)))); u8* p = tmp; u8* lastp; REF_PRINT("WR (ROOT)[%d]@%d %d Bytes\n",fid,offset,length); ASSERT(root_key != NULL, "Missing ROOT KEY\n"); ALP_ACTION_TAG(p, id, true); // Actual Operation will take place after PERM_REQ p = &tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_OFFSET]; ALP_ACTION_F_WR_DATA(p,true,fid,offset,length,data); lastp = p; modem_add_root_permission(&tmp[ALP_ACTION_TAG_SIZE], root_key, &tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_OFFSET], ALP_ACTION_F_WR_DATA_SIZE(offset,length)); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(lastp-tmp)); DEALLOC_BUFFER(tmp); } public void modem_flush_file(u8 fid, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_F_FLUSH_SIZE]; u8* p = tmp; REF_PRINT("FLUSH[%d]\n",fid); ALP_ACTION_TAG(p,id,true); ALP_ACTION_F_FLUSH(p,true,fid); SERIAL_SEND(WC_FLOW_ALP_UNS, tmp, (u8)(p-tmp)); } public void modem_flush_file_root(u8 fid, u8* root_key, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_SIZE(ALP_ACTION_F_FLUSH_SIZE)]; u8* p = tmp; u8* lastp; REF_PRINT("FLUSH (ROOT)[%d]\n",fid); ASSERT(root_key != NULL, "Missing ROOT KEY\n"); ALP_ACTION_TAG(p, id, true); // Actual Operation will take place after PERM_REQ p = &tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_OFFSET]; ALP_ACTION_F_FLUSH(p,true,fid); lastp = p; modem_add_root_permission(&tmp[ALP_ACTION_TAG_SIZE], root_key, &tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_PERM_REQ_OFFSET], ALP_ACTION_F_FLUSH_SIZE); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(lastp-tmp)); } public void modem_declare_file(u8 fid, alp_file_header_t* hdr, u8 local, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_F_DECLARE_SIZE]; u8* p = tmp; REF_PRINT("DECLARE[%d]\n",fid); ALP_ACTION_TAG(p,id,true); ALP_ACTION_F_DECLARE(p,true,fid,hdr,local); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); } public void modem_create_file(u8 fid, alp_file_header_t* hdr, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_F_CREATE_SIZE]; u8* p = tmp; REF_PRINT("CREATE[%d]\n",fid); ALP_ACTION_TAG(p,id,true); ALP_ACTION_F_CREATE(p,true,fid,hdr); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); } public void modem_notify_file(u8 fid, u32 offset, u32 length, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_F_TOUCH_SIZE_MAX]; u8* p = tmp; REF_PRINT("NOTIFY[%d]@%d %d Bytes\n",fid,offset,length); ALP_ACTION_TAG(p,id,true); ALP_ACTION_F_TOUCH(p,true,fid,offset,length); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); } public void modem_delete_file(u8 fid, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_F_DELETE_SIZE]; u8* p = tmp; REF_PRINT("DELETE[%d]\n",fid); ALP_ACTION_TAG(p,id,true); ALP_ACTION_F_DELETE(p,true,fid); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); } public void modem_send_raw_alp(u8* payload, u32 length, u8 id) { ALLOC_BUFFER(u8,tmp,ALP_ACTION_TAG_SIZE + length); u8* p = tmp; REF_PRINT("ALP RAW %d Bytes\n",length); ALP_ACTION_TAG(p,id,true); // User Payload memcpy(p,payload,length);p+=length; SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); DEALLOC_BUFFER(tmp); } public void modem_send_file_content(u8* itf, u8 itf_length, void *istatus, u8 fid, void *data, u32 offset, u32 length, u8 id) { ALLOC_BUFFER(u8,tmp,ALP_ACTION_TAG_SIZE + ALP_ACTION_FORWARD_SIZE(itf_length) + ALP_ACTION_RSP_F_DATA_SIZE_MAX(length)); u8* p = tmp; g_modem.user[id].istatus= (u8*)istatus; REF_PRINT("SEND FILE[%d] CONTENTS @%d %d Bytes (itf %d Bytes)\n",fid,offset,length,itf_length); ALP_ACTION_TAG(p,id,true); ALP_ACTION_FORWARD(p,itf,itf_length); if (istatus) { // NOP action to get istats on ACKs ALP_ACTION_NOP(p,true); } ALP_ACTION_RSP_F_DATA(p,fid,offset,length,data); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); DEALLOC_BUFFER(tmp); } public void modem_remote_read_file(u8* itf, u8 itf_length, void *istatus , u8 fid, void *data, u32 offset, u32 length, u8 id) { ALLOC_BUFFER(u8,tmp,ALP_ACTION_TAG_SIZE + ALP_ACTION_FORWARD_SIZE(itf_length) + ALP_ACTION_F_RD_DATA_SIZE_MAX); u8* p = tmp; g_modem.user[id].data = (u8*)data; g_modem.user[id].istatus = (u8*)istatus; REF_PRINT("RMT RD FILE[%d]@%d %d Bytes (itf %d Bytes)\n",fid,offset,length,itf_length); ALP_ACTION_TAG(p,id,true); ALP_ACTION_FORWARD(p,itf,itf_length); ALP_ACTION_F_RD_DATA(p,true,fid,offset,length); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); DEALLOC_BUFFER(tmp); } public void modem_remote_write_file(u8* itf, u8 itf_length, void *istatus , u8 fid, void *data, u32 offset, u32 length, u8 id) { ALLOC_BUFFER(u8,tmp,ALP_ACTION_TAG_SIZE + ALP_ACTION_FORWARD_SIZE(itf_length) + ALP_ACTION_F_WR_DATA_SIZE_MAX(length)); u8* p = tmp; g_modem.user[id].istatus = (u8*)istatus; REF_PRINT("RMT WR FILE[%d]@%d %d Bytes (itf %d Bytes)\n",fid,offset,length,itf_length); ALP_ACTION_TAG(p,id,true); ALP_ACTION_FORWARD(p,itf,itf_length); ALP_ACTION_F_WR_DATA(p,true,fid,offset,length,data); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); DEALLOC_BUFFER(tmp); } public void modem_enable_urc(u8 type, u8 ifid, u8 val, u8 enable, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_URCC_SIZE(ALP_URC_TYPE_LQUAL)]; u8* p = tmp; REF_PRINT("URC[%d] Type %d ifid %d\n",enable,type,ifid); ALP_ACTION_TAG(p,id,true); // Actual Operation if (enable) { ALP_ACTION_URCC_EN(p,true,type,ifid,val); } else { ALP_ACTION_URCC_DIS(p,true,type,ifid,val); } SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); } public void modem_activate_itf(u8 type, u8 nb_dev, u8 ifid, u8 flags, u8 enable, u8 id) { u8 tmp[ALP_ACTION_TAG_SIZE + ALP_ACTION_ACTIVATE_ITF_SIZE]; u8* p = tmp; REF_PRINT("ACTIVATE ITFTYPE[%x]:%d\n",type,enable); ALP_ACTION_TAG(p,id,true); ALP_ACTION_ACTIVATE_ITF(p,true,enable,type,nb_dev,ifid,flags); SERIAL_SEND(WC_FLOW_ALP_UNS,tmp, (u8)(p-tmp)); } public void modem_respond(u8 action, s8 status, int id) { u8 tmp[ALP_ACTION_RSP_TAG_SIZE + ALP_ACTION_RSP_STATUS_SIZE]; u8* p = tmp; REF_PRINT("RESP[%d]:%d\n",action,status); if (id>=0) { ALP_ACTION_RSP_TAG(p,id,true,(status<0)?true:false); } ALP_ACTION_RSP_STATUS(p,action,status); SERIAL_SEND(WC_FLOW_ALP_RESP,tmp, (u8)(p-tmp)); } public void modem_respond_fprop(u8 fid, u8* hdr, int id) { u8 tmp[ALP_ACTION_RSP_TAG_SIZE + ALP_ACTION_RSP_F_PROP_SIZE]; u8* p = tmp; REF_PRINT("RESP FPROP[%d]\n",fid); if (id>=0) { ALP_ACTION_RSP_TAG(p,id,true,false); } ALP_ACTION_RSP_F_PROP(p,fid,hdr); SERIAL_SEND(WC_FLOW_ALP_RESP,tmp, (u8)(p-tmp)); } public void modem_respond_read(u8 fid,void *data, u32 offset, u32 length, int id) { ALLOC_BUFFER(u8,tmp,ALP_ACTION_RSP_TAG_SIZE + ALP_ACTION_RSP_F_DATA_SIZE_MAX(length)); u8* p = tmp; REF_PRINT("F_DATA[%d]@%d %d Bytes\n",fid,offset,length); if (id>=0) { ALP_ACTION_RSP_TAG(p,id,true,false); } ALP_ACTION_RSP_F_DATA(p,fid,offset,length,data); SERIAL_SEND(WC_FLOW_ALP_RESP,tmp, (u8)(p-tmp)); DEALLOC_BUFFER(tmp); }