diff --git a/Makefile b/Makefile index 456c007..fcdac19 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ all: main.c scpi_parser.c scpi_parser.h - gcc main.c scpi_parser.c scpi_errors.c -o main.elf + gcc main.c scpi_parser.c scpi_errors.c scpi_regs.c -o main.elf run: all ./main.elf diff --git a/main.c b/main.c index 0dfe5c9..cc92ebc 100644 --- a/main.c +++ b/main.c @@ -2,13 +2,6 @@ #include #include #include "scpi_parser.h" -#include "scpi_errors.h" - - -void cmd_aIDNq_cb(const SCPI_argval_t *args) -{ - printf("cb *IDN?\n"); -} void cmd_APPL_SIN_cb(const SCPI_argval_t *args) @@ -61,11 +54,6 @@ void cmd_STQE_cb(const SCPI_argval_t *args) } const SCPI_command_t scpi_commands[] = { - { - .levels = {"*IDN?"}, - .params = {}, - .callback = cmd_aIDNq_cb - }, { .levels = {"APPLy", "SINe"}, .params = {SCPI_DT_INT, SCPI_DT_FLOAT, SCPI_DT_FLOAT}, @@ -111,28 +99,51 @@ const SCPI_command_t scpi_commands[] = { +void scpi_send_byte_impl(uint8_t b) +{ + putchar(b); +} + + +const char *scpi_device_identifier(void) +{ + return "FEL CVUT,DDS1,0,0.1"; +} + + + int main() { char buf[256]; +// SCPI_REG_QUEST.CURR = 1; +// SCPI_REG_QUEST_EN.u16 = 0xFFFF; + +// printf("0x%x\n", SCPI_REG_QUEST.u16); + +// scpi_status_update(); + + +// return 0; + // const char *inp = "*IDN?\n"; // const char *inp = "FREQ 50\n"; - const char *inp = "DISP:TEXT 'ban\\\\ana', OFF\nDISP:TEXT \"dblquot!\", 1\r\nFREQ 50\r\n"; +// const char *inp = "DISP:TEXT 'ban\\\\ana', OFF\nDISP:TEXT \"dblquot!\", 1\r\nFREQ 50\r\n"; //const char *inp = "FOO\nDATA:BLOB 13.456, #216AbcdEfghIjklMnop\nFREQ 50\r\nAPPLY:MOO\n"; //const char *inp = "STAT:QUE:ENAB?;ENAB \t 1;ENAB?;:*IDN?\n"; - //const char *inp = "*idn?;foo;apply:sin 5,6,\n"; + const char *inp = "*idn?\n"; for (int i = 0; i < strlen(inp); i++) { scpi_handle_byte(inp[i]); } - scpi_error_string(buf, E_EXE_DATA_QUESTIONABLE, "The data smells fishy"); + //scpi_error_string(buf, E_EXE_DATA_QUESTIONABLE, "The data smells fishy"); - scpi_read_error(buf), printf("%s\n", buf); + //scpi_read_error(buf), printf("%s\n", buf); // scpi_add_error(E_CMD_BLOCK_DATA_ERROR, NULL); diff --git a/scpi.pro b/scpi.pro index 517b15a..9d56d88 100644 --- a/scpi.pro +++ b/scpi.pro @@ -7,7 +7,7 @@ SOURCES += \ scpi_parser.c \ main.c \ scpi_errors.c \ - scpi_status.c + scpi_regs.c DISTFILES += \ style.astylerc \ @@ -19,4 +19,4 @@ DISTFILES += \ HEADERS += \ scpi_parser.h \ scpi_errors.h \ - scpi_status.h + scpi_regs.h diff --git a/scpi.pro.user b/scpi.pro.user index 62d90a4..38c04e3 100644 --- a/scpi.pro.user +++ b/scpi.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/scpi_parser.c b/scpi_parser.c index 8c1bdc2..56d2674 100644 --- a/scpi_parser.c +++ b/scpi_parser.c @@ -84,6 +84,8 @@ static struct { // buffer for error messages static char ebuf[256]; +// response buffer +static char sbuf[256]; // ---------------- PRIVATE PROTOTYPES ------------------ @@ -121,23 +123,188 @@ static void pars_reset_cmd_keeplevel(void); // ---------------- BUILTIN SCPI COMMANDS ------------------ -static void builtin_cb_FOO(const SCPI_argval_t *args) +static void builtin_CLS(const SCPI_argval_t *args) { - printf("Builtin FOO\n"); + // clear the registers + SCPI_REG_SESR.u8 = 0; + SCPI_REG_OPER.u16 = 0; + SCPI_REG_QUES.u16 = 0; + scpi_clear_errors(); + + if (scpi_user_CLS) { + scpi_user_CLS(); + } + + scpi_status_update(); // flags +} + + +static void builtin_RST(const SCPI_argval_t *args) +{ + if (scpi_user_RST) { + scpi_user_RST(); + } +} + + +static void builtin_TSTq(const SCPI_argval_t *args) +{ + if (scpi_user_TSTq) { + scpi_user_TSTq(); + } +} + + +static void builtin_IDNq(const SCPI_argval_t *args) +{ + scpi_send_string(scpi_device_identifier()); +} + + +static void builtin_ESE(const SCPI_argval_t *args) +{ + SCPI_REG_SESR_EN.u8 = (uint8_t) args[0].INT; +} + + +static void builtin_ESEq(const SCPI_argval_t *args) +{ + sprintf(sbuf, "%d", SCPI_REG_SESR_EN.u8); + scpi_send_string(ebuf); +} + + +static void builtin_ESRq(const SCPI_argval_t *args) +{ + sprintf(sbuf, "%d", SCPI_REG_SESR.u8); + scpi_send_string(ebuf); +} + + +static void builtin_OPC(const SCPI_argval_t *args) +{ + // implementation for instruments with no overlapping commands. + // Can be overridden in the user commands. + SCPI_REG_SESR.OPC = 1; +} + + +static void builtin_OPCq(const SCPI_argval_t *args) +{ + // implementation for instruments with no overlapping commands. + // Can be overridden in the user commands. + // (would be): sprintf(sbuf, "%d", SCPI_REG_SESR.OPC); + + scpi_send_string("1"); +} + + +static void builtin_SRE(const SCPI_argval_t *args) +{ + SCPI_REG_SRE.u8 = (uint8_t) args[0].INT; +} + + +static void builtin_SREq(const SCPI_argval_t *args) +{ + sprintf(sbuf, "%d", SCPI_REG_SRE.u8); + scpi_send_string(ebuf); +} + + +static void builtin_STBq(const SCPI_argval_t *args) +{ + sprintf(sbuf, "%d", SCPI_REG_STB.u8); + scpi_send_string(ebuf); +} + + +static void builtin_WAI(const SCPI_argval_t *args) +{ + // no-op } static const SCPI_command_t scpi_commands_builtin[] = { + // ---- COMMON COMMANDS ---- + { + .levels = {"*CLS"}, + .callback = builtin_CLS + }, + { + .levels = {"*ESE"}, + .params = {SCPI_DT_INT}, + .callback = builtin_ESE + }, + { + .levels = {"*ESE?"}, + .callback = builtin_ESEq + }, + { + .levels = {"*ESR?"}, + .callback = builtin_ESRq + }, + { + .levels = {"*IDN?"}, + .callback = builtin_IDNq + }, + { + .levels = {"*OPC"}, + .callback = builtin_OPC + }, + { + .levels = {"*OPCq"}, + .callback = builtin_OPCq + }, + { + .levels = {"*RST"}, + .callback = builtin_RST + }, { - .levels = {"FOO"}, - .params = {}, - .callback = builtin_cb_FOO + .levels = {"*SRE"}, + .params = {SCPI_DT_INT}, + .callback = builtin_SRE }, + { + .levels = {"*SRE?"}, + .callback = builtin_SREq + }, + { + .levels = {"*STB?"}, + .callback = builtin_STBq + }, + { + .levels = {"*WAI"}, + .callback = builtin_WAI + }, + { + .levels = {"*TST?"}, + .callback = builtin_TSTq + }, + // ---- REQUIRED SYST COMMANDS ---- + + {0} // end marker }; +// ------------------- MESSAGE SEND ------------------ + +/** Send a message to master. Trailing newline is added. */ +void scpi_send_string(const char *message) +{ + char c; + while ((c = *message++) != 0) { + scpi_send_byte_impl(c); + } + + scpi_send_byte_impl('\r'); + scpi_send_byte_impl('\n'); +} + + + // ------------------- ERROR QUEUE --------------------- void scpi_add_error(SCPI_error_t errno, const char *extra) @@ -163,6 +330,8 @@ void scpi_add_error(SCPI_error_t errno, const char *extra) if (pst.err_queue_w >= ERR_QUEUE_LEN) { pst.err_queue_w = 0; } + + scpi_status_update(); } @@ -179,6 +348,18 @@ void scpi_read_error(char *buf) if (pst.err_queue_r >= ERR_QUEUE_LEN) { pst.err_queue_r = 0; } + + scpi_status_update(); +} + + +void scpi_clear_errors(void) +{ + pst.err_queue_r = 0; + pst.err_queue_w = 0; + pst.err_queue_used = 0; + + scpi_status_update(); } @@ -187,6 +368,7 @@ uint8_t scpi_error_count(void) return pst.err_queue_used; } + static void err_no_such_command() { char *b = ebuf; diff --git a/scpi_parser.h b/scpi_parser.h index f55cd45..f2012f2 100644 --- a/scpi_parser.h +++ b/scpi_parser.h @@ -1,9 +1,10 @@ #pragma once -#include "scpi_errors.h" - #include #include +#include "scpi_errors.h" +#include "scpi_regs.h" + #define SCPI_MAX_CMD_LEN 12 #define SCPI_MAX_STRING_LEN 12 #define SCPI_MAX_LEVEL_COUNT 4 @@ -55,10 +56,27 @@ typedef struct { void (*blob_callback)(const uint8_t *bytes); } SCPI_command_t; +// ---------------- USER CONFIG ---------------- // Zero terminated command struct array - must be defined. extern const SCPI_command_t scpi_commands[]; +/** Send a byte to master (may be buffered) */ +extern void scpi_send_byte_impl(uint8_t b); + +/** *CLS command callback - clear non-SCPI device state */ +extern __attribute__((weak)) void scpi_user_CLS(void); + +/** *RST command callback - reset non-SCPI device state */ +extern __attribute__((weak)) void scpi_user_RST(void); + +/** *TST? command callback - perform self test and send response back. */ +extern __attribute__((weak)) void scpi_user_TSTq(void); + +/** Get device identifier. Implemented as a callback to allow dynamic serial number */ +extern const char *scpi_device_identifier(void); + + // --------------- functions -------------------- @@ -84,3 +102,10 @@ void scpi_read_error(char *buf); /** Discard the rest of the currently processed blob */ void scpi_discard_blob(void); + +/** Send a string to master. \r\n is added. */ +void scpi_send_string(const char *message); + +/** Clear the error queue */ +void scpi_clear_errors(void); + diff --git a/scpi_regs.c b/scpi_regs.c new file mode 100644 index 0000000..9322fb3 --- /dev/null +++ b/scpi_regs.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +#include "scpi_regs.h" +#include "scpi_errors.h" +#include "scpi_parser.h" + +SCPI_REG_QUES_t SCPI_REG_QUES; +SCPI_REG_QUES_t SCPI_REG_QUES_EN = {.u16 = 0xFFFF}; + +SCPI_REG_OPER_t SCPI_REG_OPER; +SCPI_REG_OPER_t SCPI_REG_OPER_EN = {.u16 = 0xFFFF}; + +SCPI_REG_SESR_t SCPI_REG_SESR; +SCPI_REG_SESR_t SCPI_REG_SESR_EN; + +SCPI_REG_STB_t SCPI_REG_STB; +SCPI_REG_STB_t SCPI_REG_SRE; + +/** Update status registers (propagate using enable registers) */ +void scpi_status_update(void) +{ + // propagate to STB + SCPI_REG_STB.ERRQ = scpi_error_count() > 0; + SCPI_REG_STB.QUES = SCPI_REG_QUES.u16 & SCPI_REG_QUES_EN.u16; + SCPI_REG_STB.OPER = SCPI_REG_OPER.u16 & SCPI_REG_OPER_EN.u16; + SCPI_REG_STB.SESR = SCPI_REG_SESR.u8 & SCPI_REG_SESR_EN.u8; + SCPI_REG_STB.MAV = false; // TODO!!! + + // Request Service + SCPI_REG_STB.RQS = SCPI_REG_STB.u8 & SCPI_REG_SRE.u8; + + + // Run service request callback + if (SCPI_REG_STB.RQS) { + if (scpi_service_request_impl) { + scpi_service_request_impl(); + } + } +} diff --git a/scpi_regs.h b/scpi_regs.h new file mode 100644 index 0000000..7fff32e --- /dev/null +++ b/scpi_regs.h @@ -0,0 +1,104 @@ +#pragma once +#include +#include + +typedef union { + struct __attribute__((packed)) { + bool VOLT: 1; + bool CURR: 1; + bool TIME: 1; + bool POWER: 1; + bool TEMP: 1; + bool FREQ: 1; + bool PHASE: 1; + bool MODUL: 1; + bool CALIB: 1; + bool BIT_9: 1; // user defined + bool BIT_10: 1; + bool BIT_11: 1; + bool BIT_12: 1; + bool INSTR_SUM: 1; // instrument summary + bool COMMAND_WARNING: 1; // command warning + bool RESERVED: 1; + }; + + uint16_t u16; +} SCPI_REG_QUES_t; + + +typedef union { + struct __attribute__((packed)) { + bool CALIB: 1; + bool SETTING: 1; + bool RANGING: 1; + bool SWEEP: 1; + bool MEAS: 1; + bool WAIT_TRIG: 1; // waiting for trigger + bool WAIT_ARM: 1; // waiting for ARM + bool CORRECTING: 1; + bool BIT_8: 1; // user defined + bool BIT_9: 1; + bool BIT_10: 1; + bool BIT_11: 1; + bool BIT_12: 1; + bool INSTR_SUM: 1; // instrument summary + bool PROG_RUN: 1; // program running + bool RESERVED: 1; + }; + + uint16_t u16; +} SCPI_REG_OPER_t; + + +typedef union { + struct __attribute__((packed)) { + bool OPC: 1; + bool REQ_CONTROL: 1; + bool QUERY_ERROR: 1; + bool DEV_ERROR: 1; + bool EXE_ERROR: 1; + bool CMD_ERROR: 1; + bool USER_REQUEST: 1; + bool POWER_ON: 1; + }; + + uint8_t u8; +} SCPI_REG_SESR_t; + + +typedef union { + struct __attribute__((packed)) { + bool BIT_0: 1; + bool BIT_1: 1; + bool ERRQ: 1; // error queue + bool QUES: 1; + bool MAV: 1; // message available + bool SESR: 1; + bool RQS: 1; // request service + bool OPER: 1; + }; + + uint8_t u8; +} SCPI_REG_STB_t; + + +// QUESTionable register +extern SCPI_REG_QUES_t SCPI_REG_QUES; +extern SCPI_REG_QUES_t SCPI_REG_QUES_EN; // picks what to use for the STB bit + +// OPERation status register +extern SCPI_REG_OPER_t SCPI_REG_OPER; +extern SCPI_REG_OPER_t SCPI_REG_OPER_EN; // picks what to use for the STB bit + +// Standard Event Status register +extern SCPI_REG_SESR_t SCPI_REG_SESR; +extern SCPI_REG_SESR_t SCPI_REG_SESR_EN; // ESE + +// Status byte +extern SCPI_REG_STB_t SCPI_REG_STB; +extern SCPI_REG_STB_t SCPI_REG_SRE; // SRE + + +void scpi_status_update(void); + +extern __attribute__((weak)) void scpi_service_request_impl(void); diff --git a/scpi_status.c b/scpi_status.c deleted file mode 100644 index 2dbec5b..0000000 --- a/scpi_status.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -#include "scpi_status.h" - -struct SCPI_SR_QUEST_struct SCPI_SR_QUEST; -struct SCPI_SR_OPER_struct SCPI_SR_OPER; -struct SCPI_SR_SESR_struct SCPI_SR_SESR; diff --git a/scpi_status.h b/scpi_status.h deleted file mode 100644 index 74153fc..0000000 --- a/scpi_status.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once -#include -#include - -struct __attribute__((packed)) SCPI_SR_QUEST_struct { - bool VOLT: 1; - bool CURR: 1; - bool TIME: 1; - bool POWER: 1; - bool TEMP: 1; - bool FREQ: 1; - bool PHASE: 1; - bool MODUL: 1; - bool CALIB: 1; - bool BIT_9: 1; // user defined - bool BIT_10: 1; - bool BIT_11: 1; - bool BIT_12: 1; - bool INSTR_SUM: 1; // instrument summary - bool COMMAND_WARNING: 1; // command warning - bool RESERVED: 1; -}; - - -struct __attribute__((packed)) SCPI_SR_OPER_struct { - bool CALIB: 1; - bool SETTING: 1; - bool RANGING: 1; - bool SWEEP: 1; - bool MEAS: 1; - bool WAIT_TRIG: 1; // waiting for trigger - bool WAIT_ARM: 1; // waiting for ARM - bool CORRECTING: 1; - bool BIT_8: 1; // user defined - bool BIT_9: 1; - bool BIT_10: 1; - bool BIT_11: 1; - bool BIT_12: 1; - bool INSTR_SUM: 1; // instrument summary - bool PROG_RUN: 1; // program running - bool RESERVED: 1; -}; - - -struct __attribute__((packed)) SCPI_SR_SESR_struct { - bool OP_COMPLETE: 1; - bool REQ_CONTROL: 1; - bool QUERY_ERROR: 1; - bool DEV_ERROR: 1; - bool EXE_ERROR: 1; - bool CMD_ERROR: 1; - bool USER_REQUEST: 1; - bool POWER_ON: 1; -}; - - -struct __attribute__((packed)) SCPI_SR_STB_struct { - bool BIT_0: 1; - bool BIT_1: 1; - bool ERROR_QUEUE: 1; - bool QUEST: 1; - bool MSG_AVAIL: 1; - bool SESR: 1; - bool RQS: 1; // request service - bool OPER: 1; -}; - - -// QUESTionable register -extern struct SCPI_SR_QUEST_struct SCPI_SR_QUEST; -extern struct SCPI_SR_QUEST_struct SCPI_SR_QUEST_EN; // picks what to use for the STB bit - -// OPERation status register -extern struct SCPI_SR_OPER_struct SCPI_SR_OPER; -extern struct SCPI_SR_OPER_struct SCPI_SR_OPER_EN; // picks what to use for the STB bit - -// Standard Event Status register -extern struct SCPI_SR_SESR_struct SCPI_SR_SESR; -extern struct SCPI_SR_SESR_struct SCPI_SR_SESR_EN; // ESE - -// Status byte -extern struct SCPI_SR_STB_struct SCPI_SR_STB; -extern struct SCPI_SR_STB_struct SCPI_SR_STB_EN; // SRE