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. 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