Trond Enger / d7a_1x

Fork of d7a_1x by WizziLab

src/d7a_fs.cpp

Committer:
Jeej
Date:
2016-09-06
Revision:
52:c7a58fc48bd2
Parent:
51:644de6fe1ee7
Child:
56:da34fc11e760

File content as of revision 52:c7a58fc48bd2:

#include "mbed.h"
#include "rtos.h"
#include "dbg.h"
#include "d7a_com.h"
#include "d7a_common.h"
#include "d7a_fs.h"
#include "d7a.h"


#define FS_MAX_FILE_QTY     256
#define FS_MAX_MIRROR_QTY   32
#define FS_MAX_WATCHERS_QTY 32

#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;
    uint32_t length;
} d7a_fs_com_req_t;

TYPEDEF_STRUCT_PACKED {
    uint8_t  id;
    uint8_t  cmd;
    int8_t   status;
    uint32_t length;
    uint8_t  data[1];
} d7a_fs_com_resp_t;

typedef struct {
    d7a_fs_com_req_t req;
    int8_t   status;
    void* data;
} d7a_fs_com_t;

typedef struct {
    Thread* thread;
    Queue<void, 8> fs_done;
    WriteFileFunction write_file;
    ReadFileFunction read_file;
    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[FS_MAX_CONCURRENCY];
} d7a_fs_ctx_t;

d7a_fs_ctx_t g_fs_ctx;

void d7a_fs_thread(const void *p);

d7a_errors_t d7a_fs_open(WriteFileFunction wf, ReadFileFunction rf)
{
    FPRINT("\r\n");
    
    g_fs_ctx.write_file = wf;
    g_fs_ctx.read_file = rf;
    g_fs_ctx.thread = new Thread(d7a_fs_thread, NULL, osPriorityHigh, DEFAULT_STACK_SIZE);
    
    return D7A_ERR_NONE;
}

static void d7a_fs_msg(uint8_t* buf, uint8_t len, uint8_t id)
{
    FPRINT("\r\n");
    d7a_com_tx_msg_t msg;
    msg.id = id;
    msg.pbuf = buf;
    msg.plen = len;
    msg.alen = 0;
    d7a_com_post_msg(&msg);
}

void d7a_fs_new_pkt(d7a_com_rx_msg_t* pkt)
{
    FPRINT("\r\n");
    ASSERT(g_fs_ctx.pkt_queue.put(pkt) == osOK, "FS queue full!\r\n");
}

d7a_com_rx_msg_t* d7a_fs_wait_pkt( uint32_t millisec )
{
    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;
}


#define OP_SIZE_RD      11
#define OP_SIZE_WR      11
#define OP_SIZE_TOUCH   11
#define OP_SIZE_SYNC    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,  FS_OP_SYNC};
uint8_t k_valid_size[]= {OP_SIZE_RD,OP_SIZE_WR,OP_SIZE_TOUCH,OP_SIZE_STAT,OP_SIZE_FLUSH,OP_SIZE_CREATE,OP_SIZE_SYNC};

// ------------------------------------------------------------------
// |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");
    d7a_com_rx_msg_t* pkt;
    int8_t status = FS_STAT_OK;
    
    while (true)
    {
        status = FS_STAT_OK;
        // TODO: For now only one outgoing-request can be pending
        //       An incoming-request response can be served simultaneously
        // TODO: handle segmentation. For now MTU = 255-10 = 245
        pkt = d7a_fs_wait_pkt();
        ASSERT(pkt != NULL, "FS NULL pkt\r\n");
        // ---------------------------------------------------------------------------
        // Peer request
        // ---------------------------------------------------------------------------
        switch (pkt->id)
        {
            case KAL_COM_FLOW_FS_CMD:
                d7a_fs_com_req_t* req = (d7a_fs_com_req_t*)pkt->buffer;
                DPRINT("Rfs[%d](%d) cmd:%d\n", req->fid, req->id, req->cmd);
                //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.
                //status = d7a_fs_check_req(req, pkt->blen);
                //buf.status = status;
                buf.status = FS_STAT_OK;
    
                // From here we assume that the request is valid
                // TODO: for now we consider that COM-FS request are targetting
                // FIDs that are "local" to the Host, but we can extend this
                // to "distant" files as well.(i.e. access SPI-Flash of an Host)
                if (status != FS_STAT_OK)
                {
                    buf.length = 0;
                    // Here we respond to request errors and OP_STAT
                    d7a_fs_msg((uint8_t*)&buf,OP_SIZE_RETSTAT, KAL_COM_FLOW_FS_RESP);
                }
                else if (req->cmd == FS_OP_RD)
                {
                    d7a_fs_com_resp_t* b = (d7a_fs_com_resp_t*)MALLOC(OP_SIZE_RETDATA + req->length);
                    ASSERT(g_fs_ctx.read_file != NULL, "FS Read callback not implemented!\r\n");
                    uint32_t len = g_fs_ctx.read_file(req->fid, req->offset, req->length, &b->data[0]);
                    
                    b->id     = req->id;
                    b->cmd    = FS_OP_RETDATA;
                    if (len == req->length)
                    {
                        b->length = len;
                        b->status = FS_STAT_OK;
                    }
                    else
                    {
                        b->length = 0;
                        b->status = FS_STAT_ERR_FID_NOEXIST;
                        WARNING(false, "FS_STAT_ERR_FID_NOEXIST\r\n");
                    }
                    
                    d7a_fs_msg((uint8_t*)b, OP_SIZE_RETDATA + b->length, KAL_COM_FLOW_FS_RESP);
                    FREE(b);
                }
                else if (req->cmd == FS_OP_WR)
                {
                    ASSERT(g_fs_ctx.write_file != NULL, "FS Write callback not implemented!\r\n");
                    buf.length = g_fs_ctx.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_TOUCH)
                {
                    DPRINT("PS Touch f:%d o:%d s:%d\r\n", 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
                {
                    ASSERT(false, "FS: Unsupported cmd %d\r\n", req->cmd);
                }
                break;
            // ---------------------------------------------------------------------------
            // Response to our commands
            // ---------------------------------------------------------------------------
            case KAL_COM_FLOW_FS_RESP:
                ASSERT(false, "FS: Commands are not used\r\n");
                break;
            default:
                EPRINT("FS Unknown Flow ID 0x%02X\r\n", pkt->id);
                break;
        }
        FREE(pkt);
    }
}