1#include "main-header.h"
3#include "platform-header.h"
29#define command_names_size 60
31#define CNWDEBUGCOM(a, ...) noop()
41const char *
const command_names[] = {
"noop",
43 "are-you-a-singingcat?",
79 "request-radio-forward",
103static 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];
123int _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));
337int command_decode_binary(
struct command *com,
const byte *buf,
int size) {
346int command_decode_ascii(
struct command *com,
const byte *buf,
int size,
int version) {
355 CNWDEBUGCOM(
"Parsing asciibuf \"%s\"\r\n", buf);
358 CNWDEBUG(
"Buf too short: %i\r\n", size);
363 num = ascii_parse_int(buf + curpos, size - curpos, &newpos);
364 curpos = curpos + newpos;
365 if ((newpos <= 0) || (curpos >= size) || (buf[curpos] !=
',')) {
366 CNWDEBUG(
"started incorrectly: newpos=%i,curpos=%i,b[]=%i\r\n", newpos, curpos, buf[curpos]);
370 CNWDEBUGCOM(
"1. size=%i,newpos=%i,curpos=%i,buf->%s\r\n", size, newpos, curpos, buf + curpos);
372 for (i = 0; i < 3; i++) {
374 h = ascii_parse_hex(buf + curpos, size - curpos, &newpos);
375 curpos = curpos + newpos;
376 if ((newpos <= 0) || (curpos >= size) || (buf[curpos] !=
',')) {
377 CNWDEBUG(
"nodeids invalid: newpos=%i,curpos=%i,b[]=%i\r\n", newpos, curpos, buf[curpos]);
387 CNWDEBUGCOM(
"2. size=%i,newpos=%i,curpos=%i,buf->%s\r\n", size, newpos, curpos, buf + curpos);
393 chksum = atoh((
const char *)buf + curpos);
397 num = ascii_parse_int(buf + curpos, size - curpos, &newpos);
398 curpos = curpos + newpos;
399 if ((newpos <= 0) || (curpos >= size) || (buf[curpos] !=
',')) {
400 CNWDEBUG(
"index invalid: idx=%i, newpos=%i,curpos=%i,b[]=%i\r\n", num, newpos, curpos, buf[curpos]);
406 com->
flags = (byte)ascii_parse_int(buf + curpos, size - curpos, &newpos);
407 curpos = curpos + newpos;
408 if ((newpos <= 0) || (curpos >= size) || (buf[curpos] !=
',')) {
412 CNWDEBUGCOM(
"3. size=%i,newpos=%i,curpos=%i,buf->%s\r\n", size, newpos, curpos, buf + curpos);
416 curpos = curpos + newpos;
417 CNWDEBUGCOM(
"4. size=%i,newpos=%i,curpos=%i,buf->%s\r\n", size, newpos, curpos, buf + curpos);
418 if ((num < 1) || (newpos <= 0)) {
419 CNWDEBUG(
"not a command! (result=%i, newpos=%i)\r\n", num, newpos);
423 if (size <= curpos) {
424 CNWDEBUG(
"5. Minimum break, size=%i, curpos=%i\r\n", size, curpos);
431 if (buf[curpos] ==
'}') {
435 if (buf[curpos] !=
',') {
436 CNWDEBUG(
"6. break, illegal character at pos %i: \"%s\"\r\n", curpos, &buf[curpos]);
442 byte backslash_detected = 0;
451 if (curpos >= size) {
454 int field_header_pos = argbufpos;
455 argbufpos = argbufpos + 3;
456 com->argbuf[field_header_pos] = com->
argctr + 1;
457 com->argbuf[field_header_pos + 1] = 129;
459 backslash_detected = 0;
461 CNWDEBUGCOM(
"argctr=%i,buf->%s\n", com->
argctr, buf + curpos);
462 if (com->
argctr > COMMAND_MAXARGS) {
463 CNWDEBUG(
"Command has too many arguments: %i (buf->%s)\n", com->
argctr, buf + curpos);
469 while ((backslash_detected || (buf[curpos] !=
','))
470 && (curpos < size)) {
472 if (((!backslash_detected)) && (buf[curpos] ==
'\\')) {
473 backslash_detected = 1;
477 if ((!backslash_detected) && (buf[curpos] ==
'}')) {
478 com->argbuf[field_header_pos + 2] = argsize;
479 CNWDEBUGCOM(
" arg length: %i\n", argsize);
480 CNWDEBUGCOM(
"end of command detected at pos %i (%s)\n", curpos, buf + curpos);
483 backslash_detected = 0;
485 com->argbuf[argbufpos] = buf[curpos];
490 com->argbuf[field_header_pos + 2] = argsize;
491 CNWDEBUGCOM(
" arg length: %i\n", argsize);
492 com->argbuf[argbufpos] = 0;
497 nc = command_calc_checksum(com);
499 fatal_error(
"checksum broken");
505 printf(
"Command checksum invalid! (calc=%x, received=%x)\r\n", nc, chksum);
514struct command *command_parse(
const byte *buf,
int size) {
516 CNWDEBUG(
"size less than 2! (%i)\n", size);
520 CNWDEBUG(
"Buf does not start with {\n");
526 while ((x > 4) && (buf[x] !=
'}')) {
530 CNWDEBUG(
"Buf does not end with } but with '%i', size=%i\r\n\r\n", buf[size - 1], size);
543 int version = buf[3] -
'0';
544 res = command_decode_ascii(
com, buf + 3, x, version);
545 }
else if (buf[1] ==
'b') {
546 res = command_decode_binary(
com, buf + 1, x);
548 CNWDEBUG(
"buf is neither ascii nor binary (%s)\n", buf);
553 printf(
"not a valid command (parse error: %i)\r\n", res);
557 for (i = 0; i <
com->argctr; i++) {
559 printf(
"Arg %i: %i (%s)\n", i, (arg -
com->argbuf), arg);
579 if (!(is_command_valid(
com))) {
582 memset(buf, 0, bufsize);
583 if ((
com->com == 0) || (
com->com > command_names_size)) {
587 printf(
"Cannot encode ascii to a buffer <5 bytes!\n");
592 snprintf(buf + bctr, bufsize - bctr,
",%i,", PROTOCOL_VERSION_ASCII);
594 if (bufsize - bctr < 17) {
597 for (i = 0; i < 3; i++) {
605 node_to_str(
id, buf + bctr);
609 if (bufsize - bctr < 17) {
615 int crc = command_calc_checksum(
com);
618 snprintf(buf + bctr, bufsize - bctr,
"%x,", crc);
622 snprintf(buf + bctr, bufsize - bctr,
"%i,%i,%s",
com->index,
628 for (i = 0; i <
com->argctr; i++) {
641 || (arg[j] ==
'}')) {
645 buf[bctr++] = arg[j];
646 if (bctr >= bufsize) {
662 com->sender = config_get_ram_struct()->nodeid;
673 const byte *buf = (
const byte *)
com->argbuf;
685 for (i = 0; i <
index; i++) {
686 len = fieldlen_inmem(buf[1], buf[2]);
706 int len = fieldlen_inmem(buf[1], buf[2]);
720 return fieldlen(buf[1], buf[2]);
732 return (
const char *)buf + 3;
734 return (
const char *)buf + 2;
740byte command_calc_checksum(
struct command *
com) {
746 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
748 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
750 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
751 chk ^=
com->recipient;
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);
760 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
761 for (i = 0; i <
com->argctr; i++) {
766 CNWDEBUGCOM(
"checksum after arg #%i of size %i: %lx (arg=%s)\r\n", i,
get_arg_size(
com, i), chk, x);
768 CNWDEBUGCOM(
"After paras: Checksum step #%i: %lx\r\n", r++, chk);
772 for (i = 0; i < 4; i++) {
773 CNWDEBUGCOM(
"RChecksum step #%i: %x\r\n", r++, res);
778 CNWDEBUGCOM(
"Checksum step #%i: %lx\r\n", r++, chk);
790 for (i = 0; i <
com->argctr; i++) {
807 uint32_t res = atoi(v);
822 uint16_t res = atoi(v);
836 printf(
"asked for more args than we have (req=%i, got=%i)\r\n",
index,
com->argctr);
845 if (num >= arraysize) {
849 *(result + num) = ascii_parse_hex((
const unsigned char *)&buf[i], size - i, &r);
861 if ((
void *)
com > (
void *)0x2000BFFF) {
866void error_com(
void *
com) {
867 printf(
"Invalid command at %p\r\n",
com);
char * command_get_source_name(byte sourcedev)
returns a human readable text identifying a source device
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
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....
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...
const char * namedarg(struct command *com, const char *name)
get a named arg (key-value pair) or NULL
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 char * command_get_name(int num)
given a command number returns its name
void command_init(struct command *com)
initialize a command structure with default values
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...
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...
void command_print(struct command *com)
prints a command in human readable format to serial console
struct command * alloc_command()
allocate a free command
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
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 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