Make library more C++ friendly
| | |
| | | */ |
| | | |
| | | #ifndef SCPI_TYPES_H |
| | | #define SCPI_TYPES_H |
| | | #define SCPI_TYPES_H |
| | | |
| | | #include <stddef.h> |
| | | #include <stdint.h> |
| | | #include <stdbool.h> |
| | | |
| | | #ifdef __cplusplus |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | |
| | | //typedef enum { FALSE = 0, TRUE } bool_t; |
| | | |
| | | /* IEEE 488.2 registers */ |
| | | enum _scpi_reg_name_t { |
| | | SCPI_REG_STB = 0, // Status Byte |
| | | SCPI_REG_SRE, // Service Request Enable Register |
| | | SCPI_REG_ESR, // Standard Event Status Register (ESR, SESR) |
| | | SCPI_REG_ESE, // Event Status Enable Register |
| | | SCPI_REG_OPER, // OPERation Status Register |
| | | SCPI_REG_OPERE, // OPERation Status Enable Register |
| | | SCPI_REG_QUES, // QUEStionable status register |
| | | SCPI_REG_QUESE, // QUEStionable status Enable Register |
| | | |
| | | /* last definition - number of registers */ |
| | | SCPI_REG_COUNT, |
| | | }; |
| | | typedef enum _scpi_reg_name_t scpi_reg_name_t; |
| | | |
| | | enum _scpi_ctrl_name_t { |
| | | SCPI_CTRL_SRQ = 1, // service request |
| | | SCPI_CTRL_GTL, // Go to local |
| | | SCPI_CTRL_SDC, // Selected device clear |
| | | SCPI_CTRL_PPC, // Parallel poll configure |
| | | SCPI_CTRL_GET, // Group execute trigger |
| | | SCPI_CTRL_TCT, // Take control |
| | | SCPI_CTRL_LLO, // Device clear |
| | | SCPI_CTRL_DCL, // Local lockout |
| | | SCPI_CTRL_PPU, // Parallel poll unconfigure |
| | | SCPI_CTRL_SPE, // Serial poll enable |
| | | SCPI_CTRL_SPD, // Serial poll disable |
| | | SCPI_CTRL_MLA, // My local address |
| | | SCPI_CTRL_UNL, // Unlisten |
| | | SCPI_CTRL_MTA, // My talk address |
| | | SCPI_CTRL_UNT, // Untalk |
| | | SCPI_CTRL_MSA, // My secondary address |
| | | }; |
| | | typedef enum _scpi_ctrl_name_t scpi_ctrl_name_t; |
| | | |
| | | typedef uint16_t scpi_reg_val_t; |
| | | |
| | | /* scpi commands */ |
| | | enum _scpi_result_t { |
| | | SCPI_RES_OK = 1, |
| | | SCPI_RES_ERR = -1, |
| | | }; |
| | | typedef enum _scpi_result_t scpi_result_t; |
| | | typedef struct _scpi_param_list_t scpi_param_list_t; |
| | | |
| | | typedef struct _scpi_command_t scpi_command_t; |
| | | |
| | | struct _scpi_param_list_t { |
| | | const scpi_command_t * cmd; |
| | | const char * parameters; |
| | | size_t length; |
| | | }; |
| | | #define SCPI_CMD_LIST_END {NULL, NULL, } |
| | | typedef struct _scpi_param_list_t scpi_param_list_t; |
| | | |
| | | /* scpi interface */ |
| | | typedef struct _scpi_t scpi_t; |
| | | typedef struct _scpi_interface_t scpi_interface_t; |
| | | |
| | | struct _scpi_buffer_t { |
| | | size_t length; |
| | | size_t position; |
| | | char * data; |
| | | }; |
| | | typedef struct _scpi_buffer_t scpi_buffer_t; |
| | | |
| | | typedef size_t(*scpi_write_t)(scpi_t * context, const char * data, size_t len); |
| | | typedef scpi_result_t(*scpi_write_control_t)(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val); |
| | | typedef int (*scpi_error_callback_t)(scpi_t * context, int_fast16_t error); |
| | | |
| | | typedef scpi_result_t(*scpi_command_callback_t)(scpi_t *); |
| | | |
| | | |
| | | /* scpi error queue */ |
| | | typedef void * scpi_error_queue_t; |
| | | |
| | | /* scpi units */ |
| | | typedef enum _scpi_unit_t scpi_unit_t; |
| | | typedef struct _scpi_unit_def_t scpi_unit_def_t; |
| | | typedef enum _scpi_special_number_t scpi_special_number_t; |
| | | typedef struct _scpi_special_number_def_t scpi_special_number_def_t; |
| | | typedef struct _scpi_number_t scpi_number_t; |
| | | |
| | | struct _scpi_param_list_t { |
| | | const scpi_command_t * cmd; |
| | | const char * parameters; |
| | | size_t length; |
| | | enum _scpi_unit_t { |
| | | SCPI_UNIT_NONE, |
| | | SCPI_UNIT_VOLT, |
| | | SCPI_UNIT_AMPER, |
| | | SCPI_UNIT_OHM, |
| | | SCPI_UNIT_HERTZ, |
| | | SCPI_UNIT_CELSIUS, |
| | | SCPI_UNIT_SECONDS, |
| | | }; |
| | | typedef enum _scpi_unit_t scpi_unit_t; |
| | | |
| | | struct _scpi_unit_def_t { |
| | | const char * name; |
| | | scpi_unit_t unit; |
| | | double mult; |
| | | }; |
| | | #define SCPI_UNITS_LIST_END {NULL, SCPI_UNIT_NONE, 0} |
| | | typedef struct _scpi_unit_def_t scpi_unit_def_t; |
| | | |
| | | #define SCPI_CMD_LIST_END {.pattern = NULL, .callback = NULL, } |
| | | enum _scpi_special_number_t { |
| | | SCPI_NUM_NUMBER, |
| | | SCPI_NUM_MIN, |
| | | SCPI_NUM_MAX, |
| | | SCPI_NUM_DEF, |
| | | SCPI_NUM_UP, |
| | | SCPI_NUM_DOWN, |
| | | SCPI_NUM_NAN, |
| | | SCPI_NUM_INF, |
| | | SCPI_NUM_NINF, |
| | | }; |
| | | typedef enum _scpi_special_number_t scpi_special_number_t; |
| | | |
| | | struct _scpi_special_number_def_t { |
| | | const char * name; |
| | | scpi_special_number_t type; |
| | | }; |
| | | #define SCPI_SPECIAL_NUMBERS_LIST_END {NULL, SCPI_NUM_NUMBER} |
| | | typedef struct _scpi_special_number_def_t scpi_special_number_def_t; |
| | | |
| | | struct _scpi_number_t { |
| | | double value; |
| | | scpi_unit_t unit; |
| | | scpi_special_number_t type; |
| | | }; |
| | | typedef struct _scpi_number_t scpi_number_t; |
| | | |
| | | struct _scpi_command_t { |
| | | const char * pattern; |
| | | scpi_command_callback_t callback; |
| | | }; |
| | | |
| | | struct _scpi_buffer_t { |
| | | size_t length; |
| | | size_t position; |
| | | char * data; |
| | | }; |
| | | |
| | | struct _scpi_interface_t { |
| | |
| | | void * user_context; |
| | | }; |
| | | |
| | | enum _scpi_unit_t { |
| | | SCPI_UNIT_NONE, |
| | | SCPI_UNIT_VOLT, |
| | | SCPI_UNIT_AMPER, |
| | | SCPI_UNIT_OHM, |
| | | SCPI_UNIT_HERTZ, |
| | | SCPI_UNIT_CELSIUS, |
| | | SCPI_UNIT_SECONDS, |
| | | }; |
| | | |
| | | |
| | | #define SCPI_UNITS_LIST_END {.name = NULL, .unit = SCPI_UNIT_NONE, .mult = 0} |
| | | |
| | | struct _scpi_unit_def_t { |
| | | const char * name; |
| | | scpi_unit_t unit; |
| | | double mult; |
| | | }; |
| | | |
| | | enum _scpi_special_number_t { |
| | | SCPI_NUM_NUMBER, |
| | | SCPI_NUM_MIN, |
| | | SCPI_NUM_MAX, |
| | | SCPI_NUM_DEF, |
| | | SCPI_NUM_UP, |
| | | SCPI_NUM_DOWN, |
| | | SCPI_NUM_NAN, |
| | | SCPI_NUM_INF, |
| | | SCPI_NUM_NINF, |
| | | }; |
| | | |
| | | #define SCPI_SPECIAL_NUMBERS_LIST_END {.name = NULL, .type = SCPI_NUM_NUMBER} |
| | | |
| | | struct _scpi_special_number_def_t { |
| | | const char * name; |
| | | scpi_special_number_t type; |
| | | }; |
| | | |
| | | struct _scpi_number_t { |
| | | double value; |
| | | scpi_unit_t unit; |
| | | scpi_special_number_t type; |
| | | }; |
| | | |
| | | enum _scpi_result_t { |
| | | SCPI_RES_OK = 1, |
| | | SCPI_RES_ERR = -1, |
| | | }; |
| | | |
| | | |
| | | enum _scpi_reg_name_t { |
| | | SCPI_REG_STB = 0, // Status Byte |
| | | SCPI_REG_SRE, // Service Request Enable Register |
| | | SCPI_REG_ESR, // Standard Event Status Register (ESR, SESR) |
| | | SCPI_REG_ESE, // Event Status Enable Register |
| | | SCPI_REG_OPER, // OPERation Status Register |
| | | SCPI_REG_OPERE, // OPERation Status Enable Register |
| | | SCPI_REG_QUES, // QUEStionable status register |
| | | SCPI_REG_QUESE, // QUEStionable status Enable Register |
| | | |
| | | /* last definition - number of registers */ |
| | | SCPI_REG_COUNT, |
| | | }; |
| | | |
| | | enum _scpi_ctrl_name_t { |
| | | SCPI_CTRL_SRQ = 1, // service request |
| | | SCPI_CTRL_GTL, // Go to local |
| | | SCPI_CTRL_SDC, // Selected device clear |
| | | SCPI_CTRL_PPC, // Parallel poll configure |
| | | SCPI_CTRL_GET, // Group execute trigger |
| | | SCPI_CTRL_TCT, // Take control |
| | | SCPI_CTRL_LLO, // Device clear |
| | | SCPI_CTRL_DCL, // Local lockout |
| | | SCPI_CTRL_PPU, // Parallel poll unconfigure |
| | | SCPI_CTRL_SPE, // Serial poll enable |
| | | SCPI_CTRL_SPD, // Serial poll disable |
| | | SCPI_CTRL_MLA, // My local address |
| | | SCPI_CTRL_UNL, // Unlisten |
| | | SCPI_CTRL_MTA, // My talk address |
| | | SCPI_CTRL_UNT, // Untalk |
| | | SCPI_CTRL_MSA, // My secondary address |
| | | }; |
| | | |
| | | #ifdef __cplusplus |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* SCPI_TYPES_H */ |
| | | #endif /* SCPI_TYPES_H */ |
| | | |
| | |
| | | */ |
| | | |
| | | #include <stdio.h> |
| | | #include <inttypes.h> |
| | | #include "scpi/debug.h" |
| | | |
| | | /** |
| | |
| | | printf("**DEBUG: %s (\"", context->paramlist.cmd->pattern); |
| | | res = fwrite(context->paramlist.parameters, 1, context->paramlist.length, stdout); |
| | | (void)res; |
| | | printf("\" - %" PRIu32 "\r\n", (uint32_t)context->paramlist.length); |
| | | printf("\" - %lu\r\n", (unsigned long)context->paramlist.length); |
| | | |
| | | return TRUE; |
| | | } |
| | |
| | | #define ERROR_DEFS_N 8 |
| | | |
| | | static const struct error_reg errs[ERROR_DEFS_N] = { |
| | | {.from = -100, .to = -199, .bit=ESR_CER}, // Command error (e.g. syntax error) ch 21.8.9 |
| | | {.from = -200, .to = -299, .bit=ESR_EER}, // Execution Error (e.g. range error) ch 21.8.10 |
| | | {.from = -300, .to = -399, .bit=ESR_DER}, // Device specific error -300, -399 ch 21.8.11 |
| | | {.from = -400, .to = -499, .bit=ESR_QER}, // Query error -400, -499 ch 21.8.12 |
| | | {.from = -500, .to = -599, .bit=ESR_PON}, // Power on event -500, -599 ch 21.8.13 |
| | | {.from = -600, .to = -699, .bit=ESR_URQ}, // User Request Event -600, -699 ch 21.8.14 |
| | | {.from = -700, .to = -799, .bit=ESR_REQ}, // Request Control Event -700, -799 ch 21.8.15 |
| | | {.from = -800, .to = -899, .bit=ESR_OPC}, // Operation Complete Event -800, -899 ch 21.8.16 |
| | | {-100, -199, ESR_CER}, // Command error (e.g. syntax error) ch 21.8.9 |
| | | {-200, -299, ESR_EER}, // Execution Error (e.g. range error) ch 21.8.10 |
| | | {-300, -399, ESR_DER}, // Device specific error -300, -399 ch 21.8.11 |
| | | {-400, -499, ESR_QER}, // Query error -400, -499 ch 21.8.12 |
| | | {-500, -599, ESR_PON}, // Power on event -500, -599 ch 21.8.13 |
| | | {-600, -699, ESR_URQ}, // User Request Event -600, -699 ch 21.8.14 |
| | | {-700, -799, ESR_REQ}, // Request Control Event -700, -799 ch 21.8.15 |
| | | {-800, -899, ESR_OPC}, // Operation Complete Event -800, -899 ch 21.8.16 |
| | | }; |
| | | |
| | | /** |
| | |
| | | * @param ctrl number of controll message |
| | | * @param value value of related register |
| | | */ |
| | | static size_t writeControl(scpi_t * context, int ctrl, scpi_reg_val_t val) { |
| | | static size_t writeControl(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) { |
| | | if (context && context->interface && context->interface->control) { |
| | | return context->interface->control(context, ctrl, val); |
| | | } else { |
| | |
| | | */ |
| | | const scpi_unit_def_t scpi_units_def[] = { |
| | | /* voltage */ |
| | | { .name = "UV", .unit = SCPI_UNIT_VOLT, .mult = 1e-6}, |
| | | { .name = "MV", .unit = SCPI_UNIT_VOLT, .mult = 1e-3}, |
| | | { .name = "V", .unit = SCPI_UNIT_VOLT, .mult = 1}, |
| | | { .name = "KV", .unit = SCPI_UNIT_VOLT, .mult = 1e3}, |
| | | {/* name */ "UV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-6}, |
| | | {/* name */ "MV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-3}, |
| | | {/* name */ "V", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1}, |
| | | {/* name */ "KV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e3}, |
| | | |
| | | /* current */ |
| | | { .name = "UA", .unit = SCPI_UNIT_AMPER, .mult = 1e-6}, |
| | | { .name = "MA", .unit = SCPI_UNIT_AMPER, .mult = 1e-3}, |
| | | { .name = "A", .unit = SCPI_UNIT_AMPER, .mult = 1}, |
| | | { .name = "KA", .unit = SCPI_UNIT_AMPER, .mult = 1e3}, |
| | | {/* name */ "UA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-6}, |
| | | {/* name */ "MA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-3}, |
| | | {/* name */ "A", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1}, |
| | | {/* name */ "KA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e3}, |
| | | |
| | | /* resistance */ |
| | | { .name = "OHM", .unit = SCPI_UNIT_OHM, .mult = 1}, |
| | | { .name = "KOHM", .unit = SCPI_UNIT_OHM, .mult = 1e3}, |
| | | { .name = "MOHM", .unit = SCPI_UNIT_OHM, .mult = 1e6}, |
| | | {/* name */ "OHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1}, |
| | | {/* name */ "KOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e3}, |
| | | {/* name */ "MOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e6}, |
| | | |
| | | /* frequency */ |
| | | { .name = "HZ", .unit = SCPI_UNIT_HERTZ, .mult = 1}, |
| | | { .name = "KHZ", .unit = SCPI_UNIT_HERTZ, .mult = 1e3}, |
| | | { .name = "MHZ", .unit = SCPI_UNIT_HERTZ, .mult = 1e6}, |
| | | { .name = "GHZ", .unit = SCPI_UNIT_HERTZ, .mult = 1e9}, |
| | | {/* name */ "HZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1}, |
| | | {/* name */ "KHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e3}, |
| | | {/* name */ "MHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e6}, |
| | | {/* name */ "GHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e9}, |
| | | |
| | | /* temperature */ |
| | | { .name = "CEL", .unit = SCPI_UNIT_CELSIUS, .mult = 1}, |
| | | {/* name */ "CEL", /* unit */ SCPI_UNIT_CELSIUS, /* mult */ 1}, |
| | | |
| | | /* time */ |
| | | { .name = "PS", .unit = SCPI_UNIT_SECONDS, .mult = 1e-12}, |
| | | { .name = "NS", .unit = SCPI_UNIT_SECONDS, .mult = 1e-9}, |
| | | { .name = "US", .unit = SCPI_UNIT_SECONDS, .mult = 1e-6}, |
| | | { .name = "MS", .unit = SCPI_UNIT_SECONDS, .mult = 1e-3}, |
| | | { .name = "S", .unit = SCPI_UNIT_SECONDS, .mult = 1}, |
| | | { .name = "MIN", .unit = SCPI_UNIT_SECONDS, .mult = 60}, |
| | | { .name = "HR", .unit = SCPI_UNIT_SECONDS, .mult = 3600}, |
| | | {/* name */ "PS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-12}, |
| | | {/* name */ "NS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-9}, |
| | | {/* name */ "US", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-6}, |
| | | {/* name */ "MS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-3}, |
| | | {/* name */ "S", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1}, |
| | | {/* name */ "MIN", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 60}, |
| | | {/* name */ "HR", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 3600}, |
| | | |
| | | SCPI_UNITS_LIST_END, |
| | | }; |
| | |
| | | * Special number values definition |
| | | */ |
| | | const scpi_special_number_def_t scpi_special_numbers_def[] = { |
| | | { .name = "MINimum", .type = SCPI_NUM_MIN}, |
| | | { .name = "MAXimum", .type = SCPI_NUM_MAX}, |
| | | { .name = "DEFault", .type = SCPI_NUM_DEF}, |
| | | { .name = "UP", .type = SCPI_NUM_UP}, |
| | | { .name = "DOWN", .type = SCPI_NUM_DOWN}, |
| | | { .name = "NAN", .type = SCPI_NUM_NAN}, |
| | | { .name = "INF", .type = SCPI_NUM_INF}, |
| | | { .name = "NINF", .type = SCPI_NUM_NINF}, |
| | | {/* name */ "MINimum", /* type */ SCPI_NUM_MIN}, |
| | | {/* name */ "MAXimum", /* type */ SCPI_NUM_MAX}, |
| | | {/* name */ "DEFault", /* type */ SCPI_NUM_DEF}, |
| | | {/* name */ "UP", /* type */ SCPI_NUM_UP}, |
| | | {/* name */ "DOWN", /* type */ SCPI_NUM_DOWN}, |
| | | {/* name */ "NAN", /* type */ SCPI_NUM_NAN}, |
| | | {/* name */ "INF", /* type */ SCPI_NUM_INF}, |
| | | {/* name */ "NINF", /* type */ SCPI_NUM_NINF}, |
| | | SCPI_SPECIAL_NUMBERS_LIST_END, |
| | | }; |
| | | |
| | |
| | | return FALSE; |
| | | } |
| | | |
| | | enum locate_text_states { |
| | | enum _locate_text_states { |
| | | STATE_FIRST_WHITESPACE, |
| | | STATE_TEXT_QUOTED, |
| | | STATE_TEXT, |
| | |
| | | STATE_COMMA, |
| | | STATE_ERROR, |
| | | }; |
| | | typedef enum _locate_text_states locate_text_states; |
| | | |
| | | struct locate_text_nfa { |
| | | enum locate_text_states state; |
| | | struct _locate_text_nfa { |
| | | locate_text_states state; |
| | | int32_t startIdx; |
| | | int32_t stopIdx; |
| | | size_t i; |
| | | }; |
| | | typedef struct _locate_text_nfa locate_text_nfa; |
| | | |
| | | /** |
| | | * Test locate text state, if it is correct final state |
| | | */ |
| | | static inline bool_t isFinalState(enum locate_text_states state) { |
| | | static inline bool_t isFinalState(locate_text_states state) { |
| | | return ( |
| | | ((state) == STATE_COMMA) |
| | | || ((state) == STATE_LAST_WHITESPACE) |
| | |
| | | * @param nfa stores automaton state |
| | | * @param c current char processed |
| | | */ |
| | | static inline bool_t locateTextAutomaton(struct locate_text_nfa * nfa, unsigned char c) { |
| | | static inline bool_t locateTextAutomaton(locate_text_nfa * nfa, unsigned char c) { |
| | | switch(nfa->state) { |
| | | /* first state locating only white spaces */ |
| | | case STATE_FIRST_WHITESPACE: |
| | |
| | | * @return string str1 contains text and str2 was set |
| | | */ |
| | | bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) { |
| | | struct locate_text_nfa nfa = { |
| | | .startIdx = 0, |
| | | .stopIdx = 0, |
| | | .state = STATE_FIRST_WHITESPACE, |
| | | }; |
| | | locate_text_nfa nfa; |
| | | nfa.state = STATE_FIRST_WHITESPACE; |
| | | nfa.startIdx = 0; |
| | | nfa.stopIdx = 0; |
| | | |
| | | for (nfa.i = 0; nfa.i < len1; nfa.i++) { |
| | | if(FALSE == locateTextAutomaton(&nfa, str1[nfa.i])) { |
| | |
| | | * @param nfa stores automaton state |
| | | * @param c current char processed |
| | | */ |
| | | static inline bool_t locateStrAutomaton(struct locate_text_nfa * nfa, unsigned char c) { |
| | | static inline bool_t locateStrAutomaton(locate_text_nfa * nfa, unsigned char c) { |
| | | switch(nfa->state) { |
| | | /* first state locating only white spaces */ |
| | | case STATE_FIRST_WHITESPACE: |
| | |
| | | * @return string str1 contains text and str2 was set |
| | | */ |
| | | bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) { |
| | | struct locate_text_nfa nfa = { |
| | | .startIdx = 0, |
| | | .stopIdx = 0, |
| | | .state = STATE_FIRST_WHITESPACE, |
| | | }; |
| | | locate_text_nfa nfa; |
| | | nfa.state = STATE_FIRST_WHITESPACE; |
| | | nfa.startIdx = 0; |
| | | nfa.stopIdx = 0; |
| | | |
| | | |
| | | for (nfa.i = 0; nfa.i < len1; nfa.i++) { |
| | | if(FALSE == locateStrAutomaton(&nfa, str1[nfa.i])) { |