19static char lower(
char c)
21 return (c >=
'A' && c <=
'Z') ? (char)(c + 32) : c;
25static bool ieq(
const char *a,
size_t alen,
const char *b,
size_t blen)
31 for (
size_t i = 0; i < alen; i++)
33 if (lower(a[i]) != lower(b[i]))
41static bool is_digit(
char c)
43 return c >=
'0' && c <=
'9';
46static bool is_alpha(
char c)
48 return (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z');
53const char *pc_scpi_common(ScpiCommon c)
57 case ScpiCommon::SCPI_CLS:
59 case ScpiCommon::SCPI_ESE:
61 case ScpiCommon::SCPI_ESE_Q:
63 case ScpiCommon::SCPI_ESR_Q:
65 case ScpiCommon::SCPI_IDN_Q:
67 case ScpiCommon::SCPI_OPC:
69 case ScpiCommon::SCPI_OPC_Q:
71 case ScpiCommon::SCPI_RST:
73 case ScpiCommon::SCPI_SRE:
75 case ScpiCommon::SCPI_SRE_Q:
77 case ScpiCommon::SCPI_STB_Q:
79 case ScpiCommon::SCPI_TST_Q:
81 case ScpiCommon::SCPI_WAI:
89size_t pc_scpi_build(
char *buf,
size_t cap,
const char *header,
const char *
const *args,
size_t argc)
91 if (!buf || !header || (argc && !args))
95 size_t hlen = strnlen(header, cap);
96 if (hlen == 0 || hlen >= cap)
102 memcpy(buf, header, hlen);
104 for (
size_t i = 0; i < argc; i++)
110 char sep = (i == 0) ?
' ' :
',';
111 size_t alen = strnlen(args[i], cap);
112 if (p + 1 + alen + 1 >= cap)
117 memcpy(buf + p, args[i], alen);
129size_t pc_scpi_fmt_real(
char *buf,
size_t cap,
double v)
131 if (!buf || cap == 0)
136 pc_sb sb_buf = {buf, cap, 0,
true};
137 pc_sb_g(&sb_buf, (
double)(v), 10);
157static int scan_digits(
const char *s,
size_t len,
size_t *i,
double *acc)
160 while (*i < len && is_digit(s[*i]))
162 *acc = *acc * 10.0 + (s[*i] -
'0');
170static bool scan_exponent(
const char *s,
size_t len,
size_t *i,
int *exp)
173 if (*i >= len || (s[*i] !=
'e' && s[*i] !=
'E'))
179 if (*i < len && (s[*i] ==
'+' || s[*i] ==
'-'))
181 neg = (s[*i] ==
'-');
185 while (*i < len && is_digit(s[*i]))
187 *exp = *exp * 10 + (s[*i] -
'0');
203static double apply_scale(
double v,
int scale)
205 for (
int k = 0; k < scale; k++)
209 for (
int k = 0; k < -scale; k++)
216bool pc_scpi_parse_number(
const char *s,
size_t len,
double *out)
218 if (!s || !out || len == 0)
224 if (s[i] ==
'+' || s[i] ==
'-')
230 int digits = scan_digits(s, len, &i, &mant);
232 if (i < len && s[i] ==
'.')
235 frac = scan_digits(s, len, &i, &mant);
243 if (!scan_exponent(s, len, &i, &exp))
252 double val = apply_scale(mant, exp - frac);
253 *out = neg ? -val : val;
257bool pc_scpi_parse_bool(
const char *s,
size_t len,
bool *out)
259 if (!s || !out || len == 0)
263 if (len == 1 && s[0] ==
'1')
268 if (len == 1 && s[0] ==
'0')
273 if (ieq(s, len,
"ON", 2))
278 if (ieq(s, len,
"OFF", 3))
286size_t pc_scpi_parse_string(
const char *s,
size_t len,
char *out,
size_t cap)
288 if (!s || !out || cap == 0 || len < 2)
293 if ((q !=
'"' && q !=
'\'') || s[len - 1] != q)
305 if (i + 2 < len && s[i + 1] == q)
325bool pc_scpi_parse_block(
const uint8_t *buf,
size_t len,
const uint8_t **data,
size_t *data_len,
size_t *consumed)
327 if (!buf || !data || !data_len || !consumed || len < 2 || buf[0] !=
'#')
331 char n = (char)buf[1];
334 if (len < 3 || buf[len - 1] !=
'\n')
343 if (n <
'1' || n >
'9')
347 size_t ndig = (size_t)(n -
'0');
353 for (
size_t i = 0; i < ndig; i++)
355 char c = (char)buf[2 + i];
360 dlen = dlen * 10 + (size_t)(c -
'0');
362 size_t start = 2 + ndig;
363 if (start + dlen > len)
369 *consumed = start + dlen;
382static const ScpiStdMsg SCPI_STD[] = {
385 {-100,
"Command error"},
386 {-101,
"Invalid character"},
387 {-102,
"Syntax error"},
388 {-103,
"Invalid separator"},
389 {-104,
"Data type error"},
390 {-108,
"Parameter not allowed"},
391 {-109,
"Missing parameter"},
392 {-110,
"Command header error"},
393 {-111,
"Header separator error"},
394 {-112,
"Program mnemonic too long"},
395 {-113,
"Undefined header"},
396 {-114,
"Header suffix out of range"},
397 {-120,
"Numeric data error"},
398 {-128,
"Numeric data not allowed"},
399 {-148,
"Character data not allowed"},
400 {-150,
"String data error"},
401 {-158,
"String data not allowed"},
402 {-168,
"Block data not allowed"},
404 {-200,
"Execution error"},
405 {-220,
"Parameter error"},
406 {-221,
"Settings conflict"},
407 {-222,
"Data out of range"},
408 {-223,
"Too much data"},
409 {-224,
"Illegal parameter value"},
410 {-230,
"Data corrupt or stale"},
411 {-240,
"Hardware error"},
412 {-241,
"Hardware missing"},
414 {-300,
"Device-specific error"},
415 {-310,
"System error"},
416 {-311,
"Memory error"},
417 {-313,
"Calibration memory lost"},
418 {-314,
"Save/recall memory lost"},
419 {-315,
"Configuration memory lost"},
420 {-321,
"Out of memory"},
421 {-330,
"Self-test failed"},
422 {-350,
"Queue overflow"},
423 {-360,
"Communication error"},
424 {-363,
"Input buffer overrun"},
426 {-400,
"Query error"},
427 {-410,
"Query INTERRUPTED"},
428 {-420,
"Query UNTERMINATED"},
429 {-430,
"Query DEADLOCKED"},
430 {-440,
"Query UNTERMINATED after indefinite response"},
433const char *pc_scpi_std_error(int16_t number)
435 for (
size_t i = 0; i <
sizeof(SCPI_STD) /
sizeof(SCPI_STD[0]); i++)
437 if (SCPI_STD[i].number == number)
439 return SCPI_STD[i].msg;
445void pc_scpi_status_init(ScpiStatus *s)
451 memset(s, 0,
sizeof(*s));
454void pc_scpi_event(ScpiStatus *s, uint8_t esr_bits)
465static uint8_t esr_bit_for(int16_t number)
469 return number == 0 ? 0 : SCPI_ESR_DDE;
507void pc_scpi_push_error(ScpiStatus *s, int16_t number,
const char *msg)
509 if (!s || number == 0)
515 msg = pc_scpi_std_error(number);
517 s->esr |= esr_bit_for(number);
522 s->queue[tail].number = -350;
523 s->queue[tail].msg = pc_scpi_std_error(-350);
524 s->esr |= SCPI_ESR_DDE;
528 s->queue[slot].number = number;
529 s->queue[slot].msg = msg;
533bool pc_scpi_pop_error(ScpiStatus *s, ScpiError *out)
539 if (!s || s->count == 0)
542 out->msg =
"No error";
545 *out = s->queue[s->head];
551uint8_t pc_scpi_stb(
const ScpiStatus *s)
557 uint8_t stb = (uint8_t)(s->summary & (SCPI_STB_QSB | SCPI_STB_MAV | SCPI_STB_OSB));
567 if (stb & s->sre & (uint8_t)~SCPI_STB_MSS)
574void pc_scpi_cls(ScpiStatus *s)
588static int suffix_val(
const char *s,
size_t len)
595 for (
size_t i = 0; i < len; i++)
601 v = v * 10 + (s[i] -
'0');
607static bool match_node(
const char *i,
size_t ilen,
const char *p,
size_t plen)
609 if (ilen == 0 || plen == 0)
615 while (palpha < plen && is_alpha(p[palpha]))
624 while (pshort < palpha && p[pshort] >=
'A' &&
631 while (ialpha < ilen && is_alpha(i[ialpha]))
636 if (!ieq(i, ialpha, p, pshort) && !ieq(i, ialpha, p, palpha))
641 int pv = suffix_val(p + palpha, plen - palpha);
642 int iv = suffix_val(i + ialpha, ilen - ialpha);
643 return pv >= 0 && iv >= 0 && pv == iv;
646bool pc_scpi_match(
const char *input,
size_t input_len,
const char *pattern)
648 if (!input || !pattern)
654 while (hlen < input_len && input[hlen] !=
' ')
658 const char *ip = input;
662 if (pattern[0] ==
'*')
664 return ieq(ip, irem, pattern, strnlen(pattern, 64));
668 if (irem && ip[0] ==
':')
674 size_t prem = strnlen(pattern, 256);
675 const char *pp = pattern;
678 bool pq = prem && pp[prem - 1] ==
'?';
679 bool iq = irem && ip[irem - 1] ==
'?';
697 while (pn < prem && pp[pn] !=
':')
702 while (in < irem && ip[in] !=
':')
706 if (!match_node(ip, in, pp, pn))
711 bool p_more = pn < prem;
712 bool i_more = in < irem;
713 if (p_more != i_more)
#define PC_SCPI_ERR_QUEUE
SCPI error/event queue depth (entries). The SCPI status model requires a queue; when it overflows the...
SCPI / IEEE 488.2 instrument-control codec (PC_ENABLE_SCPI) - a zero-heap codec for the text command ...
Bounded no-heap string builder that fails closed on overflow (one shared copy).
void pc_sb_g(pc_sb *b, double v, unsigned sig)
Append v with sig significant digits, choosing fixed or scientific form - the printf "%....
size_t pc_sb_finish(pc_sb *b)
NUL-terminate and return the built length, or 0 if the build overflowed.
Bump-append target; ok latches false once an append would overflow cap.