Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: modem_ref_helper_for_v5_3_217
Diff: src/modem_ref.cpp
- Revision:
- 19:701d5669f2e9
- Parent:
- 18:a11302a76e96
- Child:
- 20:17852941b19e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modem_ref.cpp Tue Dec 12 16:03:12 2017 +0000
@@ -0,0 +1,613 @@
+#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 { \
+ 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);
+ //REF_PRINT("Rem %d Bytes\n", rem);
+ // 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]\n",r.type);
+ switch (r.type)
+ {
+ case ALP_OPCODE_F_RD_DATA:
+ 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:
+ 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;
+ }
+ }
+ }
+ 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...
+ 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("RESP_TAG[%d]\n", r.meta.tag.id);
+ break;
+ case ALP_OPCODE_RSP_F_DATA:
+ case ALP_OPCODE_RSP_F_PROP:
+ 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:
+ err = r.meta.status.code;
+ break;
+ case ALP_OPCODE_RSP_ISTATUS:
+ 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;
+ }
+ // 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);
+}
\ No newline at end of file