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.
Fork of d7a_1x by
Diff: src/d7a_fs.cpp
- Revision:
- 30:d775c1409849
- Parent:
- 29:8e7c5c1e9aab
- Child:
- 31:ab9bfdbc6b44
--- a/src/d7a_fs.cpp	Tue May 03 16:53:52 2016 +0000
+++ b/src/d7a_fs.cpp	Wed May 25 08:23:15 2016 +0000
@@ -13,6 +13,7 @@
 #define FS_NULL_MAP             0xFF // XXX: this actually removes usage of file 255
 
 TYPEDEF_STRUCT_PACKED {
+    uint8_t  id;
     uint8_t  cmd;
     uint8_t  fid;
     uint32_t offset;
@@ -20,8 +21,9 @@
 } d7a_fs_com_req_t;
 
 TYPEDEF_STRUCT_PACKED {
+    uint8_t  id;
     uint8_t  cmd;
-    int8_t  status;
+    int8_t   status;
     uint32_t length;
     uint8_t  data[1];
 } d7a_fs_com_resp_t;
@@ -34,34 +36,42 @@
 typedef struct {
     Thread* thread;
     Queue<void, 8> fs_done;
-    WriteFileFunction write_file;
-    ReadFileFunction read_file;
-    TouchFileFunction touch_file;
+    const d7a_fs_callbacks_t* callback;
     Queue<d7a_com_rx_msg_t, 16> pkt_queue;
     uint8_t  hdr_map[FS_MAX_FILE_QTY];
     uint8_t  nb_files;
-    d7a_fs_com_t com; // just one for now
+    d7a_fs_com_t com[FS_MAX_CONCURRENCY];
 } d7a_fs_ctx_t;
 
 d7a_fs_ctx_t g_fs_ctx;
 
 void d7a_fs_thread(const void *p);
 
-void d7a_fs_open(WriteFileFunction write_file, ReadFileFunction read_file, TouchFileFunction touch_file)
+void d7a_fs_open(const d7a_fs_callbacks_t* config)
 {
     FPRINT("\r\n");
     
     memset(&g_fs_ctx.com, 0, sizeof(g_fs_ctx.com));
-    g_fs_ctx.write_file = write_file;
-    g_fs_ctx.read_file = read_file;
-    g_fs_ctx.touch_file = touch_file;
-    //g_fs_ctx.fs_done = new Semaphore(1);
-    g_fs_ctx.thread = new Thread(d7a_fs_thread, NULL, osPriorityBelowNormal, DEFAULT_STACK_SIZE*2);
-    
-    // Wait to consume Semaphore
-    //g_fs_ctx.fs_done->wait();
+    g_fs_ctx.callback = config;
+    g_fs_ctx.thread = new Thread(d7a_fs_thread, NULL, osPriorityBelowNormal, DEFAULT_STACK_SIZE);
 }
 
+static uint8_t d7a_fs_get_req_id(void)
+{
+    int i;
+    for (i=0;i<FS_MAX_CONCURRENCY;i++)
+    {
+        if (g_fs_ctx.com[i].req.cmd == FS_OP_NULL)
+        {
+            DPRINT("New req %d\r\n", i);
+            return i;
+        }
+    }
+    ASSERT(false, "FS: MAX_CONCURRENCY exceeded\r\n");
+    return 0xff;
+}
+
+
 static void d7a_fs_msg(uint8_t* buf, uint8_t len, uint8_t id)
 {
     FPRINT("\r\n");
@@ -98,15 +108,21 @@
 
 d7a_com_rx_msg_t* d7a_fs_wait_pkt( uint32_t millisec )
 {
-    FPRINT("\r\n");
+    FPRINT("(millisec:%d)\r\n", millisec);
     osEvent evt = g_fs_ctx.pkt_queue.get(millisec);
     return (evt.status == osEventMessage)? (d7a_com_rx_msg_t*)evt.value.p : NULL;
 }
 
-static uint32_t d7a_fs_hdr(uint8_t fid, d7a_fs_header_t* hdr)
+static uint32_t d7a_fs_hdr(uint8_t fid, const d7a_fs_header_t* hdr)
 {
     FPRINT("\r\n");
-    return g_fs_ctx.read_file(fid, 0, sizeof(d7a_fs_header_t), (uint8_t*)hdr);
+    d7a_fs_header_t* temp_hdr = g_fs_ctx.callback->get_stat(fid);
+    if (!temp_hdr)
+    {
+        return 0;
+    }
+    memcpy((void*)hdr, (void*)temp_hdr, sizeof(d7a_fs_header_t));
+    return sizeof(d7a_fs_header_t);
 }
 
 uint32_t d7a_fs_get_properties(uint8_t fid, d7a_fs_property_t prop, d7a_fs_properties_t* props)
@@ -146,7 +162,7 @@
                 ASSERT(false, "FS:Invalid get prop request %d\n",prop);
         }
     }
-    DPRINT("GetProp[%d](%d): %d\n",fid,prop,ret);
+    //DPRINT("GetProp[%d](%d): %d\n",fid,prop,ret);
     return ret;
 }
 
@@ -154,22 +170,23 @@
 {
     FPRINT("\r\n");
     // "Distant" Files
-    ASSERT(g_fs_ctx.com.req.cmd == FS_OP_NULL, "FS: Concurrent Distant File access\n");
-    g_fs_ctx.com.req = (d7a_fs_com_req_t){FS_OP_STAT,fid,0,0};
-    g_fs_ctx.com.data = length;
-    d7a_fs_msg((uint8_t*)&g_fs_ctx.com.req,sizeof(d7a_fs_com_req_t), KAL_COM_FLOW_FS_CMD);
+    uint8_t id = d7a_fs_get_req_id();
+    g_fs_ctx.com[id].req = (d7a_fs_com_req_t){id,FS_OP_STAT,fid,0,0};
+    g_fs_ctx.com[id].data = length;
+    d7a_fs_msg((uint8_t*)&g_fs_ctx.com[id].req,sizeof(d7a_fs_com_req_t), KAL_COM_FLOW_FS_CMD);
     // We do a "normal" STAT but we don't want to update our local(true) file-size
     // with the response of the STAT as:
     // - the distant is likely a "Host-file" with hazardous size/alloc
     // - we may not even have the corresponding local file (-> assert when getting props)
     // So flag the cmd to differentiate response treatment
-    g_fs_ctx.com.req.cmd = FS_OP_DSTAT; // XXX
+    g_fs_ctx.com[id].req.cmd = FS_OP_DSTAT; // XXX
 }
 
 int d7a_fs_distant_create(uint8_t fid, d7a_fs_properties_t* props)
 {
+    uint8_t id;
     FPRINT("\r\n");
-    DPRINT("CrD[%d] type 0x%x\n",fid,props->type);
+    //DPRINT("CrD[%d] type 0x%x\n",fid,props->type);
 
     switch (props->type)
     {
@@ -177,15 +194,15 @@
         case RAM:
         case PFLASH:
         case HOST:
-            ASSERT(g_fs_ctx.com.req.cmd == FS_OP_NULL,"FS: Concurrent Distant File access\n");
+            id = d7a_fs_get_req_id();
             // Build WR command
             uint8_t* buf = (uint8_t*)MALLOC(sizeof(d7a_fs_com_req_t) + sizeof(d7a_fs_properties_t));
             d7a_fs_com_req_t* buf_req = (d7a_fs_com_req_t*)buf;
-            *buf_req     = (d7a_fs_com_req_t){FS_OP_CREATE,fid,0,sizeof(d7a_fs_properties_t)};
+            *buf_req     = (d7a_fs_com_req_t){id,FS_OP_CREATE,fid,0,sizeof(d7a_fs_properties_t)};
             memcpy(&buf[sizeof(d7a_fs_com_req_t)],(uint8_t*)props,sizeof(d7a_fs_properties_t));
 
             // Keep command request for response treatment
-            g_fs_ctx.com.req.cmd = FS_OP_CREATE;
+            g_fs_ctx.com[id].req.cmd = FS_OP_CREATE;
             d7a_fs_msg(buf,sizeof(d7a_fs_com_req_t) + sizeof(d7a_fs_properties_t), KAL_COM_FLOW_FS_CMD);
             FREE(buf);
             break;
@@ -199,12 +216,14 @@
 
 int d7a_fs_read(uint8_t fid, void *data, uint32_t offset, uint32_t length)
 {
-    DPRINT("RdP[%d] @:%d %d bytes\n", fid, offset, length);
+    //DPRINT("RdP[%d] @:%d %d bytes\n", fid, offset, length);
     d7a_fs_header_t hdr;
     uint8_t local = 0;
+    uint8_t id;
 
     if (!d7a_fs_hdr(fid, &hdr))
     {
+        // If file is not found locally, it is a distant file
         hdr.bf.type = HOST;
     }
     
@@ -216,17 +235,17 @@
         case PFLASH:
             // "Local" file, respond right away
             d7a_fs_read(fid,data,offset,length);
-            g_fs_ctx.read_file(fid, offset+sizeof(d7a_fs_header_t), length, (uint8_t*)data);
+            g_fs_ctx.callback->read_file(fid, offset, length, (uint8_t*)data);
             // Inform requester
             g_fs_ctx.fs_done.put((void*)fid);
             local = 1;
             break;
         // "Distant" Files
         case HOST:
-            ASSERT(g_fs_ctx.com.req.cmd == FS_OP_NULL,"FS: Concurrent Distant File access\n");
-            g_fs_ctx.com.req = (d7a_fs_com_req_t){FS_OP_RD,fid,offset,length};
-            g_fs_ctx.com.data = data;
-            d7a_fs_msg((uint8_t*)&g_fs_ctx.com.req, sizeof(d7a_fs_com_req_t), KAL_COM_FLOW_FS_CMD);
+            id = d7a_fs_get_req_id();
+            g_fs_ctx.com[id].req = (d7a_fs_com_req_t){id,FS_OP_RD,fid,offset,length};
+            g_fs_ctx.com[id].data = data;
+            d7a_fs_msg((uint8_t*)&g_fs_ctx.com[id].req, sizeof(d7a_fs_com_req_t), KAL_COM_FLOW_FS_CMD);
             break;
         // Wrong type
         default:
@@ -237,30 +256,33 @@
 
 
 
-#define OP_SIZE_RD      10
-#define OP_SIZE_WR      10
-#define OP_SIZE_STAT    2
-#define OP_SIZE_FLUSH   2
-#define OP_SIZE_CREATE  10
-#define OP_SIZE_RETSTAT (2+4)
-#define OP_SIZE_RETDATA (2+4)
-uint8_t k_valid_cmd[] = {FS_OP_RD,  FS_OP_WR,  FS_OP_STAT,  FS_OP_FLUSH,  FS_OP_CREATE};
-uint8_t k_valid_size[]= {OP_SIZE_RD,OP_SIZE_WR,OP_SIZE_STAT,OP_SIZE_FLUSH,OP_SIZE_CREATE};
+#define OP_SIZE_RD      11
+#define OP_SIZE_WR      11
+#define OP_SIZE_TOUCH   11
+#define OP_SIZE_STAT    3
+#define OP_SIZE_FLUSH   3
+#define OP_SIZE_CREATE  11
+#define OP_SIZE_RETSTAT (3+4)
+#define OP_SIZE_RETDATA (3+4)
+uint8_t k_valid_cmd[] = {FS_OP_RD,  FS_OP_WR,  FS_OP_TOUCH  ,FS_OP_STAT,  FS_OP_FLUSH,  FS_OP_CREATE};
+uint8_t k_valid_size[]= {OP_SIZE_RD,OP_SIZE_WR,OP_SIZE_TOUCH,OP_SIZE_STAT,OP_SIZE_FLUSH,OP_SIZE_CREATE};
+
 
 
-//  TODO: Add a token field for multiple transactions
-/// --------------------------------------------------------
-/// |CMD/RESP|             PAYLOAD                         |
-/// --------------------------------------------------------
-/// |   1B   |            PKT.blen - 1 bytes               |
-/// --------------------------------------------------------
-/// |        |  1B  |   4B   |   4B   | PKT.blen - 10 bytes|
-/// --------------------------------------------------------
-//  | write  | FID  | offset | length | datas...           |
-//  | read   | FID  | offset | length |
-//  | flush  | FID  |
-//  | retstat|status| length | <d7a_fs_properties_t>
-//  | retdat |status| length | datas...                    |
+/// ------------------------------------------------------------------
+/// |TOKEN|CMD/RESP|             PAYLOAD                         |
+/// --------------------------------------------------------------
+/// | 1B  |   1B   |            PKT.blen - 1 bytes               |
+/// --------------------------------------------------------------
+/// |     |        |  1B  |   4B   |   4B   | PKT.blen - 11 bytes|
+/// --------------------------------------------------------------
+//  |     | write  | FID  | offset | length | datas...           |
+//  |     | read   | FID  | offset | length |
+//  |     | touch  | FID  | offset | length |
+//  |     | exist  | FID  |
+//  |     | flush  | FID  |
+//  |     | retstat|status| length | <kal_fs_properties_t>
+//  |     | retdat |status| length | datas...                    |
 void d7a_fs_thread(const void *p)
 {
     FPRINT("\r\n");
@@ -283,7 +305,9 @@
             case KAL_COM_FLOW_FS_CMD:
                 d7a_fs_com_req_t* req = (d7a_fs_com_req_t*)pkt->buffer;
                 DPRINT("Rfs[%d] cmd:%d\n",req->fid,req->cmd);
-                d7a_fs_com_resp_t buf = (d7a_fs_com_resp_t) {.cmd = FS_OP_RETSTAT};
+                //dbg_print_data("%02X ", (uint8_t*)req, sizeof(d7a_fs_com_req_t));
+                //DPRINT("\r\n");
+                d7a_fs_com_resp_t buf = (d7a_fs_com_resp_t) {.id = req->id, .cmd = FS_OP_RETSTAT};
     
                 // Error management makes sense here as we face peer-requests,
                 // and we don't want to assert because of the peer.
@@ -304,7 +328,8 @@
                 else if (req->cmd == FS_OP_RD)
                 {
                     d7a_fs_com_resp_t* b = (d7a_fs_com_resp_t*)MALLOC(OP_SIZE_RETDATA + req->length);
-                    uint32_t len = g_fs_ctx.read_file(req->fid, req->offset+sizeof(d7a_fs_header_t), req->length, &b->data[0]);
+                    uint32_t len = g_fs_ctx.callback->read_file(req->fid, req->offset, req->length, &b->data[0]);
+                    b->id     = req->id;
                     b->length = len;
                     b->cmd    = FS_OP_RETDATA;
                     b->status = FS_STAT_OK; // TODO
@@ -313,7 +338,7 @@
                 }
                 else if (req->cmd == FS_OP_WR)
                 {
-                    buf.length = g_fs_ctx.write_file(req->fid, req->offset+sizeof(d7a_fs_header_t), req->length, &pkt->buffer[OP_SIZE_WR]);
+                    buf.length = g_fs_ctx.callback->write_file(req->fid, req->offset, req->length, &pkt->buffer[OP_SIZE_WR]);
                     d7a_fs_msg((uint8_t*)&buf, OP_SIZE_RETSTAT, KAL_COM_FLOW_FS_RESP);
                 }
                 else if (req->cmd == FS_OP_STAT)
@@ -323,6 +348,7 @@
                     d7a_fs_com_resp_t* b = (d7a_fs_com_resp_t*)MALLOC(OP_SIZE_RETSTAT + sizeof(d7a_fs_properties_t));
                     d7a_fs_get_properties(req->fid, KAL_FS_PROP_ALL, (d7a_fs_properties_t*) &b->data[0]);
                     d7a_fs_properties_t* props = (d7a_fs_properties_t*)&b->data[0];
+                    b->id     = req->id;
                     b->length = props->length;
                     b->cmd    = FS_OP_RETSTAT;
                     b->status = FS_STAT_OK;
@@ -341,7 +367,7 @@
                 }
                 else if (req->cmd == FS_OP_TOUCH)
                 {
-                    buf.length = g_fs_ctx.touch_file(req->fid, req->offset, req->length);
+                    buf.length = g_fs_ctx.callback->touch_file(req->fid, req->offset, req->length);
                     d7a_fs_msg((uint8_t*)&buf, OP_SIZE_RETSTAT, KAL_COM_FLOW_FS_RESP);
                 }
                 else
@@ -354,10 +380,13 @@
             // ---------------------------------------------------------------------------
             case KAL_COM_FLOW_FS_RESP:
                 d7a_fs_com_resp_t* resp = (d7a_fs_com_resp_t*)pkt->buffer;
-                DPRINT("Rfs resp - cmd:%d status:%d bytes:%d\n", resp->cmd, resp->status, resp->length);
-                ASSERT(g_fs_ctx.com.req.cmd != FS_OP_NULL, "FS: Unexpected FS_RESP\n");
-                if (g_fs_ctx.com.req.cmd != FS_OP_STAT &&
-                    g_fs_ctx.com.req.cmd != FS_OP_DSTAT )
+                uint8_t id = resp->id;
+                DPRINT("Rfs(%d) resp - cmd:%d status:%d bytes:%d\n", id, resp->cmd, resp->status, resp->length);
+                //dbg_print_data("%02X ", (uint8_t*)resp, sizeof(d7a_fs_com_resp_t));
+                //DPRINT("\r\n");
+                ASSERT(g_fs_ctx.com[id].req.cmd != FS_OP_NULL, "FS: Unexpected FS_RESP ID:%d CMD:%d status:%d LEN:%d\n", id, resp->cmd, resp->status, resp->length);
+                if (g_fs_ctx.com[id].req.cmd != FS_OP_STAT &&
+                    g_fs_ctx.com[id].req.cmd != FS_OP_DSTAT )
                 {
                     // No pity for errors here, handled-ones should be avoided at
                     // upper level, the others diserve to assert anyway.
@@ -366,31 +395,32 @@
                     // Fill read buffer
                     if (resp->cmd == FS_OP_RETDATA)
                     {
-                        memcpy(g_fs_ctx.com.data, &resp->data[0], resp->length);
+                        memcpy(g_fs_ctx.com[id].data, &resp->data[0], resp->length);
                     }
                     else if (resp->cmd == FS_OP_RETSTAT)
                     {
-                        if (g_fs_ctx.com.req.cmd == FS_OP_WR)
+                        if (g_fs_ctx.com[id].req.cmd == FS_OP_WR)
                         {
                             // We did a successful WR, update size if needed
                             // TODO:This is not really enforcing header coherency. It will do the
                             // job for Hosted NVM storage, provided the Host doesn't use the file for
                             // writing.
                             d7a_fs_header_t hdr;
-                            d7a_fs_hdr(g_fs_ctx.com.req.fid, &hdr);
+                            d7a_fs_hdr(g_fs_ctx.com[id].req.fid, &hdr);
                             if (resp->length != hdr.bf.length)
                             {
-                                //d7a_fs_set_properties(g_fs_ctx.com.req.fid, KAL_FS_PROP_SIZE, resp->length);
+                                hdr.bf.length = resp->length;
+                                g_fs_ctx.callback->set_stat(g_fs_ctx.com[id].req.fid, &hdr);
                             }
                         }
                     }
                 }
                 else // FS_OP_STAT/DSTAT
                 {
-                    if (g_fs_ctx.com.req.cmd == FS_OP_STAT)
+                    if (g_fs_ctx.com[id].req.cmd == FS_OP_STAT)
                     {
                         d7a_fs_header_t hdr;
-                        d7a_fs_hdr(g_fs_ctx.com.req.fid, &hdr);
+                        d7a_fs_hdr(g_fs_ctx.com[id].req.fid, &hdr);
                         // Try to keep HOST-files coherency as much as we can:
                         // STAT returns the full header so we can update all fields.
                         if (hdr.byte.type == HOST)
@@ -402,14 +432,14 @@
                         }
                     }
                     // TODO: for now only keep length info for upper layer. (normal for a STAT)
-                    if (g_fs_ctx.com.data != NULL)
+                    if (g_fs_ctx.com[id].data != NULL)
                     {
-                         *(uint32_t*)g_fs_ctx.com.data = resp->length;
+                         *(uint32_t*)g_fs_ctx.com[id].data = resp->length;
                     }
                     status = resp->status;
                 }
                 // Free to serve a new request
-                g_fs_ctx.com.req.cmd = FS_OP_NULL;
+                g_fs_ctx.com[id].req.cmd = FS_OP_NULL;
                 // Inform requester
                 g_fs_ctx.fs_done.put((void*)status);
                 break;
    