Liqun Wu / Mbed 2 deprecated 90418_mbed_controller

Dependencies:   mbed

scpi-def.cpp

Committer:
wuliqunyy
Date:
2022-01-17
Revision:
0:be95bfb06686

File content as of revision 0:be95bfb06686:

/*-
 * BSD 2-Clause License
 *
 * Copyright (c) 2012-2018, Jan Breuer
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file   scpi-def.c
 * @date   Thu Nov 15 10:58:45 UTC 2012
 *
 * @brief  SCPI parser test
 *
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "uart_mbed.h"
#include "main_init.h"
#include "i2c_mbed_fpga.h"
#include "scpi/scpi.h"
#include "scpi/parser.h"
#include "scpi-def.h"
#include "i2c_ram_defines.h"
#include "nv_bitfield_map.h"
//#include "test_vector.h"
#include "test_fg.h"
#include "test_ehp_reg.h"
#include "mbed.h"

extern i2c_mbed_fpga i2c;
LocalFileSystem local("local"); 

static void reprogram_for_server()
{
    i2c.i2c_word_write_simple((0x1018-0x1000)/2, 0x2080 );
    i2c.i2c_word_write_simple((0x101A-0x1000)/2, 0xfc13);
    i2c.i2c_word_write_simple((0x101C-0x1000)/2, 0x7eb ); 
    i2c.i2c_word_write_simple((0x1022-0x1000)/2, 0x2073); 
    i2c.i2c_word_write_simple((0x1024-0x1000)/2, 0x1ff); 
    i2c.i2c_word_write_simple((0x1026-0x1000)/2, 0xc); 
    i2c.i2c_word_write_simple((0x1028-0x1000)/2, 0x800); 
    i2c.i2c_word_write_simple((0x103A-0x1000)/2, 0xfff); 
    i2c.i2c_word_write_simple((0x103C-0x1000)/2, 0x1); 
    i2c.i2c_word_write_simple((0x003E)/2, 0x1); 
    i2c.i2c_word_write_simple((0x1040-0x1000)/2, 0x0); 
    i2c.i2c_word_write_simple((0x1042-0x1000)/2, 0x0); 
    i2c.i2c_word_write_simple((0x1044-0x1000)/2, 0x7f); 
    i2c.i2c_word_write_simple((0x1046-0x1000)/2, 0x7f7f); 
    i2c.i2c_word_write_simple((0x1050-0x1000)/2, 0x700);    
}

static uint16_t word_read_helper(uint16_t address)
{
    uint16_t value;
    if((address >= 0x1000) && (address < 0x1200)) {
        address = (address - 0x1000) / 2;
        i2c.i2c_word_read_simple(address, &value);
    } else {
        i2c.i2c_word_read_interpreter(address, &value);
    }
    return value;
}

static scpi_result_t set_duty(scpi_t * context) {
    float input = 0;
    int32_t duty_cycle_scaled = 0;

    /* read first parameter if present */
    if (!SCPI_ParamFloat(context, &input, TRUE)) {
        return SCPI_RES_ERR;
    }
    duty_cycle_scaled = ((int)(input * 65535.0)) / 100u;
    i2c.i2c_set_open_loop_duty(duty_cycle_scaled);
    return SCPI_RES_OK;
}

scpi_result_t get_duty(scpi_t* context)
{
    float duty_percentage;
    uint16_t duty_cycle;
    i2c.i2c_word_read_simple(I2C_SPEED_DUTY, &duty_cycle);
    duty_percentage = ((float)duty_cycle)/655.35;
    SCPI_ResultFloat(context, duty_percentage);
    return SCPI_RES_OK;
}


const scpi_choice_def_t led_selects[] = {
    { "OFF", 0 },
    { "ON", 1 },
    SCPI_CHOICE_LIST_END
};
static scpi_result_t set_led1(scpi_t * context) {
    int32_t input = 0;

    if (!SCPI_ParamChoice(context, led_selects, &input, TRUE))
        return SCPI_RES_ERR;

    led1 = input;
    return SCPI_RES_OK;
}

scpi_result_t get_led1(scpi_t* context)
{
    int led_value = led1;
    SCPI_ResultText(context, led_selects[led_value].name);
    return SCPI_RES_OK;
}


scpi_result_t read_word(scpi_t* context)
{
    uint32_t address = 0;
    uint16_t value;

    /* read first parameter if present */
    if (!SCPI_ParamUInt32(context, &address, TRUE)) {
        return SCPI_RES_ERR;
    }
    value = word_read_helper((uint16_t)address);

    SCPI_ResultUInt16Base(context, value, 16);
    return SCPI_RES_OK;
}

scpi_result_t write_word(scpi_t* context)
{
    int32_t address = 0;
    int32_t value = 0;

    /* read first parameter: address */
    if (!SCPI_ParamInt(context, &address, TRUE)) {
        return SCPI_RES_ERR;
    }

    /* read first parameter: address */
    if (!SCPI_ParamInt(context, &value, TRUE)) {
        return SCPI_RES_ERR;
    }

    if((address >= 0x1000) && (address < 0x1200)) {
        address = (address - 0x1000) / 2;
        if(address == 15){   /* Special if-case for the windmilling debugging, writing the default registers */
            i2c.i2c_word_write_simple(address, value);
            reprogram_for_server();   
        }
        else { /* Normal write operation */
            i2c.i2c_word_write_simple(address, value);
        }
    } else {
        i2c.i2c_word_write_interpreter(address, value);
    }
    return SCPI_RES_OK;
}

scpi_result_t read_array(scpi_t* context)
{
    uint32_t start_address = 0;
    uint32_t size = 0;

    /* read first parameter: start address */
    if (!SCPI_ParamUInt32(context, &start_address, TRUE)) {
        return SCPI_RES_ERR;
    }

    /* read second parameter: size */
    if (!SCPI_ParamUInt32(context, &size, TRUE)) {
        return SCPI_RES_ERR;
    }

    if(((size % 2) != 0u) || (size == 0)) {
        SCPI_ErrorPush(context,SCPI_ERROR_ILLEGAL_PARAMETER_VALUE);
        return SCPI_RES_ERR;
    }

    uint16_t array[(size/2)];  // uint16_t* array = (uint16_t*)malloc(size);
    uint16_t index = 0;
    for(index = 0u; index < (size/2); index++) {
        array[index] = word_read_helper(start_address + (index * 2));
    }

    SCPI_ResultArrayUInt16(context, array, (sizeof(array) / sizeof(*array)), SCPI_FORMAT_ASCII);
    return SCPI_RES_OK;
}

scpi_result_t repeat_read(scpi_t* context)
{
    uint32_t interval_us;
    uint32_t first_address;
    uint32_t second_address;
    uint32_t samples;

    /* read first parameter: size */
    if (!SCPI_ParamUInt32(context, &samples, TRUE)) {
        return SCPI_RES_ERR;
    }

    if (!SCPI_ParamUInt32( context, &interval_us, TRUE)) {
        return SCPI_RES_ERR;
    }

    /* The first address. This is mandatory */
    if (!SCPI_ParamUInt32(context, &first_address, TRUE)) {
        return SCPI_RES_ERR;
    }
    /* A potential second address. Optional */
    if (!SCPI_ParamUInt32(context, &second_address, FALSE)) {
        second_address = 0;
    }

    if(second_address != 0) {
        uint16_t array[samples*2];  // uint16_t* array = (uint16_t*)malloc(size);

        for(uint32_t index = 0u; index < samples*2; index=index+2) {
            array[index] = word_read_helper(first_address);
            array[index+1] = word_read_helper(second_address);
            wait_us(interval_us);
        }
        SCPI_ResultArrayUInt16(context, array, (sizeof(array) / sizeof(*array)), SCPI_FORMAT_ASCII);
    } else {
        uint16_t array[samples];  // uint16_t* array = (uint16_t*)malloc(size);

        for(uint32_t index = 0u; index < samples; index++) {
            array[index] = word_read_helper(first_address);
            wait_us(interval_us);
        }
        SCPI_ResultArrayUInt16(context, array, (sizeof(array) / sizeof(*array)), SCPI_FORMAT_ASCII);
    }

    return SCPI_RES_OK;
}

scpi_result_t dump_ram(scpi_t* context)
{
    uint16_t start_address  = 0x1000;
    uint16_t end_address    = 0x1096;
    uint16_t data;

      
    FILE *RAMdump = fopen("/local/RAMdump.csv", "w");  // Open "RAMdump.csv" on the local file system (on the mbed) for writing    
    led4 = !led4;  
    wait_us(500000);  
    for (uint16_t address=start_address ; address<=end_address-2; address=address+2)
    {
        data = word_read_helper((uint16_t)address);
        fprintf(RAMdump, "0x%.4X,0x%.4X\r\n", address, data);     // Write each address and read data of the complete RAM to the external file 
    }
    fclose(RAMdump);
    led4 = !led4;  
    return SCPI_RES_OK;
}

scpi_result_t reset_config_mode(scpi_t* context)
{
    main_init();
    //wait_us(2000000);         /* keep FPGA in reset for 2s, to let motor stop */
    wait_us(100);               /* reset the IO-pin for minimum few us */
    enable_fpga();              /* enable FPGA */
    i2c.wait_for_idle_state();  /* wait for FPGA responsive */
    //wait_us(1000);
    wait_us(100);
    i2c.i2c_config_mode_entry();/* enter configuration mode */
    return SCPI_RES_OK;
}

scpi_result_t reset_htol_mode(scpi_t* context)
{
    i2c.i2c_soft_reset();
    i2c.wait_for_idle_state();  /* wait for FPGA responsive */
    //wait_us(1000);
    wait_us(100);
    i2c.i2c_mlx_mode_entry(); /* Enter melexis mode */
    wait_us(100);
    i2c.i2c_htol_mode_entry(); /* Enter HTOL mode */
    return SCPI_RES_OK;
}


const scpi_choice_def_t mlxmode_selects[] = {
    { "OFF", 0 },
    { "ON", 1 },
    SCPI_CHOICE_LIST_END
};
scpi_result_t reset_application_mode(scpi_t* context)
{
    int32_t mlxmode = 0;
    if (!SCPI_ParamChoice(context, mlxmode_selects, &mlxmode, FALSE))
        mlxmode = 0;
    main_init();
    wait_us(2000000);   /* keep FPGA in reset for 5s, to let motor stop*/
    enable_fpga();   /* enable FPGA */
    if(mlxmode == 1) {
        i2c.wait_for_idle_state();
        wait_us(1000);
        i2c.i2c_mlx_mode_entry();
    }
    i2c.wait_for_application_state();
    wait_us(1000);
    return SCPI_RES_OK;
}

scpi_result_t soft_reset_application_mode(scpi_t* context)
{
    int32_t mlxmode = 0;
    if (!SCPI_ParamChoice(context, mlxmode_selects, &mlxmode, FALSE))
        mlxmode = 0;
    i2c.i2c_soft_reset();
    if(mlxmode == 1) {
        i2c.wait_for_idle_state();
        wait_us(100);
        i2c.i2c_mlx_mode_entry();
        i2c.wait_for_application_state();
    }
    wait_us(100);
    return SCPI_RES_OK;
}

/* 
*   self-test routines
*/

scpi_result_t test_capture_position_timing(scpi_t* context)
{
    /*to be added*/
    reset_fpga(); /*finish*/
    return SCPI_RES_OK;
}

scpi_result_t test_ehp_reg_vector(scpi_t* context)
{

    /*vector start, use template later: TBD*/
    led3=1;
    test_ehp_reg test(p15,p16);
    test.configure();
    test.run();
    test.stop();
    SCPI_ResultArrayUInt32(context, test.getResult(), test.getBufferSize(), SCPI_FORMAT_ASCII);
    SCPI_ResultText(context, test.getResultStatus() );
    test.release();
    
    /*
    test_vector* t;
    test_ehp_reg test(p15,p16); //p15 to capture timer -> non_flat.  p16 to trigger ADC sample
    t = &test;
    t->configure();
    t->run();
    t->stop();
    SCPI_ResultArrayUInt32(context, t->getResult(), t->getBufferSize(), SCPI_FORMAT_ASCII);
    SCPI_ResultText(context, t->getResultStatus() );
    t->release();
    */
    led3=0;
    return SCPI_RES_OK;
}

scpi_result_t test_fg_vector(scpi_t* context)
{
     /*vector start, use template later: TBD*/
    led3=1;
    test_fg test(p15);
    test.configure();
    test.run();
    test.stop();
    SCPI_ResultArrayUInt32(context, test.getResult(), test.getBufferSize(), SCPI_FORMAT_ASCII);
    SCPI_ResultText(context, test.getResultStatus() );
    test.release();
    /*
    test_vector* t;
    test_fg test(p15); //only two option to capture: p15 is CAP3.0  or p16 is CAP3.1
    t = &test;
    t->configure();
    t->run();
    t->stop();
    SCPI_ResultArrayUInt32(context, t->getResult(), t->getBufferSize(), SCPI_FORMAT_ASCII);
    SCPI_ResultText(context, t->getResultStatus() );
    t->release();
    */
    led3=0;
    return SCPI_RES_OK; 
}

/**
 * Reimplement IEEE488.2 *TST?
 *
 * Result should be 0 if everything is ok
 * Result should be 1 if something goes wrong
 *
 * Return SCPI_RES_OK
 */
static scpi_result_t My_CoreTstQ(scpi_t * context) {

    SCPI_ResultInt(context, 0);
    
    
    return SCPI_RES_OK;
}

void configure_scpi(void)
{
    /* user_context will be pointer to socket */
    SCPI_Init(&scpi_context,
            scpi_commands,
            &scpi_interface,
            scpi_units_def,
            "Melexis", "MLX90418", NULL, "0",
            scpi_input_buffer, SCPI_INPUT_BUFFER_LENGTH,
            scpi_error_queue_data, SCPI_ERROR_QUEUE_SIZE);
}


const scpi_command_t scpi_commands[] = {
    /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */
    {"*CLS", SCPI_CoreCls, 0},
    {"*ESE", SCPI_CoreEse, 0},
    {"*ESE?", SCPI_CoreEseQ, 0},
    {"*ESR?", SCPI_CoreEsrQ, 0},
    {"*IDN?", SCPI_CoreIdnQ, 0},
    {"*OPC", SCPI_CoreOpc, 0},
    {"*OPC?", SCPI_CoreOpcQ, 0},
    {"*RST", SCPI_CoreRst, 0},
    {"*SRE", SCPI_CoreSre, 0},
    {"*SRE?", SCPI_CoreSreQ, 0},
    {"*STB?", SCPI_CoreStbQ, 0},
    {"*TST?", My_CoreTstQ, 0},
    {"*WAI", SCPI_CoreWai, 0},

    /* Required SCPI commands (SCPI std V1999.0 4.2.1) */
    {"SYSTem:ERRor[:NEXT]?", SCPI_SystemErrorNextQ, 0},
    {"SYSTem:ERRor:COUNt?", SCPI_SystemErrorCountQ, 0},
    {"SYSTem:VERSion?", SCPI_SystemVersionQ, 0},

    //{"STATus:OPERation?", scpi_stub_callback, 0},
    //{"STATus:OPERation:EVENt?", scpi_stub_callback, 0},
    //{"STATus:OPERation:CONDition?", scpi_stub_callback, 0},
    //{"STATus:OPERation:ENABle", scpi_stub_callback, 0},
    //{"STATus:OPERation:ENABle?", scpi_stub_callback, 0},

    {"STATus:QUEStionable[:EVENt]?", SCPI_StatusQuestionableEventQ, 0},
    //{"STATus:QUEStionable:CONDition?", scpi_stub_callback, 0},
    {"STATus:QUEStionable:ENABle", SCPI_StatusQuestionableEnable, 0},
    {"STATus:QUEStionable:ENABle?", SCPI_StatusQuestionableEnableQ, 0},

    {"STATus:PRESet", SCPI_StatusPreset, 0},

    /* DMM */
    {"TARGet:DUTYcycle", set_duty, 0},
    {"TARGet:DUTYcycle?", get_duty, 0},
    {"TARGet:SPEED", set_duty, 0},
    {"TARGet:SPEED?", get_duty, 0},
    {"LED1", set_led1, 0},
    {"LED1?", get_led1, 0},
    {"MEMory:WORD?", read_word, 0},
    {"MEMory:WORD", write_word, 0},
    {"MEMory:ARRAY?", read_array, 0},
    {"MEMory:REPEAT?", repeat_read, 0},
    {"MEMory:DUMPRAM", dump_ram, 0},
    {"SYSTem:RESET[:APPLImode]", reset_application_mode, 0},
    {"SYSTem:SOFTRESET[:APPLImode]", soft_reset_application_mode, 0},
    {"SYSTem:RESET:CONFIGmode", reset_config_mode, 0},
    {"SYSTem:RESET:HTOLmode", reset_htol_mode, 0},
    {"TEST:POSItion", test_capture_position_timing, 0},
    {"TEST:TESTfg", test_fg_vector, 0},
    {"TEST:TESTehpreg", test_ehp_reg_vector, 0},

    SCPI_CMD_LIST_END
};

scpi_interface_t scpi_interface = {
    /*.error = */ SCPI_Error,
    /*.write = */ SCPI_Write,
    /*.control = */ SCPI_Control,
    /*.flush = */ SCPI_Flush,
    /*.reset = */ SCPI_Reset,
};

char scpi_input_buffer[SCPI_INPUT_BUFFER_LENGTH];
scpi_error_t scpi_error_queue_data[SCPI_ERROR_QUEUE_SIZE];
scpi_t scpi_context;