Fine error reporting can now be disabled to save program space, added callback for new error, changed some callback names.

master
Ondřej Hruška 10 years ago
parent e4ff2e0243
commit f9d2b4cdc5
  1. 3
      Makefile
  2. 2
      example/Makefile
  3. 35
      example/example.c
  4. 12
      include/scpi_builtins.h
  5. 19
      include/scpi_errors.h
  6. 4
      include/scpi_parser.h
  7. 12
      include/scpi_regs.h
  8. 3
      scpi.pro
  9. 6
      source/scpi_builtins.c
  10. 213
      source/scpi_errors.c
  11. 4
      source/scpi_regs.c

@ -33,6 +33,9 @@ CFLAGS += -Wredundant-decls -Wfloat-equal -Wsign-compare
CFLAGS += -fno-common -ffunction-sections -fdata-sections -Wunused-function CFLAGS += -fno-common -ffunction-sections -fdata-sections -Wunused-function
CFLAGS += -I$(INCL_DIR) CFLAGS += -I$(INCL_DIR)
CFLAGS += -DSCPI_FINE_ERRORS
CFLAGS += -DSCPI_WEIRD_ERRORS
############################################################################### ###############################################################################
all: lib all: lib

@ -11,6 +11,8 @@ CFLAGS += -Wall -Wextra -Wshadow
CFLAGS += -Wwrite-strings -Wold-style-definition -Winline CFLAGS += -Wwrite-strings -Wold-style-definition -Winline
CFLAGS += -Wredundant-decls -Wfloat-equal -Wsign-compare -Wunused-function CFLAGS += -Wredundant-decls -Wfloat-equal -Wsign-compare -Wunused-function
CFLAGS += -DSCPI_FINE_ERRORS
CC = gcc CC = gcc
%.o: %.c %.o: %.c

@ -30,6 +30,8 @@ int main(void)
send_cmd("SYST:ERR:COUNT?\n"); send_cmd("SYST:ERR:COUNT?\n");
send_cmd("SYST:ERR:NEXT?\n"); send_cmd("SYST:ERR:NEXT?\n");
send_cmd("ERROR_FALLBACK\n"); // test fallback to closest related error
// test chardata // test chardata
send_cmd("CHARD FOOBAR123_MOO_abcdef_HELLO, 12\n"); send_cmd("CHARD FOOBAR123_MOO_abcdef_HELLO, 12\n");
@ -56,20 +58,25 @@ void scpi_send_byte_impl(uint8_t b)
} }
const char *scpi_device_identifier(void) const char *scpi_user_IDN(void)
{ {
return "FEL CVUT,DDS1,0,0.1"; return "MightyPork,Test SCPI device,0,0.1";
} }
void scpi_service_request_impl(void) /** Error callback */
void scpi_user_error(int16_t errno, const char * msg)
{
printf("### ERROR ADDED: %d, %s ###\n", errno, msg);
}
/** Service request impl */
void scpi_user_SRQ(void)
{ {
// NOTE: Actual instrument should send SRQ event somehow // NOTE: Actual instrument should send SRQ event somehow
printf("[SRQ] - error: "); printf("[Service Request]\n");
char buf[256];
scpi_read_error_noremove(buf); // show error message (for debug)
printf("%s\n", buf);
} }
@ -115,6 +122,16 @@ void cmd_CHARD_cb(const SCPI_argval_t *args)
} }
void cmd_ERROR_FALLBACK_cb(const SCPI_argval_t *args)
{
(void) args;
printf("Testing the error fallback feature...\n");
scpi_add_error(-427, NULL);
}
// Command definition (mandatory commands are built-in) // Command definition (mandatory commands are built-in)
const SCPI_command_t scpi_commands[] = { const SCPI_command_t scpi_commands[] = {
{ {
@ -138,6 +155,10 @@ const SCPI_command_t scpi_commands[] = {
.levels = {"USeRERRor"}, .levels = {"USeRERRor"},
.callback = cmd_USRERR_cb .callback = cmd_USRERR_cb
}, },
{
.levels = {"ERROR_FALLBACK"},
.callback = cmd_ERROR_FALLBACK_cb
},
{ {
.levels = {"CHARData"}, .levels = {"CHARData"},
.params = {SCPI_DT_CHARDATA, SCPI_DT_INT}, .params = {SCPI_DT_CHARDATA, SCPI_DT_INT},

@ -2,17 +2,17 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/** *CLS command callback - clear non-SCPI device state */ /** Optional *CLS command callback - clear non-SCPI device state */
extern __attribute__((weak)) void scpi_user_CLS(void); extern __attribute__((weak)) void scpi_user_CLS(void);
/** *RST command callback - reset non-SCPI device state */ /** Optional *RST command callback - reset non-SCPI device state */
extern __attribute__((weak)) void scpi_user_RST(void); extern __attribute__((weak)) void scpi_user_RST(void);
/** *TST? command callback - perform self test and send response back. */ /** Optional *TST? command callback - perform self test and send response back. */
extern __attribute__((weak)) void scpi_user_TSTq(void); extern __attribute__((weak)) void scpi_user_TST(void);
/** Get device *IDN? string. */ /** MANDATORY callback to get the device *IDN? string. */
extern const char *scpi_device_identifier(void); extern const char *scpi_user_IDN(void);
// Provides: // Provides:
// const SCPI_command_t scpi_commands_builtin[]; // const SCPI_command_t scpi_commands_builtin[];

@ -10,6 +10,12 @@ typedef struct {
/** User error definitions */ /** User error definitions */
extern const SCPI_error_desc scpi_user_errors[]; extern const SCPI_error_desc scpi_user_errors[];
/** Callback when error is added to the queue */
extern __attribute__((weak))
void scpi_user_error(int16_t errno, const char * msg);
// SCPI error constants // SCPI error constants
enum { enum {
E_NO_ERROR = 0, E_NO_ERROR = 0,
@ -137,17 +143,18 @@ enum {
}; };
/** Get SCPI error message (alone) */
const char *scpi_error_message(int16_t errno);
/** /**
* Get SCPI error string for reporting: * Get SCPI error string:
* <code>,"<message>[; <extra>]" * <code>,"<message>[; <extra>]"
* *
* extra can be NULL to skip the optional part. * @param buffer Buffer for storing the final string. Make sure it's big enough.
* @param errno Error number
* @param extra Extra information, appended after the generic message. Can be NULL.
*
* @returns actual error code. Code may be coerced to closest defined code (categories: tens, hundreds)
*/ */
void scpi_error_string(char *buffer, int16_t errno, const char *extra); int16_t scpi_error_string(char *buffer, int16_t errno, const char *extra);
/** Add error to the error queue */ /** Add error to the error queue */

@ -61,10 +61,10 @@ typedef struct {
// ---------------- USER CONFIG ---------------- // ---------------- USER CONFIG ----------------
// Zero terminated command struct array - must be defined. /** Zero terminated command struct array - must be defined. */
extern const SCPI_command_t scpi_commands[]; extern const SCPI_command_t scpi_commands[];
// provided by scpi_builtins.h /** Built-in SCPI commands, provided by scpi_builtins.h */
extern const SCPI_command_t scpi_commands_builtin[]; extern const SCPI_command_t scpi_commands_builtin[];
/** Send a byte to master (may be buffered) */ /** Send a byte to master (may be buffered) */

@ -99,6 +99,16 @@ extern SCPI_REG_STB_t SCPI_REG_STB;
extern SCPI_REG_STB_t SCPI_REG_SRE; // SRE extern SCPI_REG_STB_t SCPI_REG_SRE; // SRE
/** Update the status registers (perform propagation) */
void scpi_status_update(void); void scpi_status_update(void);
extern __attribute__((weak)) void scpi_service_request_impl(void);
/**
* Service Request callback.
* User may choose to implement it (eg. send request to master),
* or leave unimplemented.
*
* SRQ is issued when an event enabled in the status registers (namely SRE) occurs.
* See the SCPI spec for details.
*/
extern __attribute__((weak)) void scpi_user_SRQ(void);

@ -23,7 +23,8 @@ DISTFILES += \
.gitignore \ .gitignore \
LICENSE \ LICENSE \
README.md \ README.md \
Makefile Makefile \
example/Makefile
HEADERS += \ HEADERS += \
source/scpi_parser.h \ source/scpi_parser.h \

@ -46,8 +46,8 @@ static void builtin_TSTq(const SCPI_argval_t *args)
{ {
(void)args; (void)args;
if (scpi_user_TSTq) { if (scpi_user_TST) {
scpi_user_TSTq(); scpi_user_TST();
} }
} }
@ -56,7 +56,7 @@ static void builtin_IDNq(const SCPI_argval_t *args)
{ {
(void)args; (void)args;
scpi_send_string(scpi_device_identifier()); scpi_send_string(scpi_user_IDN());
} }

@ -13,7 +13,7 @@
// --- queue impl --- // --- queue impl ---
static struct { static struct ErrorQueueStruct {
char queue[ERR_QUEUE_LEN][MAX_ERROR_LEN + 1]; char queue[ERR_QUEUE_LEN][MAX_ERROR_LEN + 1];
int8_t r_pos; int8_t r_pos;
int8_t w_pos; int8_t w_pos;
@ -35,7 +35,13 @@ void scpi_add_error(int16_t errno, const char *extra)
} }
} }
scpi_error_string(erq.queue[erq.w_pos], errno, extra); // get string & coerce errno to valid value
errno = scpi_error_string(erq.queue[erq.w_pos], errno, extra);
// run optional user error callback
if (scpi_user_error) {
scpi_user_error(errno, erq.queue[erq.w_pos]);
}
erq.w_pos++; erq.w_pos++;
erq.count++; erq.count++;
@ -106,8 +112,55 @@ uint8_t scpi_error_count(void)
// ---- table ---- // ---- table ----
static const SCPI_error_desc error_table[] = { static const SCPI_error_desc no_error_desc = {0, "No error"};
static const SCPI_error_desc scpi_std_errors[] = {
{ -100, "Command error"}, { -100, "Command error"},
{ -110, "Command header error"},
{ -120, "Numeric data error"},
{ -130, "Suffix error"},
{ -140, "Character data error"},
{ -150, "String data error"},
{ -160, "Block data error"},
{ -170, "Expression error"},
{ -180, "Macro error"},
{ -200, "Execution error"},
{ -210, "Trigger error"},
{ -220, "Parameter error"},
{ -230, "Data corrupt or stale"},
{ -240, "Hardware error"},
{ -250, "Mass storage error"},
{ -260, "Expression error"},
{ -270, "Macro error"},
{ -280, "Program error"},
{ -290, "Memory use error"},
{ -300, "Device-specific error"},
{ -310, "System error"},
{ -320, "Storage fault"},
{ -330, "Self-test failed"},
{ -340, "Calibration failed"},
{ -350, "Queue overflow"},
{ -360, "Communication error"},
{ -400, "Query error"},
// Error codes that don't make much sense
#ifdef SCPI_WEIRD_ERRORS
{ -410, "Query INTERRUPTED"},
{ -420, "Query UNTERMINATED"},
{ -430, "Query DEADLOCKED"},
{ -440, "Query UNTERMINATED after indefinite response"},
{ -500, "Power on"},
{ -600, "User request"},
{ -700, "Request control"},
{ -800, "Operation complete"},
#endif
// Fine error codes.
// Turn off to save space
#ifdef SCPI_FINE_ERRORS
{ -101, "Invalid character"}, { -101, "Invalid character"},
{ -102, "Syntax error"}, { -102, "Syntax error"},
{ -103, "Invalid separator"}, { -103, "Invalid separator"},
@ -115,62 +168,62 @@ static const SCPI_error_desc error_table[] = {
{ -105, "GET not allowed"}, { -105, "GET not allowed"},
{ -108, "Parameter not allowed"}, { -108, "Parameter not allowed"},
{ -109, "Missing parameter"}, { -109, "Missing parameter"},
{ -110, "Command header error"},
{ -111, "Header separator error"}, { -111, "Header separator error"},
{ -112, "Program mnemonic too long"}, { -112, "Program mnemonic too long"},
{ -113, "Undefined header"}, { -113, "Undefined header"},
{ -114, "Header suffix out of range"}, { -114, "Header suffix out of range"},
{ -115, "Unexpected number of parameters"}, { -115, "Unexpected number of parameters"},
{ -120, "Numeric data error"},
{ -121, "Invalid character in number"}, { -121, "Invalid character in number"},
{ -123, "Exponent too large"}, { -123, "Exponent too large"},
{ -124, "Too many digits"}, { -124, "Too many digits"},
{ -128, "Numeric data not allowed"}, { -128, "Numeric data not allowed"},
{ -130, "Suffix error"},
{ -131, "Invalid suffix"}, { -131, "Invalid suffix"},
{ -134, "Suffix too long"}, { -134, "Suffix too long"},
{ -138, "Suffix not allowed"}, { -138, "Suffix not allowed"},
{ -140, "Character data error"},
{ -141, "Invalid character data"}, { -141, "Invalid character data"},
{ -144, "Character data too long"}, { -144, "Character data too long"},
{ -148, "Character data not allowed"}, { -148, "Character data not allowed"},
{ -150, "String data error"},
{ -151, "Invalid string data"}, { -151, "Invalid string data"},
{ -158, "String data not allowed"}, { -158, "String data not allowed"},
{ -160, "Block data error"},
{ -161, "Invalid block data"}, { -161, "Invalid block data"},
{ -168, "Block data not allowed"}, { -168, "Block data not allowed"},
{ -170, "Expression error"},
{ -171, "Invalid expression"}, { -171, "Invalid expression"},
{ -178, "Expression data not allowed"}, { -178, "Expression data not allowed"},
{ -180, "Macro error"},
{ -181, "Invalid outside macro definition"}, { -181, "Invalid outside macro definition"},
{ -183, "Invalid inside macro definition"}, { -183, "Invalid inside macro definition"},
{ -184, "Macro parameter error"}, { -184, "Macro parameter error"},
{ -200, "Execution error"},
{ -201, "Invalid while in local"}, { -201, "Invalid while in local"},
{ -202, "Settings lost due to rtl"}, { -202, "Settings lost due to rtl"},
{ -203, "Command protected"}, { -203, "Command protected"},
{ -210, "Trigger error"},
{ -211, "Trigger ignored"}, { -211, "Trigger ignored"},
{ -212, "Arm ignored"}, { -212, "Arm ignored"},
{ -213, "Init ignored"}, { -213, "Init ignored"},
{ -214, "Trigger deadlock"}, { -214, "Trigger deadlock"},
{ -215, "Arm deadlock"}, { -215, "Arm deadlock"},
{ -220, "Parameter error"},
{ -221, "Settings conflict"}, { -221, "Settings conflict"},
{ -222, "Data out of range"}, { -222, "Data out of range"},
{ -223, "Too much data"}, { -223, "Too much data"},
{ -224, "Illegal parameter value"}, { -224, "Illegal parameter value"},
{ -225, "Out of memory"}, { -225, "Out of memory"},
{ -226, "Lists not same length"}, { -226, "Lists not same length"},
{ -230, "Data corrupt or stale"},
{ -231, "Data questionable"}, { -231, "Data questionable"},
{ -232, "Invalid format"}, { -232, "Invalid format"},
{ -233, "Invalid version"}, { -233, "Invalid version"},
{ -240, "Hardware error"},
{ -241, "Hardware missing"}, { -241, "Hardware missing"},
{ -250, "Mass storage error"},
{ -251, "Missing mass storage"}, { -251, "Missing mass storage"},
{ -252, "Missing media"}, { -252, "Missing media"},
{ -253, "Corrupt media"}, { -253, "Corrupt media"},
@ -179,9 +232,9 @@ static const SCPI_error_desc error_table[] = {
{ -256, "File name not found"}, { -256, "File name not found"},
{ -257, "File name error"}, { -257, "File name error"},
{ -258, "Media protected"}, { -258, "Media protected"},
{ -260, "Expression error"},
{ -261, "Math error in expression"}, { -261, "Math error in expression"},
{ -270, "Macro error"},
{ -271, "Macro syntax error"}, { -271, "Macro syntax error"},
{ -272, "Macro execution error"}, { -272, "Macro execution error"},
{ -273, "Illegal macro label"}, { -273, "Illegal macro label"},
@ -190,105 +243,113 @@ static const SCPI_error_desc error_table[] = {
{ -276, "Macro recursion error"}, { -276, "Macro recursion error"},
{ -277, "Macro redefinition not allowed"}, { -277, "Macro redefinition not allowed"},
{ -278, "Macro header not found"}, { -278, "Macro header not found"},
{ -280, "Program error"},
{ -281, "Cannot create program"}, { -281, "Cannot create program"},
{ -282, "Illegal program name"}, { -282, "Illegal program name"},
{ -283, "Illegal variable name"}, { -283, "Illegal variable name"},
{ -284, "Program currently running"}, { -284, "Program currently running"},
{ -285, "Program syntax error"}, { -285, "Program syntax error"},
{ -286, "Program runtime error"}, { -286, "Program runtime error"},
{ -290, "Memory use error"},
{ -291, "Out of memory"}, { -291, "Out of memory"},
{ -292, "Referenced name does not exist"}, { -292, "Referenced name does not exist"},
{ -293, "Referenced name already exists"}, { -293, "Referenced name already exists"},
{ -294, "Incompatible type"}, { -294, "Incompatible type"},
{ -300, "Device-specific error"},
{ -310, "System error"},
{ -311, "Memory error"}, { -311, "Memory error"},
{ -312, "PUD memory lost"}, { -312, "PUD memory lost"},
{ -313, "Calibration memory lost"}, { -313, "Calibration memory lost"},
{ -314, "Save/recall memory lost"}, { -314, "Save/recall memory lost"},
{ -315, "Configuration memory lost"}, { -315, "Configuration memory lost"},
{ -320, "Storage fault"},
{ -321, "Out of memory"}, { -321, "Out of memory"},
{ -330, "Self-test failed"},
{ -340, "Calibration failed"},
{ -350, "Queue overflow"},
{ -360, "Communication error"},
{ -361, "Parity error in program message"}, { -361, "Parity error in program message"},
{ -362, "Framing error in program message"}, { -362, "Framing error in program message"},
{ -363, "Input buffer overrun"}, { -363, "Input buffer overrun"},
{ -365, "Time out error"}, { -365, "Time out error"},
{ -400, "Query error"}, #endif
{ -410, "Query INTERRUPTED"},
{ -420, "Query UNTERMINATED"},
{ -430, "Query DEADLOCKED"},
{ -440, "Query UNTERMINATED after indefinite response"},
{ -500, "Power on"},
{ -600, "User request"},
{ -700, "Request control"},
{ -800, "Operation complete"},
{0} // end mark {0} // end mark
}; };
const char * scpi_error_message(int16_t errno) static const SCPI_error_desc * find_error_desc(const SCPI_error_desc *table, int16_t errno)
{ {
for (int i = 0; (i == 0 || table[i].errno != 0); i++) {
if (table[i].errno == errno) {
return &table[i];
}
}
return NULL;
}
static const SCPI_error_desc * resolve_error_desc(int16_t errno)
{
const SCPI_error_desc *desc;
if (errno == 0) { if (errno == 0) {
// ok state // ok state
return "No error"; return &no_error_desc;
} else if (errno < 0) { } else if (errno < 0) {
// standard errors // standard errors
for (int i = 0; (i == 0 || error_table[i].errno != 0); i++) {
if (error_table[i].errno == errno) { desc = find_error_desc(scpi_std_errors, errno);
return error_table[i].msg; if (desc != NULL) return desc;
}
} // not found in table, use group-common error
errno += -errno % 10; // round to ten
desc = find_error_desc(scpi_std_errors, errno);
if (desc != NULL) return desc;
errno += -errno % 100; // round to hundred
desc = find_error_desc(scpi_std_errors, errno);
if (desc != NULL) return desc;
} else { } else {
// user error // user error
for (int i = 0; scpi_user_errors[i].errno != 0; i++) {
if (scpi_user_errors[i].errno == errno) { desc = find_error_desc(scpi_user_errors, errno);
return scpi_user_errors[i].msg; if (desc != NULL) return desc;
}
}
} }
return "Unknown error"; return NULL;
} }
void scpi_error_string(char *buffer, int16_t errno, const char *extra) /**
* Get error string.
*
* @param buffer Buffer for storing the final string. Make sure it's big enough.
* @param errno Error number
* @param extra Extra information, appended after the generic message.
*
* @returns actual error code. Code may be coerced to closest defined code (categories: tens, hundreds)
*/
int16_t scpi_error_string(char *buffer, int16_t errno, const char *extra)
{ {
const char *msg = scpi_error_message(errno); const SCPI_error_desc *desc = resolve_error_desc(errno);
const char *msg;
// len - total length, offs - current segment length if (desc != NULL) {
int len, offs; errno = desc->errno;
msg = desc->msg;
len = offs = sprintf(buffer, "%d,\"", errno); // <code>," } else {
buffer += offs; // bad error code
msg = "Unknown error";
offs = sprintf(buffer, "%s", msg); // Error message }
len += offs;
buffer += offs;
if (extra != NULL) {
// extra info
offs = sprintf(buffer, "; "); // ;
len += offs;
buffer += offs;
// copy in the extra string
int ll = 250 - len - 2;
int xlen = strlen(extra);
if (ll > xlen) ll = xlen;
strncpy(buffer, extra, ll); // Extra msg
len += ll; // Print.
buffer += ll; if (extra == NULL) {
sprintf(buffer, "%d,\"%s\"", errno, msg);
} else {
sprintf(buffer, "%d,\"%s; %s\"", errno, msg, extra);
} }
sprintf(buffer, "\""); // " return errno;
} }

@ -35,8 +35,8 @@ void scpi_status_update(void)
// Run service request callback // Run service request callback
if (SCPI_REG_STB.RQS) { if (SCPI_REG_STB.RQS) {
if (scpi_service_request_impl) { if (scpi_user_SRQ) {
scpi_service_request_impl(); scpi_user_SRQ();
} }
} }
} }

Loading…
Cancel
Save