/* 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 #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 history_buffer[1024]; 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; 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" "Serial: %08X-%08X-%08X", high_id, mid_id, low_id); 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; enum adc_pt1000_error pt1000_flags; 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) { pt1000_flags = adc_pt1000_check_error(); if (pt1000_flags & ADC_PT1000_INACTIVE) strcat(display_status, " DEACTIVATED "); else if (pt1000_flags & ADC_PT1000_WATCHDOG_ERROR) strcat(display_status, " WATCHDOG "); else if (pt1000_flags & ADC_PT1000_OVERFLOW) strcat(display_status, " OVERFLOW "); } 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_clear_error_status(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { (void)arguments; (void)length; (void)handle; adc_pt1000_clear_error(); 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; shellmatta_printf(handle, "Uptime: %llu secs", global_tick_ms/1000); 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; int32_t delta; rot_val = rotary_encoder_get_abs_val(); delta = rotary_encoder_get_change_val(); shellmatta_printf(handle, "Rotary encoder value: %u, delta: %d\r\n", rot_val, delta); 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_cat(const shellmatta_handle_t handle, const char *arguments, uint32_t length) { FIL file; char path_buff[256]; const char *path; UINT bytes_read; FRESULT res; strncpy(path_buff, arguments, MIN(sizeof(path_buff), length)); path_buff[MIN(length, sizeof(path_buff)-1)] = 0; path = strtok(path_buff, " "); path = strtok(NULL, " "); if (strlen(path) == 0) { shellmatta_printf(handle, "Specify path!\r\n"); return SHELLMATTA_OK; } res = f_open(&file, path, FA_READ); if (res == FR_OK) { shellmatta_write(handle, "\r\n", 2U); do { res = f_read(&file, path_buff, sizeof(path_buff), &bytes_read); if (bytes_read > 0) shellmatta_write(handle, path_buff, bytes_read); else break; } while (res == FR_OK); shellmatta_write(handle, "\r\n", 2U); } if (res != FR_OK) { shellmatta_printf(handle, "Error reading file\r\n"); } f_close(&file); return SHELLMATTA_OK; } //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[13] = { { .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 = "pt1000-clear-error", .cmdAlias = "pt-clear", .helpText = "Clear error status of PT1000 reading", .usageText = NULL, .cmdFct = shell_cmd_clear_error_status, .next = &cmd[4], }, { .cmd = "digio-get", .cmdAlias = "dg", .helpText = "Read all digital input/output ports", .usageText = NULL, .cmdFct = shell_cmd_digio_get, .next = &cmd[5], }, { .cmd = "digio-set", .cmdAlias = "ds", .helpText = "Set DIGIO Port", .usageText = "digio-set ", .cmdFct = shell_cmd_digio_set, .next = &cmd[6], }, { .cmd = "uptime", .cmdAlias = "upt", .helpText = "Get uptime in seconds", .usageText = "", .cmdFct = shell_cmd_uptime, .next = &cmd[7], }, { .cmd = "calibrate", .cmdAlias = "cal", .helpText = "Calibrate resistance measurement", .usageText = "", .cmdFct = shell_cmd_cal, .next = &cmd[8], }, { .cmd = "meminfo", .cmdAlias = NULL, .helpText = "Get information about memory usage", .usageText = "", .cmdFct = shell_meminfo, .next = &cmd[9], }, { .cmd = "rotary-encoder", .cmdAlias = "rot", .helpText = "Get current rotary encoder value", .usageText = "", .cmdFct = shell_cmd_rot, .next = &cmd[10], }, { .cmd = "ls", .cmdAlias = NULL, .helpText = "List filesystem contents", .usageText = "", .cmdFct = shell_cmd_ls, .next = &cmd[11], }, { .cmd = "reset", .cmdAlias = NULL, .helpText = "Reset controller", .usageText = "reset", .cmdFct = shell_cmd_reset, .next = &cmd[12], }, { .cmd = "cat", .cmdAlias = NULL, .helpText = "Print file contents", .usageText = "cat ", .cmdFct = shell_cmd_cat, .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)); }