diff --git a/firmware/.vscode/c_cpp_properties.json b/firmware/.vscode/c_cpp_properties.json index b0931cd..2b6970c 100644 --- a/firmware/.vscode/c_cpp_properties.json +++ b/firmware/.vscode/c_cpp_properties.json @@ -20,7 +20,8 @@ "UNICODE", "_UNICODE", "STM32F303xE", - "USE_HAL_DRIVER" + "USE_HAL_DRIVER", + "ULOG_ENABLED" ], "compilerPath": "C:/MyApps/arm-gcc/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc.exe", "cStandard": "c11", diff --git a/firmware/.vscode/launch.json b/firmware/.vscode/launch.json index 3189b99..ae12e0f 100644 --- a/firmware/.vscode/launch.json +++ b/firmware/.vscode/launch.json @@ -27,36 +27,36 @@ "type": "console", "timestamp": true }, - { - "label": "RTT graph", - "port": 0, - "encoding": "unsigned", - "graphId": "1", - "scale": 1 - } + // { + // "label": "RTT graph", + // "port": 0, + // "encoding": "unsigned", + // "graphId": "1", + // "scale": 1 + // } ] }, - "graphConfig": [ - { - "label": "Graph 1", - "type": "realtime", - "minimum": 0, - "maximum": 65535, - "timespan": 30, - "plots": [ - { - "graphId": "1", - "label": "data 1", - "color": "#53753c", - }, - { - "graphId": "2", - "label": "data 2", - "color": "#955f20" - } - ] - } - ] + // "graphConfig": [ + // { + // "label": "Graph 1", + // "type": "realtime", + // "minimum": 0, + // "maximum": 65535, + // "timespan": 30, + // "plots": [ + // { + // "graphId": "1", + // "label": "data 1", + // "color": "#53753c", + // }, + // { + // "graphId": "2", + // "label": "data 2", + // "color": "#955f20" + // } + // ] + // } + // ] } ] } \ No newline at end of file diff --git a/firmware/.vscode/settings.json b/firmware/.vscode/settings.json index c36b291..eed5eb5 100644 --- a/firmware/.vscode/settings.json +++ b/firmware/.vscode/settings.json @@ -14,6 +14,7 @@ "disp_layout_template.h": "c", "disp_layout_types.h": "c", "ctrl_app_types.h": "c", - "tim.h": "c" + "tim.h": "c", + "ulog.h": "c" } } \ No newline at end of file diff --git a/firmware/func_gen_stm32f303re_nucleo/Core/Inc/main.h b/firmware/func_gen_stm32f303re_nucleo/Core/Inc/main.h index cb9931c..3aab5bd 100644 --- a/firmware/func_gen_stm32f303re_nucleo/Core/Inc/main.h +++ b/firmware/func_gen_stm32f303re_nucleo/Core/Inc/main.h @@ -1,21 +1,21 @@ /* USER CODE BEGIN Header */ /** - ****************************************************************************** - * @file : main.h - * @brief : Header for main.c file. - * This file contains the common defines of the application. - ****************************************************************************** - * @attention - * - * Copyright (c) 2023 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + * Copyright (c) 2023 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ @@ -23,7 +23,8 @@ #define __MAIN_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif /* Includes ------------------------------------------------------------------*/ @@ -31,26 +32,27 @@ extern "C" { /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ +// #include "SEGGER_RTT.h" +#include "ulog.h" + /* USER CODE END Includes */ -/* USER CODE END Includes */ + /* Exported types ------------------------------------------------------------*/ + /* USER CODE BEGIN ET */ -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ + /* USER CODE END ET */ -/* USER CODE END ET */ + /* Exported constants --------------------------------------------------------*/ + /* USER CODE BEGIN EC */ -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ + /* USER CODE END EC */ -/* USER CODE END EC */ + /* Exported macro ------------------------------------------------------------*/ + /* USER CODE BEGIN EM */ -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ + /* USER CODE END EM */ -/* USER CODE END EM */ - -/* Exported functions prototypes ---------------------------------------------*/ -void Error_Handler(void); + /* Exported functions prototypes ---------------------------------------------*/ + void Error_Handler(void); /* USER CODE BEGIN EFP */ @@ -91,9 +93,9 @@ void Error_Handler(void); #define ST7565_A0_GPIO_Port GPIOD #define SWO_Pin GPIO_PIN_3 #define SWO_GPIO_Port GPIOB -/* USER CODE BEGIN Private defines */ + /* USER CODE BEGIN Private defines */ -/* USER CODE END Private defines */ + /* USER CODE END Private defines */ #ifdef __cplusplus } diff --git a/firmware/func_gen_stm32f303re_nucleo/Core/Src/main.c b/firmware/func_gen_stm32f303re_nucleo/Core/Src/main.c index b48f5e0..c3e49e8 100644 --- a/firmware/func_gen_stm32f303re_nucleo/Core/Src/main.c +++ b/firmware/func_gen_stm32f303re_nucleo/Core/Src/main.c @@ -30,6 +30,7 @@ #include "display_gfx.h" #include "disp_layout.h" #include "st7565.h" +#include "SEGGER_RTT.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -57,7 +58,7 @@ APP_data_t app_data; /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ - +void RTT_console_logger(ulog_level_t severity, char *msg); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ @@ -66,41 +67,47 @@ void SystemClock_Config(void); /* USER CODE END 0 */ /** - * @brief The application entry point. - * @retval int - */ + * @brief The application entry point. + * @retval int + */ int main(void) { - /* USER CODE BEGIN 1 */ + /* USER CODE BEGIN 1 */ - /* USER CODE END 1 */ + /* USER CODE END 1 */ - /* MCU Configuration--------------------------------------------------------*/ + /* MCU Configuration--------------------------------------------------------*/ - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ - HAL_Init(); + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + HAL_Init(); - /* USER CODE BEGIN Init */ + /* USER CODE BEGIN Init */ - /* USER CODE END Init */ + /* USER CODE END Init */ - /* Configure the system clock */ - SystemClock_Config(); + /* Configure the system clock */ + SystemClock_Config(); - /* USER CODE BEGIN SysInit */ + /* USER CODE BEGIN SysInit */ - /* USER CODE END SysInit */ + /* USER CODE END SysInit */ + + /* Initialize all configured peripherals */ + MX_GPIO_Init(); + MX_USART2_UART_Init(); + MX_SPI2_Init(); + MX_I2C1_Init(); + MX_SPI3_Init(); + MX_TIM2_Init(); + MX_TIM3_Init(); + /* USER CODE BEGIN 2 */ + ulog_init(); + ulog_subscribe(RTT_console_logger, ULOG_DEBUG_LEVEL); - /* Initialize all configured peripherals */ - MX_GPIO_Init(); - MX_USART2_UART_Init(); - MX_SPI2_Init(); - MX_I2C1_Init(); - MX_SPI3_Init(); - MX_TIM2_Init(); - MX_TIM3_Init(); - /* USER CODE BEGIN 2 */ APP_init(&app_data); + HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL); + // SEGGER_RTT_WriteString(0, "App start...\n"); + ULOG_INFO("start app..."); hst7565.hspi = &hspi3; hst7565.cs_port = ST7565_CS_GPIO_Port; @@ -111,10 +118,10 @@ int main(void) hst7565.rst_pin = ST7565_RST_Pin; ST7565_Init(&hst7565, &disp); - /* USER CODE END 2 */ + /* USER CODE END 2 */ - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ DISP_clearScreen(&disp); ST7565_DisplayAll(&hst7565); @@ -128,95 +135,99 @@ int main(void) ST7565_DisplayAll(&hst7565); LAY_drawDisplayLayout(&disp, &app_data); } - /* USER CODE END WHILE */ + /* USER CODE END WHILE */ - /* USER CODE BEGIN 3 */ + /* USER CODE BEGIN 3 */ } - /* USER CODE END 3 */ + /* USER CODE END 3 */ } /** - * @brief System Clock Configuration - * @retval None - */ + * @brief System Clock Configuration + * @retval None + */ void SystemClock_Config(void) { - RCC_OscInitTypeDef RCC_OscInitStruct = {0}; - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; - /** Initializes the RCC Oscillators according to the specified parameters - * in the RCC_OscInitTypeDef structure. - */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; - RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; - RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - Error_Handler(); - } + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; + RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; + RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } - /** Initializes the CPU, AHB and APB buses clocks - */ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK - |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) - { - Error_Handler(); - } - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2|RCC_PERIPHCLK_I2C1 - |RCC_PERIPHCLK_TIM2|RCC_PERIPHCLK_TIM34; - PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1; - PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI; - PeriphClkInit.Tim2ClockSelection = RCC_TIM2CLK_HCLK; - PeriphClkInit.Tim34ClockSelection = RCC_TIM34CLK_HCLK; - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) - { - Error_Handler(); - } + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) + { + Error_Handler(); + } + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2 | RCC_PERIPHCLK_I2C1 | RCC_PERIPHCLK_TIM2 | RCC_PERIPHCLK_TIM34; + PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1; + PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI; + PeriphClkInit.Tim2ClockSelection = RCC_TIM2CLK_HCLK; + PeriphClkInit.Tim34ClockSelection = RCC_TIM34CLK_HCLK; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) + { + Error_Handler(); + } } /* USER CODE BEGIN 4 */ - +void RTT_console_logger(ulog_level_t severity, char *msg) +{ + SEGGER_RTT_printf(0, "[%s]: %s\n", + // HAL_GetTick(), // user defined function + ulog_level_name(severity), + msg); +} /* USER CODE END 4 */ /** - * @brief This function is executed in case of error occurrence. - * @retval None - */ + * @brief This function is executed in case of error occurrence. + * @retval None + */ void Error_Handler(void) { - /* USER CODE BEGIN Error_Handler_Debug */ + /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } - /* USER CODE END Error_Handler_Debug */ + /* USER CODE END Error_Handler_Debug */ } -#ifdef USE_FULL_ASSERT +#ifdef USE_FULL_ASSERT /** - * @brief Reports the name of the source file and the source line number - * where the assert_param error has occurred. - * @param file: pointer to the source file name - * @param line: assert_param error line source number - * @retval None - */ + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ void assert_failed(uint8_t *file, uint32_t line) { - /* USER CODE BEGIN 6 */ + /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ - /* USER CODE END 6 */ + /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ diff --git a/firmware/func_gen_stm32f303re_nucleo/Makefile b/firmware/func_gen_stm32f303re_nucleo/Makefile index 1718e2f..c5a2606 100644 --- a/firmware/func_gen_stm32f303re_nucleo/Makefile +++ b/firmware/func_gen_stm32f303re_nucleo/Makefile @@ -91,12 +91,15 @@ C_SOURCES += ../shared_libs/disp_layout/disp_layout.c C_SOURCES += ../shared_libs/controllers/ctrl_bottom_button.c C_SOURCES += ../shared_libs/controllers/ctrl_channel_button.c C_SOURCES += ../shared_libs/controllers/ctrl_app.c +C_SOURCES += ../shared_libs/controllers/ctrl_encoder.c # utils/printf C_SOURCES += ../shared_libs/utils/printf/printf.c # utils/rtt C_SOURCES += ../shared_libs/utils/rtt/SEGGER_RTT.c C_SOURCES += ../shared_libs/utils/rtt/SEGGER_RTT_printf.c +# utils/ulog +C_SOURCES += ../shared_libs/utils/ulog/ulog.c # ASM sources ASM_SOURCES = \ @@ -145,7 +148,8 @@ AS_DEFS = # C defines C_DEFS = \ -DUSE_HAL_DRIVER \ --DSTM32F303xE +-DSTM32F303xE \ +-DULOG_ENABLED # AS includes @@ -181,6 +185,7 @@ C_INCLUDES += -I../shared_libs/controllers # utils includes C_INCLUDES += -I../shared_libs/utils/printf C_INCLUDES += -I../shared_libs/utils/rtt +C_INCLUDES += -I../shared_libs/utils/ulog # compile gcc flags diff --git a/firmware/shared_libs/controllers/ctrl_app.c b/firmware/shared_libs/controllers/ctrl_app.c index 3d5cb34..4d76d96 100644 --- a/firmware/shared_libs/controllers/ctrl_app.c +++ b/firmware/shared_libs/controllers/ctrl_app.c @@ -2,18 +2,16 @@ #include "hw_button.h" #include "ctrl_bottom_button.h" #include "ctrl_channel_button.h" +#include "ctrl_encoder.h" #include "ctrl_app.h" -#define FUN_GEN_FOCUS_MAX 6U -#define PWM_GEN_FOCUS_MAX 4U - typedef void (*btn_action_t)(void); typedef struct { - btn_action_t command; - BITMAP_buttonName_t bitmap_name; + btn_action_t command; + BITMAP_buttonName_t bitmap_name; } CMD_button_t; static GEN_fg_t func_gen[3]; @@ -21,382 +19,528 @@ static GEN_pwm_t pwm_gen[3]; static const CMD_button_t btn_command[BTN_STATE_MAX][DISP_BTN_MAX]; static const LAY_dispBtn_t btn_hw_to_disp[BTN_BOT_MAX] = {DISP_BTN_1, DISP_BTN_2, DISP_BTN_3, DISP_BTN_4, DISP_BTN_5}; +static const uint32_t pow_of_10[7] = {1, 10, 100, 1000, 10000, 100000, 1000000}; static HW_BotBtnName_t last_key; static APP_data_t *_app_data; static const GENERATOR_t generators[CHANNEL_MAX] = { - {.gen_type = GEN_FG_TYPE, .gen = &func_gen[0]}, - {.gen_type = GEN_FG_TYPE, .gen = &func_gen[1]}, - {.gen_type = GEN_FG_TYPE, .gen = &func_gen[2]}, - {.gen_type = GEN_PWM_TYPE, .gen = &pwm_gen[0]}, - {.gen_type = GEN_PWM_TYPE, .gen = &pwm_gen[1]}, - {.gen_type = GEN_PWM_TYPE, .gen = &pwm_gen[2]}, + {.gen_type = GEN_FG_TYPE, .gen = &func_gen[0]}, + {.gen_type = GEN_FG_TYPE, .gen = &func_gen[1]}, + {.gen_type = GEN_FG_TYPE, .gen = &func_gen[2]}, + {.gen_type = GEN_PWM_TYPE, .gen = &pwm_gen[0]}, + {.gen_type = GEN_PWM_TYPE, .gen = &pwm_gen[1]}, + {.gen_type = GEN_PWM_TYPE, .gen = &pwm_gen[2]}, }; void APP_init(APP_data_t *app_data) { - _app_data = app_data; - _app_data->freq_focus_digit = 0; - _app_data->ampl_focus_digit = 0; - _app_data->offs_focus_digit = 0; - _app_data->phas_focus_digit = 0; - _app_data->duty_focus_digit = 0; + _app_data = app_data; + _app_data->freq_focus_digit = 4; + _app_data->ampl_focus_digit = 1; + _app_data->offs_focus_digit = 1; + _app_data->phas_focus_digit = 0; + _app_data->duty_focus_digit = 0; - _app_data->curr_gen_type = GEN_FG_TYPE; - _app_data->generator = generators[CHANNEL1].gen; + _app_data->curr_gen_type = GEN_FG_TYPE; + _app_data->generator = generators[CHANNEL1].gen; - _app_data->curr_state_lay = LAY_MAIN; - _app_data->curr_state_btn = BTN_MAIN_FG; + _app_data->curr_state_lay = LAY_MAIN; + _app_data->curr_state_btn = BTN_MAIN_FG; - _app_data->isChannelChange = 1; - _app_data->isGraphChange = 1; - _app_data->isValueChange = 1; - _app_data->isButtonChange = 1; - _app_data->isButtonBlink = 1; + _app_data->isChannelChange = 1; + _app_data->isGraphChange = 1; + _app_data->isValueChange = 1; + _app_data->isButtonChange = 1; + _app_data->isButtonBlink = 1; - CTRL_buttonsInit(); + CTRL_buttonsInit(); } void CTRL_buttonsInit(void) { - CTRL_bottomButtonInit(); - // CTRL_channelButtonInit(); + CTRL_bottomButtonInit(); + // CTRL_channelButtonInit(); } void CTRL_buttonsHandler(void) { - CTRL_bottomButtonsHandler(); - CTRL_channelButtonsHandler(); + CTRL_bottomButtonsHandler(); + CTRL_channelButtonsHandler(); + CTRL_encoderHandler(); } void CTRL_pushedDispBtnEvent(ButtonKey_t *key) { - last_key = btn_hw_to_disp[key->instance]; - btn_command[_app_data->curr_state_btn][last_key].command(); + ULOG_TRACE("Disp btn: %d", key->instance); + last_key = btn_hw_to_disp[key->instance]; + btn_command[_app_data->curr_state_btn][last_key].command(); } void CTRL_pushedChanBtnEvent(ButtonKey_t *key) { - UNUSED(key); + ULOG_TRACE("Chan btn: %d", key->instance); + UNUSED(key); +} + +static void _changeValueFunGen(int8_t dir) +{ + GEN_fg_t *gen = (GEN_fg_t *)_app_data->generator; + + switch (_app_data->curr_state_lay) + { + case LAY_FREQ: + { + uint32_t new_freq = dir * pow_of_10[_app_data->freq_focus_digit] + gen->frequency; + ULOG_DEBUG(" New freq: %lu", new_freq); + if (new_freq > MAX_FREQ) + { + return; + } + gen->frequency = new_freq; + break; + } + case LAY_AMPL: + { + uint16_t new_ampl = dir * pow_of_10[_app_data->ampl_focus_digit] + gen->amplitude; + ULOG_DEBUG(" New ampl: %u", new_ampl); + if (gen->offset + new_ampl > MAX_VOLT_POS || gen->offset - new_ampl < MAX_VOLT_NEG) + { + return; + } + gen->amplitude = new_ampl; + break; + } + case LAY_OFFS: + { + int16_t new_offs = dir * pow_of_10[_app_data->offs_focus_digit] + gen->offset; + ULOG_DEBUG(" New offs: %i", new_offs); + if (new_offs + gen->amplitude > MAX_VOLT_POS || new_offs - gen->amplitude < MAX_VOLT_NEG) + { + return; + } + gen->offset = new_offs; + break; + } + case LAY_PHAS: + { + uint16_t new_phas = dir * pow_of_10[_app_data->phas_focus_digit] + gen->phase; + ULOG_DEBUG(" New phas: %u", new_phas); + if (new_phas > MAX_PHAS) + { + return; + } + gen->phase = new_phas; + break; + } + default: + ULOG_ERROR("%s:%d: Unknown layout: %d", __FILE__, __LINE__, _app_data->curr_state_lay); + break; + } +} + +static void _changeValuePwmGen(int8_t dir) +{ + GEN_pwm_t *gen = (GEN_pwm_t *)_app_data->generator; + + switch (_app_data->curr_state_lay) + { + case LAY_FREQ: + { + uint32_t new_freq = dir * pow_of_10[_app_data->freq_focus_digit] + gen->frequency; + ULOG_DEBUG(" New freq: %lu", new_freq); + if (new_freq > MAX_FREQ) + { + return; + } + gen->frequency = new_freq; + break; + } + case LAY_AMPL: + { + uint16_t new_ampl = dir * pow_of_10[_app_data->ampl_focus_digit] + gen->amplitude; + ULOG_DEBUG(" New ampl: %u", new_ampl); + if (gen->offset + new_ampl > MAX_VOLT_POS || gen->offset - new_ampl < MAX_VOLT_NEG) + { + return; + } + gen->amplitude = new_ampl; + break; + } + case LAY_OFFS: + { + int16_t new_offs = dir * pow_of_10[_app_data->offs_focus_digit] + gen->offset; + ULOG_DEBUG(" New offs: %i", new_offs); + if (new_offs + gen->amplitude > MAX_VOLT_POS || new_offs - gen->amplitude < MAX_VOLT_NEG) + { + return; + } + gen->offset = new_offs; + break; + } + case LAY_PHAS: + { + uint16_t new_phas = dir * pow_of_10[_app_data->phas_focus_digit] + gen->phase; + ULOG_DEBUG(" New phas: %u", new_phas); + if (new_phas > MAX_PHAS) + { + return; + } + gen->phase = new_phas; + break; + } + case LAY_DUTY: + { + uint8_t new_duty = dir * pow_of_10[_app_data->duty_focus_digit] + gen->duty; + ULOG_DEBUG(" New duty: %u", new_duty); + if (new_duty > MAX_DUTY) + { + return; + } + gen->duty = new_duty; + break; + } + default: + break; + } +} + +void CTRL_encoderEvent(int8_t enc) +{ + ULOG_TRACE("Enco event: %i", enc); + switch (_app_data->curr_gen_type) + { + case GEN_FG_TYPE: + _changeValueFunGen(enc / 2); + break; + case GEN_PWM_TYPE: + _changeValuePwmGen(enc / 2); + break; + + default: + ULOG_ERROR("%s:%d: Unknown generator type.", __FILE__, __LINE__); + break; + } + + _app_data->isValueChange = 1; } inline BITMAP_buttonName_t CTRL_getBitmapName(LAY_dispBtn_t disp_btn) { - return btn_command[_app_data->curr_state_btn][disp_btn].bitmap_name; + return btn_command[_app_data->curr_state_btn][disp_btn].bitmap_name; } static void _doNoting(void) { - return; + return; } static void _backToMain(void) { - _app_data->curr_state_lay = LAY_MAIN; + _app_data->curr_state_lay = LAY_MAIN; - switch (_app_data->curr_gen_type) - { - case GEN_FG_TYPE: - _app_data->curr_state_btn = BTN_MAIN_FG; - break; + switch (_app_data->curr_gen_type) + { + case GEN_FG_TYPE: + _app_data->curr_state_btn = BTN_MAIN_FG; + break; - case GEN_PWM_TYPE: - _app_data->curr_state_btn = BTN_MAIN_PWM; - break; + case GEN_PWM_TYPE: + _app_data->curr_state_btn = BTN_MAIN_PWM; + break; - default: - break; - } + default: + break; + } - _app_data->isButtonChange = 1; - _app_data->isGraphChange = 1; - _app_data->isValueChange = 1; - _app_data->isGraphChange = 1; + _app_data->isButtonChange = 1; + _app_data->isGraphChange = 1; + _app_data->isValueChange = 1; + _app_data->isGraphChange = 1; } static void _blockFocusAtMaxAndMin(void) { - switch (_app_data->curr_state_btn) - { - case BTN_FREQ_MIN: - if (_app_data->freq_focus_digit > 0) - { - _app_data->curr_state_btn = BTN_FREQ; - _app_data->isButtonChange = 1; - } - break; - case BTN_FREQ_MAX: - if (_app_data->freq_focus_digit < FUN_GEN_FOCUS_MAX) - { - _app_data->curr_state_btn = BTN_FREQ; - _app_data->isButtonChange = 1; - } - break; - case BTN_FREQ: - if (_app_data->freq_focus_digit == 0) - { - _app_data->curr_state_btn = BTN_FREQ_MIN; - _app_data->isButtonChange = 1; - } - else if (_app_data->freq_focus_digit == FUN_GEN_FOCUS_MAX) - { - _app_data->curr_state_btn = BTN_FREQ_MAX; - _app_data->isButtonChange = 1; - } - break; - default: - break; - } + switch (_app_data->curr_state_btn) + { + case BTN_FREQ_MIN: + if (_app_data->freq_focus_digit > 0) + { + _app_data->curr_state_btn = BTN_FREQ; + _app_data->isButtonChange = 1; + } + break; + case BTN_FREQ_MAX: + if (_app_data->freq_focus_digit < FUN_GEN_FOCUS_MAX) + { + _app_data->curr_state_btn = BTN_FREQ; + _app_data->isButtonChange = 1; + } + break; + case BTN_FREQ: + if (_app_data->freq_focus_digit == 0) + { + _app_data->curr_state_btn = BTN_FREQ_MIN; + _app_data->isButtonChange = 1; + } + else if (_app_data->freq_focus_digit == FUN_GEN_FOCUS_MAX) + { + _app_data->curr_state_btn = BTN_FREQ_MAX; + _app_data->isButtonChange = 1; + } + break; + default: + break; + } } static void _enterToFreqLayout(void) { - _app_data->curr_state_lay = LAY_FREQ; - _app_data->curr_state_btn = BTN_FREQ; - _blockFocusAtMaxAndMin(); + _app_data->curr_state_lay = LAY_FREQ; + _app_data->curr_state_btn = BTN_FREQ; + _blockFocusAtMaxAndMin(); - _app_data->isButtonChange = 1; - _app_data->isGraphChange = 1; - _app_data->isValueChange = 1; + _app_data->isButtonChange = 1; + _app_data->isGraphChange = 1; + _app_data->isValueChange = 1; } static void _enterToAmplLayout(void) { - _app_data->curr_state_lay = LAY_AMPL; - _app_data->curr_state_btn = BTN_AMPL; + _app_data->curr_state_lay = LAY_AMPL; + _app_data->curr_state_btn = BTN_AMPL; - _app_data->isButtonChange = 1; - _app_data->isGraphChange = 1; - _app_data->isValueChange = 1; + _app_data->isButtonChange = 1; + _app_data->isGraphChange = 1; + _app_data->isValueChange = 1; } static void _enterToOffslLayout(void) { - _app_data->curr_state_lay = LAY_OFFS; - _app_data->curr_state_btn = BTN_OFFS; + _app_data->curr_state_lay = LAY_OFFS; + _app_data->curr_state_btn = BTN_OFFS; - _app_data->isButtonChange = 1; - _app_data->isGraphChange = 1; - _app_data->isValueChange = 1; + _app_data->isButtonChange = 1; + _app_data->isGraphChange = 1; + _app_data->isValueChange = 1; } static void _enterToPhasLayout(void) { - _app_data->curr_state_lay = LAY_PHAS; - _app_data->curr_state_btn = BTN_PHAS; + _app_data->curr_state_lay = LAY_PHAS; + _app_data->curr_state_btn = BTN_PHAS; - _app_data->isButtonChange = 1; - _app_data->isGraphChange = 1; - _app_data->isValueChange = 1; + _app_data->isButtonChange = 1; + _app_data->isGraphChange = 1; + _app_data->isValueChange = 1; } static void _enterToDutyLayout(void) { - _app_data->curr_state_lay = LAY_DUTY; - _app_data->curr_state_btn = BTN_DUTY; + _app_data->curr_state_lay = LAY_DUTY; + _app_data->curr_state_btn = BTN_DUTY; - _app_data->isButtonChange = 1; - _app_data->isGraphChange = 1; - _app_data->isValueChange = 1; + _app_data->isButtonChange = 1; + _app_data->isGraphChange = 1; + _app_data->isValueChange = 1; } static void _enterToWavelLayout(void) { - _app_data->curr_state_lay = LAY_WAVE; - _app_data->curr_state_btn = BTN_WAVE; + _app_data->curr_state_lay = LAY_WAVE; + _app_data->curr_state_btn = BTN_WAVE; - _app_data->isButtonChange = 1; - _app_data->isGraphChange = 1; - _app_data->isValueChange = 1; + _app_data->isButtonChange = 1; + _app_data->isGraphChange = 1; + _app_data->isValueChange = 1; } static void _moveToLeftFocusFreqNumber(void) { - _app_data->freq_focus_digit += 1; - _app_data->isValueChange = 1; + _app_data->freq_focus_digit += 1; + _app_data->isValueChange = 1; - _blockFocusAtMaxAndMin(); - _app_data->timer_blink[last_key] = 2; - _app_data->isButtonBlink |= (1 << last_key); + _blockFocusAtMaxAndMin(); + _app_data->timer_blink[last_key] = 2; + _app_data->isButtonBlink |= (1 << last_key); } static void _moveToRighttFocusFreqNumber(void) { - _app_data->freq_focus_digit -= 1; - _app_data->isValueChange = 1; + _app_data->freq_focus_digit -= 1; + _app_data->isValueChange = 1; - _blockFocusAtMaxAndMin(); - _app_data->timer_blink[last_key] = 2; - _app_data->isButtonBlink |= (1 << last_key); + _blockFocusAtMaxAndMin(); + _app_data->timer_blink[last_key] = 2; + _app_data->isButtonBlink |= (1 << last_key); } static void _setTo0_01xFocusNumber(void) { - switch (_app_data->curr_state_lay) - { - case LAY_AMPL: - _app_data->ampl_focus_digit = 0; - break; - case LAY_OFFS: - _app_data->offs_focus_digit = 0; - break; - default: - break; - } + switch (_app_data->curr_state_lay) + { + case LAY_AMPL: + _app_data->ampl_focus_digit = 0; + break; + case LAY_OFFS: + _app_data->offs_focus_digit = 0; + break; + default: + break; + } - _app_data->timer_blink[last_key] = 2; - _app_data->isButtonBlink |= (1 << last_key); - _app_data->isValueChange = 1; + _app_data->timer_blink[last_key] = 2; + _app_data->isButtonBlink |= (1 << last_key); + _app_data->isValueChange = 1; } static void _setTo0_1xFocusNumber(void) { - switch (_app_data->curr_state_lay) - { - case LAY_AMPL: - _app_data->ampl_focus_digit = 1; - break; - case LAY_OFFS: - _app_data->offs_focus_digit = 1; - break; - default: - break; - } + switch (_app_data->curr_state_lay) + { + case LAY_AMPL: + _app_data->ampl_focus_digit = 1; + break; + case LAY_OFFS: + _app_data->offs_focus_digit = 1; + break; + default: + break; + } - _app_data->timer_blink[last_key] = 2; - _app_data->isButtonBlink |= (1 << last_key); - _app_data->isValueChange = 1; + _app_data->timer_blink[last_key] = 2; + _app_data->isButtonBlink |= (1 << last_key); + _app_data->isValueChange = 1; } static void _setTo1xFocusNumber(void) { - switch (_app_data->curr_state_lay) - { - case LAY_AMPL: - _app_data->ampl_focus_digit = 2; - break; - case LAY_OFFS: - _app_data->offs_focus_digit = 2; - break; - case LAY_PHAS: - _app_data->offs_focus_digit = 0; - break; - case LAY_DUTY: - _app_data->offs_focus_digit = 0; - break; - default: - break; - } + switch (_app_data->curr_state_lay) + { + case LAY_AMPL: + _app_data->ampl_focus_digit = 2; + break; + case LAY_OFFS: + _app_data->offs_focus_digit = 2; + break; + case LAY_PHAS: + _app_data->phas_focus_digit = 0; + break; + case LAY_DUTY: + _app_data->duty_focus_digit = 0; + break; + default: + break; + } - _app_data->timer_blink[last_key] = 2; - _app_data->isButtonBlink |= (1 << last_key); - _app_data->isValueChange = 1; + _app_data->timer_blink[last_key] = 2; + _app_data->isButtonBlink |= (1 << last_key); + _app_data->isValueChange = 1; } static void _setTo10xFocusNumber(void) { - switch (_app_data->curr_state_lay) - { - case LAY_AMPL: - _app_data->ampl_focus_digit = 3; - break; - case LAY_OFFS: - _app_data->offs_focus_digit = 3; - break; - case LAY_PHAS: - _app_data->offs_focus_digit = 1; - break; - case LAY_DUTY: - _app_data->offs_focus_digit = 1; - break; - default: - break; - } + switch (_app_data->curr_state_lay) + { + case LAY_AMPL: + _app_data->ampl_focus_digit = 3; + break; + case LAY_OFFS: + _app_data->offs_focus_digit = 3; + break; + case LAY_PHAS: + _app_data->phas_focus_digit = 1; + break; + case LAY_DUTY: + _app_data->duty_focus_digit = 1; + break; + default: + break; + } - _app_data->timer_blink[last_key] = 2; - _app_data->isButtonBlink |= (1 << last_key); - _app_data->isValueChange = 1; + _app_data->timer_blink[last_key] = 2; + _app_data->isButtonBlink |= (1 << last_key); + _app_data->isValueChange = 1; } static const CMD_button_t btn_command[BTN_STATE_MAX][DISP_BTN_MAX] = { - { - // BTN_MAIN_FG - {_enterToFreqLayout, BITMAP_BTN_FREQ}, - {_enterToAmplLayout, BITMAP_BTN_AMPL}, - {_enterToOffslLayout, BITMAP_BTN_OFFS}, - {_enterToPhasLayout, BITMAP_BTN_PHAS}, - {_enterToWavelLayout, BITMAP_BTN_WAVE}, - }, - { - // BTN_MAIN_PWM - {_enterToFreqLayout, BITMAP_BTN_FREQ}, - {_enterToAmplLayout, BITMAP_BTN_AMPL}, - {_enterToOffslLayout, BITMAP_BTN_OFFS}, - {_enterToPhasLayout, BITMAP_BTN_PHAS}, - {_enterToDutyLayout, BITMAP_BTN_NONE}, - }, - { - // BTN_FREQ - {_moveToLeftFocusFreqNumber, BITMAP_BTN_LEFT}, - {_moveToRighttFocusFreqNumber, BITMAP_BTN_RIGHT}, - {_doNoting, BITMAP_BTN_NONE}, - {_doNoting, BITMAP_BTN_NONE}, - {_backToMain, BITMAP_BTN_BACK}, - }, - { - // BTN_FREQ_MIN - {_moveToLeftFocusFreqNumber, BITMAP_BTN_LEFT}, - {_doNoting, BITMAP_BTN_EMPTY}, - {_doNoting, BITMAP_BTN_NONE}, - {_doNoting, BITMAP_BTN_NONE}, - {_backToMain, BITMAP_BTN_BACK}, - }, - { - // BTN_FREQ_MAX - {_doNoting, BITMAP_BTN_EMPTY}, - {_moveToRighttFocusFreqNumber, BITMAP_BTN_RIGHT}, - {_doNoting, BITMAP_BTN_NONE}, - {_doNoting, BITMAP_BTN_NONE}, - {_backToMain, BITMAP_BTN_BACK}, - }, - { - // BTN_AMPL - {_setTo1xFocusNumber, BITMAP_BTN_X1}, - {_setTo0_1xFocusNumber, BITMAP_BTN_X0_1}, - {_setTo0_01xFocusNumber, BITMAP_BTN_X0_01}, - {_doNoting, BITMAP_BTN_NONE}, - {_backToMain, BITMAP_BTN_BACK}, - }, - { - // BTN_OFFS - {_setTo1xFocusNumber, BITMAP_BTN_X1}, - {_setTo0_1xFocusNumber, BITMAP_BTN_X0_1}, - {_setTo0_01xFocusNumber, BITMAP_BTN_X0_01}, - {_doNoting, BITMAP_BTN_NONE}, - {_backToMain, BITMAP_BTN_BACK}, - }, - { - // BTN_PHAS - {_setTo10xFocusNumber, BITMAP_BTN_X10}, - {_setTo1xFocusNumber, BITMAP_BTN_X1}, - {_doNoting, BITMAP_BTN_NONE}, - {_doNoting, BITMAP_BTN_NONE}, - {_backToMain, BITMAP_BTN_BACK}, - }, - { - // BTN_DUTY - {_setTo10xFocusNumber, BITMAP_BTN_X10}, - {_setTo1xFocusNumber, BITMAP_BTN_X1}, - {_doNoting, BITMAP_BTN_NONE}, - {_doNoting, BITMAP_BTN_NONE}, - {_backToMain, BITMAP_BTN_BACK}, - }, - { - // BTN_WAVE - {_doNoting, BITMAP_BTN_NONE}, - {_doNoting, BITMAP_BTN_NONE}, - {_doNoting, BITMAP_BTN_NONE}, - {_doNoting, BITMAP_BTN_NONE}, - {_backToMain, BITMAP_BTN_BACK}, - }, + { + // BTN_MAIN_FG + {_enterToFreqLayout, BITMAP_BTN_FREQ}, + {_enterToAmplLayout, BITMAP_BTN_AMPL}, + {_enterToOffslLayout, BITMAP_BTN_OFFS}, + {_enterToPhasLayout, BITMAP_BTN_PHAS}, + {_enterToWavelLayout, BITMAP_BTN_WAVE}, + }, + { + // BTN_MAIN_PWM + {_enterToFreqLayout, BITMAP_BTN_FREQ}, + {_enterToAmplLayout, BITMAP_BTN_AMPL}, + {_enterToOffslLayout, BITMAP_BTN_OFFS}, + {_enterToPhasLayout, BITMAP_BTN_PHAS}, + {_enterToDutyLayout, BITMAP_BTN_NONE}, + }, + { + // BTN_FREQ + {_moveToLeftFocusFreqNumber, BITMAP_BTN_LEFT}, + {_moveToRighttFocusFreqNumber, BITMAP_BTN_RIGHT}, + {_doNoting, BITMAP_BTN_NONE}, + {_doNoting, BITMAP_BTN_NONE}, + {_backToMain, BITMAP_BTN_BACK}, + }, + { + // BTN_FREQ_MIN + {_moveToLeftFocusFreqNumber, BITMAP_BTN_LEFT}, + {_doNoting, BITMAP_BTN_EMPTY}, + {_doNoting, BITMAP_BTN_NONE}, + {_doNoting, BITMAP_BTN_NONE}, + {_backToMain, BITMAP_BTN_BACK}, + }, + { + // BTN_FREQ_MAX + {_doNoting, BITMAP_BTN_EMPTY}, + {_moveToRighttFocusFreqNumber, BITMAP_BTN_RIGHT}, + {_doNoting, BITMAP_BTN_NONE}, + {_doNoting, BITMAP_BTN_NONE}, + {_backToMain, BITMAP_BTN_BACK}, + }, + { + // BTN_AMPL + {_setTo1xFocusNumber, BITMAP_BTN_X1}, + {_setTo0_1xFocusNumber, BITMAP_BTN_X0_1}, + {_setTo0_01xFocusNumber, BITMAP_BTN_X0_01}, + {_doNoting, BITMAP_BTN_NONE}, + {_backToMain, BITMAP_BTN_BACK}, + }, + { + // BTN_OFFS + {_setTo1xFocusNumber, BITMAP_BTN_X1}, + {_setTo0_1xFocusNumber, BITMAP_BTN_X0_1}, + {_setTo0_01xFocusNumber, BITMAP_BTN_X0_01}, + {_doNoting, BITMAP_BTN_NONE}, + {_backToMain, BITMAP_BTN_BACK}, + }, + { + // BTN_PHAS + {_setTo10xFocusNumber, BITMAP_BTN_X10}, + {_setTo1xFocusNumber, BITMAP_BTN_X1}, + {_doNoting, BITMAP_BTN_NONE}, + {_doNoting, BITMAP_BTN_NONE}, + {_backToMain, BITMAP_BTN_BACK}, + }, + { + // BTN_DUTY + {_setTo10xFocusNumber, BITMAP_BTN_X10}, + {_setTo1xFocusNumber, BITMAP_BTN_X1}, + {_doNoting, BITMAP_BTN_NONE}, + {_doNoting, BITMAP_BTN_NONE}, + {_backToMain, BITMAP_BTN_BACK}, + }, + { + // BTN_WAVE + {_doNoting, BITMAP_BTN_NONE}, + {_doNoting, BITMAP_BTN_NONE}, + {_doNoting, BITMAP_BTN_NONE}, + {_doNoting, BITMAP_BTN_NONE}, + {_backToMain, BITMAP_BTN_BACK}, + }, }; diff --git a/firmware/shared_libs/controllers/ctrl_app.h b/firmware/shared_libs/controllers/ctrl_app.h index 9dc33bf..89b4a5a 100644 --- a/firmware/shared_libs/controllers/ctrl_app.h +++ b/firmware/shared_libs/controllers/ctrl_app.h @@ -21,7 +21,7 @@ typedef struct uint16_t phase; uint8_t wave; uint8_t enabled; - uint8_t connected; + uint8_t link; } GEN_fg_t; typedef struct @@ -59,4 +59,5 @@ void CTRL_buttonsInit(void); void CTRL_buttonsHandler(void); void CTRL_pushedDispBtnEvent(ButtonKey_t *key); void CTRL_pushedChanBtnEvent(ButtonKey_t *key); +void CTRL_encoderEvent(int8_t enc); BITMAP_buttonName_t CTRL_getBitmapName(LAY_dispBtn_t disp_btn); diff --git a/firmware/shared_libs/controllers/ctrl_app_types.h b/firmware/shared_libs/controllers/ctrl_app_types.h index 91a6de9..d2d5c1e 100644 --- a/firmware/shared_libs/controllers/ctrl_app_types.h +++ b/firmware/shared_libs/controllers/ctrl_app_types.h @@ -1,5 +1,13 @@ #pragma once +#define FUN_GEN_FOCUS_MAX 6U +#define PWM_GEN_FOCUS_MAX 4U +#define MAX_FREQ 1000000U +#define MAX_VOLT_POS 500 +#define MAX_VOLT_NEG -500 +#define MAX_PHAS 360 +#define MAX_DUTY 100 + typedef enum { GEN_FG_TYPE, diff --git a/firmware/shared_libs/controllers/ctrl_encoder.c b/firmware/shared_libs/controllers/ctrl_encoder.c new file mode 100644 index 0000000..6d43074 --- /dev/null +++ b/firmware/shared_libs/controllers/ctrl_encoder.c @@ -0,0 +1,16 @@ +#include "main.h" +#include "tim.h" +#include "ctrl_app.h" + +void CTRL_encoderHandler(void) +{ + static uint8_t cnt; + if (htim3.Instance->CNT == cnt || htim3.Instance->CNT % 2 == 1) + { + return; + } + + // SEGGER_RTT_printf(0, "TIM3.cnt: %d\n", htim3.Instance->CNT); + CTRL_encoderEvent(htim3.Instance->CNT - cnt); + cnt = (uint8_t)htim3.Instance->CNT; +} \ No newline at end of file diff --git a/firmware/shared_libs/controllers/ctrl_encoder.h b/firmware/shared_libs/controllers/ctrl_encoder.h new file mode 100644 index 0000000..3dccd1a --- /dev/null +++ b/firmware/shared_libs/controllers/ctrl_encoder.h @@ -0,0 +1,3 @@ +#pragma once + +void CTRL_encoderHandler(void); \ No newline at end of file diff --git a/firmware/shared_libs/disp_layout/disp_layout.c b/firmware/shared_libs/disp_layout/disp_layout.c index 1a3bc06..42e9ff3 100644 --- a/firmware/shared_libs/disp_layout/disp_layout.c +++ b/firmware/shared_libs/disp_layout/disp_layout.c @@ -16,6 +16,7 @@ const uint8_t btn_pos_x[DISP_BTN_MAX] = {0, 26, 52, 78, 104}; const uint8_t marker_freq_pos_x[FREQ_MAX_DIGIT] = {76, 84, 90, 96, 105, 111, 118}; const uint8_t marker_ampl_pos_x[AMPL_MAX_DIGIT] = {82, 94, 100}; +const uint8_t marker_phas_pos_x[AMPL_MAX_DIGIT] = {82, 88, 96}; // clang-format off const GFX_bitmap_t marker_down = {05, 03, (uint8_t[]){0x01,0x03,0x07,0x03,0x01}};// res: 5x3(8) - 5 bytes @@ -28,7 +29,6 @@ static void _drawFreqValue(GFX_display_t *disp, uint32_t freq, uint8_t pos_y) uint8_t data[8]; snprintf((char *)data, 8, "%07u", freq); DISP_writeString(disp, &font5x7Info, (uint8_t[]){data[0], 0}, 76, pos_y, BM_NORMAL); - DISP_writeString(disp, &font5x7Info, (uint8_t[]){data[0], 0}, 76, pos_y, BM_NORMAL); DISP_writeString(disp, &font5x7Info, (uint8_t[]){data[1], data[2], data[3], 0}, 84, pos_y, BM_NORMAL); DISP_writeString(disp, &font5x7Info, (uint8_t[]){data[4], data[5], data[6], 0}, 105, pos_y, BM_NORMAL); } @@ -44,6 +44,10 @@ static void _drawOffsValue(GFX_display_t *disp, int16_t offs, uint8_t pos_y) { uint8_t data[8]; snprintf((char *)data, 8, "%+01d.%02d V", offs / 100, abs(offs) % 100); + if (offs < 0) + { + data[0] = '-'; + } DISP_writeString(disp, &font5x7Info, data, 76, pos_y, BM_NORMAL); } @@ -54,12 +58,12 @@ static void _drawPhasValue(GFX_display_t *disp, uint16_t phase, uint8_t pos_y) DISP_writeString(disp, &font5x7Info, data, 76, pos_y, BM_NORMAL); } -static void _drawDutyValue(GFX_display_t *disp, uint8_t duty, uint8_t pos_y) -{ - uint8_t data[8]; - snprintf((char *)data, 8, "%03u%%", duty); - DISP_writeString(disp, &font5x7Info, data, 76, pos_y, BM_NORMAL); -} +// static void _drawDutyValue(GFX_display_t *disp, uint8_t duty, uint8_t pos_y) +// { +// uint8_t data[8]; +// snprintf((char *)data, 8, "%03u%%", duty); +// DISP_writeString(disp, &font5x7Info, data, 76, pos_y, BM_NORMAL); +// } static void _blinkButtons(GFX_display_t *disp, APP_data_t *app_data) { @@ -168,7 +172,7 @@ static void _drawPhaseValueHelper(GFX_display_t *disp, uint32_t phase, uint8_t f DISP_clearRegion(disp, 64, 13, 66, 40); DISP_writeString(disp, &font5x7Info, (uint8_t *)"P:", 64, 20, BM_NORMAL); _drawPhasValue(disp, phase, 20); - DISP_drawBitmap(disp, &marker_down, marker_ampl_pos_x[(AMPL_MAX_DIGIT - 1) - focus_digit], 15, BM_NORMAL); + DISP_drawBitmap(disp, &marker_down, marker_phas_pos_x[(AMPL_MAX_DIGIT - 1) - focus_digit], 15, BM_NORMAL); } static void _drawFuncGenValues(GFX_display_t *disp, APP_data_t *app_data) @@ -178,19 +182,19 @@ static void _drawFuncGenValues(GFX_display_t *disp, APP_data_t *app_data) { case LAY_FREQ: _drawFreqValueHelper(disp, fun_gen->frequency, app_data->freq_focus_digit); - _drawMeterHelper(disp, "1", "1M", _calcMarkerPos(990000, 1000000)); + _drawMeterHelper(disp, "1", "1M", _calcMarkerPos(fun_gen->frequency, MAX_FREQ)); break; case LAY_AMPL: _drawAmplValueHelper(disp, fun_gen->amplitude, app_data->ampl_focus_digit); - _drawMeterHelper(disp, "0V", "5V", _calcMarkerPos(100, 500)); + _drawMeterHelper(disp, "0V", "5V", _calcMarkerPos(fun_gen->amplitude, MAX_VOLT_POS)); break; case LAY_OFFS: _drawOffsValueHelper(disp, fun_gen->offset, app_data->offs_focus_digit); - _drawMeterHelper(disp, "-5V", "+5V", _calcMarkerPos(100 + 250, 500 + 250)); + _drawMeterHelper(disp, "-5V", "+5V", _calcMarkerPos(MAX_VOLT_POS + fun_gen->offset, MAX_VOLT_POS * 2)); break; case LAY_PHAS: _drawPhaseValueHelper(disp, fun_gen->phase, app_data->phas_focus_digit); - _drawMeterHelper(disp, "0", "360", _calcMarkerPos(100, 500)); + _drawMeterHelper(disp, "0", "360", _calcMarkerPos(fun_gen->phase, MAX_PHAS)); break; case LAY_MAIN: DISP_clearRegion(disp, 62, 13, 66, 40); @@ -213,7 +217,7 @@ static void _drawFuncGenValues(GFX_display_t *disp, APP_data_t *app_data) static void _drawPwmGenValues(GFX_display_t *disp, APP_data_t *app_data) { - GEN_pwm_t *pwm_gen = app_data->generator; + // GEN_pwm_t *pwm_gen = app_data->generator; } static void _drawValues(GFX_display_t *disp, APP_data_t *app_data) @@ -251,14 +255,14 @@ static void _drawOffsetLine(GFX_display_t *disp, int16_t offs, uint32_t ampl) DISP_drawHorizontalLine(disp, 2, 31 + offs_shift, 57, GFX_WHITE); } -static void _drawMaxAmpLine(GFX_display_t *disp, int16_t offs, uint32_t ampl) -{ - DISP_drawHorizontalLine(disp, 2, 12, 57, GFX_WHITE); - DISP_drawBitmap(disp, &marker_up, 0, 13, BM_NORMAL); +// static void _drawMaxAmpLine(GFX_display_t *disp, int16_t offs, uint32_t ampl) +// { +// DISP_drawHorizontalLine(disp, 2, 12, 57, GFX_WHITE); +// DISP_drawBitmap(disp, &marker_up, 0, 13, BM_NORMAL); - DISP_drawHorizontalLine(disp, 2, 51, 57, GFX_WHITE); - DISP_drawBitmap(disp, &marker_down, 0, 48, BM_NORMAL); -} +// DISP_drawHorizontalLine(disp, 2, 51, 57, GFX_WHITE); +// DISP_drawBitmap(disp, &marker_down, 0, 48, BM_NORMAL); +// } static void _drawFunGenGraph(GFX_display_t *disp, APP_data_t *app_data) { diff --git a/firmware/shared_libs/utils/ulog/ulog.c b/firmware/shared_libs/utils/ulog/ulog.c new file mode 100644 index 0000000..52b8ae3 --- /dev/null +++ b/firmware/shared_libs/utils/ulog/ulog.c @@ -0,0 +1,154 @@ +/** +MIT License + +Copyright (c) 2019 R. Dunbar Poor + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * \file ulog.c + * + * \brief uLog: lightweight logging for embedded systems + * + * See ulog.h for sparse documentation. + */ + +#include "ulog.h" + +#ifdef ULOG_ENABLED // whole file... + +// #include +#include "printf.h" +#include +#include + +// ============================================================================= +// types and definitions + +typedef struct +{ + ulog_function_t fn; + ulog_level_t threshold; +} subscriber_t; + +// ============================================================================= +// local storage + +static subscriber_t s_subscribers[ULOG_MAX_SUBSCRIBERS]; +static char s_message[ULOG_MAX_MESSAGE_LENGTH]; + +// ============================================================================= +// user-visible code + +void ulog_init() +{ + memset(s_subscribers, 0, sizeof(s_subscribers)); +} + +// search the s_subscribers table to install or update fn +ulog_err_t ulog_subscribe(ulog_function_t fn, ulog_level_t threshold) +{ + int available_slot = -1; + int i; + for (i = 0; i < ULOG_MAX_SUBSCRIBERS; i++) + { + if (s_subscribers[i].fn == fn) + { + // already subscribed: update threshold and return immediately. + s_subscribers[i].threshold = threshold; + return ULOG_ERR_NONE; + } + else if (s_subscribers[i].fn == NULL) + { + // found a free slot + available_slot = i; + } + } + // fn is not yet a subscriber. assign if possible. + if (available_slot == -1) + { + return ULOG_ERR_SUBSCRIBERS_EXCEEDED; + } + s_subscribers[available_slot].fn = fn; + s_subscribers[available_slot].threshold = threshold; + return ULOG_ERR_NONE; +} + +// search the s_subscribers table to remove +ulog_err_t ulog_unsubscribe(ulog_function_t fn) +{ + int i; + for (i = 0; i < ULOG_MAX_SUBSCRIBERS; i++) + { + if (s_subscribers[i].fn == fn) + { + s_subscribers[i].fn = NULL; // mark as empty + return ULOG_ERR_NONE; + } + } + return ULOG_ERR_NOT_SUBSCRIBED; +} + +const char *ulog_level_name(ulog_level_t severity) +{ + switch (severity) + { + case ULOG_TRACE_LEVEL: + return "TRACE"; + case ULOG_DEBUG_LEVEL: + return "DEBUG"; + case ULOG_INFO_LEVEL: + return "INFO"; + case ULOG_WARNING_LEVEL: + return "WARNING"; + case ULOG_ERROR_LEVEL: + return "ERROR"; + case ULOG_CRITICAL_LEVEL: + return "CRITICAL"; + case ULOG_ALWAYS_LEVEL: + return "ALWAYS"; + default: + return "UNKNOWN"; + } +} + +void ulog_message(ulog_level_t severity, const char *fmt, ...) +{ + va_list ap; + int i; + va_start(ap, fmt); + vsnprintf(s_message, ULOG_MAX_MESSAGE_LENGTH, fmt, ap); + va_end(ap); + + for (i = 0; i < ULOG_MAX_SUBSCRIBERS; i++) + { + if (s_subscribers[i].fn != NULL) + { + if (severity >= s_subscribers[i].threshold) + { + s_subscribers[i].fn(severity, s_message); + } + } + } +} + +// ============================================================================= +// private code + +#endif // #ifdef ULOG_ENABLED diff --git a/firmware/shared_libs/utils/ulog/ulog.h b/firmware/shared_libs/utils/ulog/ulog.h new file mode 100644 index 0000000..6186896 --- /dev/null +++ b/firmware/shared_libs/utils/ulog/ulog.h @@ -0,0 +1,188 @@ +/** +MIT License + +Copyright (c) 2019 R. Dunbar Poor + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * \file + * + * \brief uLog: lightweight logging for embedded systems + * + * A quick intro by example: + * + * #include "ulog.h" + * + * // To use uLog, you must define a function to process logging messages. + * // It can write the messages to a console, to a file, to an in-memory + * // buffer: the choice is yours. And you get to choose the format of + * // the message. This example prints to the console. One caveat: msg + * // is a static string and will be over-written at the next call to ULOG. + * // You may print it or copy it, but saving a pointer to it will lead to + * // confusion and astonishment. + * // + * void my_console_logger(ulog_level_t level, const char *msg) { + * printf("%s [%s]: %s\n", + * get_timestamp(), + * ulog_level_name(level), + * msg); + * } + * + * int main() { + * ULOG_INIT(); + * + * // log to the console messages that are WARNING or more severe. You + * // can re-subscribe at any point to change the severity level. + * ULOG_SUBSCRIBE(my_console_logger, ULOG_WARNING); + * + * // log to a file messages that are DEBUG or more severe + * ULOG_SUBSCRIBE(my_file_logger, ULOG_DEBUG); + * + * int arg = 42; + * ULOG_INFO("Arg is %d", arg); // logs to file but not console + * } + */ + +#ifndef ULOG_H_ +#define ULOG_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef enum + { + ULOG_TRACE_LEVEL = 100, + ULOG_DEBUG_LEVEL, + ULOG_INFO_LEVEL, + ULOG_WARNING_LEVEL, + ULOG_ERROR_LEVEL, + ULOG_CRITICAL_LEVEL, + ULOG_ALWAYS_LEVEL + } ulog_level_t; + + // The following macros enable or disable uLog. If `ULOG_ENABLED` is + // defined at compile time, a macro such as `ULOG_INFO(...)` expands + // into `ulog_message(ULOG_INFO_LEVEL, ...)`. If `ULOG_ENABLED` is not + // defined, then the same macro expands into `do {} while(0)` and will + // not generate any code at all. + // + // There are two ways to enable uLog: you can uncomment the following + // line, or -- if it is commented out -- you can add -DULOG_ENABLED to + // your compiler switches. + // #define ULOG_ENABLED + +#ifdef ULOG_ENABLED +#define ULOG_INIT() ulog_init() +#define ULOG_SUBSCRIBE(a, b) ulog_subscribe(a, b) +#define ULOG_UNSUBSCRIBE(a) ulog_unsubscribe(a) +#define ULOG_LEVEL_NAME(a) ulog_level_name(a) +#define ULOG(...) ulog_message(__VA_ARGS__) +#define ULOG_TRACE(...) ulog_message(ULOG_TRACE_LEVEL, __VA_ARGS__) +#define ULOG_DEBUG(...) ulog_message(ULOG_DEBUG_LEVEL, __VA_ARGS__) +#define ULOG_INFO(...) ulog_message(ULOG_INFO_LEVEL, __VA_ARGS__) +#define ULOG_WARNING(...) ulog_message(ULOG_WARNING_LEVEL, __VA_ARGS__) +#define ULOG_ERROR(...) ulog_message(ULOG_ERROR_LEVEL, __VA_ARGS__) +#define ULOG_CRITICAL(...) ulog_message(ULOG_CRITICAL_LEVEL, __VA_ARGS__) +#define ULOG_ALWAYS(...) ulog_message(ULOG_ALWAYS_LEVEL, __VA_ARGS__) +#else +// uLog vanishes when disabled at compile time... +#define ULOG_INIT() \ + do \ + { \ + } while (0) +#define ULOG_SUBSCRIBE(a, b) \ + do \ + { \ + } while (0) +#define ULOG_UNSUBSCRIBE(a) \ + do \ + { \ + } while (0) +#define ULOG_LEVEL_NAME(a) \ + do \ + { \ + } while (0) +#define ULOG(s, f, ...) \ + do \ + { \ + } while (0) +#define ULOG_TRACE(f, ...) \ + do \ + { \ + } while (0) +#define ULOG_DEBUG(f, ...) \ + do \ + { \ + } while (0) +#define ULOG_INFO(f, ...) \ + do \ + { \ + } while (0) +#define ULOG_WARNING(f, ...) \ + do \ + { \ + } while (0) +#define ULOG_ERROR(f, ...) \ + do \ + { \ + } while (0) +#define ULOG_CRITICAL(f, ...) \ + do \ + { \ + } while (0) +#define ULOG_ALWAYS(f, ...) \ + do \ + { \ + } while (0) +#endif + + typedef enum + { + ULOG_ERR_NONE = 0, + ULOG_ERR_SUBSCRIBERS_EXCEEDED, + ULOG_ERR_NOT_SUBSCRIBED, + } ulog_err_t; + +// define the maximum number of concurrent subscribers +#ifndef ULOG_MAX_SUBSCRIBERS +#define ULOG_MAX_SUBSCRIBERS 6 +#endif +// maximum length of formatted log message +#ifndef ULOG_MAX_MESSAGE_LENGTH +#define ULOG_MAX_MESSAGE_LENGTH 120 +#endif + /** + * @brief: prototype for uLog subscribers. + */ + typedef void (*ulog_function_t)(ulog_level_t severity, char *msg); + + void ulog_init(void); + ulog_err_t ulog_subscribe(ulog_function_t fn, ulog_level_t threshold); + ulog_err_t ulog_unsubscribe(ulog_function_t fn); + const char *ulog_level_name(ulog_level_t level); + void ulog_message(ulog_level_t severity, const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* ULOG_H_ */