diff --git a/main.c b/main.c index f7480c1..6000ead 100644 --- a/main.c +++ b/main.c @@ -6,16 +6,23 @@ // ------- TESTING ---------- +static void send_cmd(const char *cmd) +{ + printf("\n> %s\n", cmd); + scpi_handle_string(cmd); +} + int main() { - scpi_handle_string("*IDN?\n"); - scpi_handle_string("*SRE 4\n"); - scpi_handle_string("FOO:BAR:BAZ\n"); - scpi_handle_string("SYST:ERR:COUNT?\n"); - scpi_handle_string("SYST:ERR?\n"); - scpi_handle_string("SYST:ERR?\n"); - scpi_handle_string("DATA:BLOB #216abcdefghijklmnop\n"); - scpi_handle_string("SYST:ERR?\n"); + send_cmd("*IDN?\n"); // builtin commands.. + send_cmd("*SRE 4\n"); // enable SRQ on error + send_cmd("FOO:BAR:BAZ\n"); // invalid command causes error + send_cmd("SYST:ERR:COUNT?\n"); // error subsystem + send_cmd("SYST:ERR:NEXT?;COUNT?;NEXT?\n"); // semicolon works according to spec + send_cmd("DATA:BLOB #216abcdefghijklmnop\n"); // binary data block + + send_cmd("APPLY:SINE 50, 1.0, 2.17\n"); // floats + send_cmd("DISP:TEXT \"Hello world\"\n"); // string } @@ -35,37 +42,43 @@ const char *scpi_device_identifier(void) void scpi_service_request_impl(void) { - printf("[SRQ]\n"); + // NOTE: Actual instrument should send SRQ event somehow + + printf("[SRQ] - error: "); + char buf[256]; + scpi_read_error_noremove(buf); // show error message (for debug) + printf("%s\n", buf); } -// ---- COMMANDS ---- +// ---- INSTRUMENT COMMANDS ---- void cmd_APPL_SIN_cb(const SCPI_argval_t *args) { - printf("cb APPLy:SINe %d, %f, %f\n", args[0].INT, args[0].FLOAT, args[0].FLOAT); + printf("cb APPLy:SINe %d, %f, %f\n", args[0].INT, args[1].FLOAT, args[2].FLOAT); } void cmd_DISP_TEXT_cb(const SCPI_argval_t *args) { - printf("cb DISPlay:TEXT %s\n", args[0].STRING); + printf("cb DISPlay:TEXT %s\n", args[0].STRING); } void cmd_DATA_BLOB_cb(const SCPI_argval_t *args) { - printf("cb DATA:BLOB <%d>\n", args[1].BLOB_LEN); + printf("cb DATA:BLOB <%d>\n", args[0].BLOB_LEN); } void cmd_DATA_BLOB_data(const uint8_t *bytes) { - printf("blob item: %s\n", bytes); + printf("binary data: \"%s\"\n", bytes); } +// Command definition (mandatory commands are built-in) const SCPI_command_t scpi_commands[] = { { .levels = {"APPLy", "SINe"}, diff --git a/source/scpi_errors.c b/source/scpi_errors.c index 54d1208..980e98e 100644 --- a/source/scpi_errors.c +++ b/source/scpi_errors.c @@ -5,12 +5,104 @@ #include #include "scpi_errors.h" +#include "scpi_regs.h" + +#define ERR_QUEUE_LEN 4 +#define MAX_ERROR_LEN 255 + +// --- queue impl --- + + +static struct { + char queue[ERR_QUEUE_LEN][MAX_ERROR_LEN + 1]; + int8_t r_pos; + int8_t w_pos; + int8_t count; // signed for backtracking +} erq; + + +void scpi_add_error(SCPI_error_t errno, const char *extra) +{ + bool added = true; + if (erq.count >= ERR_QUEUE_LEN) { + errno = E_DEV_QUEUE_OVERFLOW; + extra = NULL; + added = false; // replaced only + + // backtrack + erq.w_pos--; + erq.count--; + if (erq.w_pos < 0) { + erq.w_pos = ERR_QUEUE_LEN - 1; + } + } + + scpi_error_string(erq.queue[erq.w_pos], errno, extra); + + erq.w_pos++; + erq.count++; + if (erq.w_pos >= ERR_QUEUE_LEN) { + erq.w_pos = 0; + } + + scpi_status_update(); +} + + +void scpi_read_error_noremove(char *buf) +{ + if (erq.count == 0) { + scpi_error_string(buf, E_NO_ERROR, NULL); + return; + } + + strcpy(buf, erq.queue[erq.r_pos]); +} + + +void scpi_read_error(char *buf) +{ + if (erq.count == 0) { + scpi_error_string(buf, E_NO_ERROR, NULL); + return; + } + + strcpy(buf, erq.queue[erq.r_pos++]); + erq.count--; + + if (erq.r_pos >= ERR_QUEUE_LEN) { + erq.r_pos = 0; + } + + scpi_status_update(); +} + + +void scpi_clear_errors(void) +{ + erq.r_pos = 0; + erq.w_pos = 0; + erq.count = 0; + + scpi_status_update(); +} + + +uint8_t scpi_error_count(void) +{ + return erq.count; +} + + +// ---- table ---- + typedef struct { const int16_t errno; const char *msg; } SCPI_error_desc; + static const SCPI_error_desc error_table[] = { { 0, "No error"}, { -100, "Command error"}, @@ -184,3 +276,4 @@ void scpi_error_string(char *buffer, SCPI_error_t errno, const char *extra) sprintf(buffer, "\""); // " } + diff --git a/source/scpi_errors.h b/source/scpi_errors.h index 5b83078..2b30fa5 100644 --- a/source/scpi_errors.h +++ b/source/scpi_errors.h @@ -132,6 +132,7 @@ typedef enum { /** Get SCPI error message (alone) */ const char *scpi_error_message(SCPI_error_t errno); + /** * Get SCPI error string for reporting: * ,"[; ]" @@ -139,3 +140,24 @@ const char *scpi_error_message(SCPI_error_t errno); * extra can be NULL to skip the optional part. */ void scpi_error_string(char *buffer, SCPI_error_t errno, const char *extra); + + +/** Add error to the error queue */ +void scpi_add_error(SCPI_error_t errno, const char *extra); + + +/** Get number of errors in the error queue */ +uint8_t scpi_error_count(void); + + +/** + * Read and remove one entry from the error queue. + * Returns 0,"No error" if the queue is empty. + * + * The entry is copied to the provided buffer, which must be 256 chars long. + */ +void scpi_read_error(char *buf); + + +/** Read error, do not remove from queue */ +void scpi_read_error_noremove(char *buf); diff --git a/source/scpi_parser.c b/source/scpi_parser.c index 5b4acbe..df918b6 100644 --- a/source/scpi_parser.c +++ b/source/scpi_parser.c @@ -11,8 +11,6 @@ #include "scpi_regs.h" // Config -#define ERR_QUEUE_LEN 4 -#define MAX_ERROR_LEN 255 #define MAX_CHARBUF_LEN 255 @@ -52,11 +50,6 @@ typedef enum { /** Parser internal state struct */ static struct { - char err_queue[ERR_QUEUE_LEN][MAX_ERROR_LEN + 1]; - int8_t err_queue_r; - int8_t err_queue_w; - int8_t err_queue_used; // signed for backtracking - parser_state_t state; // current parser internal state // string buffer, chars collected here until recognized @@ -140,70 +133,7 @@ void scpi_send_string(const char *message) scpi_send_byte_impl('\n'); } - -// ------------------- ERROR QUEUE --------------------- - -void scpi_add_error(SCPI_error_t errno, const char *extra) -{ - bool added = true; - if (pst.err_queue_used >= ERR_QUEUE_LEN) { - errno = E_DEV_QUEUE_OVERFLOW; - extra = NULL; - added = false; // replaced only - - // backtrack - pst.err_queue_w--; - pst.err_queue_used--; - if (pst.err_queue_w < 0) { - pst.err_queue_w = ERR_QUEUE_LEN - 1; - } - } - - scpi_error_string(pst.err_queue[pst.err_queue_w], errno, extra); - - pst.err_queue_w++; - pst.err_queue_used++; - if (pst.err_queue_w >= ERR_QUEUE_LEN) { - pst.err_queue_w = 0; - } - - scpi_status_update(); -} - - -void scpi_read_error(char *buf) -{ - if (pst.err_queue_used == 0) { - scpi_error_string(buf, E_NO_ERROR, NULL); - return; - } - - strcpy(buf, pst.err_queue[pst.err_queue_r++]); - pst.err_queue_used--; - - 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(); -} - - -uint8_t scpi_error_count(void) -{ - return pst.err_queue_used; -} - +// ------- Error shortcuts ---------- static void err_no_such_command() { diff --git a/source/scpi_parser.h b/source/scpi_parser.h index 3d175e3..96bcd91 100644 --- a/source/scpi_parser.h +++ b/source/scpi_parser.h @@ -40,7 +40,7 @@ typedef union { */ typedef struct { // levels MUST BE FIRST! - const char levels[SCPI_MAX_LEVEL_COUNT][SCPI_MAX_CMD_LEN+2]; // up to 4 parts (+? and \0) + const char levels[SCPI_MAX_LEVEL_COUNT][SCPI_MAX_CMD_LEN + 2]; // up to 4 parts (+? and \0) // called when the command is completed. BLOB arg must be last in the argument list, // and only the first part is collected. @@ -84,20 +84,6 @@ void scpi_handle_byte(const uint8_t b); void scpi_handle_string(const char* str); -/** Add error to the error queue */ -void scpi_add_error(SCPI_error_t errno, const char *extra); - -/** Get number of errors in the error queue */ -uint8_t scpi_error_count(void); - -/** - * Read and remove one entry from the error queue. - * Returns 0,"No error" if the queue is empty. - * - * The entry is copied to the provided buffer, which must be 256 chars long. - */ -void scpi_read_error(char *buf); - /** Discard the rest of the currently processed blob */ void scpi_discard_blob(void);