diff --git a/src/cmnds/fortest.c b/src/cmnds/fortest.c new file mode 100644 index 000000000..f09f52d84 --- /dev/null +++ b/src/cmnds/fortest.c @@ -0,0 +1,68 @@ + + +#include "../logging/logging.h" +#include "../new_pins.h" +#include "../obk_config.h" +#include +#include "../new_cmd.h" +#ifdef BK_LITTLEFS + #include "../littlefs/our_lfs.h" +#endif + + +extern int wal_stricmp(const char *a, const char *b); +extern int wal_strnicmp(const char *a, const char *b, int count); + +char *cmds[16] = { NULL }; +char *names[16] = { NULL }; + + +// run an aliased command +static int runcmd(const void * context, const char *cmd, const char *args){ + char *c = (char *)context; + char *p = c; + + while (*p && !isWhiteSpace(*p)) { + p++; + } + if (*p) p++; + return CMD_ExecuteCommand(p); +} + +// run an aliased command +static int addcmd(const void * context, const char *cmd, const char *args){ + if (!wal_strnicmp(cmd, "addcmd", 6)){ + int index = 0; + char cmd[32]; + int len; + if (strlen(cmd) > 6) { + index = atoi(cmd+6); + } + if ((index < 0) || (index > 16)){ + return 0; + } + + if (cmds[index]){ + os_free(cmds[index]); + } + if (names[index]){ + os_free(names[index]); + } + cmds[index] = os_malloc(strlen(args)+1); + + strcpy(cmds[index], args); + len = get_cmd(args, cmd, 32, 1); + names[index] = os_malloc(strlen(cmd)+1); + strcpy(names[index], cmd); + ADDLOG_ERROR(LOG_FEATURE_CMD, "cmd %d set to %s", index, cmd); + + CMD_RegisterCommand(names[index], "", runcmd, "custom", cmds[index]); + return 1; + } + return 0; +} + +int fortest_commands_init(){ + CMD_RegisterCommand("addcmd", "", addcmd, "add a custom command", NULL); + return 0; +} diff --git a/src/cmnds/fortest.h b/src/cmnds/fortest.h new file mode 100644 index 000000000..f9da35fe9 --- /dev/null +++ b/src/cmnds/fortest.h @@ -0,0 +1 @@ +int fortest_commands_init(); \ No newline at end of file diff --git a/src/cmnds/taslike.c b/src/cmnds/taslike.c new file mode 100644 index 000000000..c2eb6b119 --- /dev/null +++ b/src/cmnds/taslike.c @@ -0,0 +1,159 @@ + +#include "../logging/logging.h" +#include "../new_pins.h" +#include "../obk_config.h" +#include +#include "../new_cmd.h" +#ifdef BK_LITTLEFS + #include "../littlefs/our_lfs.h" +#endif + + +extern int wal_stricmp(const char *a, const char *b); +extern int wal_strnicmp(const char *a, const char *b, int count); + + +static int power(const void *context, const char *cmd, const char *args){ + if (!wal_strnicmp(cmd, "POWER", 5)){ + int channel = 0; + int iVal = 0; + if (strlen(cmd) > 5) { + channel = atoi(cmd+5); + } + iVal = atoi(args); + CHANNEL_Set(channel, iVal, false); + return 1; + } + return 0; +} + +static int color(const void *context, const char *cmd, const char *args){ + if (!wal_strnicmp(cmd, "COLOR", 5)){ + if (args[0] != '#'){ + ADDLOG_ERROR(LOG_FEATURE_CMD, "tasCmnd COLOR expected a # prefixed color"); + return 0; + } else { + const char *c = args; + int val = 0; + int channel = 0; + c++; + while (*c){ + char tmp[3]; + int r; + tmp[0] = *(c++); + if (!*c) break; + tmp[1] = *(c++); + r = sscanf(tmp, "%x", &val); + if (!r) break; + // if this channel is not PWM, find a PWM channel; + while ((channel < 32) && (IOR_PWM != CHANNEL_GetRoleForChannel(channel))) { + channel ++; + } + + if (channel >= 32) break; + + val = (val * 100)/255; + CHANNEL_Set(channel, val, 0); + // move to next channel. + channel ++; + } + } + return 1; + } + return 0; +} + +static int cmnd_backlog(const void * context, const char *cmd, const char *args){ + const char *subcmd; + const char *p; + int count = 0; + char copy[128]; + char *c; + if (stricmp(cmd, "backlog")){ + return -1; + } + ADDLOG_DEBUG(LOG_FEATURE_CMD, "backlog [%s]", args); + + subcmd = args; + p = args; + while (*subcmd){ + c = copy; + while (*p){ + if (*p == ';'){ + *c = '\0'; + p++; + break; + } + *(c) = *(p++); + if (c - copy < 127){ + c++; + } + } + count++; + CMD_ExecuteCommand(copy); + subcmd = p; + } + ADDLOG_DEBUG(LOG_FEATURE_CMD, "backlog executed %d", count); + + return 1; +} + + +static int cmnd_lfsexec(const void * context, const char *cmd, const char *args){ +#ifdef BK_LITTLEFS + ADDLOG_DEBUG(LOG_FEATURE_CMD, "exec %s", args); + if (lfs_present()){ + lfs_file_t *file = os_malloc(sizeof(lfs_file_t)); + if (file){ + int lfsres; + char line[256]; + const char *fname = "autoexec.bat"; + memset(file, 0, sizeof(lfs_file_t)); + if (args && *args){ + fname = args; + } + lfsres = lfs_file_open(&lfs, file, fname, LFS_O_RDONLY); + if (lfsres >= 0) { + ADDLOG_DEBUG(LOG_FEATURE_CMD, "openned file %s", fname); + do { + char *p = line; + do { + lfsres = lfs_file_read(&lfs, file, p, 1); + if ((lfsres <= 0) || (*p < 0x20) || (p - line) == 255){ + *p = 0; + break; + } + p++; + } while ((p - line) < 255); + ADDLOG_DEBUG(LOG_FEATURE_CMD, "line is %s", line); + + if (lfsres >= 0){ + if (*line && (*line != '#')){ + CMD_ExecuteCommand(line); + } + } + } while (lfsres > 0); + + lfs_file_close(&lfs, file); + ADDLOG_DEBUG(LOG_FEATURE_CMD, "closed file %s", fname); + } else { + ADDLOG_ERROR(LOG_FEATURE_CMD, "no file %s err %d", fname, lfsres); + } + os_free(file); + file = NULL; + } + } else { + ADDLOG_ERROR(LOG_FEATURE_CMD, "lfs is absent"); + } +#endif + return 1; +} + + +int taslike_commands_init(){ + CMD_RegisterCommand("power", "", power, "set output POWERn 0..100", NULL); + CMD_RegisterCommand("color", "", color, "set PWN color using #RRGGBB[cw][ww]", NULL); + CMD_RegisterCommand("backlog", "", cmnd_backlog, "run a sequence of ; separated commands", NULL); + CMD_RegisterCommand("exec", "", cmnd_lfsexec, "exec - run autoexec.bat or other file from LFS if present", NULL); + return 0; +} \ No newline at end of file diff --git a/src/cmnds/taslike.h b/src/cmnds/taslike.h new file mode 100644 index 000000000..3cb438650 --- /dev/null +++ b/src/cmnds/taslike.h @@ -0,0 +1,2 @@ + +int taslike_commands_init(); \ No newline at end of file diff --git a/src/drv_tuyaMCU.c b/src/drv_tuyaMCU.c index 4bbb96eeb..bcfde8d3b 100644 --- a/src/drv_tuyaMCU.c +++ b/src/drv_tuyaMCU.c @@ -260,7 +260,7 @@ void TuyaMCU_Send_SetTime(rtcc_t *pTime) { TuyaMCU_SendCommandWithData(TUYA_CMD_SET_TIME, payload_buffer, 8); } -int TuyaMCU_Send_Hex(const void *context, const char *cmd, char *args) { +int TuyaMCU_Send_Hex(const void *context, const char *cmd, const char *args) { //const char *args = CMD_GetArg(1); if(!(*args)) { printf("TuyaMCU_Send_Hex: requires 1 argument (hex string, like FFAABB00CCDD\n"); @@ -277,7 +277,7 @@ int TuyaMCU_Send_Hex(const void *context, const char *cmd, char *args) { return 1; } -int TuyaMCU_Send_SetTime_Example(const void *context, const char *cmd, char *args) { +int TuyaMCU_Send_SetTime_Example(const void *context, const char *cmd, const char *args) { rtcc_t testTime; testTime.year = 2012; diff --git a/src/logging/logging.c b/src/logging/logging.c index 40987ff27..184f835a2 100644 --- a/src/logging/logging.c +++ b/src/logging/logging.c @@ -547,7 +547,7 @@ static int http_getlog(http_request_t *request){ } -int log_command(const void *context, const char *cmd, char *args){ +int log_command(const void *context, const char *cmd, const char *args){ int result = 0; if (!cmd) return -1; if (!args) return -1; diff --git a/src/logging/logging.h b/src/logging/logging.h index 02ba7ffb6..c37d26d3a 100644 --- a/src/logging/logging.h +++ b/src/logging/logging.h @@ -17,7 +17,7 @@ void addLog(char *fmt, ...); void addLogAdv(int level, int feature, char *fmt, ...); -int log_command(const void *context, const char *cmd, char *args); +int log_command(const void *context, const char *cmd, const char *args); #define ADDLOG_ERROR(x, fmt, ...) addLogAdv(LOG_ERROR, x, fmt, ##__VA_ARGS__) #define ADDLOG_WARN(x, fmt, ...) addLogAdv(LOG_WARN, x, fmt, ##__VA_ARGS__) diff --git a/src/mqtt/new_mqtt.c b/src/mqtt/new_mqtt.c index de4f98a26..a53ec6b52 100644 --- a/src/mqtt/new_mqtt.c +++ b/src/mqtt/new_mqtt.c @@ -4,6 +4,7 @@ #include "../new_cfg.h" #include "../logging/logging.h" #include +#include "../new_cmd.h" #undef os_printf @@ -279,9 +280,7 @@ int tasCmnd(mqtt_request_t* request){ // we only need a few bytes to receive a decimal number 0-100 char copy[64]; int len = request->receivedLen; - char *p = request->topic; - int channel = 0; - int iValue = 0; + const char *p = request->topic; // assume a string input here, copy and terminate if(len > sizeof(copy)-1) { @@ -291,8 +290,6 @@ int tasCmnd(mqtt_request_t* request){ // strncpy does not terminate??!!!! copy[len] = '\0'; - PR_NOTICE("tas? data is %s for ch %s\n", copy, request->topic); - // TODO: better // skip to after second forward slash while(*p != '/') { if(*p == 0) return 0; p++; } @@ -300,61 +297,8 @@ int tasCmnd(mqtt_request_t* request){ while(*p != '/') { if(*p == 0) return 0; p++; } p++; - do{ - // accept POWER and POWER0-n - if (!wal_strnicmp(p, "POWER", 5)){ - p += 5; - if ((*p - '0' >= 0) && (*p - '0' <= 9)){ - channel = atoi(p); - } else { - channel = 0; - } - // if channel out of range, stop here. - if ((channel < 0) || (channel > 32)) return 0; - - //PR_NOTICE("MQTT client in mqtt_incoming_data_cb\n"); - PR_NOTICE("MQTT client in tasCmnd data is %s for ch %i\n", copy, channel); - iValue = atoi((char *)copy); - CHANNEL_Set(channel,iValue,0); - break; - } - - if (!wal_strnicmp(p, "COLOR", 5)){ - p += 5; - if (copy[0] != '#'){ - PR_NOTICE("tasCmnd COLOR expected a # prefixed color"); - } else { - char *c = copy; - int val = 0; - int channel = 0; - c++; - while (*c){ - char tmp[3]; - int r; - tmp[0] = *(c++); - if (!*c) break; - tmp[1] = *(c++); - r = sscanf(tmp, "%x", &val); - if (!r) break; - // if this channel is not PWM, find a PWM channel; - while ((channel < 32) && (IOR_PWM != CHANNEL_GetRoleForChannel(channel))) { - channel ++; - } - - if (channel >= 32) break; - - val = (val * 100)/255; - CHANNEL_Set(channel, val, 0); - // move to next channel. - channel ++; - } - } - break; - } - - PR_NOTICE("MQTT client unprocessed in tasCmnd data is %s for topic \n", copy, request->topic); - break; - } while (0); + // use command executor.... + CMD_ExecuteCommandArgs(p, copy); // return 1 to stop processing callbacks here. // return 0 to allow later callbacks to process this topic. diff --git a/src/new_cmd.c b/src/new_cmd.c index f85ceac50..35eea2ee8 100644 --- a/src/new_cmd.c +++ b/src/new_cmd.c @@ -1,9 +1,9 @@ -#include "new_cmd.h" #include "new_pins.h" #include "new_cfg.h" #include "logging/logging.h" #include "obk_config.h" #include +#include "new_cmd.h" #ifdef BK_LITTLEFS #include "littlefs/our_lfs.h" #endif @@ -29,15 +29,8 @@ static int generateHashValue(const char *fname) { } command_t *g_commands[HASH_SIZE] = { NULL }; -static int cmnd_backlog(const void * context, const char *cmd, char *args); -static int cmnd_lfsexec(const void * context, const char *cmd, char *args); -void CMD_Init(int runautoexec) { - CMD_RegisterCommand("backlog", "", cmnd_backlog, "run a sequence of ; separated commands", NULL); - CMD_RegisterCommand("exec", "", cmnd_lfsexec, "exec - run autoexec.bat or other file from LFS if present", NULL); - if (runautoexec){ - cmnd_lfsexec(NULL, "exec", "autoexec.bat"); - } +void CMD_Init() { } @@ -61,9 +54,10 @@ void CMD_RegisterCommand(const char *name, const char *args, commandHandler_t ha // check newCmd = CMD_Find(name); if(newCmd != 0) { - printf("ERROR: command with name %s already exists!\n",name); + ADDLOG_ERROR(LOG_FEATURE_CMD, "command with name %s already exists!",name); return; } + ADDLOG_DEBUG(LOG_FEATURE_CMD, "Adding command %s",name); hash = generateHashValue(name); newCmd = (command_t*)malloc(sizeof(command_t)); @@ -87,7 +81,8 @@ command_t *CMD_Find(const char *name) { if(!stricmp(newCmd->name,name)) { return newCmd; } - } + newCmd = newCmd->next; +} return 0; } @@ -118,163 +113,84 @@ bool isWhiteSpace(char ch) { // return g_args[i]; //} -int CMD_ExecuteCommand(char *s) { - //int r = 0; - char *p; - //int i; - char *cmd; - char *args; +// get a string up to whitespace. +// if stripnum is set, stop at numbers. +int get_cmd(const char *s, char *dest, int maxlen, int stripnum){ + int i; + int count = 0; + for (i = 0; i < maxlen-1; i++){ + if (isWhiteSpace(*s)) { + break; + } + if (stripnum && *s >= '0' && *s <= '9'){ + break; + } + *(dest++) = *(s++); + count++; + } + *dest = '\0'; + return count; +} + + +// execute a command from cmd and args - used below and in MQTT +int CMD_ExecuteCommandArgs(const char *cmd, const char *args) { command_t *newCmd; + int len; + + // look for complete commmand + newCmd = CMD_Find(cmd); + if (!newCmd) { + // not found, so... + char nonums[32]; + // get the complete string up to numbers. + len = get_cmd(cmd, nonums, 32, 1); + newCmd = CMD_Find(nonums); + if (!newCmd) { + // if still not found, then error + ADDLOG_ERROR(LOG_FEATURE_CMD, "cmd %s NOT found", cmd); + return 0; + } + } else { + } + + if (newCmd->handler){ + int res; + res = newCmd->handler(newCmd->context, cmd, args); + return res; + } + return 0; +} + + +// execute a raw command - single string +int CMD_ExecuteCommand(const char *s) { + const char *p; + const char *args; + + char copy[32]; + int len; + const char *org; ADDLOG_DEBUG(LOG_FEATURE_CMD, "cmd [%s]", s); while(isWhiteSpace(*s)) { s++; } + org = s; + + // get the complete string up to whitespace. + len = get_cmd(s, copy, 32, 0); + s += len; - cmd = s; p = s; - while(*p != 0) { - if(isWhiteSpace(*p)) { - *p = 0; - p++; - break; - } - p++; - } while(*p && isWhiteSpace(*p)) { p++; } args = p; - newCmd = CMD_Find(cmd); - if (!newCmd) { - ADDLOG_ERROR(LOG_FEATURE_CMD, "cmd %s not found", cmd); - return 0; - } - - if (newCmd->handler){ - return newCmd->handler(newCmd->context, cmd, args); - } - return 0; - -/* - strcpy(g_buffer,s); - p = g_buffer; - g_numArgs = 0; - g_args[g_numArgs] = p; - g_numArgs++; - while(*p != 0) { - if(isWhiteSpace(*p)) { - *p = 0; - if((p[1] != 0)) { - g_args[g_numArgs] = p+1; - g_numArgs++; - } - } - if(*p == ',') { - *p = 0; - g_args[g_numArgs] = p+1; - g_numArgs++; - } - p++; - } - - if(1){ - printf("Command parsed debug out! %i args\n",g_numArgs); - for(i = 0; i < g_numArgs; i++) { - printf("Arg %i is %s\n",i,g_args[i]); - } - } - - newCmd = CMD_Find(g_args[0]); - if(newCmd != 0) { - r++; - newCmd->handler(); - } - - return r; -*/ + return CMD_ExecuteCommandArgs(copy, args); } -static int cmnd_backlog(const void * context, const char *cmd, char *args){ - char *subcmd; - char *p; - int count = 0; - if (stricmp(cmd, "backlog")){ - return -1; - } - ADDLOG_DEBUG(LOG_FEATURE_CMD, "backlog [%s]", args); - - subcmd = args; - p = args; - while (*subcmd){ - while (*p){ - if (*p == ';'){ - *p = '\0'; - p++; - break; - } - p++; - } - count++; - CMD_ExecuteCommand(subcmd); - subcmd = p; - } - ADDLOG_DEBUG(LOG_FEATURE_CMD, "backlog executed %d", count); - - return 1; -} - - -static int cmnd_lfsexec(const void * context, const char *cmd, char *args){ -#ifdef BK_LITTLEFS - ADDLOG_DEBUG(LOG_FEATURE_CMD, "exec %s", args); - if (lfs_present()){ - lfs_file_t *file = os_malloc(sizeof(lfs_file_t)); - if (file){ - int lfsres; - char line[256]; - char *fname = "autoexec.bat"; - memset(file, 0, sizeof(lfs_file_t)); - if (args && *args){ - fname = args; - } - lfsres = lfs_file_open(&lfs, file, fname, LFS_O_RDONLY); - if (lfsres >= 0) { - ADDLOG_DEBUG(LOG_FEATURE_CMD, "openned file %s", fname); - do { - char *p = line; - do { - lfsres = lfs_file_read(&lfs, file, p, 1); - if ((lfsres <= 0) || (*p < 0x20) || (p - line) == 255){ - *p = 0; - break; - } - p++; - } while ((p - line) < 255); - ADDLOG_DEBUG(LOG_FEATURE_CMD, "line is %s", line); - - if (lfsres >= 0){ - if (*line && (*line != '#')){ - CMD_ExecuteCommand(line); - } - } - } while (lfsres > 0); - - lfs_file_close(&lfs, file); - ADDLOG_DEBUG(LOG_FEATURE_CMD, "closed file %s", fname); - } else { - ADDLOG_ERROR(LOG_FEATURE_CMD, "no file %s err %d", fname, lfsres); - } - os_free(file); - file = NULL; - } - } else { - ADDLOG_ERROR(LOG_FEATURE_CMD, "lfs is absent"); - } -#endif - return 1; -} diff --git a/src/new_cmd.h b/src/new_cmd.h index df2ad4204..96ff62d9c 100644 --- a/src/new_cmd.h +++ b/src/new_cmd.h @@ -1,6 +1,6 @@ -typedef int (*commandHandler_t)(const void *context, const char *cmd, char *args); +typedef int (*commandHandler_t)(const void *context, const char *cmd, const char *args); typedef struct command_s { const char *name; @@ -11,17 +11,19 @@ typedef struct command_s { struct command_s *next; } command_t; -void CMD_Init(int runautoexec); +void CMD_Init(); command_t *CMD_Find(const char *name); void CMD_RegisterCommand(const char *name, const char *args, commandHandler_t handler, const char *userDesc, void *context); -// allow modification of s -int CMD_ExecuteCommand(char *s); +int CMD_ExecuteCommand(const char *s); +int CMD_ExecuteCommandArgs(const char *cmd, const char *args); // NOTE: argsCount includes commands name, so 1 tells "only command" int CMD_GetArgsCount() ; // NOTE: arg0 is command name const char *CMD_GetArg(int i); // for autocompletion? void CMD_ListAllCommands(void *userData, void (*callback)(command_t *cmd, void *userData)); +int get_cmd(const char *s, char *dest, int maxlen, int stripnum); +bool isWhiteSpace(char ch); diff --git a/src/user_main.c b/src/user_main.c index ce50506c8..294f4260c 100644 --- a/src/user_main.c +++ b/src/user_main.c @@ -59,6 +59,8 @@ #include "ntp_time.h" #include "new_cmd.h" +#include "cmnds/taslike.h" +#include "cmnds/fortest.h" #undef Malloc #undef Free @@ -416,11 +418,19 @@ void user_main(void) // all MQTT happens in timer thread? MQTT_init(); + // add some commands... + taslike_commands_init(); + fortest_commands_init(); // NOTE: this will try to read autoexec.bat, // so ALL commands expected in autoexec.bat should have been registered by now... // but DON't run autoexec if we have had 2+ boot failures - CMD_Init(bootFailures < 2); + CMD_Init(); + + if (bootFailures < 2){ + CMD_ExecuteCommand("exec autoexec.bat"); + } + err = rtos_init_timer(&led_timer, 1 * 1000,