1 #include "main-header.h"
3 #include "platform-header.h"
29 #define command_names_size 60
31 #define CNWDEBUGCOM(a, ...) noop()
41 const char *
const command_names[] = {
"noop",
43 "are-you-a-singingcat?",
79 "request-radio-forward",
103 static uint8_t command_match[command_names_size];
108 memset(&command_match, 0,
sizeof(command_match));
114 if ((num > command_names_size) || (num < 1)) {
117 return command_names[num - 1];
123 int _command_add_encoded_arg(
struct command *com,
byte *buf) {
133 va_start(args, format);
144 if (com->
argctr >= COMMAND_MAXARGS) {
145 printf(
"ERROR - command has already maximum args\r\n");
151 r =
sizeof(com->argbuf);
157 vsnprintf(buf + 3,
sizeof(com->argbuf) - (buf - com->argbuf) - 3, format, args);
160 buf[2] = strlen(buf + 3);
173 r =
sizeof(com->argbuf);
178 r =
sizeof(com->argbuf) - (buf - com->argbuf);
183 for (i = 0; i < len; i++) {
190 IPLOG(
"buf too long: %i, only got %i bytes left\r\n", len, r);
213 for (i = 0; i < command_names_size; i++) {
214 const char *com_name = command_names[i];
215 if (strlen(com_name) > size) {
219 for (j = 0; j < strlen(com_name); j++) {
220 if (buf[j] != com_name[j]) {
228 if ((j < size) && (buf[j] !=
',') && (buf[j] !=
'}')) {
231 *newpos = strlen(com_name);
241 if (sourcedev == 1) {
243 }
else if (sourcedev == 2) {
245 }
else if (sourcedev == 3) {
247 }
else if (sourcedev == 4) {
249 }
else if (sourcedev == 5) {
251 }
else if (sourcedev == 6) {
270 snprintf(buf + strlen(buf), 20,
"NONE");
272 if (flags & COMFLAGS_ACK) {
273 snprintf(buf + strlen(buf), 20,
"%sACK", deli);
276 if (flags & COMFLAGS_SUCCESS) {
277 snprintf(buf + strlen(buf), 20,
"%sSUCCESS", deli);
279 }
else if (flags != 0) {
280 snprintf(buf + strlen(buf), 20,
"%sFAILURE", deli);
283 if (flags & COMFLAGS_DATA) {
284 snprintf(buf + strlen(buf), 20,
"%sDATA", deli);
287 if (flags & COMFLAGS_FORWARDED) {
288 snprintf(buf + strlen(buf), 20,
"%sFWD", deli);
291 if (flags & COMFLAGS_POWERSAVE) {
292 snprintf(buf + strlen(buf), 20,
"%sPWR", deli);
295 snprintf(buf + strlen(buf), 20,
"(%i)", flags);
307 if (!is_command_valid(com)) {
311 if ((com->
com > command_names_size) || (com->
com < 1)) {
312 IPLOG(
"Command error: %i is out of range (not a valid command!)\r\n", com->
com);
316 pretty_node_to_str(com->
sender, (
char *)&sbuf);
317 pretty_node_to_str(com->
recipient, (
char *)&rbuf);
318 pretty_node_to_str(com->
target, (
char *)&tbuf);
319 IPLOG(
" [command %p]\r\n device=%s, index=%i, com=%s, flags=%s\r\n sender=%s recipient=%s target=%s\r\n",
323 (
char *)&sbuf, (
char *)&rbuf, (
char *)&tbuf
325 if (com->
com == 28) {
326 IPLOG(
" arg: [data]\r\n");
329 for (i = 0; i < com->
argctr; i++) {
330 IPLOG(
" arg %i: %s\r\n", i,
get_arg(com, i));
337 int command_decode_binary(
struct command *com,
const byte *buf,
int size) {
345 int command_decode_ascii(
struct command *com,
const byte *buf,
int size) {
354 CNWDEBUGCOM(
"Parsing asciibuf \"%s\"\r\n", buf);
357 CNWDEBUG(
"Buf too short: %i\r\n", size);
362 num = ascii_parse_int(buf + curpos, size - curpos, &newpos);
363 curpos = curpos + newpos;
364 if ((newpos <= 0) || (curpos >= size) || (buf[curpos] !=
',')) {
365 CNWDEBUG(
"started incorrectly: newpos=%i,curpos=%i,b[]=%i\r\n", newpos, curpos, buf[curpos]);
369 CNWDEBUGCOM(
"1. size=%i,newpos=%i,curpos=%i,buf->%s\r\n", size, newpos, curpos, buf + curpos);
371 for (i = 0; i < 3; i++) {
373 h = ascii_parse_hex(buf + curpos, size - curpos, &newpos);
374 curpos = curpos + newpos;
375 if ((newpos <= 0) || (curpos >= size) || (buf[curpos] !=
',')) {
376 CNWDEBUG(
"nodeids invalid: newpos=%i,curpos=%i,b[]=%i\r\n", newpos, curpos, buf[curpos]);
386 CNWDEBUGCOM(
"2. size=%i,newpos=%i,curpos=%i,buf->%s\r\n", size, newpos, curpos, buf + curpos);
392 chksum = atoh((
const char *)buf + curpos);
396 num = ascii_parse_int(buf + curpos, size - curpos, &newpos);
397 curpos = curpos + newpos;
398 if ((newpos <= 0) || (curpos >= size) || (buf[curpos] !=
',')) {
399 CNWDEBUG(
"index invalid: idx=%i, newpos=%i,curpos=%i,b[]=%i\r\n", num, newpos, curpos, buf[curpos]);
405 com->
flags = (byte)ascii_parse_int(buf + curpos, size - curpos, &newpos);
406 curpos = curpos + newpos;
407 if ((newpos <= 0) || (curpos >= size) || (buf[curpos] !=
',')) {
411 CNWDEBUGCOM(
"3. size=%i,newpos=%i,curpos=%i,buf->%s\r\n", size, newpos, curpos, buf + curpos);
415 curpos = curpos + newpos;
416 CNWDEBUGCOM(
"4. size=%i,newpos=%i,curpos=%i,buf->%s\r\n", size, newpos, curpos, buf + curpos);
417 if ((num < 1) || (newpos <= 0)) {
418 CNWDEBUG(
"not a command! (result=%i, newpos=%i)\r\n", num, newpos);
422 if (size <= curpos) {
423 CNWDEBUG(
"5. Minimum break, size=%i, curpos=%i\r\n", size, curpos);
430 if (buf[curpos] ==
'}') {
434 if (buf[curpos] !=
',') {
435 CNWDEBUG(
"6. break, illegal character at pos %i: \"%s\"\r\n", curpos, &buf[curpos]);
441 byte backslash_detected = 0;
450 if (curpos >= size) {
453 int field_header_pos = argbufpos;
454 argbufpos = argbufpos + 3;
455 com->argbuf[field_header_pos] = com->
argctr + 1;
456 com->argbuf[field_header_pos + 1] = 129;
458 backslash_detected = 0;
460 CNWDEBUGCOM(
"argctr=%i,buf->%s\n", com->
argctr, buf + curpos);
461 if (com->
argctr > COMMAND_MAXARGS) {
462 CNWDEBUG(
"Command has too many arguments: %i (buf->%s)\n", com->
argctr, buf + curpos);
468 while ((backslash_detected || (buf[curpos] !=
','))
469 && (curpos < size)) {
471 if (((!backslash_detected)) && (buf[curpos] ==
'\\')) {
472 backslash_detected = 1;
476 if ((!backslash_detected) && (buf[curpos] ==
'}')) {
477 com->argbuf[field_header_pos + 2] = argsize;
478 CNWDEBUGCOM(
" arg length: %i\n", argsize);
479 CNWDEBUGCOM(
"end of command detected at pos %i (%s)\n", curpos, buf + curpos);
482 backslash_detected = 0;
484 com->argbuf[argbufpos] = buf[curpos];
489 com->argbuf[field_header_pos + 2] = argsize;
490 CNWDEBUGCOM(
" arg length: %i\n", argsize);
491 com->argbuf[argbufpos] = 0;
496 nc = command_calc_checksum(com);
498 fatal_error(
"checksum broken");
504 printf(
"Command checksum invalid! (calc=%x, received=%x)\r\n", nc, chksum);
513 struct command *command_parse(
const byte *buf,
int size) {
515 CNWDEBUG(
"size less than 2! (%i)\n", size);
519 CNWDEBUG(
"Buf does not start with {\n");
525 while ((x > 4) && (buf[x] !=
'}')) {
529 CNWDEBUG(
"Buf does not end with } but with '%i', size=%i\r\n\r\n", buf[size - 1], size);
542 res = command_decode_ascii(
com, buf + 3, x);
543 }
else if (buf[1] ==
'b') {
544 res = command_decode_binary(
com, buf + 1, x);
546 CNWDEBUG(
"buf is neither ascii nor binary (%s)\n", buf);
551 printf(
"not a valid command (parse error: %i)\r\n", res);
555 for (i = 0; i <
com->argctr; i++) {
557 printf(
"Arg %i: %i (%s)\n", i, (arg -
com->argbuf), arg);
577 if (!(is_command_valid(
com))) {
580 memset(buf, 0, bufsize);
581 if ((
com->com == 0) || (
com->com > command_names_size)) {
585 printf(
"Cannot encode ascii to a buffer <5 bytes!\n");
590 snprintf(buf + bctr, bufsize - bctr,
",%i,", PROTOCOL_VERSION_ASCII);
592 if (bufsize - bctr < 17) {
595 for (i = 0; i < 3; i++) {
603 node_to_str(
id, buf + bctr);
607 if (bufsize - bctr < 17) {
613 int crc = command_calc_checksum(
com);
616 snprintf(buf + bctr, bufsize - bctr,
"%x,", crc);
620 snprintf(buf + bctr, bufsize - bctr,
"%i,%i,%s",
com->index,
626 for (i = 0; i <
com->argctr; i++) {
639 || (arg[j] ==
'}')) {
643 buf[bctr++] = arg[j];
644 if (bctr >= bufsize) {
660 com->sender = config_get_ram_struct()->nodeid;
671 const byte *buf = (
const byte *)
com->argbuf;
683 for (i = 0; i <
index; i++) {
684 len = fieldlen_inmem(buf[1], buf[2]);
704 int len = fieldlen_inmem(buf[1], buf[2]);
718 return fieldlen(buf[1], buf[2]);
730 return (
const char *)buf + 3;
732 return (
const char *)buf + 2;
738 byte command_calc_checksum(
struct command *
com) {
744 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
746 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
748 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
749 chk ^=
com->recipient;
750 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
752 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
754 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
756 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
758 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
759 for (i = 0; i <
com->argctr; i++) {
764 CNWDEBUGCOM(
"checksum after arg #%i of size %i: %lx (arg=%s)\r\n", i,
get_arg_size(
com, i), chk, x);
766 CNWDEBUGCOM(
"After paras: Checksum step #%i: %lx\r\n", r++, chk);
770 for (i = 0; i < 4; i++) {
771 CNWDEBUGCOM(
"RChecksum step #%i: %x\r\n", r++, res);
776 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
788 for (i = 0; i <
com->argctr; i++) {
805 uint32_t res = atoi(v);
820 uint16_t res = atoi(v);
834 printf(
"asked for more args than we have (req=%i, got=%i)\r\n",
index,
com->argctr);
843 if (num >= arraysize) {
847 *(result + num) = ascii_parse_hex((
const unsigned char *)&buf[i], size - i, &r);
856 #ifdef DEBUG_ON_LINUX
859 if ((
void *)
com > (
void *)0x2000BFFF) {
864 void error_com(
void *
com) {
865 printf(
"Invalid command at %p\r\n",
com);
int namedarg_uint16(struct command *com, const char *name, uint16_t *value)
get a named arg (key-value pair), parsed as integer. result in "value". if return value == 0 ,...
int command_encode_ascii(struct command *com, int bufsize, char *buf)
encode a command to an ascii blob properly surrounded by '{' and '}' and escaped returns length if ok...
void free_command(struct command *com)
free a command
struct command * alloc_command()
allocate a free command
int get_arg_size_inmem(const struct command *com, int index)
given an argument by index [0..n], will returns the number in bytes this argument takes up in memory....
const char * command_get_name(int num)
given a command number returns its name
void command_add_arg(struct command *com, const char *format,...)
adds an arg to a partially initialised command structure
void flagstostr(char *buf, int flags)
given a pointer to a buffer and command flags, it will fill the buffer with a human readable text des...
int ascii_commandstring_to_num(const byte *buf, int size, int *const newpos)
match a string to a command num.
void command_add_varg(struct command *com, const char *format, va_list args)
adds a varg list of parameters to a command
int namedarg_uint32(struct command *com, const char *name, uint32_t *value)
get a named arg (key-value pair), parsed as integer. result in "value". if return value == 0 ,...
const byte * get_arg_new(const struct command *com, int index)
given an argument by index[0..n], will returns a pointer to it. This will include the fieldnumber and...
void command_init(struct command *com)
initialize a command structure with default values
int get_arg_int_array(const struct command *com, const int index, int *result, const int arraysize)
given a command and argument index, will attempt to parse the arg as array and return it array syntax...
const char * namedarg(struct command *com, const char *name)
get a named arg (key-value pair) or NULL
char * command_get_source_name(byte sourcedev)
returns a human readable text identifying a source device
void command_print(struct command *com)
prints a command in human readable format to serial console
const char * get_arg(const struct command *com, int index)
given an argument by index[0..n], will return a pointer to the bytearray (excluding the fieldtype) th...
int command_add_binary_arg(struct command *com, const int len, const byte *srcbuf)
adds a binary parameter to command returns 0 if ok otherwise errorcode
int get_arg_size(const struct command *com, int index)
given an argument by index [0..n], will returns the size of the value in bytes. for a string/array it...
void command_start()
initialization for command parser