/* Reflow Oven Controller * * Copyright (C) 2020 Mario Hüttel * * This file is part of the Reflow Oven Controller Project. * * The reflow oven controller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * The Reflow Oven Control Firmware is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with the reflow oven controller project. * If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef GIT_VER #define GIT_VER "VERSION NOT SET" #endif extern struct stm_uart shell_uart; static shellmatta_instance_t shell; static char shell_buffer[512]; static char IN_SECTION(.ccm.bss) history_buffer[512]; static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)arguments; (void)length; uint32_t low_id; uint32_t mid_id; uint32_t high_id; const char *hw_rev_str; enum hw_revision pcb_rev; unique_id_get(&high_id, &mid_id, &low_id); shellmatta_printf(handle, "Reflow Oven Controller Firmware " xstr(GIT_VER) "\r\n" "Compiled: " __DATE__ " at " __TIME__ "\r\n"); shellmatta_printf(handle, "Serial: %08X-%08X-%08X\r\n", high_id, mid_id, low_id); pcb_rev = get_pcb_hardware_version(); switch (pcb_rev) { case HW_REV_V1_2: hw_rev_str = "Hardware: v1.2"; break; case HW_REV_V1_3: hw_rev_str = "Hardware: v1.3"; break; default: hw_rev_str = "Hardware: Unknown Revision. You might have to update the firmware!"; break; } shellmatta_printf(handle, "%s", hw_rev_str); return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_digio_get(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)arguments; (void)length; shellmatta_printf(handle, "DIGIO0 DIGIO1 DIGIO2 DIGIO3 LED0 LED1 LS\r\n" "%d %d %d %d %d %d %d\r\n", digio_get(0), digio_get(1), digio_get(2), digio_get(3), led_get(0), led_get(1), loudspeaker_get()); return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_digio_set(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)length; (void)handle; int num = 100; int state; char buff[64]; char *curr_token; strncpy(buff, arguments, sizeof(buff)-1); buff[63] = '\0'; curr_token = strtok(buff, " "); curr_token = strtok(NULL, " "); if (!curr_token) return SHELLMATTA_ERROR; num = atoi(curr_token); if (!curr_token) return SHELLMATTA_ERROR; curr_token = strtok(NULL, " "); state = atoi(curr_token); if (num < 4 && num >= 0) digio_set(num, state); else if (num >= 4 && num <= 5) led_set(num - 4, state); else if (num == 6) loudspeaker_set(state); else return SHELLMATTA_ERROR; return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_pt1000_res(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)arguments; (void)length; float resistance; int pt1000_status; char display_status[100]; float temp; int temp_conv_status; const char *temp_prefix; display_status[0] = 0; pt1000_status = adc_pt1000_get_current_resistance(&resistance); if (pt1000_status == 2) { strcat(display_status, "UNSTABLE"); } else if (pt1000_status) { strcpy(display_status, "ERROR"); } else { strcpy(display_status, "VALID"); } temp_conv_status = temp_converter_convert_resistance_to_temp(resistance, &temp); switch (temp_conv_status) { case 1: temp_prefix = ">"; break; case -1: temp_prefix = "<"; break; case 0: /* FALLTHRU */ default: temp_prefix = ""; break; } shellmatta_printf(handle, "PT1000 resistance: %.2f Ohm (%s%.1f °C) [%s]\r\n", resistance, temp_prefix,temp, display_status); return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_uptime(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)arguments; (void)length; uint32_t days; uint32_t hours; uint32_t mins; uint32_t secs; systick_get_uptime_from_tick(&days, &hours, &mins, &secs); shellmatta_printf(handle, "Uptime: %u day%s %02u:%02u:%02u", days, (days == 1 ? "" : "s"), hours, mins, secs); return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_cal(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)arguments; (void)length; return calibration_sequence_shell_cmd(handle, arguments, length); } static shellmatta_retCode_t shell_meminfo(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)arguments; (void)length; struct mallinfo mi; shellmatta_printf(handle, "Stack pointer: %p\r\n" "Stack usage: 0x%x bytes\r\n" "Lim to heap: 0x%x bytes\r\n", read_stack_pointer(), stack_check_get_usage(), stack_check_get_free()); mi = mallinfo(); shellmatta_printf(handle, "\r\nDynamic Memory Management\r\n"); shellmatta_printf(handle, "Allocated bytes: %d\r\n", mi.arena, mi.arena); shellmatta_printf(handle, "Number of free chunks: %d\r\n", mi.ordblks); shellmatta_printf(handle, "Top-most, releasable space: %d\r\n", mi.keepcost); shellmatta_printf(handle, "Total free space: %d\r\n", mi.fordblks); shellmatta_printf(handle, "Total allocated space: %d\r\n", mi.uordblks); return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_rot(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)arguments; (void)length; uint32_t rot_val; rot_val = rotary_encoder_get_abs_val(); //delta = rotary_encoder_get_change_val(); shellmatta_printf(handle, "Rotary encoder value: %u\r\n", rot_val); return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_pt1000_res_loop(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)arguments; (void)length; static uint64_t timestamp = 0ULL; if (systick_ticks_have_passed(timestamp, 150)) { shell_cmd_pt1000_res(handle, "", 0UL); timestamp = systick_get_global_tick(); } return SHELLMATTA_CONTINUE; } static shellmatta_retCode_t shell_cmd_ls(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)length; (void)arguments; DIR dir; FRESULT res; FILINFO fno; res = f_opendir(&dir, "/"); if (res != FR_OK) { shellmatta_printf(handle, "Filesystem inaccessible. Is an SD Card inserted?\r\n"); return SHELLMATTA_OK; } while (f_readdir(&dir, &fno) == FR_OK) { if (fno.fname[0] == 0) break; shellmatta_printf(handle, "%c\t%s\r\n", (fno.fattrib & AM_DIR ? 'd' : 'f'), fno.fname); } f_closedir(&dir); return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_reset(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)handle; (void)length; (void)arguments; NVIC_SystemReset(); return SHELLMATTA_BUSY; } static shellmatta_retCode_t shell_cmd_read_flags(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)length; (void)arguments; uint32_t count; uint32_t i; char name[64]; bool flag; bool tryack = false; int status; enum safety_flag flag_enum; struct analog_monitor_info amon_info; struct timing_monitor_info timing_info; char *argument; uint32_t len; char option; shellmatta_retCode_t opt_ret; static const shellmatta_opt_long_t options[] = { {"ack", 'a', SHELLMATTA_OPT_ARG_NONE}, {NULL, '\0', SHELLMATTA_OPT_ARG_NONE} }; do { opt_ret = shellmatta_opt_long(handle, options, &option, &argument, &len); if (opt_ret != SHELLMATTA_OK) { break; } switch (option) { case 'a': tryack = true; break; default: break; } } while(1); shellmatta_printf(handle, "Error Flags\r\n" "-----------\r\n"); count = safety_controller_get_flag_count(); for (i = 0; i < count; i++) { status = safety_controller_get_flag_name_by_index(i, name, sizeof(name)); if (status) { shellmatta_printf(handle, "Error getting flag name %lu\r\n", i); continue; } status = safety_controller_get_flag_by_index(i, &flag, &flag_enum); if (status) { shellmatta_printf(handle, "Error getting flag value %lu\r\n", i); continue; } if (tryack) safety_controller_ack_flag(flag_enum); shellmatta_printf(handle, "\t%2lu) %-20s\t[%s]\r\n", i+1, name, (flag ? "\e[1;31mERR\e[m" : "\e[32mOK\e[m")); } shellmatta_printf(handle, "\r\nAnalog Monitors\r\n" "---------------\r\n"); count = safety_controller_get_analog_monitor_count(); for (i = 0; i < count; i++) { status = safety_controller_get_analog_mon_name_by_index(i, name, sizeof(name)); if (status) { shellmatta_printf(handle, "Error getting analog value monitor %lu name\r\n", i); continue; } status = safety_controller_get_analog_mon_by_index(i, &amon_info); if (status) { shellmatta_printf(handle, "Error reading analog monitor status %lu\r\n", i); continue; } shellmatta_printf(handle, "\t%2lu) %-20s\t[%s%8.2f%s]", i+1, name, amon_info.status == ANALOG_MONITOR_OK ? "\e[32m" : "\e[1;31m", amon_info.value, "\e[m"); if (amon_info.status == ANALOG_MONITOR_INACTIVE) { shellmatta_printf(handle, "Inactive\r\n"); } else { shellmatta_printf(handle, " valid from %-8.2f to %-8.2f", amon_info.min, amon_info.max); shellmatta_printf(handle, "\tchecked %llu ms ago\r\n", systick_get_global_tick() - amon_info.timestamp); } } shellmatta_printf(handle, "\r\nTiming Monitors\r\n" "---------------\r\n"); count = safety_controller_get_timing_monitor_count(); for (i = 0; i < count; i++) { (void)safety_controller_get_timing_mon_by_index(i, &timing_info); (void)safety_controller_get_timing_mon_name_by_index(i, name, sizeof(name)); shellmatta_printf(handle, "\t%2lu) %-20s\t", i+1, name); if (timing_info.enabled) shellmatta_printf(handle, "last tick: %lu ms\r\n", (unsigned long int)timing_info.delta); else shellmatta_printf(handle, "\e[1;31mDISABLED\e[m\r\n"); } return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_save_cal(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)length; (void)arguments; int res; float offset, sens_dev; bool active; adc_pt1000_get_resistance_calibration(&offset, &sens_dev, &active); res = settings_save_calibration(sens_dev, offset, active); if (res) { shellmatta_printf(handle, "Error saving %d\r\n", res); } else { shellmatta_printf(handle, "Saved!\r\n"); } return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_hang(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)handle; (void)arguments; (void)length; while (1337); return SHELLMATTA_OK; } static shellmatta_retCode_t shell_cmd_ui_emulation(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)length; (void)arguments; uint32_t i; uint32_t len; char *buff; shellmatta_read(handle, &buff, &len); for (i = 0; i < len; i++) { switch (buff[i]) { case 'W': case 'w': rotary_encoder_override_delta(4); break; case 's': case 'S': rotary_encoder_override_delta(-4); break; case '\r': button_override_event(BUTTON_SHORT_RELEASED); break; case 'l': case 'L': button_override_event(BUTTON_LONG); break; case 'k': case 'K': button_override_event(BUTTON_SHORT); break; case 'r': case 'R': button_override_event(BUTTON_LONG_RELEASED); break; } } return SHELLMATTA_CONTINUE; } static shellmatta_retCode_t shell_cmd_panic(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)handle; (void)arguments; (void)length; panic_mode(); return SHELLMATTA_OK; } static char *get_safety_mem_dump(size_t *used_bytes) { char *buffer; int res; buffer = (char *)malloc(5470); res = safety_memory_dump_base64(buffer, 5470UL, used_bytes); if (res) { if (buffer) free(buffer); buffer = NULL; } return buffer; } static shellmatta_retCode_t shell_cmd_dump_safety_mem(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { static char *buffer; static const char *ptr; size_t used_bytes; static size_t full_lines = 0; static size_t current_line; size_t remainder; static const char *hline = "----------------------------------------------------------------"; char string[200]; const char *token; const char * const token_delim = "\t "; FRESULT fres; FIL file; UINT bw; /* Check if the dump shall be stored to disk */ strncpy(string, arguments, MIN(sizeof(string), length+1)); string[sizeof(string) - 1] = '\0'; token = strtok(string, token_delim); token = strtok(NULL, token_delim); if (token) { buffer = get_safety_mem_dump(&used_bytes); if (!buffer) { shellmatta_printf(handle, "Error generating dump"); return SHELLMATTA_OK; } fres = f_open(&file, token, FA_CREATE_NEW | FA_WRITE); if (fres == FR_EXIST) { free(buffer); shellmatta_printf(handle, "File already esists!\r\n"); return SHELLMATTA_OK; } else if (fres != FR_OK) { free(buffer); shellmatta_printf(handle, "Error opening file %s\r\n", token); return SHELLMATTA_OK; } fres = f_write(&file, buffer, used_bytes - 1, &bw); if (fres != FR_OK) { shellmatta_printf(handle, "Error writing to file %s\r\n", token); } free(buffer); f_close(&file); return SHELLMATTA_OK; } if (full_lines == 0) { shellmatta_printf(handle, "Safety memory content\r\n%s\r\n", hline); buffer = get_safety_mem_dump(&used_bytes); if (!buffer) { shellmatta_printf(handle, "Error dumping memory!\r\n"); return SHELLMATTA_OK; } full_lines = (used_bytes - 1) / 64; remainder = (used_bytes - 1) % 64; if (remainder) full_lines++; ptr = buffer; current_line = 0; return SHELLMATTA_BUSY; } else { if (current_line < full_lines) { shellmatta_printf(handle, "%.64s\r\n", ptr); ptr += 64; current_line++; } else { shellmatta_printf(handle, "%s\r\n", hline); full_lines = 0; if (buffer) free(buffer); buffer = NULL; return SHELLMATTA_OK; } } return SHELLMATTA_BUSY; } shellmatta_retCode_t shell_cmd_reset_cal(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)handle; (void)arguments; (void)length; adc_pt1000_set_resistance_calibration(0.0f, 0.0f, false); return SHELLMATTA_OK; } shellmatta_retCode_t shell_cmd_update(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)handle; (void)arguments; (void)length; shellmatta_retCode_t opt_stat; char option; char *argument; uint32_t arg_len; const char *update_file = NULL; const shellmatta_opt_long_t options[] = { {NULL, '\0', SHELLMATTA_OPT_ARG_NONE}, }; while (1) { opt_stat = shellmatta_opt_long(handle, options, &option, &argument, &arg_len); if (opt_stat != SHELLMATTA_OK) break; switch (option) { case '\0': update_file = argument; break; default: break; } } if (!update_file || !strlen(update_file)) { shellmatta_printf(handle, "Please specify a valid update file!\r\n"); return SHELLMATTA_ERROR; } updater_update_from_file(update_file); return SHELLMATTA_OK; } shellmatta_retCode_t shell_cmd_overtemp_cfg(const shellmatta_handle_t handle, const char *args, uint32_t len) { float overtemp_lim; shellmatta_retCode_t ret; char *argument; uint32_t arg_length; char option; bool temp_passed = false; bool persistent = false; (void)args; (void)len; static const shellmatta_opt_long_t options[] = { {"persistent", 'p', SHELLMATTA_OPT_ARG_NONE}, {NULL, '\0', SHELLMATTA_OPT_ARG_NONE}, }; do { ret = shellmatta_opt_long(handle, options, &option, &argument, &arg_length); if (ret != SHELLMATTA_OK) break; switch (option) { case 'p': persistent = true; break; case '\0': temp_passed = true; overtemp_lim = strtof(argument, NULL); break; } } while (1); if (temp_passed) { safety_controller_set_overtemp_limit(overtemp_lim); if (persistent) settings_save_overtemp_limit(overtemp_lim, true); } overtemp_lim = safety_controller_get_overtemp_limit(); shellmatta_printf(handle, "Overtemperature configured for: %.1f °C\r\n", overtemp_lim); return ret; } shellmatta_retCode_t shell_cmd_execute(const shellmatta_handle_t handle, const char *args, uint32_t len) { enum pl_ret_val res; const struct tpe_current_state *state; static bool running = false; char *data; uint32_t dlen; (void)args; (void)len; int opt_stat; char option; char *argument; uint32_t arg_len; const char *script_name = NULL; const shellmatta_opt_long_t options[] = { {NULL, '\0', SHELLMATTA_OPT_ARG_NONE}, }; while (1) { opt_stat = shellmatta_opt_long(handle, options, &option, &argument, &arg_len); if (opt_stat != SHELLMATTA_OK) break; switch (option) { case '\0': script_name = argument; break; default: break; } } if (!script_name) { shellmatta_printf(handle, "No script name specified!\r\n"); return SHELLMATTA_ERROR; } shellmatta_read(handle, &data, &dlen); if (!running) { res = temp_profile_executer_start(script_name); if (res != PL_RET_SUCCESS) { switch (res) { case PL_RET_DISK_ERR: shellmatta_printf(handle, "Error reading file\r\n"); break; case PL_RET_LIST_FULL: shellmatta_printf(handle, "Script too long!\r\n"); break; case PL_RET_SCRIPT_ERR: shellmatta_printf(handle, "Error in script\r\n"); break; default: shellmatta_printf(handle, "Unspecified error occured\r\n"); break; } return SHELLMATTA_ERROR; } running = true; } else { state = temp_profile_executer_status(); if (state->status != TPE_RUNNING) { shellmatta_printf(handle, "Profile executed.\r\n"); running = false; if(state->status == TPE_ABORT) { shellmatta_printf(handle, "Profile execution aborted!\r\n"); } return SHELLMATTA_OK; } if (dlen > 0 && *data == '\x03') { temp_profile_executer_stop(); running = false; return SHELLMATTA_OK; } } return SHELLMATTA_CONTINUE; } shellmatta_retCode_t shell_cmd_cycle_count(const shellmatta_handle_t handle, const char *args, uint32_t len) { uint64_t counter; (void)args; (void)len; char option; char *argument; uint32_t arg_len; int opt_stat; bool clear = false; const shellmatta_opt_long_t options[] = { {"clear", 'c', SHELLMATTA_OPT_ARG_NONE}, {NULL, '\0', SHELLMATTA_OPT_ARG_NONE}, }; while (1) { opt_stat = shellmatta_opt_long(handle, options, &option, &argument, &arg_len); if (opt_stat != SHELLMATTA_OK) break; switch (option) { case 'c': clear = true; break; default: break; } } counter = main_cycle_counter_get(); shellmatta_printf(handle, "%"PRIu64"\r\n", counter); if (clear) main_cycle_counter_init(); return SHELLMATTA_OK; } shellmatta_retCode_t shell_cmd_filter_alpha(const shellmatta_handle_t handle, const char *args, uint32_t len) { shellmatta_retCode_t opt_stat; char option; char *argument; uint32_t arg_len; char *alpha_string = NULL; float alpha; (void)len; (void)args; const shellmatta_opt_long_t options[] = { {NULL, '\0', SHELLMATTA_OPT_ARG_NONE}, }; while (1) { opt_stat = shellmatta_opt_long(handle, options, &option, &argument, &arg_len); if (opt_stat != SHELLMATTA_OK) break; switch (option) { case '\0': alpha_string = argument; break; default: break; } } if (!alpha_string) { shellmatta_printf(handle, "Specify filter value!\r\n"); return SHELLMATTA_OK; } alpha = strtof(alpha_string, NULL); if (alpha < 0.0f || alpha == 0.0f || alpha > 0.9f) { shellmatta_printf(handle, "Filter param outside of valid range!\r\n"); return SHELLMATTA_OK; } adc_pt1000_set_moving_average_filter_param(alpha); shellmatta_printf(handle, "Filter param set to %f\r\n", alpha); return SHELLMATTA_OK; } #if 0 shellmatta_retCode_t shell_cmd_hf_stream(const shellmatta_handle_t handle, const char *args, uint32_t len) { float *data1; volatile int flag; FRESULT fres; char *strbuff; FIL f; const size_t buff_size = 2000UL; uint32_t idx; uint32_t blocks; uint32_t remainder; int cnt; UINT bw; data1 = (float *)malloc(buff_size*sizeof(float)); strbuff = (char *)malloc(1024); if (!data1 || !strbuff) { shellmatta_printf(handle, "Allocating memory failed!\r\n"); goto free_data; } fres = f_open(&f, "pt1000_hf.dat", FA_CREATE_ALWAYS | FA_WRITE); if (fres != FR_OK) { shellmatta_printf(handle, "Cannot open file.\r\n"); goto free_data; } shellmatta_printf(handle, "Acquire data...\r\n"); flag = 0; adc_pt1000_stream_raw_value_to_memory(data1, buff_size, &flag); while (!flag) { safety_controller_handle(); } shellmatta_printf(handle, "Finished. Writing file...\r\n"); blocks = buff_size / 10UL; remainder = buff_size % 10UL; for (idx = 0; idx < blocks; idx++) { cnt = snprintf(strbuff, 1024, "%.2f\n%.2f\n%.2f\n%.2f\n%.2f\n%.2f\n%.2f\n%.2f\n%.2f\n%.2f\n", data1[idx * 10+0], data1[idx * 10+1], data1[idx * 10+2], data1[idx * 10+3], data1[idx * 10+4], data1[idx * 10+5], data1[idx * 10+6], data1[idx * 10+7], data1[idx * 10+8], data1[idx * 10+9]); f_write(&f, strbuff, (UINT)cnt, &bw); safety_controller_handle(); } for (idx = 0; idx < remainder; idx++) { cnt = snprintf(strbuff, 1024, "%.2f\n", data1[blocks * 10 + idx]); f_write(&f, strbuff, (UINT)cnt, &bw); } f_close(&f); shellmatta_printf(handle, "Completed!\r\n"); free_data: if (data1) free(data1); if (strbuff) free(strbuff); return SHELLMATTA_OK; } #endif //typedef struct shellmatta_cmd //{ // char *cmd; /**< command name */ // char *cmdAlias; /**< command alias */ // char *helpText; /**< help text to print in "help" command */ // char *usageText; /**< usage text to print on parameter error */ // shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */ // struct shellmatta_cmd *next; /**< pointer to next command or NULL */ //} shellmatta_cmd_t; static shellmatta_cmd_t cmd[24] = { { .cmd = "version", .cmdAlias = "ver", .helpText = "Print firmware version", .usageText = NULL, .cmdFct = shell_cmd_ver, .next = &cmd[1], }, { .cmd = "pt1000", .cmdAlias = "pt", .helpText = "Get current filtered and calibrated PT1000 resistance", .usageText = NULL, .cmdFct = shell_cmd_pt1000_res, .next = &cmd[2], }, { .cmd = "pt1000-dump", .cmdAlias = "ptdump", .helpText = "Get current filtered and calibrated PT1000 resistance in a loop", .usageText = "pt1000-dump", .cmdFct = shell_cmd_pt1000_res_loop, .next = &cmd[3], }, { .cmd = "digio-get", .cmdAlias = "dg", .helpText = "Read all digital input/output ports", .usageText = NULL, .cmdFct = shell_cmd_digio_get, .next = &cmd[4], }, { .cmd = "digio-set", .cmdAlias = "ds", .helpText = "Set DIGIO Port", .usageText = "digio-set ", .cmdFct = shell_cmd_digio_set, .next = &cmd[5], }, { .cmd = "uptime", .cmdAlias = "upt", .helpText = "Get uptime in seconds", .usageText = "", .cmdFct = shell_cmd_uptime, .next = &cmd[6], }, { .cmd = "calibrate", .cmdAlias = "cal", .helpText = "Calibrate resistance measurement", .usageText = "", .cmdFct = shell_cmd_cal, .next = &cmd[7], }, { .cmd = "meminfo", .cmdAlias = NULL, .helpText = "Get information about memory usage", .usageText = "", .cmdFct = shell_meminfo, .next = &cmd[8], }, { .cmd = "rotary-encoder", .cmdAlias = "rot", .helpText = "Get current rotary encoder value", .usageText = "", .cmdFct = shell_cmd_rot, .next = &cmd[9], }, { .cmd = "ls", .cmdAlias = NULL, .helpText = "List filesystem contents", .usageText = "", .cmdFct = shell_cmd_ls, .next = &cmd[10], }, { .cmd = "reset", .cmdAlias = NULL, .helpText = "Reset controller", .usageText = "reset", .cmdFct = shell_cmd_reset, .next = &cmd[11], }, { .cmd = "safety-flags", .cmdAlias = "flags", .helpText = "Reads and may clear safety flags", .usageText = "flags [--ack]", .cmdFct = shell_cmd_read_flags, .next = &cmd[12], }, { .cmd = "save-calibration", .cmdAlias = "save-cal", .helpText = "Permanently save the calibration to EEPROM", .usageText = "", .cmdFct = shell_cmd_save_cal, .next = &cmd[13], }, { .cmd = "hang", .cmdAlias = NULL, .helpText = "", .usageText = "", .cmdFct = shell_cmd_hang, .next = &cmd[14], }, { .cmd = "ui-emulate", .cmdAlias = NULL, .helpText = "", .usageText = "", .cmdFct = shell_cmd_ui_emulation, .next = &cmd[15], }, { .cmd = "panic", .cmdAlias = NULL, .helpText = "Panic Mode!", .usageText = "", .cmdFct = shell_cmd_panic, .next = &cmd[16], }, { .cmd = "safety-mem-dump", .cmdAlias = NULL, .helpText = "", .usageText = "safety-mem-dump [output-file]", .cmdFct = shell_cmd_dump_safety_mem, .next = &cmd[17], }, { .cmd = "reset-cal", .cmdAlias = NULL, .helpText = "Reset Calibration", .usageText = "", .cmdFct = shell_cmd_reset_cal, .next = &cmd[18], }, { .cmd = "update", .cmdAlias = NULL, .helpText = "Update Firmware from HEX file", .usageText = "update ", .cmdFct = shell_cmd_update, .next = &cmd[19], }, { .cmd = "overtemp", .cmdAlias = NULL, .helpText = "Overtemperature Config", .usageText = "", .cmdFct = shell_cmd_overtemp_cfg, .next = &cmd[20], }, { .cmd = "execute", .cmdAlias = NULL, .helpText = "Execute Temp Profile", .usageText = "execute /path/to/script.tpr", .cmdFct = shell_cmd_execute, .next = &cmd[21], }, { .cmd = "cyclecount", .cmdAlias = "cc", .helpText = "Print out the cycle counter of the main loop", .usageText = "cyclecount [--clear]", .cmdFct = shell_cmd_cycle_count, .next = &cmd[22], }, { .cmd = "filter-alpha", .cmdAlias = "alpha", .helpText = "Sets the filter constant", .usageText = "filter-alpha ", .cmdFct = shell_cmd_filter_alpha, .next = NULL, } }; shellmatta_handle_t shell_init(shellmatta_write_t write_func) { shellmatta_handle_t handle; shellmatta_retCode_t ret; ret = shellmatta_doInit(&shell, &handle, shell_buffer, sizeof(shell_buffer), history_buffer, sizeof(history_buffer), "\e[1;32mReflow Controller>\e[m ", cmd, write_func); if (ret != SHELLMATTA_OK) handle = NULL; return handle; } void shell_print_motd(shellmatta_handle_t shell) { /* Clear display and set cursor to home position */ shellmatta_printf(shell, "\e[2J\e[H"); shellmatta_printf(shell, "Shimatta Reflow Controller ready\r\n\r\n"); shell_cmd_ver(shell, NULL, 0UL); shell_handle_input(shell, "\r\n", 2UL); } void shell_handle_input(shellmatta_handle_t shell, const char *data, size_t len) { if (!shell) return; shellmatta_processData(shell, (char *)data, (uint32_t)len); } void shell_print_string(shellmatta_handle_t shell, const char *string) { if (!shell) return; shellmatta_write(shell, (char *)string, strlen(string)); }