Generic communication interface between the wireless board (mote) and the sensor board. Any kind of sensor board can be connected to the mote using this specification given it provides a SPI peripheral, one input pin with interrupt capability and one digital output. The sensor board must implement a special register set from which all required information can be retrieved. Protocol: http://is.gd/wuQorh Github: http://is.gd/ySj1L9

Dependencies:   mbed-src

sens_itf/sens_itf.c

Committer:
marcelobarrosalmeida
Date:
2014-04-08
Revision:
1:acdf490d94a7

File content as of revision 1:acdf490d94a7:

#include <string.h>
#include <stdint.h>
#include "sens_itf.h"
#include "../util/buf_io.h"
#include "../util/crc16.h"

#define SENS_ITF_DBG_FRAME 1

uint8_t sens_itf_unpack_point_value(sens_itf_cmd_point_t *point, uint8_t *buf)
{
    uint8_t size = 0;

    switch (point->type)
    {
    case SENS_ITF_DT_U8:
        point->value.u8 = buf_io_get8_fl(buf);
        size = 1;
        break;
    case SENS_ITF_DT_S8:
        point->value.s8 = buf_io_get8_fl(buf);
        size = 1;
        break;
    case SENS_ITF_DT_U16:
        point->value.u16 = buf_io_get16_fl(buf);
        size = 2;
        break;
    case SENS_ITF_DT_S16:
        point->value.s16 = buf_io_get16_fl(buf);
        size = 2;
        break;
    case SENS_ITF_DT_U32:
        point->value.u32 = buf_io_get32_fl(buf);
        size = 4;
        break;
    case SENS_ITF_DT_S32:
        point->value.s32 = buf_io_get32_fl(buf);
        size = 4;
        break;
    case SENS_ITF_DT_U64:
        point->value.u64 = buf_io_get64_fl(buf);
        size = 8;
        break;
    case SENS_ITF_DT_S64:
        point->value.s64 = buf_io_get64_fl(buf);
        size = 8;
        break;
    case SENS_ITF_DT_FLOAT:
        point->value.fp32 = buf_io_getf_fl(buf);
        size = 4;
        break;
    case SENS_ITF_DT_DOUBLE:
        point->value.fp64 = buf_io_getd_fl(buf);
        size = 8;
        break;
    default:
        break;
    }

    return size;
}

uint8_t sens_itf_pack_point_value(const sens_itf_cmd_point_t *point, uint8_t *buf)
{
    uint8_t size = 0;

    switch (point->type)
    {
    case SENS_ITF_DT_U8:
        buf_io_put8_tl(point->value.u8, buf);
        size = 1;
        break;
    case SENS_ITF_DT_S8:
        buf_io_put8_tl(point->value.s8, buf);
        size = 1;
        break;
    case SENS_ITF_DT_U16:
        buf_io_put16_tl(point->value.u16, buf);
        size = 2;
        break;
    case SENS_ITF_DT_S16:
        buf_io_put16_tl(point->value.s16, buf);
        size = 2;
        break;
    case SENS_ITF_DT_U32:
        buf_io_put32_tl(point->value.u32, buf);
        size = 4;
        break;
    case SENS_ITF_DT_S32:
        buf_io_put32_tl(point->value.s32, buf);
        size = 4;
        break;
    case SENS_ITF_DT_U64:
        buf_io_put64_tl(point->value.u64, buf);
        size = 8;
        break;
    case SENS_ITF_DT_S64:
        buf_io_put64_tl(point->value.s64, buf);
        size = 8;
        break;
    case SENS_ITF_DT_FLOAT:
        buf_io_putf_tl(point->value.fp32, buf);
        size = 4;
        break;
    case SENS_ITF_DT_DOUBLE:
        buf_io_putd_tl(point->value.fp64, buf);
        size = 8;
        break;
    default:
        break;
    }

    return size;
}

uint8_t sens_itf_unpack_cmd_req(sens_itf_cmd_req_t *cmd, uint8_t *frame, uint8_t frame_size)
{
    uint8_t *buf = frame;
    uint16_t crc;
    uint16_t frame_crc;
    uint8_t size;

    if (frame_size < 3)
    {
        //OS_UTIL_LOG(SENS_ITF_DBG_FRAME, ("Invalid frame size %d", frame_size));
        return 0;
    }
    
    // minimal header decoding
    cmd->hdr.size = buf_io_get8_fl_ap(buf);
    cmd->hdr.addr = buf_io_get8_fl_ap(buf);

    frame_crc = buf_io_get16_fl(&frame[cmd->hdr.size]);
    crc = crc16_calc(frame, cmd->hdr.size);
    cmd->crc = frame_crc;

    if (frame_crc != crc)
    {
        //OS_UTIL_LOG(SENS_ITF_DBG_FRAME, ("Invalid CRC %04X <> %04X", frame_crc, crc));
        return 0;
    }
    
    switch (cmd->hdr.addr)
    {
    case SENS_ITF_REGMAP_BRD_CMD:
        cmd->payload.command_cmd.cmd = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_WRITE_BAT_STATUS:
        cmd->payload.bat_status_cmd.status = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_WRITE_BAT_CHARGE:
        cmd->payload.bat_charge_cmd.charge = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_DSP_WRITE:
        cmd->payload.write_display_cmd.line = buf_io_get8_fl_ap(buf);
        memcpy(cmd->payload.write_display_cmd.msg,buf,SENS_ITF_DSP_MSG_MAX_SIZE);
        buf += SENS_ITF_DSP_MSG_MAX_SIZE;
        break;
    case SENS_ITF_REGMAP_WPAN_STATUS:
        cmd->payload.wpan_status_cmd.status = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_WPAN_STRENGTH:
        cmd->payload.wpan_strength_cmd.strenght = buf_io_get8_fl_ap(buf);
        break;
    default:
        break;
    }

    if ((cmd->hdr.addr >= SENS_ITF_REGMAP_WRITE_POINT_DATA_1) && 
        (cmd->hdr.addr <= SENS_ITF_REGMAP_WRITE_POINT_DATA_32))
    {
        //uint8_t point = cmd->hdr.addr - SENS_ITF_REGMAP_WRITE_POINT_DATA_1;
        cmd->payload.point_value_cmd.type =  buf_io_get8_fl_ap(buf);
        buf += sens_itf_unpack_point_value(&cmd->payload.point_value_cmd, buf);
    }

    size = cmd->hdr.size + 2; // + crc 
    return size;
}

uint8_t sens_itf_pack_cmd_res(sens_itf_cmd_res_t *cmd, uint8_t *frame)
{
    uint8_t *buf = &frame[1];
    uint8_t size = 0;
    uint16_t crc;

    buf_io_put8_tl_ap(cmd->hdr.addr, buf);
    buf_io_put8_tl_ap(cmd->hdr.status, buf);

    // only fill command when status is OK, otherwise an error will be reported
    if (cmd->hdr.status == SENS_ITF_ANS_OK)
    {
        switch (cmd->hdr.addr)
        {
        case SENS_ITF_REGMAP_ITF_VERSION:
            buf_io_put8_tl_ap(cmd->payload.itf_version_cmd.version, buf);
            break;
        case SENS_ITF_REGMAP_BRD_ID:
            memcpy(buf, cmd->payload.brd_id_cmd.model, SENS_ITF_MODEL_NAME_SIZE);
            buf += SENS_ITF_MODEL_NAME_SIZE;
            memcpy(buf, cmd->payload.brd_id_cmd.manufactor, SENS_ITF_MANUF_NAME_SIZE);
            buf += SENS_ITF_MODEL_NAME_SIZE;
            buf_io_put32_tl_ap(cmd->payload.brd_id_cmd.sensor_id, buf);
            buf_io_put8_tl_ap(cmd->payload.brd_id_cmd.hardware_revision, buf);
            buf_io_put8_tl_ap(cmd->payload.brd_id_cmd.num_of_points, buf);
            buf_io_put8_tl_ap(cmd->payload.brd_id_cmd.cabalities, buf);
            break;
        case SENS_ITF_REGMAP_BRD_STATUS:
            buf_io_put8_tl_ap(cmd->payload.brd_status_cmd.status, buf);
            break;
        case SENS_ITF_REGMAP_BRD_CMD:
            buf_io_put8_tl_ap(cmd->payload.command_res_cmd.status, buf);
            break;
        case SENS_ITF_REGMAP_READ_BAT_STATUS:
            buf_io_put8_tl_ap(cmd->payload.bat_status_cmd.status, buf);
            break;
        case SENS_ITF_REGMAP_READ_BAT_CHARGE:
            buf_io_put8_tl_ap(cmd->payload.bat_charge_cmd.charge, buf);
            break;
        case SENS_ITF_REGMAP_SVR_MAIN_ADDR:
        case SENS_ITF_REGMAP_SVR_SEC_ADDR:
            memcpy(buf, cmd->payload.svr_addr_cmd.addr, SENS_ITF_SERVER_ADDR_SIZE);
            buf += SENS_ITF_SERVER_ADDR_SIZE;
            break;
        default:
            break;
        }

        if ((cmd->hdr.addr >= SENS_ITF_REGMAP_POINT_DESC_1) &&
            (cmd->hdr.addr <= SENS_ITF_REGMAP_POINT_DESC_32))
        {
            //uint8_t point = cmd->hdr.addr - SENS_ITF_REGMAP_POINT_DESC_1;
            memcpy(buf, cmd->payload.point_desc_cmd.name, SENS_ITF_POINT_NAME_SIZE);
            buf += SENS_ITF_POINT_NAME_SIZE;
            buf_io_put8_tl_ap(cmd->payload.point_desc_cmd.type, buf);
            buf_io_put8_tl_ap(cmd->payload.point_desc_cmd.unit, buf);
            buf_io_put8_tl_ap(cmd->payload.point_desc_cmd.access_rights, buf);
            buf_io_put32_tl_ap(cmd->payload.point_desc_cmd.sampling_time_x250ms, buf);
        }

        if ((cmd->hdr.addr >= SENS_ITF_REGMAP_READ_POINT_DATA_1) &&
            (cmd->hdr.addr <= SENS_ITF_REGMAP_READ_POINT_DATA_32))
        {
            //uint8_t point = cmd->hdr.addr - SENS_ITF_REGMAP_READ_POINT_DATA_1;
            buf_io_put8_tl_ap(cmd->payload.point_value_cmd.type,buf);
            buf += sens_itf_pack_point_value(&cmd->payload.point_value_cmd, buf);
        }
    }

    size = buf - frame;
    buf_io_put8_tl(size, frame);
    crc = crc16_calc(frame, size);
    cmd->crc = crc;
    cmd->hdr.size = size;
    buf_io_put16_tl(crc, buf);
    
    size += 2; // +crc 
    return size;
}


uint8_t sens_itf_unpack_cmd_res(sens_itf_cmd_res_t * cmd, uint8_t *frame, uint8_t frame_size)
{
    uint8_t size;
    uint8_t *buf = frame;
    uint16_t crc;
    uint16_t frame_crc;

    if (frame_size < 3)
    {
        cmd->hdr.status = SENS_ITF_ANS_ERROR;
        return 0;
    }
    
    // minimal header decoding
    cmd->hdr.size = buf_io_get8_fl_ap(buf);
    cmd->hdr.addr = buf_io_get8_fl_ap(buf);
    cmd->hdr.status = buf_io_get8_fl_ap(buf);

    frame_crc = buf_io_get16_fl(&frame[cmd->hdr.size]);
    crc = crc16_calc(frame, cmd->hdr.size);
    cmd->crc = frame_crc;

    if (frame_crc != crc)
    {
        //OS_UTIL_LOG(SENS_ITF_DBG_FRAME, ("Invalid CRC %04X <> %04X", frame_crc, crc));
        cmd->hdr.status = SENS_ITF_ANS_CRC_ERROR;
        return 0;
    }

    if (cmd->hdr.status != SENS_ITF_ANS_OK)
    {
        //OS_UTIL_LOG(SENS_ITF_DBG_FRAME, ("Response error %d", cmd->hdr.status));
        return 0;
    }

    switch (cmd->hdr.addr)
    {
    case SENS_ITF_REGMAP_ITF_VERSION:
        cmd->payload.itf_version_cmd.version = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_BRD_ID:
        memcpy(cmd->payload.brd_id_cmd.model, buf, SENS_ITF_MODEL_NAME_SIZE);
        buf += SENS_ITF_MODEL_NAME_SIZE;
        memcpy(cmd->payload.brd_id_cmd.manufactor, buf, SENS_ITF_MANUF_NAME_SIZE);
        buf += SENS_ITF_MODEL_NAME_SIZE;
        cmd->payload.brd_id_cmd.sensor_id = buf_io_get32_fl_ap(buf);
        cmd->payload.brd_id_cmd.hardware_revision = buf_io_get8_fl_ap(buf);
        cmd->payload.brd_id_cmd.num_of_points = buf_io_get8_fl_ap(buf);
        cmd->payload.brd_id_cmd.cabalities = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_BRD_STATUS:
        cmd->payload.brd_status_cmd.status = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_BRD_CMD:
        cmd->payload.command_res_cmd.status = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_READ_BAT_STATUS:
        cmd->payload.bat_status_cmd.status = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_READ_BAT_CHARGE:
        cmd->payload.bat_charge_cmd.charge = buf_io_get8_fl_ap(buf);
        break;
    case SENS_ITF_REGMAP_SVR_MAIN_ADDR:
    case SENS_ITF_REGMAP_SVR_SEC_ADDR:
        memcpy(cmd->payload.svr_addr_cmd.addr, buf, SENS_ITF_SERVER_ADDR_SIZE);
        buf += SENS_ITF_SERVER_ADDR_SIZE;
        break;
    default:
        break;
    }

    if ((cmd->hdr.addr >= SENS_ITF_REGMAP_POINT_DESC_1) && 
        (cmd->hdr.addr <= SENS_ITF_REGMAP_POINT_DESC_32))
    {
        memcpy(cmd->payload.point_desc_cmd.name, buf, SENS_ITF_POINT_NAME_SIZE);
        buf += SENS_ITF_POINT_NAME_SIZE;
        cmd->payload.point_desc_cmd.type = buf_io_get8_fl_ap(buf);
        cmd->payload.point_desc_cmd.unit = buf_io_get8_fl_ap(buf);
        cmd->payload.point_desc_cmd.access_rights = buf_io_get8_fl_ap(buf);
        cmd->payload.point_desc_cmd.sampling_time_x250ms = buf_io_get32_fl_ap(buf);
    }

    if ((cmd->hdr.addr >= SENS_ITF_REGMAP_READ_POINT_DATA_1) &&
        (cmd->hdr.addr <= SENS_ITF_REGMAP_READ_POINT_DATA_32))
    {
        cmd->payload.point_value_cmd.type = buf_io_get8_fl_ap(buf);
        buf += sens_itf_unpack_point_value(&cmd->payload.point_value_cmd, buf);
    }

    size = cmd->hdr.size + 2; // crc 
    return size;
}

uint8_t sens_itf_pack_cmd_req(sens_itf_cmd_req_t *cmd, uint8_t *frame)
{
    uint8_t *buf = &frame[1];
    uint8_t size = 0;
    uint16_t crc;

    // address
    // commands without arguments are handled only with this line
    buf_io_put8_tl_ap(cmd->hdr.addr, buf);
    
    switch (cmd->hdr.addr)
    {
    case SENS_ITF_REGMAP_BRD_CMD:
        buf_io_put8_tl_ap(cmd->payload.command_cmd.cmd, buf);
        break;
    case SENS_ITF_REGMAP_WRITE_BAT_STATUS:
        buf_io_put8_tl_ap(cmd->payload.bat_status_cmd.status, buf);
        break;
    case SENS_ITF_REGMAP_WRITE_BAT_CHARGE:
        buf_io_put8_tl_ap(cmd->payload.bat_charge_cmd.charge, buf);
        break;
    case SENS_ITF_REGMAP_DSP_WRITE:
        buf_io_put8_tl_ap(cmd->payload.write_display_cmd.line, buf);
        memcpy(buf, cmd->payload.write_display_cmd.msg, SENS_ITF_DSP_MSG_MAX_SIZE);
        buf += SENS_ITF_DSP_MSG_MAX_SIZE;
        break;
    case SENS_ITF_REGMAP_WPAN_STATUS:
        buf_io_put8_tl_ap(cmd->payload.wpan_status_cmd.status,buf);
        break;
    case SENS_ITF_REGMAP_WPAN_STRENGTH:
        buf_io_put8_tl_ap(cmd->payload.wpan_strength_cmd.strenght,buf);
        break;
    default:
        break;
    }

    if ((cmd->hdr.addr >= SENS_ITF_REGMAP_WRITE_POINT_DATA_1) && 
        (cmd->hdr.addr <= SENS_ITF_REGMAP_WRITE_POINT_DATA_32))
    {
        buf_io_put8_tl_ap(cmd->payload.point_value_cmd.type, buf);
        buf += sens_itf_pack_point_value(&cmd->payload.point_value_cmd, buf);
    }

    size = buf - frame;
    buf_io_put8_tl(size, frame);
    crc = crc16_calc(frame, size);
    cmd->crc = crc;
    cmd->hdr.size = size;
    buf_io_put16_tl(crc, buf);

    size += 2; // + crc

    return size;
}