#include #include #include #include #include #include "scpi_errors.h" #include "scpi_regs.h" #define ERR_QUEUE_LEN 4 #define MAX_ERROR_LEN 150 // --- 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(int16_t errno, const char *extra) { if (erq.count >= ERR_QUEUE_LEN) { errno = E_DEV_QUEUE_OVERFLOW; extra = NULL; // 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; } // error type status flags if (errno >= -499 && errno <= -400) { SCPI_REG_SESR.QUERY_ERROR = true; } else if ((errno >= -399 && errno <= -300) || errno > 0) { SCPI_REG_SESR.DEV_ERROR = true; } else if (errno >= -299 && errno <= -200) { SCPI_REG_SESR.EXE_ERROR = true; } else if (errno >= -199 && errno <= -100) { SCPI_REG_SESR.CMD_ERROR = true; } // update the error queue bit and propagate the above flags 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 ---- static const SCPI_error_desc error_table[] = { { -100, "Command error"}, { -101, "Invalid character"}, { -102, "Syntax error"}, { -103, "Invalid separator"}, { -104, "Data type error"}, { -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"}, { -254, "Media full"}, { -255, "Directory full"}, { -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"}, { -274, "Macro parameter error"}, { -275, "Macro definition too long"}, { -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"}, {0} // end mark }; const char * scpi_error_message(int16_t errno) { if (errno == 0) { // ok state return "No error"; } 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; } } } 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; } } } return "Unknown error"; } void scpi_error_string(char *buffer, int16_t errno, const char *extra) { const char *msg = scpi_error_message(errno); // len - total length, offs - current segment length int len, offs; len = offs = sprintf(buffer, "%d,\"", errno); // ," 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 len += ll; buffer += ll; } sprintf(buffer, "\""); // " }