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_sensor.cpp

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

File content as of revision 1:acdf490d94a7:

#include <string.h>
#include <stdint.h>
#include "mbed.h"
#include "sens_itf.h"
#include "sens_util.h"
#include "../util/buf_io.h"
#include "../util/crc16.h"
#include "../pt/pt.h"
#include "SLCD.h"
#include "MMA8451Q.h"

#define SENS_ITF_SENSOR_DBG_FRAME     1
#define SENS_ITF_DBG_FRAME 1
#define SENS_ITF_SENSOR_NUM_OF_POINTS 5

#define MMA8451_I2C_ADDRESS (0x1d<<1)

static uint8_t main_svr_addr[SENS_ITF_SERVER_ADDR_SIZE];
static uint8_t secon_svr_addr[SENS_ITF_SERVER_ADDR_SIZE];
static uint8_t rx_frame[SENS_ITF_MAX_FRAME_SIZE];
static volatile uint8_t num_rx_bytes;
static Timeout rx_trmout_timer ;
static Ticker acq_data_timer;
static sens_itf_point_ctrl_t sensor_points;
static sens_itf_cmd_brd_id_t board_info;
static struct pt pt_updt;
static struct pt pt_data;
static volatile uint8_t frame_timeout;
static volatile uint8_t acq_data ;
static DigitalOut  greenLED(LED1);
static DigitalOut  redLED(LED2);
static AnalogIn    lightSensor(PTE22);
static SLCD        sLCD;
static Serial      pcSerial(USBTX, USBRX);
static MMA8451Q    acc(PTE25, PTE24, MMA8451_I2C_ADDRESS);
static InterruptIn mode_switch(SW3);    
static volatile uint8_t  view_mode;

void scroll_message(char *message, unsigned char len)
{
    sLCD.All_Segments(0);
    
    for (int start = 0; start < len - 4; start++)
    {
        for (int digit = 0; digit < 4; digit++)
            sLCD.putc(message[start + digit]);
        wait(0.4);
    }
}

static void dump_frame(uint8_t *frame, uint8_t size)
{
	int n,m;
	char buf[64];
	
	buf[0] = buf[1] = buf[2] = buf[3] = ' ';
	
	for(n = 0, m = 4; n < size ; n++, m+=3)
	{
		sprintf(&buf[m],"%02X_",frame[n]);
	}
	
	buf[m] = buf[m+1] = buf[m+2] = buf[m+3] = ' ';
	buf[m+4] = '\0';
	
	m +=4;
	scroll_message(buf,m);
	
}
	
static uint8_t sens_itf_get_point_type(uint8_t point)
{
    return sensor_points.points[point].desc.type;
}

static uint8_t sens_itf_get_number_of_points(void)
{
    return SENS_ITF_SENSOR_NUM_OF_POINTS;
}

static sens_itf_cmd_point_desc_t *sens_itf_get_point_desc(uint8_t point)
{
    sens_itf_cmd_point_desc_t *d = 0;

    if (point < sens_itf_get_number_of_points())
        d = &sensor_points.points[point].desc;

    return d;
}

static sens_itf_cmd_point_t *sens_itf_get_point_value(uint8_t point)
{
    sens_itf_cmd_point_t *v = 0;

    if (point < sens_itf_get_number_of_points())
        v = &sensor_points.points[point].value;

    return v;
}

static uint8_t sens_itf_set_point_value(uint8_t point, sens_itf_cmd_point_t *v)
{
    uint8_t ret = 0;

    if (point < sens_itf_get_number_of_points())
    {
        sensor_points.points[point].value = *v;
        ret = 1;
    }
    else
    {
        ret = 0;
    }

    return ret;
}

static sens_itf_cmd_brd_id_t *sens_itf_get_board_info(void)
{
    return &board_info;
}

static uint8_t sens_itf_sensor_send_frame(uint8_t *frame, uint8_t size)
{
    //dump_frame(frame, size);
    
    for(int n = 0 ; n < size ; n++)
    	pcSerial.putc((unsigned int )frame[n]);
    //pcSerial.puts((char *)frame,size); // puts returns the size sent ?
    return size;
}

static uint8_t sens_itf_sensor_check_register_map(sens_itf_cmd_req_t *cmd, sens_itf_cmd_res_t *ans, uint8_t *frame)
{
    uint8_t size = 0;
    if ( // check global register map for valid address ranges
                ((cmd->hdr.addr > SENS_ITF_REGMAP_SVR_SEC_ADDR) && 
                (cmd->hdr.addr < SENS_ITF_REGMAP_POINT_DESC_1)) ||
                (cmd->hdr.addr > SENS_ITF_REGMAP_WRITE_POINT_DATA_32) ||
                // check local register map - reading
                ((cmd->hdr.addr >= SENS_ITF_REGMAP_READ_POINT_DATA_1) && 
                (cmd->hdr.addr <= SENS_ITF_REGMAP_READ_POINT_DATA_32) &&
                ((cmd->hdr.addr - SENS_ITF_REGMAP_READ_POINT_DATA_1) >= sens_itf_get_number_of_points())) ||
                // check local register map - writing
                ((cmd->hdr.addr >= SENS_ITF_REGMAP_WRITE_POINT_DATA_1) && 
                (cmd->hdr.addr <= SENS_ITF_REGMAP_WRITE_POINT_DATA_32) &&
                ((cmd->hdr.addr - SENS_ITF_REGMAP_WRITE_POINT_DATA_1) >= sens_itf_get_number_of_points())))
    {
        sens_util_log(SENS_ITF_SENSOR_DBG_FRAME, "Invalid register address %02X",cmd->hdr.addr);
        ans->hdr.status = SENS_ITF_ANS_REGISTER_NOT_IMPLEMENTED;
        size = sens_itf_pack_cmd_res(ans, frame);
    }
    return size;
}

static uint8_t sens_itf_sensor_writings(sens_itf_cmd_req_t *cmd, sens_itf_cmd_res_t *ans, uint8_t *frame)
{
    uint8_t size = 0;
    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;
        //sLCD.printf("R%dV%d",point,cmd->payload.point_value_cmd.value.u8);
        //wait(0.5);
        uint8_t acr = sens_itf_get_point_desc(point)->access_rights & SENS_ITF_ACCESS_WRITE_ONLY;
            
        if (acr)
        {
            ans->hdr.status = SENS_ITF_ANS_OK;
            sens_itf_set_point_value(point,&cmd->payload.point_value_cmd);
        }
        else
        {
            sens_util_log(SENS_ITF_SENSOR_DBG_FRAME, "Point %d does not allow writings",point);                
            ans->hdr.status = SENS_ITF_ANS_READY_ONLY;
        }
        size = sens_itf_pack_cmd_res(ans, frame);
    }
    return size;
}

static uint8_t sens_itf_sensor_readings(sens_itf_cmd_req_t *cmd, sens_itf_cmd_res_t *ans, uint8_t *frame)
{
    uint8_t size = 0;
    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;
        uint8_t acr = sens_itf_get_point_desc(point)->access_rights & SENS_ITF_ANS_READY_ONLY;
            
        if (acr)
        {
            ans->hdr.status = SENS_ITF_ANS_OK;
            ans->payload.point_value_cmd = *sens_itf_get_point_value(point);
        }
        else
        {
            sens_util_log(SENS_ITF_SENSOR_DBG_FRAME, "Point %d does not allow readings",point);                
            ans->hdr.status = SENS_ITF_ANS_WRITE_ONLY;
        }
        size = sens_itf_pack_cmd_res(ans, frame);
    }
    return size;
}

static uint8_t sens_itf_check_other_cmds(sens_itf_cmd_req_t *cmd, sens_itf_cmd_res_t *ans, uint8_t *frame)
{
    uint8_t size = 0;
    switch (cmd->hdr.addr)
    {
        case SENS_ITF_REGMAP_ITF_VERSION:
            ans->payload.itf_version_cmd.version = SENS_ITF_LATEST_VERSION;
            break;
        case SENS_ITF_REGMAP_BRD_ID:
            memcpy(&ans->payload.brd_id_cmd,sens_itf_get_board_info(),sizeof(sens_itf_cmd_brd_id_t));
            break;
        case SENS_ITF_REGMAP_BRD_STATUS:
            ans->payload.brd_status_cmd.status = 0; // TBD
            break;
        case SENS_ITF_REGMAP_BRD_CMD:
            ans->payload.command_res_cmd.status = 0; // TBD
            break;
        case SENS_ITF_REGMAP_READ_BAT_STATUS:
            ans->payload.bat_status_cmd.status = 0; // TBD
            break;
        case SENS_ITF_REGMAP_READ_BAT_CHARGE:
            ans->payload.bat_charge_cmd.charge = 100; // TBD
            break;
        case SENS_ITF_REGMAP_SVR_MAIN_ADDR:
            memcpy(ans->payload.svr_addr_cmd.addr,main_svr_addr, SENS_ITF_SERVER_ADDR_SIZE); 
            break;
        case SENS_ITF_REGMAP_SVR_SEC_ADDR:
            memcpy(ans->payload.svr_addr_cmd.addr,secon_svr_addr, 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(&ans->payload.point_desc_cmd, &sensor_points.points[point].desc, sizeof(sens_itf_cmd_point_desc_t));
    }
        
    ans->hdr.status = SENS_ITF_ANS_OK;
    size = sens_itf_pack_cmd_res(ans, frame);
    return size;
}
static void sens_itf_process_cmd(uint8_t *frame, uint8_t num_rx_bytes)
{
    uint8_t ret;
    uint8_t size = 0;
    sens_itf_cmd_req_t cmd;
    sens_itf_cmd_res_t ans;

    ret = sens_itf_unpack_cmd_req(&cmd, frame, num_rx_bytes);

    if (ret > 0)
    {
        ans.hdr.addr = cmd.hdr.addr;
        
        size = sens_itf_sensor_check_register_map(&cmd, &ans,frame);
        if (size == 0)
            size = sens_itf_sensor_writings(&cmd, &ans,frame);

        if (size == 0)
            size = sens_itf_sensor_readings(&cmd, &ans,frame);
 
        if (size == 0)
            size = sens_itf_check_other_cmds(&cmd, &ans,frame);

        if (size == 0)
        {
            ans.hdr.status = SENS_ITF_ANS_ERROR;
            sLCD.printf("   D");
        }
 
        size = sens_itf_pack_cmd_res(&ans,frame);
        sens_itf_sensor_send_frame(frame, size);
    }
}

void sens_itf_init_point_db(void)
{
    uint8_t n;
    char *point_names[SENS_ITF_POINT_NAME_SIZE] = { "LIGHT", "LEDG", "ACCX", "ACCY", "ACCXZ" };
    uint8_t data_types[SENS_ITF_POINT_NAME_SIZE] = {SENS_ITF_DT_U8, SENS_ITF_DT_U8, SENS_ITF_DT_FLOAT, SENS_ITF_DT_FLOAT, SENS_ITF_DT_FLOAT};
    uint8_t access_rights[SENS_ITF_POINT_NAME_SIZE] = { SENS_ITF_ACCESS_READ_ONLY, SENS_ITF_ACCESS_WRITE_ONLY, SENS_ITF_ACCESS_READ_ONLY,
        SENS_ITF_ACCESS_READ_ONLY, SENS_ITF_ACCESS_READ_ONLY};
    uint32_t sampling_time[SENS_ITF_POINT_NAME_SIZE] = {4*10, 0, 4*15, 4*20, 4*25};

	memset(&sensor_points, 0, sizeof(sensor_points));
	memset(&board_info, 0, sizeof(board_info));
	
    strcpy((char *)board_info.model, "KL46Z");
    strcpy((char *)board_info.manufactor, "TESLA");
    board_info.sensor_id = 0xDEADBEEF;
    board_info.hardware_revision = 0x01;
    board_info.num_of_points = SENS_ITF_SENSOR_NUM_OF_POINTS;
    board_info.cabalities = SENS_ITF_CAPABILITIES_DISPLAY |
        SENS_ITF_CAPABILITIES_WPAN_STATUS | 
        SENS_ITF_CAPABILITIES_BATTERY_STATUS;

    sensor_points.num_of_points = SENS_ITF_SENSOR_NUM_OF_POINTS;

    for (n = 0; n < SENS_ITF_SENSOR_NUM_OF_POINTS; n++)
    {
        strcpy((char *)sensor_points.points[n].desc.name, point_names[n]);
        sensor_points.points[n].desc.type = data_types[n];
        sensor_points.points[n].desc.unit = 0; // TDB
        sensor_points.points[n].desc.access_rights = access_rights[n];
        sensor_points.points[n].desc.sampling_time_x250ms = sampling_time[n];
        sensor_points.points[n].value.type = data_types[n];
    }
}

static void sens_itf_rx_tmrout_timer_func(void)
{
	//greenLED = greenLED == 1 ? 0 : 1; 
    frame_timeout = 1;
}

static void sens_itf_acq_data_timer_func(void)
{
    redLED = redLED == 1 ? 0 : 1;   
    acq_data = 1;
}

static void sens_itf_rx_tmrout_timer_reesched(void)
{
	rx_trmout_timer.detach();
	rx_trmout_timer.attach_us(sens_itf_rx_tmrout_timer_func,500*1000);
}

// Serial or SPI interrupt, called when a new byte is received
static void sens_itf_sensor_rx_byte(void)
{
    uint8_t value;
    
    // DISABLE INTERRUPTS
    if (frame_timeout)
        return;

	value = (uint8_t) pcSerial.getc();
	
    if (num_rx_bytes < SENS_ITF_MAX_FRAME_SIZE)
        rx_frame[num_rx_bytes] = value;
    
    num_rx_bytes++;
    if (num_rx_bytes >= SENS_ITF_MAX_FRAME_SIZE)
        num_rx_bytes = 0;

    sens_itf_rx_tmrout_timer_reesched();
    // ENABLE INTERRUPTS
}

uint8_t sens_itf_sensor_init(void)
{

    sens_itf_init_point_db();
    memcpy(main_svr_addr,"1212121212121212",SENS_ITF_SERVER_ADDR_SIZE);
    memcpy(secon_svr_addr,"aabbccddeeff1122",SENS_ITF_SERVER_ADDR_SIZE);
    num_rx_bytes = 0;
    acq_data = 0;
    frame_timeout = 0;
    greenLED = 0; 
    redLED = 1;
    sens_itf_rx_tmrout_timer_reesched();
    acq_data_timer.attach(sens_itf_acq_data_timer_func,2);
	pcSerial.attach(sens_itf_sensor_rx_byte);
	
    return 1;
}

static int pt_data_func(struct pt *pt)
{
    PT_BEGIN(pt);

    while (1)
    {
        // wait a frame timeout
        PT_WAIT_UNTIL(pt, frame_timeout == 1);

        if (num_rx_bytes > 0)
        {
            // process it
            sens_itf_process_cmd(rx_frame, num_rx_bytes);
            num_rx_bytes = 0;
        }

        // restart reception
        frame_timeout = 0;
        sens_itf_rx_tmrout_timer_reesched();
    }

    PT_END(pt);
}

static int pt_updt_func(struct pt *pt)
{
    PT_BEGIN(pt);

    while (1)
    {
	    char buf[5];    
	    uint8_t v;
	    
        // wait job
        PT_WAIT_UNTIL(pt, acq_data == 1);

	    v = (uint8_t)(lightSensor.read()*100);  
	    sensor_points.points[0].value.value.u8 = v;
	    greenLED = sensor_points.points[1].value.value.u8;
	    sensor_points.points[2].value.value.fp32 = 1.0 - abs(acc.getAccX());
	    sensor_points.points[3].value.value.fp32 = 1.0 - abs(acc.getAccY());
	    sensor_points.points[4].value.value.fp32 = 1.0 - abs(acc.getAccZ());
	    
	    sLCD.All_Segments(0);
	    switch(view_mode)
	    {
	    	case 0:
			  	sprintf(buf,"L %2d",v);
	    		sLCD.printf("%s",buf);   	
	    		break;
	    	case 1:
			  	sprintf(buf,"%4d",(uint16_t) (sensor_points.points[2].value.value.fp32*1000));
	    		sLCD.printf("%s",buf);   	
	    		break;
	    	case 2:
			  	sprintf(buf,"%4d",(uint16_t) (sensor_points.points[3].value.value.fp32*1000));
	    		sLCD.printf("%s",buf);   	
	    		break;
	    	case 3:
			  	sprintf(buf,"%4d",(uint16_t) (sensor_points.points[4].value.value.fp32*1000));
	    		sLCD.printf("%s",buf);   	
	    		break;
	    	default:
	  		  	break;	
	    }
   
        acq_data = 0;
    }

    PT_END(pt);
}

void set_mode(void)
{
	view_mode = ++view_mode > 3 ? 0 : view_mode;
}

void main(void)
{
    frame_timeout = 0;
    acq_data = 0;
    view_mode = 0;

    sLCD.All_Segments(0); 
    sLCD.DP2(0);
    sLCD.printf("INIT"); 
	pcSerial.baud(115200);
    sens_itf_sensor_init();
    
    mode_switch.rise(set_mode);
    
    PT_INIT(&pt_data);
    PT_INIT(&pt_updt);

	
    while(1)
    {
        pt_data_func(&pt_data);
        pt_updt_func(&pt_updt);
    }    
}