Trond Enger / d7a_1x

Fork of d7a_1x by WizziLab

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;