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 7 years ago
parent e4ff2e0243
commit f9d2b4cdc5
  1. 3
      Makefile
  2. 4
      example/Makefile
  3. 39
      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 += -I$(INCL_DIR)
CFLAGS += -DSCPI_FINE_ERRORS
CFLAGS += -DSCPI_WEIRD_ERRORS
###############################################################################
all: lib

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

@ -30,10 +30,12 @@ int main(void)
send_cmd("SYST:ERR:COUNT?\n");
send_cmd("SYST:ERR:NEXT?\n");
send_cmd("ERROR_FALLBACK\n"); // test fallback to closest related error
// test chardata
send_cmd("CHARD FOOBAR123_MOO_abcdef_HELLO, 12\n");
send_cmd("SYST:ERR:ALL?\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 "MightyPork,Test SCPI device,0,0.1";
}
/** Error callback */
void scpi_user_error(int16_t errno, const char * msg)
{
return "FEL CVUT,DDS1,0,0.1";
printf("### ERROR ADDED: %d, %s ###\n", errno, msg);
}
void scpi_service_request_impl(void)
/** Service request impl */
void scpi_user_SRQ(void)
{
// 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);
printf("[Service Request]\n");
}
@ -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)
const SCPI_command_t scpi_commands[] = {
{
@ -138,6 +155,10 @@ const SCPI_command_t scpi_commands[] = {
.levels = {"USeRERRor"},
.callback = cmd_USRERR_cb
},
{
.levels = {"ERROR_FALLBACK"},
.callback = cmd_ERROR_FALLBACK_cb
},
{
.levels = {"CHARData"},
.params = {SCPI_DT_CHARDATA, SCPI_DT_INT},

@ -2,17 +2,17 @@
#include <stdint.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);
/** *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);
/** *TST? command callback - perform self test and send response back. */
extern __attribute__((weak)) void scpi_user_TSTq(void);
/** Optional *TST? command callback - perform self test and send response back. */
extern __attribute__((weak)) void scpi_user_TST(void);
/** Get device *IDN? string. */
extern const char *scpi_device_identifier(void);
/** MANDATORY callback to get the device *IDN? string. */
extern const char *scpi_user_IDN(void);
// Provides:
// const SCPI_command_t scpi_commands_builtin[];

@ -10,6 +10,12 @@ typedef struct {
/** User error definitions */
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
enum {
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>]"
*
* 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 */

@ -61,10 +61,10 @@ typedef struct {
// ---------------- 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[];
// provided by scpi_builtins.h
/** Built-in SCPI commands, provided by scpi_builtins.h */
extern const SCPI_command_t scpi_commands_builtin[];
/** 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
/** Update the status registers (perform propagation) */
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 \
LICENSE \
README.md \
Makefile
Makefile \
example/Makefile
HEADERS += \
source/scpi_parser.h \

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

@ -13,7 +13,7 @@
// --- queue impl ---
static struct {
static struct ErrorQueueStruct {
char queue[ERR_QUEUE_LEN][MAX_ERROR_LEN + 1];
int8_t r_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.count++;
@ -106,8 +112,55 @@ uint8_t scpi_error_count(void)
// ---- 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"},
{ -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"},
{ -102, "Syntax error"},
{ -103, "Invalid separator"},
@ -115,62 +168,62 @@ static const SCPI_error_desc error_table[] = {
{ -105, "GET not allowed"},
{ -108, "Parameter not allowed"},
{ -109, "Missing parameter"},
{ -110, "Command header error"},
{ -111, "Header separator error"},
{ -112, "Program mnemonic too long"},
{ -113, "Undefined header"},
{ -114, "Header suffix out of range"},
{ -115, "Unexpected number of parameters"},
{ -120, "Numeric data error"},
{ -121, "Invalid character in number"},
{ -123, "Exponent too large"},
{ -124, "Too many digits"},
{ -128, "Numeric data not allowed"},
{ -130, "Suffix error"},
{ -131, "Invalid suffix"},
{ -134, "Suffix too long"},
{ -138, "Suffix not allowed"},
{ -140, "Character data error"},
{ -141, "Invalid character data"},
{ -144, "Character data too long"},
{ -148, "Character data not allowed"},
{ -150, "String data error"},
{ -151, "Invalid string data"},
{ -158, "String data not allowed"},
{ -160, "Block data error"},
{ -161, "Invalid block data"},
{ -168, "Block data not allowed"},
{ -170, "Expression error"},
{ -171, "Invalid expression"},
{ -178, "Expression data not allowed"},
{ -180, "Macro error"},
{ -181, "Invalid outside macro definition"},
{ -183, "Invalid inside macro definition"},
{ -184, "Macro parameter error"},
{ -200, "Execution error"},
{ -201, "Invalid while in local"},
{ -202, "Settings lost due to rtl"},
{ -203, "Command protected"},
{ -210, "Trigger error"},
{ -211, "Trigger ignored"},
{ -212, "Arm ignored"},
{ -213, "Init ignored"},
{ -214, "Trigger deadlock"},
{ -215, "Arm deadlock"},
{ -220, "Parameter error"},
{ -221, "Settings conflict"},
{ -222, "Data out of range"},
{ -223, "Too much data"},
{ -224, "Illegal parameter value"},
{ -225, "Out of memory"},
{ -226, "Lists not same length"},
{ -230, "Data corrupt or stale"},
{ -231, "Data questionable"},
{ -232, "Invalid format"},
{ -233, "Invalid version"},
{ -240, "Hardware error"},
{ -241, "Hardware missing"},
{ -250, "Mass storage error"},
{ -251, "Missing mass storage"},
{ -252, "Missing media"},
{ -253, "Corrupt media"},
@ -179,9 +232,9 @@ static const SCPI_error_desc error_table[] = {
{ -256, "File name not found"},
{ -257, "File name error"},
{ -258, "Media protected"},
{ -260, "Expression error"},
{ -261, "Math error in expression"},
{ -270, "Macro error"},
{ -271, "Macro syntax error"},
{ -272, "Macro execution error"},
{ -273, "Illegal macro label"},
@ -190,105 +243,113 @@ static const SCPI_error_desc error_table[] = {
{ -276, "Macro recursion error"},
{ -277, "Macro redefinition not allowed"},
{ -278, "Macro header not found"},
{ -280, "Program error"},
{ -281, "Cannot create program"},
{ -282, "Illegal program name"},
{ -283, "Illegal variable name"},
{ -284, "Program currently running"},
{ -285, "Program syntax error"},
{ -286, "Program runtime error"},
{ -290, "Memory use error"},
{ -291, "Out of memory"},
{ -292, "Referenced name does not exist"},
{ -293, "Referenced name already exists"},
{ -294, "Incompatible type"},
{ -300, "Device-specific error"},
{ -310, "System error"},
{ -311, "Memory error"},
{ -312, "PUD memory lost"},
{ -313, "Calibration memory lost"},
{ -314, "Save/recall memory lost"},
{ -315, "Configuration memory lost"},
{ -320, "Storage fault"},
{ -321, "Out of memory"},
{ -330, "Self-test failed"},
{ -340, "Calibration failed"},
{ -350, "Queue overflow"},
{ -360, "Communication error"},
{ -361, "Parity error in program message"},
{ -362, "Framing error in program message"},
{ -363, "Input buffer overrun"},
{ -365, "Time out error"},
{ -400, "Query error"},
{ -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
{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) {
// ok state
return "No error";
return &no_error_desc;
} else if (errno < 0) {
// standard errors
for (int i = 0; (i == 0 || error_table[i].errno != 0); i++) {
if (error_table[i].errno == errno) {
return error_table[i].msg;
}
}
desc = find_error_desc(scpi_std_errors, errno);
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 {
// user error
for (int i = 0; scpi_user_errors[i].errno != 0; i++) {
if (scpi_user_errors[i].errno == errno) {
return scpi_user_errors[i].msg;
}
}
desc = find_error_desc(scpi_user_errors, errno);
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
int len, offs;
len = offs = sprintf(buffer, "%d,\"", errno); // <code>,"
buffer += offs;
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
if (desc != NULL) {
errno = desc->errno;
msg = desc->msg;
} else {
// bad error code
msg = "Unknown error";
}
len += ll;
buffer += ll;
// Print.
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
if (SCPI_REG_STB.RQS) {
if (scpi_service_request_impl) {
scpi_service_request_impl();
if (scpi_user_SRQ) {
scpi_user_SRQ();
}
}
}

Loading…
Cancel
Save