| 14 | | #include "base/lib/rcmd/_rcmd.h" |
| | 19 | |
| | 20 | static rcmd_err_t nx_rcmd_move(char *line); |
| | 21 | static rcmd_err_t nx_rcmd_print(char *line); |
| | 22 | static rcmd_err_t nx_rcmd_clear(char *line); |
| | 23 | static rcmd_err_t nx_rcmd_play(char *line); |
| | 24 | static rcmd_err_t nx_rcmd_exec(char *line); |
| | 25 | static rcmd_err_t nx_rcmd_wait(char *line); |
| | 26 | |
| | 27 | static rcmd_command_def rcmd_commands[] = { |
| | 28 | { "move", 4, nx_rcmd_move }, |
| | 29 | { "print", 2, nx_rcmd_print }, |
| | 30 | { "clear", 1, nx_rcmd_clear }, |
| | 31 | { "play", 3, nx_rcmd_play }, |
| | 32 | { "exec", 2, nx_rcmd_exec }, |
| | 33 | { "wait", 2, nx_rcmd_wait }, |
| | 34 | { NULL, 0, NULL }, |
| | 35 | }; |
| | 36 | |
| | 37 | static char *rcmd_err_str[RCMD_ERR_N_ERRS] = { |
| | 38 | "No error.", |
| | 39 | "Invalid parameter count.", |
| | 40 | "Invalid parameter.", |
| | 41 | "File I/O error.", |
| | 42 | "Parser reached end of file.", |
| | 43 | "Command not found.", |
| | 44 | }; |
| | 45 | |
| | 46 | static void nx_rcmd_tokenize(char *line, char sep, int *ntokens, int *indices) { |
| | 47 | size_t len; |
| | 48 | U32 i; |
| | 49 | |
| | 50 | len = strlen(line); |
| | 51 | *ntokens = 0; |
| | 52 | i = 0; |
| | 53 | |
| | 54 | while (i < len) { |
| | 55 | while (i < len && line[i] == sep) { |
| | 56 | /* Replace all occurences of the token separator char by \0. */ |
| | 57 | line[i++] = 0; |
| | 58 | } |
| | 59 | |
| | 60 | if (i == len || *ntokens == RCMD_MAX_TOKENS) { |
| | 61 | return; |
| | 62 | } |
| | 63 | |
| | 64 | indices[*ntokens] = i; |
| | 65 | (*ntokens)++; |
| | 66 | |
| | 67 | while (i < len && line[i] != sep) { |
| | 68 | /* Pass token characters. */ |
| | 69 | i++; |
| | 70 | } |
| | 71 | } |
| | 72 | } |
| | 73 | |
| | 74 | static rcmd_err_t nx_rcmd_move(char *line) { |
| | 75 | int ntokens, indices[RCMD_MAX_TOKENS], subind[NXT_N_MOTORS], i; |
| | 76 | char *spec; |
| | 77 | |
| | 78 | bool active[NXT_N_MOTORS] = {FALSE}; |
| | 79 | S32 speeds[NXT_N_MOTORS]; |
| | 80 | U32 durations[NXT_N_MOTORS]; |
| | 81 | bool success; |
| | 82 | |
| | 83 | nx_rcmd_tokenize(line, RCMD_TOKEN_SEPARATOR, &ntokens, indices); |
| | 84 | |
| | 85 | if (ntokens != rcmd_commands[RCMD_CMD_MOVE].argc) { |
| | 86 | return RCMD_ERR_INCORRECT_ARGC; |
| | 87 | } |
| | 88 | |
| | 89 | /* Parse motors spec. */ |
| | 90 | spec = line + indices[1]; |
| | 91 | nx_rcmd_tokenize(spec, ',', &ntokens, subind); |
| | 92 | for (i=0; i<ntokens; i++) { |
| | 93 | U8 motor = spec[subind[i]] - 'A'; |
| | 94 | if (motor < NXT_N_MOTORS) { |
| | 95 | active[motor] = TRUE; |
| | 96 | } else { |
| | 97 | return RCMD_ERR_INVALID_PARAMETER; |
| | 98 | } |
| | 99 | } |
| | 100 | |
| | 101 | /* Parse speeds spec. */ |
| | 102 | spec = line + indices[2]; |
| | 103 | nx_rcmd_tokenize(spec, ',', &ntokens, subind); |
| | 104 | for (i=0; i<NXT_N_MOTORS; i++) { |
| | 105 | if (ntokens <= i) { |
| | 106 | success = atos32(spec + subind[ntokens-1], &speeds[i]); |
| | 107 | } else { |
| | 108 | success = atos32(spec + subind[i], &speeds[i]); |
| | 109 | } |
| | 110 | |
| | 111 | if (!success || speeds[i] > 100 || speeds[i] < -100) { |
| | 112 | return RCMD_ERR_INVALID_PARAMETER; |
| | 113 | } |
| | 114 | } |
| | 115 | |
| | 116 | /* Parse durations spec. */ |
| | 117 | spec = line + indices[3]; |
| | 118 | nx_rcmd_tokenize(spec, ',', &ntokens, subind); |
| | 119 | for (i=0; i<NXT_N_MOTORS; i++) { |
| | 120 | if (ntokens <= i) { |
| | 121 | success = atou32(spec + subind[ntokens-1], &durations[i]); |
| | 122 | } else { |
| | 123 | success = atou32(spec + subind[i], &durations[i]); |
| | 124 | } |
| | 125 | |
| | 126 | if (!success || (speeds[i] != 0 && durations[i] == 0)) { |
| | 127 | return RCMD_ERR_INVALID_PARAMETER; |
| | 128 | } |
| | 129 | } |
| | 130 | |
| | 131 | /* Activate motors. */ |
| | 132 | for (i=0; i<NXT_N_MOTORS; i++) { |
| | 133 | if (active[i]) { |
| | 134 | if (speeds[i] != 0) { |
| | 135 | nx_motors_rotate_time(i, (S8) speeds[i], durations[i], FALSE); |
| | 136 | } else { |
| | 137 | nx_motors_stop(i, TRUE); |
| | 138 | } |
| | 139 | } |
| | 140 | } |
| | 141 | |
| | 142 | nx_display_string("moving?\n"); |
| | 143 | |
| | 144 | return RCMD_ERR_NO_ERROR; |
| | 145 | } |
| | 146 | |
| | 147 | static rcmd_err_t nx_rcmd_print(char *line) { |
| | 148 | int ntokens, indices[RCMD_MAX_TOKENS], i; |
| | 149 | |
| | 150 | nx_rcmd_tokenize(line, RCMD_TOKEN_SEPARATOR, &ntokens, indices); |
| | 151 | |
| | 152 | for (i=1; i<ntokens; i++) { |
| | 153 | nx_display_string(line + indices[i]); |
| | 154 | if (i < ntokens-1) |
| | 155 | nx_display_string(" "); |
| | 156 | } |
| | 157 | |
| | 158 | nx_display_end_line(); |
| | 159 | return RCMD_ERR_NO_ERROR; |
| | 160 | } |
| | 161 | |
| | 162 | static rcmd_err_t nx_rcmd_clear(char *line) { |
| | 163 | /* No-op. */ |
| | 164 | char c; |
| | 165 | c = line[0]; |
| | 166 | |
| | 167 | nx_display_clear(); |
| | 168 | return RCMD_ERR_NO_ERROR; |
| | 169 | } |
| | 170 | |
| | 171 | static rcmd_err_t nx_rcmd_play(char *line) { |
| | 172 | int ntokens, indices[RCMD_MAX_TOKENS]; |
| | 173 | U32 freq, duration; |
| | 174 | |
| | 175 | nx_rcmd_tokenize(line, RCMD_TOKEN_SEPARATOR, &ntokens, indices); |
| | 176 | |
| | 177 | if (ntokens < rcmd_commands[RCMD_CMD_PLAY].argc) { |
| | 178 | return RCMD_ERR_INCORRECT_ARGC; |
| | 179 | } |
| | 180 | |
| | 181 | if (!atou32(line + indices[1], &freq) || freq < 200 || |
| | 182 | !atou32(line + indices[2], &duration) || duration < 100) { |
| | 183 | return RCMD_ERR_INVALID_PARAMETER; |
| | 184 | } |
| | 185 | |
| | 186 | if (ntokens == 4 && streq(line + indices[3], "sync") == 0) { |
| | 187 | nx_sound_freq(freq, duration); |
| | 188 | } else { |
| | 189 | nx_sound_freq_async(freq, duration); |
| | 190 | } |
| | 191 | |
| | 192 | return RCMD_ERR_NO_ERROR; |
| | 193 | } |
| | 194 | |
| | 195 | static rcmd_err_t nx_rcmd_exec(char *line) { |
| | 196 | int ntokens, indices[RCMD_MAX_TOKENS]; |
| | 197 | char *filename; |
| | 198 | |
| | 199 | nx_rcmd_tokenize(line, RCMD_TOKEN_SEPARATOR, &ntokens, indices); |
| | 200 | |
| | 201 | if (ntokens != rcmd_commands[RCMD_CMD_EXEC].argc) { |
| | 202 | return RCMD_ERR_INCORRECT_ARGC; |
| | 203 | } |
| | 204 | |
| | 205 | filename = line + indices[1]; |
| | 206 | |
| | 207 | /* Open the requested file and branch execution. */ |
| | 208 | nx_display_string("exec:"); |
| | 209 | nx_display_string(filename); |
| | 210 | nx_display_end_line(); |
| | 211 | |
| | 212 | return RCMD_ERR_NO_ERROR; |
| | 213 | } |
| | 214 | |
| | 215 | static rcmd_err_t nx_rcmd_wait(char *line) { |
| | 216 | int ntokens, indices[RCMD_MAX_TOKENS]; |
| | 217 | U32 wait; |
| | 218 | |
| | 219 | nx_rcmd_tokenize(line, RCMD_TOKEN_SEPARATOR, &ntokens, indices); |
| | 220 | |
| | 221 | if (ntokens != rcmd_commands[RCMD_CMD_EXEC].argc) { |
| | 222 | return RCMD_ERR_INCORRECT_ARGC; |
| | 223 | } |
| | 224 | |
| | 225 | if (!atou32(line + indices[1], &wait) || wait == 0) { |
| | 226 | return RCMD_ERR_INVALID_PARAMETER; |
| | 227 | } |
| | 228 | |
| | 229 | nx_systick_wait_ms(wait); |
| | 230 | return RCMD_ERR_NO_ERROR; |
| | 231 | } |
| | 232 | |
| | 233 | static rcmd_err_t nx_rcmd_readline(fs_fd_t fd, char *line) { |
| | 234 | fs_err_t err; |
| | 235 | U32 i = 0; |
| | 236 | U8 *buf = (U8 *)line; |
| | 237 | |
| | 238 | while (i < RCMD_BUF_LEN - 2) { |
| | 239 | err = nx_fs_read(fd, &(buf[i])); |
| | 240 | |
| | 241 | if (err == FS_ERR_END_OF_FILE) { |
| | 242 | buf[i] = 0; |
| | 243 | return RCMD_ERR_END_OF_FILE; |
| | 244 | } else if (err != FS_ERR_NO_ERROR) { |
| | 245 | nx_display_uint(err); |
| | 246 | nx_display_end_line(); |
| | 247 | return RCMD_ERR_READ_ERROR; |
| | 248 | } |
| | 249 | |
| | 250 | if (buf[i] == '\n') { |
| | 251 | break; |
| | 252 | } |
| | 253 | |
| | 254 | i++; |
| | 255 | } |
| | 256 | |
| | 257 | buf[i] = 0; |
| | 258 | return RCMD_ERR_NO_ERROR; |
| | 259 | } |
| | 260 | |
| | 261 | static void nx_rcmd_error(rcmd_err_t err, char *filename, int line) { |
| | 262 | /* nx_display_clear(); */ |
| | 263 | |
| | 264 | nx_display_string("Error in file:\n"); |
| | 265 | nx_display_string(filename); |
| | 266 | nx_display_end_line(); |
| | 267 | |
| | 268 | nx_display_string("At line "); |
| | 269 | nx_display_uint(line); |
| | 270 | nx_display_end_line(); |
| | 271 | |
| | 272 | nx_display_string(rcmd_err_str[err]); |
| | 273 | } |
| | 274 | |
| | 275 | static rcmd_err_t nx_rcmd_find_command(char *line, rcmd_command_def *command) { |
| | 276 | U32 i = 0; |
| | 277 | char *sep; |
| | 278 | |
| | 279 | sep = strchr(line, RCMD_TOKEN_SEPARATOR); |
| | 280 | if (sep) { |
| | 281 | *sep = '\0'; |
| | 282 | } |
| | 283 | |
| | 284 | while (rcmd_commands[i].name) { |
| | 285 | if (streq(line, rcmd_commands[i].name)) { |
| | 286 | *command = rcmd_commands[i]; |
| | 287 | *sep = RCMD_TOKEN_SEPARATOR; |
| | 288 | return RCMD_ERR_NO_ERROR; |
| | 289 | } |
| | 290 | |
| | 291 | i++; |
| | 292 | } |
| | 293 | |
| | 294 | *sep = RCMD_TOKEN_SEPARATOR; |
| | 295 | return RCMD_ERR_COMMAND_NOT_FOUND; |
| | 296 | } |