├── COPYING ├── Doxyfile ├── README.md ├── ade791x ├── ade791x.c └── ade791x.h ├── bits └── bits.h ├── bootloader ├── app │ ├── Makefile │ ├── main.c │ ├── startup.c │ ├── stm32f103rb_bld_app.ld │ ├── stm32f10x_sections.ld │ ├── system_stm32f10x.c │ └── system_stm32f10x.h └── boot │ ├── Makefile │ ├── bootloader_modbus.c │ ├── bootloader_modbus.h │ ├── gdbinit.txt │ ├── main.c │ ├── startup.c │ ├── stm32f103rb_bld_boot.ld │ ├── stm32f10x_conf.h │ ├── stm32f10x_sections.ld │ ├── system_stm32f10x.c │ └── system_stm32f10x.h ├── buffer ├── buffer.h ├── buffer_defs.h ├── circular_buffer.c └── circular_buffer.h ├── calc_lines_count.sh ├── cordic ├── cordic10_6.c ├── cordic10_6.h ├── cordic16.c ├── cordic16.h ├── cordic32.c └── cordic32.h ├── counter ├── counter.c └── counter.h ├── crc ├── crc16_ccitt.c └── crc16_ccitt.h ├── debounce ├── debounce.c └── debounce.h ├── defs └── defs.h ├── dma ├── dma.c └── dma.h ├── ds1307 ├── ds1307.c ├── ds1307.h └── ds1307mem.h ├── ds18x20 ├── ds18x20.c └── ds18x20.h ├── dsp ├── avg.c ├── avg.h ├── decim.c ├── decim.h ├── decim_avg.c ├── decim_avg.h ├── edge_detect.c ├── edge_detect.h ├── fir.c ├── fir.h ├── maj.c ├── maj.h ├── mwin.c └── mwin.h ├── errors └── errors.h ├── filter_ab ├── filter_ab.c └── filter_ab.h ├── fixed ├── fixed.h ├── fixed16.h ├── fixed32.h ├── fixed_math.c ├── fixed_math.h ├── fixed_quat.c ├── fixed_quat.h ├── fixed_vec2.c ├── fixed_vec2.h ├── fixed_vec3.c ├── fixed_vec3.h ├── fixed_vec4.c └── fixed_vec4.h ├── flash ├── flash.c └── flash.h ├── future ├── future.c └── future.h ├── gpio ├── gpio.c └── gpio.h ├── graphics ├── font.c ├── font.h ├── font_10x16_utf8.h ├── font_5x8_utf8.h ├── font_ascii_5x8.h ├── graphics.c ├── graphics.h ├── graphics_inlines.h ├── painter.c ├── painter.h ├── point.h └── rect.h ├── gui ├── gui.c ├── gui.h ├── gui_anim_bitmap.c ├── gui_anim_bitmap.h ├── gui_button.c ├── gui_button.h ├── gui_checkbox.c ├── gui_checkbox.h ├── gui_event.c ├── gui_event.h ├── gui_label.c ├── gui_label.h ├── gui_number_label.c ├── gui_number_label.h ├── gui_object.c ├── gui_object.h ├── gui_radiobutton.c ├── gui_radiobutton.h ├── gui_spinbox.c ├── gui_spinbox.h ├── gui_widget.c └── gui_widget.h ├── gyro6050 ├── gyro6050.c └── gyro6050.h ├── hmc5883l ├── hmc5883l.c └── hmc5883l.h ├── i2c ├── i2c.c └── i2c.h ├── input ├── key_input.c ├── key_input.h ├── key_layout_en.h ├── key_layout_ru.h └── keys.h ├── lcd12864 ├── lcd12864.c └── lcd12864.h ├── lcd44780 ├── lcd44780.c └── lcd44780.h ├── lcd8544 ├── lcd8544.c └── lcd8544.h ├── ld-scripts ├── stm32f103c8.ld ├── stm32f103rb.ld ├── stm32f103rb_bld_app.ld ├── stm32f103rb_bld_boot.ld ├── stm32f103vc.ld ├── stm32f103ze.ld └── stm32f10x_sections.ld ├── list ├── list.c └── list.h ├── lm75 ├── lm75.c └── lm75.h ├── localization ├── localization.c └── localization.h ├── m95x ├── m95x.c └── m95x.h ├── menu ├── menu.c └── menu.h ├── mid_filter ├── mid_filter3i.c └── mid_filter3i.h ├── modbus ├── modbus_rtu.c └── modbus_rtu.h ├── mutex ├── mutex.c └── mutex.h ├── mvsources.sh ├── newlib └── newlib_stubs.c ├── one_wire ├── one_wire.c └── one_wire.h ├── orientation ├── orientation.c └── orientation.h ├── pca9555 ├── pca9555.c ├── pca9555.h └── pca9555_mem.h ├── pid_controller ├── pid_controller.c └── pid_controller.h ├── q15 ├── q15.h ├── q15_str.c └── q15_str.h ├── rtc ├── rtc.c └── rtc.h ├── scheduler ├── scheduler.c └── scheduler.h ├── sdcard ├── sdcard.c ├── sdcard.h ├── sdcard_cmd.h ├── sdcard_diskio.c ├── sdcard_diskio.h ├── sdcard_reg.h ├── sdcard_reply.h └── sdcard_token.h ├── spi ├── spi.c └── spi.h ├── startup └── startup.c ├── stpm3x ├── stpm3x.c └── stpm3x.h ├── system ├── system.c └── system.h ├── template ├── Makefile ├── gdbinit.txt ├── main.c └── stm32f10x_conf.h ├── template_freertos ├── FreeRTOS-openocd.c ├── FreeRTOSConfig.h ├── Makefile ├── gdbinit.txt ├── main.c └── stm32f10x_conf.h ├── tft9341 ├── tft9341.c ├── tft9341.h ├── tft9341_cache.c ├── tft9341_cache.h └── tft9341_cache_vbuf.h ├── timers ├── timers.c └── timers.h ├── tree ├── rbtree.c └── rbtree.h ├── usart ├── usart.c ├── usart.h ├── usart_buf.c ├── usart_buf.h ├── usart_bus.c └── usart_bus.h └── utils ├── critical.h ├── delay.c ├── delay.h ├── net.h ├── utf8.c ├── utf8.h └── utils.h /README.md: -------------------------------------------------------------------------------- 1 | # stm32libs 2 | Libraries for working with microcontrollers STM32. 3 | -------------------------------------------------------------------------------- /bootloader/app/main.c: -------------------------------------------------------------------------------- 1 | #include "stm32f10x.h" 2 | 3 | 4 | #define LED1 4 5 | #define LED2 8 6 | 7 | static void init_led(void) 8 | { 9 | // LED1. 10 | GPIOA->CRL |= GPIO_CRL_MODE2_1; 11 | GPIOA->CRL &= ~GPIO_CRL_CNF2; 12 | // LED2. 13 | GPIOA->CRL |= GPIO_CRL_MODE3_1; 14 | GPIOA->CRL &= ~GPIO_CRL_CNF3; 15 | } 16 | 17 | static void led_on(uint16_t led_pin) 18 | { 19 | GPIOA->BSRR = led_pin; 20 | } 21 | 22 | static void led_off(uint16_t led_pin) 23 | { 24 | GPIOA->BRR = led_pin; 25 | } 26 | 27 | static void led_toggle(uint16_t led_pin) 28 | { 29 | GPIOA->ODR ^= led_pin; 30 | } 31 | 32 | static void init_periph_clock(void) 33 | { 34 | // GPIO. 35 | RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; 36 | } 37 | 38 | 39 | int leds_to_on = LED1; 40 | int leds_to_off = LED2; 41 | int leds_to_toggle = LED1 | LED2; 42 | 43 | 44 | void delay_1s(void) 45 | { 46 | volatile int i = 8000000; 47 | while(-- i); 48 | } 49 | 50 | /** 51 | * Инициализация тактирования на 72 МГц. 52 | */ 53 | void init_rcc(void) 54 | { 55 | // Предделители шин. 56 | // AHB - нет предделителя. 57 | RCC->CFGR &= ~RCC_CFGR_HPRE; 58 | // APB1 - делитель на 2. 59 | RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; 60 | // APB2 - нет предделителя. 61 | RCC->CFGR &= ~RCC_CFGR_PPRE2; 62 | // ADC - делитель на 6. 63 | RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6; 64 | // USB - делитель на 1.5. 65 | RCC->CFGR &= ~RCC_CFGR_USBPRE; 66 | 67 | // ФАПЧ. 68 | // Источник. 69 | RCC->CFGR |= RCC_CFGR_PLLSRC_HSE; 70 | // Делитель частоты внешнего осциллятора. 71 | RCC->CFGR &= ~RCC_CFGR_PLLXTPRE; 72 | // Умножитель частоты. 73 | RCC->CFGR |= RCC_CFGR_PLLMULL9; 74 | 75 | // Переход на тактирование от PLL. 76 | // Включение внешнего осциллятора. 77 | RCC->CR |= RCC_CR_HSEON; 78 | // Подождём запуска внешнего осциллятора. 79 | while(!(RCC->CR & RCC_CR_HSERDY)); 80 | // Запустим ФАПЧ. 81 | RCC->CR |= RCC_CR_PLLON; 82 | // Подождём запуска ФАПЧ. 83 | while(!(RCC->CR & RCC_CR_PLLRDY)); 84 | 85 | // Настройка чтения флеш-памяти. 86 | // Запретим доступ по половине цикла тактирования. 87 | // Доступ по половине цикла тактирования запрещён при загрузке. 88 | //FLASH->ACR &= ~FLASH_ACR_HLFCYA; 89 | // Установим задержку чтения из флеш-памяти в 2 такта. 90 | FLASH->ACR |= FLASH_ACR_LATENCY_2; 91 | 92 | // Разрешим буфер предвыборки. 93 | // Буфер предвыборки включен после загрузки. 94 | //FLASH->ACR |= FLASH_ACR_PRFTBE; 95 | // Подождём включения предвыборки. 96 | //while(!(FLASH->ACR & FLASH_ACR_PRFTBS)); 97 | 98 | // Перейдём на тактирование от ФАПЧ. 99 | RCC->CFGR |= RCC_CFGR_SW_PLL; 100 | // Подождём перехода на ФАПЧ. 101 | while(!(RCC->CFGR & RCC_CFGR_SWS_PLL)); 102 | 103 | // Установим значение частоты ядра. 104 | SystemCoreClock = 72000000; 105 | } 106 | 107 | int main(void) 108 | { 109 | init_rcc(); 110 | init_periph_clock(); 111 | init_led(); 112 | 113 | led_on(leds_to_on); 114 | led_off(leds_to_off); 115 | 116 | for(;;){ 117 | delay_1s(); 118 | led_toggle(leds_to_toggle); 119 | } 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /bootloader/app/stm32f103rb_bld_app.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания адресов и областей памяти. 4 | */ 5 | 6 | /* Точка входа. */ 7 | ENTRY(Reset_Handler) 8 | 9 | /* Память. */ 10 | MEMORY 11 | { 12 | BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 8K /* Загрузчик. */ 13 | APP (rx) : ORIGIN = 0x08000000 + LENGTH(BOOT), LENGTH = 128K - LENGTH(BOOT) /* Флеш-память. */ 14 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K /* ОЗУ */ 15 | } 16 | 17 | /* Синоним региона. */ 18 | REGION_ALIAS("FLASH", APP); 19 | 20 | /* Минимальный размер стека. */ 21 | _min_stack_size = 0x200; 22 | 23 | /* Конец стека. */ 24 | _estack = ORIGIN(RAM) + LENGTH(RAM); 25 | 26 | /* Адрес начала сегмента основного приложения. */ 27 | _app_origin = ORIGIN(APP); 28 | 29 | /* Декларация секций. */ 30 | INCLUDE "stm32f10x_sections.ld" 31 | -------------------------------------------------------------------------------- /bootloader/app/stm32f10x_sections.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания секций. 4 | */ 5 | 6 | /* Секции. */ 7 | SECTIONS 8 | { 9 | /* Вектора прерываний. */ 10 | .isr_vector : ALIGN(4) 11 | { 12 | _sisr = .; 13 | 14 | KEEP(*(.isr_vector)) 15 | 16 | . = ALIGN(4); 17 | _eisr = .; 18 | } > FLASH 19 | 20 | /* Код и данные только для чтения. */ 21 | .text : ALIGN(4) 22 | { 23 | _stext = .; 24 | 25 | *(.text) 26 | *(.text.*) 27 | *(.rodata) 28 | *(.rodata.*) 29 | *(.glue_7) 30 | *(.glue_7t) 31 | 32 | . = ALIGN(4); 33 | _etext = .; 34 | } > FLASH 35 | 36 | /* Массив предварительной инициализации. */ 37 | .preinit : ALIGN(4) 38 | { 39 | _spreinit_array = .; 40 | 41 | KEEP(*(SORT(.preinit_array.*))) 42 | KEEP(*(.preinit_array)) 43 | 44 | . = ALIGN(4); 45 | _epreinit_array = .; 46 | } > FLASH 47 | 48 | /* Массив инициализации. */ 49 | .init : ALIGN(4) 50 | { 51 | _sinit_array = .; 52 | 53 | KEEP(*(SORT(.init_array.*))) 54 | KEEP(*(.init_array)) 55 | 56 | . = ALIGN(4); 57 | _einit_array = .; 58 | } > FLASH 59 | 60 | /* Массив деинициализации. */ 61 | .fini : ALIGN(4) 62 | { 63 | _sfini_array = .; 64 | 65 | KEEP(*(SORT(.fini_array.*))) 66 | KEEP(*(.fini_array)) 67 | 68 | . = ALIGN(4); 69 | _efini_array = .; 70 | } > FLASH 71 | 72 | /* ARM magic sections */ 73 | .ARM.extab : ALIGN(4) 74 | { 75 | *(.ARM.extab* .gnu.linkonce.armextab.*) 76 | } > FLASH 77 | 78 | .ARM.exidx : ALIGN(4) 79 | { 80 | __exidx_start = .; 81 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 82 | __exidx_end = .; 83 | } > FLASH 84 | 85 | . = ALIGN(4); 86 | /* Адрес инициализированных данных. */ 87 | _sidata = .; 88 | 89 | /* Инициализированные данные. */ 90 | .data : AT(_sidata) ALIGN(4) 91 | { 92 | _sdata = .; 93 | 94 | *(.data) 95 | *(.data.*) 96 | 97 | . = ALIGN(4); 98 | _edata = .; 99 | } > RAM 100 | 101 | /* Неинициализированные данные. */ 102 | .bss : ALIGN(4) 103 | { 104 | _sbss = .; 105 | 106 | *(.bss) 107 | *(.bss.*) 108 | *(COMMON) 109 | 110 | . = ALIGN(4); 111 | _ebss = .; 112 | } > RAM 113 | 114 | /* Стек минимального размера. */ 115 | .min_stack : ALIGN(4) 116 | { 117 | _smin_stack = .; 118 | 119 | . = . + _min_stack_size; 120 | 121 | . = ALIGN(4); 122 | _emin_stack = .; 123 | } > RAM 124 | 125 | /* Отладочная информация стандартных библиотек. */ 126 | /DISCARD/ : 127 | { 128 | libc.a ( * ) 129 | libm.a ( * ) 130 | libgcc.a ( * ) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /bootloader/app/system_stm32f10x.c: -------------------------------------------------------------------------------- 1 | #include "system_stm32f10x.h" 2 | 3 | /** 4 | * Определение переменной со значением частоты ядра. 5 | * Частота по-умолчанию при включении равна 8 МГц. 6 | */ 7 | uint32_t SystemCoreClock = 8000000; 8 | 9 | -------------------------------------------------------------------------------- /bootloader/app/system_stm32f10x.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file system_stm32f10x.h Библиотека инициализации часов. 3 | */ 4 | 5 | #ifndef _SYSTEM_STM32F10X_H_ 6 | #define _SYSTEM_STM32F10X_H_ 7 | 8 | #include 9 | 10 | //! Значение частоты ядра. 11 | extern uint32_t SystemCoreClock; 12 | 13 | #endif //_SYSTEM_STM32F10X_H_ 14 | -------------------------------------------------------------------------------- /bootloader/boot/bootloader_modbus.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bootloader_modbus.h Интерфейс Modbus загрузчика. 3 | */ 4 | 5 | #ifndef BOOTLOADER_MODBUS_H 6 | #define BOOTLOADER_MODBUS_H 7 | 8 | #include "defs/defs.h" 9 | #include "errors/errors.h" 10 | #include "modbus/modbus_rtu.h" 11 | #include 12 | 13 | 14 | //! Функция обратного вызова запуска приложения. 15 | typedef void (*bootloader_run_app_callback_t)(void); 16 | 17 | 18 | /** 19 | * Инициализирует интерфейс Modbus загрузчика. 20 | * @return Код ошибки. 21 | */ 22 | EXTERN err_t bootloader_modbus_init(void); 23 | 24 | /** 25 | * Устанавливает функцию обратного вызова запуска приложения. 26 | * @param callback Функция обратного вызова запуска приложения. 27 | */ 28 | EXTERN void bootloader_modbus_set_run_app_callback(bootloader_run_app_callback_t callback); 29 | 30 | /** 31 | * Настраивает Modbus для работы с загрузчиком. 32 | * @param modbus Модбас. 33 | * @return Код ошибки. 34 | */ 35 | EXTERN err_t bootloader_modbus_setup_modbus(modbus_rtu_t* modbus); 36 | 37 | #endif /* BOOTLOADER_MODBUS_H */ 38 | 39 | -------------------------------------------------------------------------------- /bootloader/boot/gdbinit.txt: -------------------------------------------------------------------------------- 1 | # Файл инициализации GDB. 2 | 3 | # Тайм-аут 10 сек. 4 | set remotetimeout 10 5 | 6 | # Лимиты. 7 | set remote hardware-watchpoint-limit 4 8 | set remote hardware-breakpoint-limit 6 9 | 10 | # Цель. 11 | target extended-remote | openocd -f "interface/stlink-v2.cfg" -f "target/stm32f1x.cfg" -c "gdb_port pipe" 12 | #; log_output openocd.log 13 | 14 | # Сброс. 15 | monitor reset halt 16 | 17 | # Файл отладки 18 | file main 19 | 20 | ## Раскомментировать, если необходимо 21 | ## каждый раз загружать прошивку. 22 | ## Загрузка прошивки. 23 | #load 24 | # 25 | ## Сброс. 26 | #monitor reset halt 27 | 28 | # Удалить точки останова. 29 | delete 30 | 31 | # Точка останова на main 32 | break main 33 | 34 | # Запуск 35 | continue 36 | -------------------------------------------------------------------------------- /bootloader/boot/stm32f103rb_bld_boot.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания адресов и областей памяти. 4 | */ 5 | 6 | /* Точка входа. */ 7 | ENTRY(Reset_Handler) 8 | 9 | /* Память. */ 10 | MEMORY 11 | { 12 | BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 8K /* Загрузчик. */ 13 | APP (rx) : ORIGIN = 0x08000000 + LENGTH(BOOT), LENGTH = 128K - LENGTH(BOOT) /* Флеш-память. */ 14 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K /* ОЗУ */ 15 | } 16 | 17 | /* Синоним региона. */ 18 | REGION_ALIAS("FLASH", BOOT); 19 | 20 | /* Минимальный размер стека. */ 21 | _min_stack_size = 0x200; 22 | 23 | /* Конец стека. */ 24 | _estack = ORIGIN(RAM) + LENGTH(RAM); 25 | 26 | /* Адрес начала сегмента основного приложения. */ 27 | _app_origin = ORIGIN(APP); 28 | 29 | /* Декларация секций. */ 30 | INCLUDE "stm32f10x_sections.ld" 31 | -------------------------------------------------------------------------------- /bootloader/boot/stm32f10x_conf.h: -------------------------------------------------------------------------------- 1 | #ifndef STM32F10X_CONF_H 2 | #define STM32F10X_CONF_H 3 | 4 | // #include "misc.h" 5 | // #include "stm32f10x_adc.h" 6 | // #include "stm32f10x_bkp.h" 7 | // #include "stm32f10x_can.h" 8 | // #include "stm32f10x_cec.h" 9 | // #include "stm32f10x_crc.h" 10 | // #include "stm32f10x_dac.h" 11 | // #include "stm32f10x_dbgmcu.h" 12 | // #include "stm32f10x_dma.h" 13 | // #include "stm32f10x_exti.h" 14 | // #include "stm32f10x_flash.h" 15 | // #include "stm32f10x_fsmc.h" 16 | // #include "stm32f10x_gpio.h" 17 | // #include "stm32f10x_i2c.h" 18 | // #include "stm32f10x_iwdg.h" 19 | // #include "stm32f10x_pwr.h" 20 | // #include "stm32f10x_rcc.h" 21 | // #include "stm32f10x_rtc.h" 22 | // #include "stm32f10x_sdio.h" 23 | // #include "stm32f10x_spi.h" 24 | // #include "stm32f10x_tim.h" 25 | // #include "stm32f10x_usart.h" 26 | // #include "stm32f10x_wwdg.h" 27 | 28 | #ifndef USE_FULL_ASSERT 29 | #define assert_param(param) 30 | #endif 31 | 32 | #endif //STM32F10X_CONF_H -------------------------------------------------------------------------------- /bootloader/boot/stm32f10x_sections.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания секций. 4 | */ 5 | 6 | /* Секции. */ 7 | SECTIONS 8 | { 9 | /* Вектора прерываний. */ 10 | .isr_vector : ALIGN(4) 11 | { 12 | _sisr = .; 13 | 14 | KEEP(*(.isr_vector)) 15 | 16 | . = ALIGN(4); 17 | _eisr = .; 18 | } > FLASH 19 | 20 | /* Код. */ 21 | .text : ALIGN(4) 22 | { 23 | _stext = .; 24 | 25 | *(.text) 26 | *(.text.*) 27 | *(.glue_7) 28 | *(.glue_7t) 29 | 30 | . = ALIGN(4); 31 | _etext = .; 32 | } > FLASH 33 | 34 | /* Данные только для чтения. */ 35 | .rodata : ALIGN(4) 36 | { 37 | _srodata = .; 38 | 39 | *(.rodata) 40 | *(.rodata.*) 41 | 42 | . = ALIGN(4); 43 | _erodata = .; 44 | } > FLASH 45 | 46 | /* Массив предварительной инициализации. */ 47 | .preinit : ALIGN(4) 48 | { 49 | _spreinit_array = .; 50 | 51 | KEEP(*(SORT(.preinit_array.*))) 52 | KEEP(*(.preinit_array)) 53 | 54 | . = ALIGN(4); 55 | _epreinit_array = .; 56 | } > FLASH 57 | 58 | /* Массив инициализации. */ 59 | .init : ALIGN(4) 60 | { 61 | _sinit_array = .; 62 | 63 | KEEP(*(SORT(.init_array.*))) 64 | KEEP(*(.init_array)) 65 | 66 | . = ALIGN(4); 67 | _einit_array = .; 68 | } > FLASH 69 | 70 | /* Массив деинициализации. */ 71 | .fini : ALIGN(4) 72 | { 73 | _sfini_array = .; 74 | 75 | KEEP(*(SORT(.fini_array.*))) 76 | KEEP(*(.fini_array)) 77 | 78 | . = ALIGN(4); 79 | _efini_array = .; 80 | } > FLASH 81 | 82 | /* ARM magic sections */ 83 | .ARM.extab : ALIGN(4) 84 | { 85 | *(.ARM.extab* .gnu.linkonce.armextab.*) 86 | } > FLASH 87 | 88 | .ARM.exidx : ALIGN(4) 89 | { 90 | __exidx_start = .; 91 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 92 | __exidx_end = .; 93 | } > FLASH 94 | 95 | . = ALIGN(4); 96 | /* Адрес инициализированных данных. */ 97 | _sidata = .; 98 | 99 | /* Инициализированные данные. */ 100 | .data : AT(_sidata) ALIGN(4) 101 | { 102 | _sdata = .; 103 | 104 | *(.data) 105 | *(.data.*) 106 | 107 | . = ALIGN(4); 108 | _edata = .; 109 | } > RAM 110 | 111 | /* Неинициализированные данные. */ 112 | .bss : ALIGN(4) 113 | { 114 | _sbss = .; 115 | 116 | *(.bss) 117 | *(.bss.*) 118 | *(COMMON) 119 | 120 | . = ALIGN(4); 121 | _ebss = .; 122 | } > RAM 123 | 124 | /* Стек минимального размера. */ 125 | .min_stack : ALIGN(4) 126 | { 127 | _smin_stack = .; 128 | 129 | . = . + _min_stack_size; 130 | 131 | . = ALIGN(4); 132 | _emin_stack = .; 133 | } > RAM 134 | 135 | /* Отладочная информация стандартных библиотек. */ 136 | /DISCARD/ : 137 | { 138 | libc.a ( * ) 139 | libm.a ( * ) 140 | libgcc.a ( * ) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /bootloader/boot/system_stm32f10x.c: -------------------------------------------------------------------------------- 1 | #include "system_stm32f10x.h" 2 | 3 | /** 4 | * Определение переменной со значением частоты ядра. 5 | * Частота по-умолчанию при включении равна 8 МГц. 6 | */ 7 | uint32_t SystemCoreClock = 8000000; 8 | 9 | -------------------------------------------------------------------------------- /bootloader/boot/system_stm32f10x.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file system_stm32f10x.h Библиотека инициализации часов. 3 | */ 4 | 5 | #ifndef _SYSTEM_STM32F10X_H_ 6 | #define _SYSTEM_STM32F10X_H_ 7 | 8 | #include 9 | 10 | //! Значение частоты ядра. 11 | extern uint32_t SystemCoreClock; 12 | 13 | #endif //_SYSTEM_STM32F10X_H_ 14 | -------------------------------------------------------------------------------- /buffer/buffer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file buffer.h 3 | * Функции для работы с буфером. 4 | */ 5 | 6 | #ifndef BUFFER_H 7 | #define BUFFER_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include "buffer_defs.h" 13 | #include "defs/defs.h" 14 | 15 | 16 | /** 17 | * Структура буфера. 18 | */ 19 | typedef struct _Buffer { 20 | uint8_t* ptr; 21 | size_t size; 22 | volatile size_t pos; 23 | }buffer_t; 24 | 25 | 26 | /** 27 | * Инициализирует буфер. 28 | * @param buffer Буфер. 29 | * @param ptr Указатель на данные. 30 | * @param size Размер данных. 31 | * @param pos Позиция в данных. 32 | */ 33 | ALWAYS_INLINE static void buffer_init(buffer_t* buffer, uint8_t* ptr, size_t size) 34 | { 35 | buffer->ptr = ptr; 36 | buffer->size = size; 37 | buffer->pos = 0; 38 | } 39 | 40 | /** 41 | * Сбрасывает позицию буфера. 42 | * @param buffer Буфер. 43 | */ 44 | ALWAYS_INLINE static void buffer_reset(buffer_t* buffer) 45 | { 46 | buffer->pos = 0; 47 | } 48 | 49 | /** 50 | * Получает флаг валидности буфера. 51 | * @param buffer Буфер. 52 | */ 53 | ALWAYS_INLINE static bool buffer_valid(buffer_t* buffer) 54 | { 55 | return buffer->ptr != NULL; 56 | } 57 | 58 | /** 59 | * Инкрементирует позицию буфера. 60 | * @param buffer Буфер. 61 | */ 62 | ALWAYS_INLINE static void buffer_next(buffer_t* buffer) 63 | { 64 | buffer->pos ++; 65 | } 66 | 67 | /** 68 | * Получает оставшееся число байт данных до конца. 69 | * @param buffer Буфер. 70 | * @return Оставшееся число байт. 71 | */ 72 | ALWAYS_INLINE static uint8_t buffer_remain(buffer_t* buffer) 73 | { 74 | return buffer->size - buffer->pos; 75 | } 76 | 77 | /** 78 | * Получает флаг нахождения указателя перед концом буфера. 79 | * @param buffer Буфер. 80 | * @return Флаг нахождения указателя перед концом буфера. 81 | */ 82 | ALWAYS_INLINE static bool buffer_at_last(buffer_t* buffer) 83 | { 84 | return BUFFER_POS_AT_LAST(buffer->pos, buffer->size); 85 | } 86 | 87 | /** 88 | * Получает флаг нахождения указателя в конце буфера. 89 | * @param buffer Буфер. 90 | * @return Флаг нахождения указателя в конце буфера. 91 | */ 92 | ALWAYS_INLINE static bool buffer_at_end(buffer_t* buffer) 93 | { 94 | return BUFFER_POS_AT_END(buffer->pos, buffer->size); 95 | } 96 | 97 | /** 98 | * Получает флаг наличия следующего байта в буфере. 99 | * @param buffer Буфер. 100 | * @return Флаг наличия следующего байта в буфере. 101 | */ 102 | ALWAYS_INLINE static bool buffer_has_next(buffer_t* buffer) 103 | { 104 | return BUFFER_POS_HAS_NEXT(buffer->pos, buffer->size); 105 | } 106 | 107 | /** 108 | * Получает байт из буфера в текущей позиции. 109 | * @param buffer Буфер. 110 | * @return Байт из буфера в текущей позиции. 111 | */ 112 | ALWAYS_INLINE static uint8_t buffer_get(buffer_t* buffer) 113 | { 114 | return BUFFER_POS_GET(buffer->ptr, buffer->pos); 115 | } 116 | 117 | /** 118 | * Получает байт из буфера в текущей позиции, инкрементируя указатель. 119 | * @param buffer Буфер. 120 | * @return Байт из буфера в текущей позиции. 121 | */ 122 | ALWAYS_INLINE static uint8_t buffer_get_next(buffer_t* buffer) 123 | { 124 | return BUFFER_POS_GET(buffer->ptr, buffer->pos ++); 125 | } 126 | 127 | /** 128 | * Записывает байт в буфер в текущую позицию. 129 | * @param buffer Буфер. 130 | * @param byte Байт. 131 | */ 132 | ALWAYS_INLINE static void buffer_set(buffer_t* buffer, uint8_t byte) 133 | { 134 | BUFFER_POS_SET(buffer->ptr, buffer->pos, byte); 135 | } 136 | 137 | /** 138 | * Записывает байт в буфер в текущую позицию, инкрементируя указатель. 139 | * @param buffer Буфер. 140 | * @param byte Байт. 141 | */ 142 | ALWAYS_INLINE static void buffer_set_next(buffer_t* buffer, uint8_t byte) 143 | { 144 | BUFFER_POS_SET(buffer->ptr, buffer->pos ++, byte); 145 | } 146 | 147 | 148 | #endif /* BUFFER_H */ 149 | 150 | -------------------------------------------------------------------------------- /buffer/buffer_defs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file buffer_defs.h 3 | * Макросы для работы с буфером. 4 | */ 5 | 6 | #ifndef BUFFER_DEFS_H 7 | #define BUFFER_DEFS_H 8 | 9 | /** 10 | * Имеется ли данные после позиции P в буфере размера S. 11 | */ 12 | #define BUFFER_POS_HAS_NEXT(P, S) (P < S) 13 | 14 | /** 15 | * Находится ли позиция P в конце буфера размера S. 16 | */ 17 | #define BUFFER_POS_AT_END(P, S) (P == S) 18 | 19 | /** 20 | * Находится ли позиция P перед концом буфера размера S. 21 | */ 22 | #define BUFFER_POS_AT_LAST(P, S) ((P + 1) == S) 23 | 24 | /** 25 | * Получает значение буфера с адресом PTR на позиции P. 26 | */ 27 | #define BUFFER_POS_GET(PTR, P) (PTR[P]) 28 | 29 | /** 30 | * Получает значение буфера с адресом PTR на позиции P со смещением O. 31 | */ 32 | #define BUFFER_POS_GET_OFFSET(PTR, P, O) (PTR[P + O]) 33 | 34 | /** 35 | * Устанавливает значение V буфера с адресом PTR на позиции P. 36 | */ 37 | #define BUFFER_POS_SET(PTR, P, V) (PTR[P] = V) 38 | 39 | /** 40 | * Устанавливает значение V буфера с адресом PTR на позиции P со смещением O. 41 | */ 42 | #define BUFFER_POS_SET_OFFSET(PTR, P, V) (PTR[P + O] = V) 43 | 44 | #endif /* BUFFER_DEFS_H */ 45 | 46 | -------------------------------------------------------------------------------- /buffer/circular_buffer.c: -------------------------------------------------------------------------------- 1 | #include "circular_buffer.h" 2 | #include 3 | #include "utils/utils.h" 4 | 5 | 6 | void circular_buffer_init(circular_buffer_t* buffer, uint8_t* ptr, size_t size) 7 | { 8 | buffer->ptr = ptr; 9 | buffer->put = 0; 10 | buffer->get = 0; 11 | buffer->size = size; 12 | buffer->count = 0; 13 | } 14 | 15 | void circular_buffer_reset(circular_buffer_t* buffer) 16 | { 17 | buffer->put = 0; 18 | buffer->get = 0; 19 | buffer->count = 0; 20 | } 21 | 22 | bool circular_buffer_valid(circular_buffer_t* buffer) 23 | { 24 | return /* buffer->size != 0 && */ buffer->ptr != NULL; 25 | } 26 | 27 | size_t circular_buffer_size(circular_buffer_t* buffer) 28 | { 29 | return buffer->size; 30 | } 31 | 32 | size_t circular_buffer_free_size(circular_buffer_t* buffer) 33 | { 34 | return buffer->size - buffer->count; 35 | } 36 | 37 | size_t circular_buffer_avail_size(circular_buffer_t* buffer) 38 | { 39 | return buffer->count; 40 | } 41 | 42 | size_t circular_buffer_put(circular_buffer_t* buffer, uint8_t data) 43 | { 44 | if(buffer->count == buffer->size) return 0; 45 | 46 | buffer->ptr[buffer->put] = data; 47 | 48 | CYCLIC_INC(buffer->put, 0, buffer->size); 49 | 50 | buffer->count ++; 51 | 52 | return 1; 53 | } 54 | 55 | size_t circular_buffer_get(circular_buffer_t* buffer, uint8_t* data) 56 | { 57 | if(buffer->count == 0) return 0; 58 | 59 | *data = buffer->ptr[buffer->get]; 60 | 61 | CYCLIC_INC(buffer->get, 0, buffer->size); 62 | 63 | buffer->count --; 64 | 65 | return 1; 66 | } 67 | 68 | size_t circular_buffer_peek(circular_buffer_t* buffer, uint8_t* data) 69 | { 70 | if(buffer->count == 0) return 0; 71 | 72 | *data = buffer->ptr[buffer->get]; 73 | 74 | return 1; 75 | } 76 | 77 | size_t circular_buffer_write(circular_buffer_t* buffer, const uint8_t* data, size_t size) 78 | { 79 | // Если места недостаточно или размер данных равен 0 - возврат 0. 80 | if(buffer->size - buffer->count < size || size == 0) return 0; 81 | 82 | size_t n; 83 | for(n = 0; n < size; n ++) circular_buffer_put(buffer, *data ++); 84 | 85 | return size; 86 | } 87 | 88 | size_t circular_buffer_read(circular_buffer_t* buffer, uint8_t* data, size_t size) 89 | { 90 | // Если в буфере нет данных, или размер данных равен 0 - возврат 0. 91 | if(buffer->count == 0 || size == 0) return 0; 92 | 93 | size_t n; 94 | for(n = 0; n < size; n ++) circular_buffer_get(buffer, data ++); 95 | 96 | return size; 97 | } 98 | 99 | -------------------------------------------------------------------------------- /buffer/circular_buffer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file circular_buffer.h 3 | * Функции для работы с кольцевым буфером. 4 | */ 5 | 6 | #ifndef CIRCULAR_BUFFER_H 7 | #define CIRCULAR_BUFFER_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include "defs/defs.h" 13 | 14 | 15 | /** 16 | * Структура кольцевого буфера. 17 | */ 18 | typedef struct _CircularBuffer { 19 | uint8_t* ptr; 20 | size_t size; 21 | volatile size_t put; 22 | volatile size_t get; 23 | volatile size_t count; 24 | }circular_buffer_t; 25 | 26 | 27 | /** 28 | * Инициализирует кольцевой буфер. 29 | * @param buffer Кольцевой буфер. 30 | * @param ptr Указатель на память для буфера. 31 | * @param size Размер буфера. 32 | */ 33 | EXTERN void circular_buffer_init(circular_buffer_t* buffer, uint8_t* ptr, size_t size); 34 | 35 | /** 36 | * Сбрасывает кольцевой буфер. 37 | * @param buffer Кольцевой буфер. 38 | */ 39 | EXTERN void circular_buffer_reset(circular_buffer_t* buffer); 40 | 41 | /** 42 | * Получает флаг валидности кольцевого буфера. 43 | * @param buffer Кольцевой буфер. 44 | * @return Флаг валидности кольцевого буфера. 45 | */ 46 | EXTERN bool circular_buffer_valid(circular_buffer_t* buffer); 47 | 48 | /** 49 | * Получает размер кольцевого буфера. 50 | * @param buffer Кольцевой буфер. 51 | * @return Размер кольцевого буфера. 52 | */ 53 | EXTERN size_t circular_buffer_size(circular_buffer_t* buffer); 54 | 55 | /** 56 | * Получает свободное место в кольцевом буфере. 57 | * @param buffer Кольцевой буфер. 58 | * @return Свободное место в кольцевом буфере. 59 | */ 60 | EXTERN size_t circular_buffer_free_size(circular_buffer_t* buffer); 61 | 62 | /** 63 | * Получает размер данных в кольцевом буфере. 64 | * @param buffer Кольцевой буфер. 65 | * @return Размер данных в кольцевом буфере. 66 | */ 67 | EXTERN size_t circular_buffer_avail_size(circular_buffer_t* buffer); 68 | 69 | /** 70 | * Помещает байт данных в кольцевой буфер. 71 | * @param buffer Кольцевой буфер. 72 | * @param data Байт данных. 73 | * @return Число помещённых данных в кольцевой буфер (ноль если места недостаточно). 74 | */ 75 | EXTERN size_t circular_buffer_put(circular_buffer_t* buffer, uint8_t data); 76 | 77 | /** 78 | * Получает байт данных из кольцевого буфера. 79 | * @param buffer Кольцевой буфер. 80 | * @param data Указатель на байт данных. 81 | * @return Число полученных данных из кольцевого буфера (ноль если нет данных). 82 | */ 83 | EXTERN size_t circular_buffer_get(circular_buffer_t* buffer, uint8_t* data); 84 | 85 | /** 86 | * Получает байт данных из кольцевого буфера без извлечения из буфера. 87 | * @param buffer Кольцевой буфер. 88 | * @param data Указатель на байт данных. 89 | * @return Число полученных данных из кольцевого буфера (ноль если нет данных). 90 | */ 91 | EXTERN size_t circular_buffer_peek(circular_buffer_t* buffer, uint8_t* data); 92 | 93 | /** 94 | * Помещает данные в кольцевой буфер. 95 | * @param buffer Кольцевой буфер. 96 | * @param data Данные. 97 | * @param size Размер данных. 98 | * @return Число помещённых данных в кольцевой буфер (ноль если места недостаточно). 99 | */ 100 | EXTERN size_t circular_buffer_write(circular_buffer_t* buffer, const uint8_t* data, size_t size); 101 | 102 | /** 103 | * Получает данные из кольцевого буфера. 104 | * @param buffer Кольцевой буфер. 105 | * @param data Указатель на данные. 106 | * @param size Размер данных. 107 | * @return Число полученных данных из кольцевого буфера (ноль если нет данных). 108 | */ 109 | EXTERN size_t circular_buffer_read(circular_buffer_t* buffer, uint8_t* data, size_t size); 110 | 111 | #endif /* CIRCULAR_BUFFER_H */ 112 | 113 | -------------------------------------------------------------------------------- /calc_lines_count.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find -type f -name "*.h" -or -name "*.c" -or -name "*m16" -or -name "*m8" | xargs cat | wc -l 4 | 5 | -------------------------------------------------------------------------------- /cordic/cordic10_6.c: -------------------------------------------------------------------------------- 1 | #include "cordic10_6.h" 2 | #include 3 | #include 4 | 5 | #define CORDIC10_6_TAN_TABLE_LEN 14 6 | static const fixed10_6_t cordic10_6_table[CORDIC10_6_TAN_TABLE_LEN] = { 7 | 2880, 1700, 898, 456, 229, 115, 57, 29, 14, 7, 4, 2, 1, 0 8 | }; 9 | #define CORDIC10_6_GAIN 39 //fixed10_6_t(0.607253) 10 | 11 | void cordic10_6_atan2_hyp(fixed10_6_t x, fixed10_6_t y, fixed10_6_t* angle, fixed10_6_t* hyp) 12 | { 13 | if(angle == NULL && hyp == NULL) return; 14 | 15 | fixed10_6_t sum_angle = 0; 16 | uint8_t loop_n = 0; 17 | 18 | fixed10_6_t new_x, new_y; 19 | 20 | if(x < 0){ 21 | x = -x; 22 | y = -y; 23 | sum_angle = CORDIC10_6_ANGLE_180; 24 | }else if(y < 0){ 25 | sum_angle = CORDIC10_6_ANGLE_360; 26 | } 27 | 28 | while((y != 0) && (loop_n < CORDIC10_6_TAN_TABLE_LEN)){ 29 | if(y > 0){ 30 | new_x = x + (y >> loop_n); 31 | new_y = y - (x >> loop_n); 32 | sum_angle += cordic10_6_table[loop_n]; 33 | }else{ 34 | new_x = x - (y >> loop_n); 35 | new_y = y + (x >> loop_n); 36 | sum_angle -= cordic10_6_table[loop_n]; 37 | } 38 | loop_n ++; 39 | x = new_x; 40 | y = new_y; 41 | } 42 | 43 | if(angle) { *angle = sum_angle; } 44 | if(hyp) { *hyp = x / 8 * CORDIC10_6_GAIN / 8; } 45 | } 46 | 47 | void cordic10_6_sincos(fixed10_6_t angle, fixed10_6_t* sin, fixed10_6_t* cos) 48 | { 49 | if(sin == NULL && cos == NULL) return; 50 | 51 | fixed10_6_t sum_angle = 0; 52 | uint8_t loop_n = 0; 53 | 54 | fixed10_6_t x = CORDIC10_6_GAIN; 55 | fixed10_6_t y = 0; 56 | 57 | fixed10_6_t new_x, new_y; 58 | 59 | if(angle >= CORDIC10_6_ANGLE_360) angle -= CORDIC10_6_ANGLE_360; 60 | else if(angle <= -CORDIC10_6_ANGLE_360) angle += CORDIC10_6_ANGLE_360; 61 | 62 | if(angle < 0) angle = CORDIC10_6_ANGLE_360 + angle; 63 | 64 | if(angle > CORDIC10_6_ANGLE_270) sum_angle = CORDIC10_6_ANGLE_360; 65 | else if(angle > CORDIC10_6_ANGLE_90) sum_angle = CORDIC10_6_ANGLE_180; 66 | 67 | while(loop_n < CORDIC10_6_TAN_TABLE_LEN){ 68 | if(sum_angle < angle){ 69 | new_x = x - (y >> loop_n); 70 | new_y = y + (x >> loop_n); 71 | sum_angle += cordic10_6_table[loop_n]; 72 | }else{ 73 | new_x = x + (y >> loop_n); 74 | new_y = y - (x >> loop_n); 75 | sum_angle -= cordic10_6_table[loop_n]; 76 | } 77 | loop_n ++; 78 | x = new_x; 79 | y = new_y; 80 | } 81 | 82 | if(angle > CORDIC10_6_ANGLE_90 && angle < CORDIC10_6_ANGLE_270){ x = -x; y = -y; } 83 | 84 | if(sin) { *sin = y; } 85 | if(cos) { *cos = x; } 86 | } 87 | -------------------------------------------------------------------------------- /cordic/cordic10_6.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cordic.h 3 | * Библиотека для вычисления тригонометрических функций алгоритмом CORDIC, 4 | * используя 10_6-битные числа с фиксированной запятой. 5 | */ 6 | #ifndef CORDIC10_6_H 7 | #define CORDIC10_6_H 8 | 9 | #include 10 | #include 11 | #include "fixed/fixed16.h" 12 | #include "defs/defs.h" 13 | 14 | // Углы. 15 | #define CORDIC10_6_ANGLE_90 5760 16 | #define CORDIC10_6_ANGLE_180 11520 17 | #define CORDIC10_6_ANGLE_270 17280 18 | #define CORDIC10_6_ANGLE_360 23040 19 | 20 | /** 21 | * Вычисляет угол и радиус от значений X и Y. 22 | * @param x Координата X. 23 | * @param y Координата Y. 24 | * @param angle Результат - угол, может быть передан NULL. 25 | * @param hyp Результат - радиус, может быть передан NULL. 26 | */ 27 | EXTERN void cordic10_6_atan2_hyp(fixed10_6_t x, fixed10_6_t y, fixed10_6_t* angle, fixed10_6_t* hyp); 28 | 29 | /** 30 | * Вычисляет синус и косинус угла. 31 | * @param angle Угол. 32 | * @param sin Результат: синус угла, может быть передан NULL. 33 | * @param cos Результат: косинус угла, может быть передан NULL. 34 | */ 35 | EXTERN void cordic10_6_sincos(fixed10_6_t angle, fixed10_6_t* sin, fixed10_6_t* cos); 36 | 37 | #endif /* CORDIC10_6_H */ 38 | -------------------------------------------------------------------------------- /cordic/cordic16.c: -------------------------------------------------------------------------------- 1 | #include "cordic16.h" 2 | #include 3 | #include 4 | 5 | #define CORDIC16_TAN_TABLE_LEN 16 6 | static const fixed16_t cordic16_table[CORDIC16_TAN_TABLE_LEN] = { 7 | 11520, 6801, 3593, 1824, 916, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1, 0 8 | }; 9 | #define CORDIC16_GAIN 155 //fixed16_t(0.607253) 10 | 11 | void cordic16_atan2_hyp(fixed16_t x, fixed16_t y, fixed16_t* angle, fixed16_t* hyp) 12 | { 13 | if(angle == NULL && hyp == NULL) return; 14 | 15 | fixed16_t sum_angle = 0; 16 | uint8_t loop_n = 0; 17 | 18 | fixed16_t new_x, new_y; 19 | 20 | while((y != 0) && (loop_n < CORDIC16_TAN_TABLE_LEN)){ 21 | if(y > 0){ 22 | new_x = x + (y >> loop_n); 23 | new_y = y - (x >> loop_n); 24 | sum_angle += cordic16_table[loop_n]; 25 | }else{ 26 | new_x = x - (y >> loop_n); 27 | new_y = y + (x >> loop_n); 28 | sum_angle -= cordic16_table[loop_n]; 29 | } 30 | loop_n ++; 31 | x = new_x; 32 | y = new_y; 33 | } 34 | 35 | if(angle) { *angle = sum_angle; } 36 | if(hyp) { *hyp = x / 16 * CORDIC16_GAIN / 16; } 37 | } 38 | 39 | void cordic16_sincos(fixed16_t angle, fixed16_t* sin, fixed16_t* cos) 40 | { 41 | if(sin == NULL && cos == NULL) return; 42 | 43 | fixed16_t sum_angle = 0; 44 | uint8_t loop_n = 0; 45 | 46 | fixed16_t x = CORDIC16_GAIN; 47 | fixed16_t y = 0; 48 | 49 | fixed16_t new_x, new_y; 50 | 51 | while(loop_n < CORDIC16_TAN_TABLE_LEN){ 52 | if(sum_angle < angle){ 53 | new_x = x - (y >> loop_n); 54 | new_y = y + (x >> loop_n); 55 | sum_angle += cordic16_table[loop_n]; 56 | }else{ 57 | new_x = x + (y >> loop_n); 58 | new_y = y - (x >> loop_n); 59 | sum_angle -= cordic16_table[loop_n]; 60 | } 61 | loop_n ++; 62 | x = new_x; 63 | y = new_y; 64 | } 65 | 66 | if(sin) { *sin = y; } 67 | if(cos) { *cos = x; } 68 | } 69 | -------------------------------------------------------------------------------- /cordic/cordic16.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cordic.h 3 | * Библиотека для вычисления тригонометрических функций алгоритмом CORDIC, 4 | * используя 16-битные числа с фиксированной запятой. 5 | */ 6 | #ifndef CORDIC16_H 7 | #define CORDIC16_H 8 | 9 | #include 10 | #include 11 | #include "fixed/fixed16.h" 12 | #include "defs/defs.h" 13 | 14 | // Углы. 15 | #define CORDIC16_ANGLE_90 23040 16 | 17 | /** 18 | * Вычисляет угол и радиус от значений X и Y. 19 | * @param x Координата X. 20 | * @param y Координата Y. 21 | * @param angle Результат - угол, может быть передан NULL. 22 | * @param hyp Результат - радиус, может быть передан NULL. 23 | */ 24 | EXTERN void cordic16_atan2_hyp(fixed16_t x, fixed16_t y, fixed16_t* angle, fixed16_t* hyp); 25 | 26 | /** 27 | * Вычисляет синус и косинус угла. 28 | * @param angle Угол. 29 | * @param sin Результат: синус угла, может быть передан NULL. 30 | * @param cos Результат: косинус угла, может быть передан NULL. 31 | */ 32 | EXTERN void cordic16_sincos(fixed16_t angle, fixed16_t* sin, fixed16_t* cos); 33 | 34 | #endif /* CORDIC16_H */ 35 | 36 | -------------------------------------------------------------------------------- /cordic/cordic32.c: -------------------------------------------------------------------------------- 1 | #include "cordic32.h" 2 | #include 3 | #include 4 | 5 | #define CORDIC32_TAN_TABLE_LEN 24 6 | static const fixed32_t cordic32_table[CORDIC32_TAN_TABLE_LEN] = { 7 | 2949120, 1740967, 919879, 466945, 234379, 117304, 58666, 29335, 14668, 8 | 7334, 3667, 1833, 917, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1, 0 9 | }; 10 | #define CORDIC32_GAIN 39797 //fixed32_t(0.607253) 11 | 12 | void cordic32_atan2_hyp(fixed32_t x, fixed32_t y, fixed32_t* angle, fixed32_t* hyp) 13 | { 14 | if(angle == NULL && hyp == NULL) return; 15 | 16 | fixed32_t sum_angle = 0; 17 | uint8_t loop_n = 0; 18 | 19 | fixed32_t new_x, new_y; 20 | 21 | if(x < 0){ 22 | x = -x; 23 | y = -y; 24 | sum_angle = CORDIC32_ANGLE_180; 25 | }else if(y < 0){ 26 | sum_angle = CORDIC32_ANGLE_360; 27 | } 28 | 29 | while((y != 0) && (loop_n < CORDIC32_TAN_TABLE_LEN)){ 30 | if(y > 0){ 31 | new_x = x + (y >> loop_n); 32 | new_y = y - (x >> loop_n); 33 | sum_angle += cordic32_table[loop_n]; 34 | }else{ 35 | new_x = x - (y >> loop_n); 36 | new_y = y + (x >> loop_n); 37 | sum_angle -= cordic32_table[loop_n]; 38 | } 39 | loop_n ++; 40 | x = new_x; 41 | y = new_y; 42 | } 43 | 44 | if(angle) { *angle = sum_angle; } 45 | if(hyp) { *hyp = x / 256 * CORDIC32_GAIN / 256; } 46 | } 47 | 48 | void cordic32_sincos(fixed32_t angle, fixed32_t* sin, fixed32_t* cos) 49 | { 50 | if(sin == NULL && cos == NULL) return; 51 | 52 | fixed32_t sum_angle = 0; 53 | uint8_t loop_n = 0; 54 | 55 | fixed32_t x = CORDIC32_GAIN; 56 | fixed32_t y = 0; 57 | 58 | fixed32_t new_x, new_y; 59 | 60 | if(angle >= CORDIC32_ANGLE_360) angle -= CORDIC32_ANGLE_360; 61 | else if(angle <= -CORDIC32_ANGLE_360) angle += CORDIC32_ANGLE_360; 62 | 63 | if(angle < 0) angle = CORDIC32_ANGLE_360 + angle; 64 | 65 | if(angle > CORDIC32_ANGLE_270) sum_angle = CORDIC32_ANGLE_360; 66 | else if(angle > CORDIC32_ANGLE_90) sum_angle = CORDIC32_ANGLE_180; 67 | 68 | while(loop_n < CORDIC32_TAN_TABLE_LEN){ 69 | if(sum_angle < angle){ 70 | new_x = x - (y >> loop_n); 71 | new_y = y + (x >> loop_n); 72 | sum_angle += cordic32_table[loop_n]; 73 | }else{ 74 | new_x = x + (y >> loop_n); 75 | new_y = y - (x >> loop_n); 76 | sum_angle -= cordic32_table[loop_n]; 77 | } 78 | loop_n ++; 79 | x = new_x; 80 | y = new_y; 81 | } 82 | 83 | if(angle > CORDIC32_ANGLE_90 && angle < CORDIC32_ANGLE_270){ x = -x; y = -y; } 84 | 85 | if(sin) { *sin = y; } 86 | if(cos) { *cos = x; } 87 | } 88 | -------------------------------------------------------------------------------- /cordic/cordic32.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cordic.h 3 | * Библиотека для вычисления тригонометрических функций алгоритмом CORDIC, 4 | * используя 32-битные числа с фиксированной запятой. 5 | */ 6 | #ifndef CORDIC32_H 7 | #define CORDIC32_H 8 | 9 | #include 10 | #include 11 | #include "fixed/fixed32.h" 12 | #include "defs/defs.h" 13 | 14 | // Углы. 15 | #define CORDIC32_ANGLE_90 5898240 16 | #define CORDIC32_ANGLE_180 11796480 17 | #define CORDIC32_ANGLE_270 17694720 18 | #define CORDIC32_ANGLE_360 23592960 19 | 20 | /** 21 | * Вычисляет угол и радиус от значений X и Y. 22 | * @param x Координата X. 23 | * @param y Координата Y. 24 | * @param angle Результат - угол, может быть передан NULL. 25 | * @param hyp Результат - радиус, может быть передан NULL. 26 | */ 27 | EXTERN void cordic32_atan2_hyp(fixed32_t x, fixed32_t y, fixed32_t* angle, fixed32_t* hyp); 28 | 29 | /** 30 | * Вычисляет синус и косинус угла. 31 | * @param angle Угол. 32 | * @param sin Результат: синус угла, может быть передан NULL. 33 | * @param cos Результат: косинус угла, может быть передан NULL. 34 | */ 35 | EXTERN void cordic32_sincos(fixed32_t angle, fixed32_t* sin, fixed32_t* cos); 36 | 37 | #endif /* CORDIC32_H */ 38 | -------------------------------------------------------------------------------- /counter/counter.c: -------------------------------------------------------------------------------- 1 | #include "counter.h" 2 | 3 | 4 | 5 | /*void counter_init(counter_t* counter) 6 | { 7 | *counter = 0; 8 | } 9 | 10 | void counter_tick(counter_t* counter) 11 | { 12 | (*counter) ++; 13 | }*/ 14 | 15 | counter_diff_t counter_diff(counter_t* counter_next, counter_t* counter_prev) 16 | { 17 | if(*counter_prev > *counter_next){ 18 | return *counter_next - (counter_int_t)*counter_prev; 19 | } 20 | return *counter_next - *counter_prev; 21 | } 22 | 23 | 24 | typedef struct _Sys_Counter_State { 25 | counter_t counter; 26 | counter_t ticks_per_sec; 27 | } system_counter_state_t; 28 | 29 | static system_counter_state_t sys_counter_state; 30 | 31 | 32 | void system_counter_init(counter_t ticks_per_sec) 33 | { 34 | sys_counter_state.counter = 0; 35 | sys_counter_state.ticks_per_sec = ticks_per_sec; 36 | } 37 | 38 | void system_counter_tick() 39 | { 40 | sys_counter_state.counter ++; 41 | } 42 | 43 | counter_diff_t system_counter_diff(counter_t* counter) 44 | { 45 | return counter_diff(&sys_counter_state.counter, counter); 46 | } 47 | 48 | counter_t system_counter_ticks() 49 | { 50 | return sys_counter_state.counter; 51 | } 52 | 53 | counter_t system_counter_ticks_per_sec() 54 | { 55 | return sys_counter_state.ticks_per_sec; 56 | } 57 | 58 | void system_counter_set_ticks_per_sec(counter_t ticks_per_sec) 59 | { 60 | sys_counter_state.ticks_per_sec = ticks_per_sec; 61 | } 62 | -------------------------------------------------------------------------------- /counter/counter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file counter.h 3 | * Библиотека для работы со счётчиками и системный счётчик. 4 | */ 5 | 6 | #ifndef COUNTER_H 7 | #define COUNTER_H 8 | 9 | #include 10 | #include "defs/defs.h" 11 | 12 | #define COUNTER_BITS 32 13 | 14 | #define MAKE_COUNTER_TYPE(type, bits) type ## bits ## _t 15 | 16 | typedef volatile MAKE_COUNTER_TYPE(uint, 32) counter_uint_t; 17 | typedef volatile MAKE_COUNTER_TYPE(int, 32) counter_int_t; 18 | 19 | typedef counter_uint_t counter_t; 20 | typedef counter_uint_t counter_diff_t; 21 | 22 | /** 23 | * Инициализирует счётчик. 24 | * @param counter Счётчик. 25 | */ 26 | ALWAYS_INLINE static void counter_init(counter_t* counter) 27 | { 28 | *counter = 0; 29 | } 30 | 31 | /** 32 | * Инкрементирует счётчик. 33 | * @param counter Счётчик. 34 | */ 35 | ALWAYS_INLINE static void counter_tick(counter_t* counter) 36 | { 37 | (*counter) ++; 38 | } 39 | 40 | /** 41 | * Вычисляет разницу между предыдущим счётчиком counter_prev и текущим counter_next. 42 | * @param counter_next Текущий счётчик. 43 | * @param counter_prev Предыдущий счётчик. 44 | * @return Разница между счётчиками. 45 | */ 46 | EXTERN counter_diff_t counter_diff(counter_t* counter_next, counter_t* counter_prev); 47 | 48 | 49 | /* 50 | * Системный счётчик. 51 | */ 52 | 53 | /** 54 | * Инициализация системного счётчика. 55 | * @param ticks_per_sec Число тиков за секунду. 56 | */ 57 | EXTERN void system_counter_init(counter_t ticks_per_sec); 58 | 59 | /** 60 | * Инкремент системного счётчика. 61 | */ 62 | EXTERN void system_counter_tick(); 63 | 64 | /** 65 | * Получения разницы между сохранённым и системным счётчиком. 66 | * @param counter Сохранённый счётчик. 67 | * @return Разница между счётчиками. 68 | */ 69 | EXTERN counter_diff_t system_counter_diff(counter_t* counter); 70 | 71 | /** 72 | * Получение числа тиков системного счётчика. 73 | * @return Число тиков системного счётчика. 74 | */ 75 | EXTERN counter_t system_counter_ticks(); 76 | 77 | /** 78 | * Число тиков системного счётчика в секунду. 79 | * @return Число тиков системного счётчика в секунду. 80 | */ 81 | EXTERN counter_t system_counter_ticks_per_sec(); 82 | 83 | /** 84 | * Устанавливает значение числа тиков за секунду. 85 | * @param ticks_per_sec Число тиков за секунду. 86 | */ 87 | EXTERN void system_counter_set_ticks_per_sec(counter_t ticks_per_sec); 88 | 89 | #endif /* COUNTER_H */ 90 | 91 | -------------------------------------------------------------------------------- /crc/crc16_ccitt.c: -------------------------------------------------------------------------------- 1 | #include "crc16_ccitt.h" 2 | 3 | /* 4 | Name : CRC-16 CCITT 5 | Poly : 0x1021 x^16 + x^12 + x^5 + 1 6 | Init : 0xFFFF 7 | Revert: false 8 | XorOut: 0x0000 9 | Check : 0x29B1 ("123456789") 10 | MaxLen: 4095 байт (32767 бит) - обнаружение 11 | одинарных, двойных, тройных и всех нечетных ошибок 12 | */ 13 | static const uint16_t crc16_ccitt_table[256] = { 14 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 15 | 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 16 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 17 | 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 18 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 19 | 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 20 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 21 | 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 22 | 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 23 | 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 24 | 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 25 | 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 26 | 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 27 | 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 28 | 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 29 | 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 30 | 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 31 | 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 32 | 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 33 | 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 34 | 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 35 | 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 36 | 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 37 | 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 38 | 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 39 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 40 | 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 41 | 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 42 | 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 43 | 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 44 | 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 45 | 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 46 | }; 47 | 48 | uint16_t crc16_ccitt(const void* data, size_t size) 49 | { 50 | uint16_t crc = 0xffff; 51 | 52 | while (size --) 53 | crc = (crc << 8) ^ crc16_ccitt_table[(crc >> 8) ^ *(uint8_t*)data ++]; 54 | 55 | return crc; 56 | } 57 | 58 | uint16_t crc16_ccitt_initial(const void* data, size_t size, uint16_t init) 59 | { 60 | uint16_t crc = init; 61 | 62 | while (size --) 63 | crc = (crc << 8) ^ crc16_ccitt_table[(crc >> 8) ^ *(uint8_t*)data ++]; 64 | 65 | return crc; 66 | } 67 | 68 | uint16_t crc16_ccitt_first(void) 69 | { 70 | return 0xffff; 71 | } 72 | 73 | uint16_t crc16_ccitt_next(uint16_t crc, const void* data) 74 | { 75 | return (crc << 8) ^ crc16_ccitt_table[(crc >> 8) ^ *(uint8_t*)data]; 76 | } 77 | -------------------------------------------------------------------------------- /crc/crc16_ccitt.h: -------------------------------------------------------------------------------- 1 | #ifndef CRC16_CCITT_H 2 | #define CRC16_CCITT_H 3 | 4 | #include 5 | #include 6 | #include "defs/defs.h" 7 | 8 | /** 9 | * Вычисляет CRC16 CCITT переданных данных. 10 | * Полином x^16 + x^12 + x^5 + 1 (0x1021). 11 | * Начальное значение 0xffff. 12 | * @param data Данные. 13 | * @param size Размер данных. 14 | * @return CRC16. 15 | */ 16 | EXTERN uint16_t crc16_ccitt(const void* data, size_t size); 17 | 18 | /** 19 | * Вычисляет CRC16 CCITT переданных данных 20 | * с заданным начальным значением. 21 | * Полином x^16 + x^12 + x^5 + 1 (0x1021). 22 | * @param data Данные. 23 | * @param size Размер данных. 24 | * @param init Начальное значение. 25 | * @return CRC16. 26 | */ 27 | EXTERN uint16_t crc16_ccitt_initial(const void* data, size_t size, uint16_t init); 28 | 29 | /** 30 | * Получает начальное значение CRC16 CCITT. 31 | * @return Начальное значение CRC16. 32 | */ 33 | EXTERN uint16_t crc16_ccitt_first(void); 34 | 35 | /** 36 | * Вычисляет CRC16 CCITT для очередного байта данных. 37 | * @param crc Предыдущее значение CRC16. 38 | * @param data Указатель на очередной байт данных. 39 | * @return CRC16. 40 | */ 41 | EXTERN uint16_t crc16_ccitt_next(uint16_t crc, const void* data); 42 | 43 | #endif //CRC16_CCITT_H 44 | -------------------------------------------------------------------------------- /debounce/debounce.c: -------------------------------------------------------------------------------- 1 | #include "debounce.h" 2 | 3 | 4 | void debounce_init(debounce_t* debounce) 5 | { 6 | debounce->timeout = 0; 7 | debounce->time = 0; 8 | debounce->state = false; 9 | debounce->changed = false; 10 | } 11 | 12 | void debounce_reset(debounce_t* debounce) 13 | { 14 | debounce->time = 0; 15 | debounce->state = false; 16 | debounce->changed = false; 17 | } 18 | 19 | void debounce_init_timeout(debounce_t* debounce, fixed32_t timeout) 20 | { 21 | debounce->timeout = timeout; 22 | debounce->time = 0; 23 | debounce->state = false; 24 | debounce->changed = false; 25 | } 26 | 27 | void debounce_set_timeout(debounce_t* debounce, fixed32_t timeout) 28 | { 29 | debounce->timeout = timeout; 30 | } 31 | 32 | bool debounce_process(debounce_t* debounce, bool state, fixed32_t dt) 33 | { 34 | if(state != debounce->state){ 35 | debounce->time += dt; 36 | if(debounce->time >= debounce->timeout){ 37 | debounce->state = state; 38 | debounce->time = 0; 39 | debounce->changed = true; 40 | } 41 | }else{ 42 | debounce->time = 0; 43 | debounce->changed = false; 44 | } 45 | 46 | return debounce->changed; 47 | } 48 | 49 | bool debounce_state_changed(debounce_t* debounce) 50 | { 51 | return debounce->changed; 52 | } 53 | 54 | bool debounce_state_stable(debounce_t* debounce) 55 | { 56 | return debounce->time == 0; 57 | } 58 | 59 | bool debounce_state(debounce_t* debounce) 60 | { 61 | return debounce->state; 62 | } 63 | -------------------------------------------------------------------------------- /debounce/debounce.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file debounce.h Библиотека устранения дребезга величин. 3 | */ 4 | 5 | #ifndef DEBOUNCE_H_ 6 | #define DEBOUNCE_H_ 7 | 8 | #include "defs/defs.h" 9 | #include 10 | #include "fixed/fixed32.h" 11 | #include 12 | 13 | /** 14 | * Тип структуры устранения дребезга величин. 15 | */ 16 | typedef struct _Debounce { 17 | fixed32_t timeout; //!< Тайм-аут изменения величины. 18 | fixed32_t time; //!< Время с последнего изменения величины. 19 | bool changed; //!< Флаг изменения состояния величины. 20 | bool state; //!< Текущее состояние величины. 21 | } debounce_t; 22 | 23 | /** 24 | * Инициализирует устранение дребезга. 25 | * @param debounce Устранение дребезга. 26 | */ 27 | EXTERN void debounce_init(debounce_t* debounce); 28 | 29 | /** 30 | * Сбрасывает устранение дребезга. 31 | * @param debounce Устранение дребезга. 32 | */ 33 | EXTERN void debounce_reset(debounce_t* debounce); 34 | 35 | /** 36 | * Инициализирует устранение дребезга. 37 | * @param debounce Устранение дребезга. 38 | * @param deadtime Тайм-аут. 39 | */ 40 | EXTERN void debounce_init_timeout(debounce_t* debounce, fixed32_t timeout); 41 | 42 | /** 43 | * Устанавливает тайм-аут. 44 | * @param debounce Устранение дребезга. 45 | * @param timeout Тайм-аут. 46 | */ 47 | EXTERN void debounce_set_timeout(debounce_t* debounce, fixed32_t timeout); 48 | 49 | /** 50 | * Выполняет обработку состояния величины. 51 | * @param debounce Устранение дребезга. 52 | * @param state Состояние величины. 53 | * @param dt Интервал времени с последней обработки. 54 | * @return Флаг изменения состояния величины. 55 | */ 56 | EXTERN bool debounce_process(debounce_t* debounce, bool state, fixed32_t dt); 57 | 58 | /** 59 | * Получает флаг изменения состояния величины. 60 | * @param debounce Устранение дребезга. 61 | * @return Флаг изменения состояния величины. 62 | */ 63 | EXTERN bool debounce_state_changed(debounce_t* debounce); 64 | 65 | /** 66 | * Получает флаг стабильности состояния величины. 67 | * @param debounce Устранение дребезга. 68 | * @return Флаг стабильности состояния величины. 69 | */ 70 | EXTERN bool debounce_state_stable(debounce_t* debounce); 71 | 72 | /** 73 | * Получает состояние величины. 74 | * @param debounce Устранение дребезга. 75 | * @return Состояние величины. 76 | */ 77 | EXTERN bool debounce_state(debounce_t* debounce); 78 | 79 | #endif /* DEBOUNCE_H_ */ 80 | -------------------------------------------------------------------------------- /defs/defs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file defs.h 3 | * Общие часто встречающиеся макросы. 4 | */ 5 | 6 | #ifndef DEFS_H 7 | #define DEFS_H 8 | 9 | #ifdef __cplusplus 10 | #define EXTERN extern "C" 11 | #else 12 | #define EXTERN extern 13 | #endif 14 | 15 | #define ALWAYS_INLINE inline __attribute__((always_inline)) 16 | 17 | #define WEAK __attribute__((weak)) 18 | 19 | #define PACKED __attribute__((packed)) 20 | 21 | #define STRING(s) #s 22 | #define MAKE_STRING(s) STRING(s) 23 | #define CONCAT_SIMPLE(a, ...) a ## __VA_ARGS__ 24 | #define CONCAT_SIMPLE3(a, b, ...) a ## b ## __VA_ARGS__ 25 | #define CONCAT(a, ...) CONCAT_SIMPLE(a, __VA_ARGS__) 26 | 27 | #define IS_NULL_ARG_IS_NULL 1, 1, 28 | #define IS_NULL_ARGS(t, res, ...) res 29 | #define IS_NULL_IMPL(...) IS_NULL_ARGS(__VA_ARGS__) 30 | #define IS_NULL_ARG(n) IS_NULL_IMPL(n, 0) 31 | #define IS_NULL(n) IS_NULL_IMPL(IS_NULL_ARG_IS_ ## n, 0) 32 | 33 | #define IF(cond) CONCAT_SIMPLE(IF_, cond) 34 | #define IF_1(if_true, ...) if_true 35 | #define IF_0(if_true, ...) __VA_ARGS__ 36 | 37 | #define IF_NOT(cond) CONCAT_SIMPLE(IF_NOT_, cond) 38 | #define IF_NOT_1(if_true, ...) __VA_ARGS__ 39 | #define IF_NOT_0(if_true, ...) if_true 40 | 41 | #endif /* DEFS_H */ 42 | 43 | -------------------------------------------------------------------------------- /dma/dma.c: -------------------------------------------------------------------------------- 1 | #include "dma.h" 2 | #include "mutex/mutex.h" 3 | 4 | #define DMA_CHANNELS_COUNT 12 5 | 6 | static mutex_t dma_mutexes[DMA_CHANNELS_COUNT] = {MUTEX_UNLOCKED}; 7 | 8 | uint32_t dma_channel_number(DMA_Channel_TypeDef* dma_channel) 9 | { 10 | if((uint32_t)dma_channel >= DMA1_Channel1_BASE && 11 | (uint32_t)dma_channel <= DMA1_Channel7_BASE){ 12 | 13 | return ((uint32_t)dma_channel - DMA1_Channel1_BASE) / 0x14 + 1; 14 | 15 | }else if((uint32_t)dma_channel >= DMA2_Channel1_BASE && 16 | (uint32_t)dma_channel <= DMA2_Channel5_BASE){ 17 | 18 | return ((uint32_t)dma_channel - DMA2_Channel1_BASE) / 0x14 + 8; 19 | } 20 | return 0; 21 | } 22 | 23 | DMA_TypeDef* dma_channel_dma_periph(DMA_Channel_TypeDef* dma_channel) 24 | { 25 | if((uint32_t)dma_channel >= DMA1_Channel1_BASE && 26 | (uint32_t)dma_channel <= DMA1_Channel7_BASE){ 27 | 28 | return DMA1; 29 | 30 | }else if((uint32_t)dma_channel >= DMA2_Channel1_BASE && 31 | (uint32_t)dma_channel <= DMA2_Channel5_BASE){ 32 | 33 | return DMA2; 34 | } 35 | return 0; 36 | } 37 | 38 | uint32_t dma_channel_it_flag(DMA_Channel_TypeDef* dma_channel, uint32_t dma_it_flag) 39 | { 40 | uint32_t channel_number = dma_channel_number(dma_channel); 41 | 42 | // Error. 43 | if(channel_number == 0) return 0; 44 | // DMA1. 45 | if(channel_number <= 7) return dma_it_flag << ((channel_number - 1) * 4); 46 | // DMA2. 47 | return (dma_it_flag << ((channel_number - 8) * 4)) | DMA_PERIPH_SEL; 48 | } 49 | 50 | bool dma_channel_it_flag_status(uint32_t dma_ch_it_flag) 51 | { 52 | // DMA1 53 | if(!(dma_ch_it_flag & DMA_PERIPH_SEL)){ 54 | return (DMA1->ISR & dma_ch_it_flag) != 0; 55 | } 56 | // DMA2. 57 | else{ 58 | return (DMA2->ISR & (dma_ch_it_flag & ~DMA_PERIPH_SEL)) != 0; 59 | } 60 | } 61 | 62 | void dma_channel_it_flag_clear(uint32_t dma_ch_it_flag) 63 | { 64 | // DMA1 65 | if(!(dma_ch_it_flag & DMA_PERIPH_SEL)){ 66 | DMA1->IFCR = dma_ch_it_flag; 67 | } 68 | // DMA2. 69 | else{ 70 | DMA2->IFCR = (dma_ch_it_flag & ~DMA_PERIPH_SEL); 71 | } 72 | } 73 | 74 | err_t dma_channel_lock(DMA_Channel_TypeDef* dma_channel) 75 | { 76 | uint32_t channel_number = dma_channel_number(dma_channel); 77 | 78 | if(channel_number == 0) return E_INVALID_VALUE; 79 | 80 | mutex_lock(&dma_mutexes[channel_number - 1]); 81 | 82 | return E_NO_ERROR; 83 | } 84 | 85 | bool dma_channel_trylock(DMA_Channel_TypeDef* dma_channel) 86 | { 87 | uint32_t channel_number = dma_channel_number(dma_channel); 88 | 89 | if(channel_number == 0) return false; 90 | 91 | return mutex_trylock(&dma_mutexes[channel_number - 1]); 92 | } 93 | 94 | err_t dma_channel_unlock(DMA_Channel_TypeDef* dma_channel) 95 | { 96 | uint32_t channel_number = dma_channel_number(dma_channel); 97 | 98 | if(channel_number == 0) return E_INVALID_VALUE; 99 | 100 | mutex_unlock(&dma_mutexes[channel_number - 1]); 101 | 102 | return E_NO_ERROR; 103 | } 104 | -------------------------------------------------------------------------------- /dma/dma.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dma.h Утилиты по работе с DMA. 3 | */ 4 | 5 | #ifndef DMA_H 6 | #define DMA_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include "errors/errors.h" 12 | #include "defs/defs.h" 13 | 14 | /* 15 | * Флаги прерываний DMA. 16 | */ 17 | //! Флаг глобального прерывания. 18 | #ifndef DMA_IT_GL 19 | #define DMA_IT_GL 0x1 20 | #endif 21 | //! Флаг прерывания завершения передачи. 22 | #ifndef DMA_IT_TC 23 | #define DMA_IT_TC 0x2 24 | #endif 25 | //! Флаг прерывания завершения половины передачи. 26 | #ifndef DMA_IT_HT 27 | #define DMA_IT_HT 0x4 28 | #endif 29 | //! Флаг прерывания ошибки передачи. 30 | #ifndef DMA_IT_TE 31 | #define DMA_IT_TE 0x8 32 | #endif 33 | 34 | //! Селектор периферии DMA. 35 | #define DMA_PERIPH_SEL 0x10000000 36 | 37 | /** 38 | * Получает номер канала DMA, 1-7 для DMA1 и 8-12 для DMA2. 39 | * @param dma_channel Канал DMA. 40 | * @return Номер канала DMA, либо 0 в случае ошибки. 41 | */ 42 | EXTERN uint32_t dma_channel_number(DMA_Channel_TypeDef* dma_channel); 43 | 44 | /** 45 | * Получает периферию DMA заданного канала. 46 | * @param dma_channel Канал DMA. 47 | * @return Периферия DMA. 48 | */ 49 | EXTERN DMA_TypeDef* dma_channel_dma_periph(DMA_Channel_TypeDef* dma_channel); 50 | 51 | /** 52 | * Получает заданный флаг прерывания для заданного канала. 53 | * Если канал принадлежит DMA2 - в результате установлен флаг DMA_PERIPH_SEL. 54 | * @param dma_channel Канал DMA. 55 | * @param dma_it_flag Флаг прерывания (DMA_IT_GL, DMA_IT_TC, DMA_IT_HT, DMA_IT_TE). 56 | * @return Флаг прерывания для заданного канала, 0 в случае ошибки. 57 | */ 58 | EXTERN uint32_t dma_channel_it_flag(DMA_Channel_TypeDef* dma_channel, uint32_t dma_it_flag); 59 | 60 | /** 61 | * Получает состояние флага прерывания для заданного канала 62 | * @param dma_ch_it_flag Флаг прерывания канала DMA. 63 | * @return Состояние флага прерывания канала DMA. 64 | */ 65 | EXTERN bool dma_channel_it_flag_status(uint32_t dma_ch_it_flag); 66 | 67 | /** 68 | * Очищает флаг прерывания для заданного канала. 69 | * @param dma_ch_it_flag Флаг прерывания канала DMA. 70 | */ 71 | EXTERN void dma_channel_it_flag_clear(uint32_t dma_ch_it_flag); 72 | 73 | /** 74 | * Ждёт разблокировки канала DMA и блокирует его. 75 | * @param dma_channel Канал DMA. 76 | * @return Код ошибки. 77 | */ 78 | EXTERN err_t dma_channel_lock(DMA_Channel_TypeDef* dma_channel); 79 | 80 | /** 81 | * Пытается заблокировать канал DMA. 82 | * @param dma_channel Кнала DMA. 83 | * @return true в случае блокировки канала, иначе false. 84 | */ 85 | EXTERN bool dma_channel_trylock(DMA_Channel_TypeDef* dma_channel); 86 | 87 | /** 88 | * Разблокирует канал DMA. 89 | * @param dma_channel Канал DMA. 90 | * @return Код ошибки. 91 | */ 92 | EXTERN err_t dma_channel_unlock(DMA_Channel_TypeDef* dma_channel); 93 | 94 | /** 95 | * Деинициализирует канал DMA. 96 | * @param dma_channel Канал DMA. 97 | */ 98 | ALWAYS_INLINE static void dma_channel_deinit(DMA_Channel_TypeDef* dma_channel) 99 | { 100 | dma_channel->CCR &= ~DMA_CCR1_EN; 101 | dma_channel->CCR = 0; 102 | dma_channel->CNDTR = 0; 103 | dma_channel->CPAR = 0; 104 | dma_channel->CMAR = 0; 105 | } 106 | 107 | #endif /* DMA_H */ 108 | 109 | -------------------------------------------------------------------------------- /ds1307/ds1307mem.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ds1307mem.h Структура памяти часов DS1307. 3 | */ 4 | 5 | #ifndef DS1307MEM_H 6 | #define DS1307MEM_H 7 | 8 | #include 9 | 10 | //Структура памяти в ds1307. 11 | 12 | //Побайтно. 13 | #pragma pack(push, 1) 14 | typedef struct _SecondsByte { 15 | uint8_t seconds:4; 16 | uint8_t seconds10:3; 17 | uint8_t clock_halt:1; 18 | }seconds_byte_t; 19 | #pragma pack(pop) 20 | 21 | #pragma pack(push, 1) 22 | typedef struct _MinutesByte { 23 | uint8_t minutes:4; 24 | uint8_t minutes10:3; 25 | uint8_t reserved1:1; 26 | }minutes_byte_t; 27 | #pragma pack(pop) 28 | 29 | #pragma pack(push, 1) 30 | typedef struct _HoursByte { 31 | uint8_t hours:4; 32 | uint8_t hours10:2; 33 | uint8_t ampm:1; 34 | uint8_t reserved2:1; 35 | }hours_byte_t; 36 | #pragma pack(pop) 37 | 38 | #pragma pack(push, 1) 39 | typedef struct _DayByte { 40 | uint8_t day:3; 41 | uint8_t reserved3:5; 42 | }day_byte_t; 43 | #pragma pack(pop) 44 | 45 | #pragma pack(push, 1) 46 | typedef struct _DateByte { 47 | uint8_t date:4; 48 | uint8_t date10:2; 49 | uint8_t reserved4:2; 50 | }date_byte_t; 51 | #pragma pack(pop) 52 | 53 | #pragma pack(push, 1) 54 | typedef struct _MonthByte { 55 | uint8_t month:4; 56 | uint8_t month10:1; 57 | uint8_t reserved5:3; 58 | }month_byte_t; 59 | #pragma pack(pop) 60 | 61 | #pragma pack(push, 1) 62 | typedef struct _YearByte { 63 | uint8_t year:4; 64 | uint8_t year10:4; 65 | }year_byte_t; 66 | #pragma pack(pop) 67 | 68 | #pragma pack(push, 1) 69 | typedef struct _SqweByte { 70 | uint8_t rs:2; 71 | uint8_t reserved7_1:2; 72 | uint8_t sqwe:1; 73 | uint8_t reserved7_2:2; 74 | uint8_t out:1; 75 | }sqwe_byte_t; 76 | #pragma pack(pop) 77 | 78 | //Полная память. 79 | #pragma pack(push, 1) 80 | typedef struct _Ds1307mem { 81 | //byte 0 82 | seconds_byte_t seconds_byte; 83 | //byte 1 84 | minutes_byte_t minutes_byte; 85 | //byte 2 86 | hours_byte_t hours_byte; 87 | //byte 3 88 | day_byte_t day_byte; 89 | //byte 4 90 | date_byte_t date_byte; 91 | //byte 5 92 | month_byte_t month_byte; 93 | //byte 6 94 | year_byte_t year_byte; 95 | //byte 7; 96 | sqwe_byte_t sqwe_byte; 97 | } ds1307mem_t; 98 | #pragma pack(pop) 99 | 100 | #endif /* DS1307MEM_H */ 101 | 102 | -------------------------------------------------------------------------------- /ds18x20/ds18x20.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ds18x20.h 3 | * Библиотека для работы с датчиками температуры DS18x20. 4 | */ 5 | 6 | #ifndef DS18X20_H 7 | #define DS18X20_H 8 | 9 | #include 10 | #include "one_wire/one_wire.h" 11 | #include "errors/errors.h" 12 | #include "fixed/fixed16.h" 13 | #include "bits/bits.h" 14 | #include "defs/defs.h" 15 | 16 | #ifndef DS18X20_READ_SCRATCHPAD_FULLY 17 | #define DS18X20_READ_SCRATCHPAD_FULLY 1 18 | #endif 19 | 20 | //Команды сенсора. 21 | #define DS18X20_CMD_SCRATCHPAD_READ 0xbe 22 | #define DS18X20_CMD_SCRATCHPAD_WRITE 0x4e 23 | #define DS18X20_CMD_TEMP_START_CONVERT 0x44 24 | 25 | //Сигнализируемые значения температуры. 26 | #define DS18X20_ALARM_TEMP_MAX (127) 27 | #define DS18X20_ALARM_TEMP_MIN (-128) 28 | 29 | //Разрешение. 30 | //Смещение битов разрешения в регистре конфигурации. 31 | #define DS18X20_RESOLUTION_BITS_OFFSET 5 32 | //Значения разрешения. 33 | #define DS18X20_RESOLUTION_12BIT (3 << DS18X20_RESOLUTION_BITS_OFFSET) 34 | #define DS18X20_RESOLUTION_11BIT (2 << DS18X20_RESOLUTION_BITS_OFFSET) 35 | #define DS18X20_RESOLUTION_10BIT (1 << DS18X20_RESOLUTION_BITS_OFFSET) 36 | #define DS18X20_RESOLUTION_9BIT (0 << DS18X20_RESOLUTION_BITS_OFFSET) 37 | #define DS18X20_RESOLUTION_MAX DS18X20_RESOLUTION_12BIT 38 | #define DS18X20_RESOLUTION_MIN DS18X20_RESOLUTION_9BIT 39 | 40 | //Структура сенсора. 41 | typedef struct _Ds18x20 { 42 | one_wire_t* one_wire; 43 | one_wire_rom_id_t* rom; 44 | } ds18x20_t; 45 | 46 | /** 47 | * Инициализирует структура сенсора. 48 | * @param sensor Структура сенсора. 49 | * @param ow Шина 1-wire. 50 | * @param rom Идентификатор устройства, NULL если устройство 51 | * на шине одно и можно игнорировать идентификатор. 52 | * @return Код ошибки. 53 | */ 54 | EXTERN err_t ds18x20_init(ds18x20_t* sensor, one_wire_t* ow, one_wire_rom_id_t* rom); 55 | 56 | /** 57 | * Выбирает сенсор. 58 | * @param sensor Сенсор. 59 | * @return Код ошибки. 60 | */ 61 | EXTERN err_t ds18x20_select(ds18x20_t* sensor); 62 | 63 | /** 64 | * Конфигурирует сенсор. 65 | * @param resolution Разрешение конвертирования температуры. 66 | * @param alarm_temp_lo Нижнее сигнализируемое значение температуры. 67 | * @param alarm_temp_hi Верхнее сигнализируемое значение температуры. 68 | * @return Код ошибки. 69 | */ 70 | EXTERN err_t ds18x20_configure(ds18x20_t* sensor, uint8_t resolution, 71 | int8_t alarm_temp_lo, int8_t alarm_temp_hi); 72 | 73 | /** 74 | * Инициирует конвертирование температуры. 75 | * @param sensor Сенсор. 76 | * @return Код ошибки. 77 | */ 78 | EXTERN err_t ds18x20_start_conversion(ds18x20_t* sensor); 79 | 80 | /** 81 | * Проверяет статус конвертирования температуры. 82 | * @param sensor Сенсор. 83 | * @return true если конвертирование окончено или не начиналось, иначе false. 84 | */ 85 | EXTERN bool ds18x20_conversion_done(ds18x20_t* sensor); 86 | 87 | /** 88 | * Считывает температуру. 89 | * @param sensor Сенсор. 90 | * @param temp указатель на переменную для возвращения температуры. 91 | * @return Код ошибки. 92 | */ 93 | EXTERN err_t ds18x20_read_temp(ds18x20_t* sensor, fixed16_t* temp); 94 | 95 | #endif /* DS18X20_H */ 96 | 97 | -------------------------------------------------------------------------------- /dsp/avg.c: -------------------------------------------------------------------------------- 1 | #include "avg.h" 2 | 3 | 4 | err_t avg_init(avg_t* avg) 5 | { 6 | avg->count = 0; 7 | avg->data = 0; 8 | avg->sum = 0; 9 | 10 | return E_NO_ERROR; 11 | } 12 | 13 | void avg_reset(avg_t* avg) 14 | { 15 | avg->sum = 0; 16 | avg->data = 0; 17 | avg->count = 0; 18 | } 19 | 20 | void avg_put(avg_t* avg, avg_data_t data) 21 | { 22 | avg->sum = iq15_add(avg->sum, data); 23 | avg->count ++; 24 | } 25 | 26 | avg_data_t avg_calc(avg_t* avg) 27 | { 28 | if(avg->count > 1){ 29 | avg->data = iq15_idiv(avg->sum, (int32_t)avg->count); 30 | }else if(avg->count == 1){ 31 | avg->data = avg->sum; 32 | }else{ 33 | avg->data = 0; 34 | } 35 | avg->sum = 0; 36 | avg->count = 0; 37 | 38 | return avg->data; 39 | } 40 | -------------------------------------------------------------------------------- /dsp/avg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file avg.h Библиотека усреднениея. 3 | */ 4 | 5 | #ifndef AVG_H_ 6 | #define AVG_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "errors/errors.h" 12 | #include "defs/defs.h" 13 | #include "q15/q15.h" 14 | 15 | //! Тип данных для усреднения. 16 | typedef q15_t avg_data_t; 17 | 18 | //! Тип суммы данных для усреднения. 19 | typedef iq15_t avg_sum_t; 20 | 21 | //! Структура усреднения. 22 | typedef struct _Avg { 23 | size_t count; //!< Количество элементов для усреднения. 24 | avg_sum_t sum; //!< Сумма данных. 25 | avg_data_t data; //!< Текущие данные. 26 | } avg_t; 27 | 28 | 29 | /** 30 | * Инициализирует усреднение. 31 | * @param avg Усреднение. 32 | * @return Код ошибки. 33 | */ 34 | extern err_t avg_init(avg_t* avg); 35 | 36 | /** 37 | * Сбрасывает усреднение. 38 | * @param avg Усреднение. 39 | */ 40 | extern void avg_reset(avg_t* avg); 41 | 42 | /** 43 | * Помещает данные в усреднение. 44 | * @param avg Усреднение. 45 | * @param data Данные. 46 | */ 47 | extern void avg_put(avg_t* avg, avg_data_t data); 48 | 49 | /** 50 | * Вычисляет среднее. 51 | * @param avg Усреднение. 52 | * @return Последние данные. 53 | */ 54 | extern avg_data_t avg_calc(avg_t* avg); 55 | 56 | /** 57 | * Получает последние данные. 58 | * @param avg Усреднение. 59 | * @return Последние данные. 60 | */ 61 | ALWAYS_INLINE static avg_data_t avg_data(avg_t* avg) 62 | { 63 | return avg->data; 64 | } 65 | 66 | #endif /* AVG_H_ */ 67 | -------------------------------------------------------------------------------- /dsp/decim.c: -------------------------------------------------------------------------------- 1 | #include "decim.h" 2 | 3 | 4 | err_t decim_init(decim_t* decim, size_t scale) 5 | { 6 | if(scale == 0) return E_INVALID_VALUE; 7 | 8 | decim->scale = scale; 9 | decim->index = 0; 10 | decim->data = 0; 11 | 12 | return E_NO_ERROR; 13 | } 14 | 15 | void decim_reset(decim_t* decim) 16 | { 17 | decim->data = 0; 18 | decim->index = 0; 19 | } 20 | 21 | void decim_put(decim_t* decim, decim_data_t data) 22 | { 23 | size_t next = decim->index + 1; 24 | 25 | if(next >= decim->scale){ 26 | decim->data = data; 27 | next = 0; 28 | } 29 | 30 | decim->index = next; 31 | } 32 | -------------------------------------------------------------------------------- /dsp/decim.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file decim.h Библиотека дециматора. 3 | */ 4 | 5 | #ifndef DECIM_H_ 6 | #define DECIM_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "errors/errors.h" 12 | #include "defs/defs.h" 13 | #include "q15/q15.h" 14 | 15 | //! Тип данных для децимации. 16 | typedef q15_t decim_data_t; 17 | 18 | //! Структура дециматора. 19 | typedef struct _Decim { 20 | size_t scale; //!< Коэффициент децимации. 21 | size_t index; //!< Счётчик семплов. 22 | decim_data_t data; //!< Текущие данные. 23 | } decim_t; 24 | 25 | 26 | /** 27 | * Инициализирует дециматор. 28 | * @param decim Дециматор. 29 | * @param scale Коэффициент децимации. 30 | * @return Код ошибки. 31 | */ 32 | extern err_t decim_init(decim_t* decim, size_t scale); 33 | 34 | /** 35 | * Сбрасывает дециматор. 36 | * @param decim Дециматор. 37 | */ 38 | extern void decim_reset(decim_t* decim); 39 | 40 | /** 41 | * Помещает данные в дециматор. 42 | * @param decim Дециматор. 43 | * @param data Данные. 44 | */ 45 | extern void decim_put(decim_t* decim, decim_data_t data); 46 | 47 | /** 48 | * Получает флаг готовности данных. 49 | * @param decim Дециматор. 50 | * @return Флаг готовности данных. 51 | */ 52 | ALWAYS_INLINE static bool decim_ready(decim_t* decim) 53 | { 54 | return decim->index == 0; 55 | } 56 | 57 | /** 58 | * Получает последние данные. 59 | * @param decim Дециматор. 60 | * @return Последние данные. 61 | */ 62 | ALWAYS_INLINE static decim_data_t decim_data(decim_t* decim) 63 | { 64 | return decim->data; 65 | } 66 | /** 67 | * Получает коэффициент децимации. 68 | * @param decim Дециматор. 69 | * @return Коэффициент децимации. 70 | */ 71 | ALWAYS_INLINE static size_t decim_scale(decim_t* decim) 72 | { 73 | return decim->scale; 74 | } 75 | 76 | /** 77 | * Получает смещение с последней выборки исходного сигнала. 78 | * @param decim Дециматор. 79 | * @return Смещение. 80 | */ 81 | ALWAYS_INLINE static size_t decim_skew(decim_t* decim) 82 | { 83 | return decim->index; 84 | } 85 | 86 | #endif /* DECIM_H_ */ 87 | -------------------------------------------------------------------------------- /dsp/decim_avg.c: -------------------------------------------------------------------------------- 1 | #include "decim_avg.h" 2 | 3 | 4 | err_t decim_avg_init(decim_avg_t* decim, size_t scale) 5 | { 6 | if(scale == 0) return E_INVALID_VALUE; 7 | 8 | decim->scale = scale; 9 | decim->index = 0; 10 | decim->data = 0; 11 | decim->sum = 0; 12 | 13 | return E_NO_ERROR; 14 | } 15 | 16 | void decim_avg_reset(decim_avg_t* decim) 17 | { 18 | decim->sum = 0; 19 | decim->data = 0; 20 | decim->index = 0; 21 | } 22 | 23 | void decim_avg_put(decim_avg_t* decim, decim_avg_data_t data) 24 | { 25 | size_t next = decim->index + 1; 26 | 27 | decim->sum = iq15_add(decim->sum, data); 28 | 29 | if(next >= decim->scale){ 30 | if(decim->scale > 1){ 31 | decim->data = iq15_idiv(decim->sum, (int32_t)decim->scale); 32 | }else if(decim->scale == 1){ 33 | decim->data = decim->sum; 34 | }else{ 35 | decim->data = 0; 36 | } 37 | decim->sum = 0; 38 | next = 0; 39 | } 40 | 41 | decim->index = next; 42 | } 43 | -------------------------------------------------------------------------------- /dsp/decim_avg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file decim_avg_avg.h Библиотека дециматора с усреднением. 3 | */ 4 | 5 | #ifndef DECIM_AVG_H_ 6 | #define DECIM_AVG_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "errors/errors.h" 12 | #include "defs/defs.h" 13 | #include "q15.h" 14 | 15 | //! Тип данных для децимации. 16 | typedef q15_t decim_avg_data_t; 17 | 18 | //! Тип суммы данных для децимации. 19 | typedef iq15_t decim_avg_sum_t; 20 | 21 | //! Структура дециматора. 22 | typedef struct _Decim_Avg { 23 | size_t scale; //!< Коэффициент децимации. 24 | size_t index; //!< Счётчик семплов. 25 | decim_avg_sum_t sum; //!< Сумма данных. 26 | decim_avg_data_t data; //!< Текущие данные. 27 | } decim_avg_t; 28 | 29 | 30 | /** 31 | * Инициализирует дециматор. 32 | * @param decim Дециматор. 33 | * @param scale Коэффициент децимации. 34 | * @return Код ошибки. 35 | */ 36 | extern err_t decim_avg_init(decim_avg_t* decim, size_t scale); 37 | 38 | /** 39 | * Сбрасывает дециматор. 40 | * @param decim Дециматор. 41 | */ 42 | extern void decim_avg_reset(decim_avg_t* decim); 43 | 44 | /** 45 | * Помещает данные в дециматор. 46 | * @param decim Дециматор. 47 | * @param data Данные. 48 | */ 49 | extern void decim_avg_put(decim_avg_t* decim, decim_avg_data_t data); 50 | 51 | /** 52 | * Получает флаг готовности данных. 53 | * @param decim Дециматор. 54 | * @return Флаг готовности данных. 55 | */ 56 | ALWAYS_INLINE static bool decim_avg_ready(decim_avg_t* decim) 57 | { 58 | return decim->index == 0; 59 | } 60 | 61 | /** 62 | * Получает последние данные. 63 | * @param decim Дециматор. 64 | * @return Последние данные. 65 | */ 66 | ALWAYS_INLINE static decim_avg_data_t decim_avg_data(decim_avg_t* decim) 67 | { 68 | return decim->data; 69 | } 70 | /** 71 | * Получает коэффициент децимации. 72 | * @param decim Дециматор. 73 | * @return Коэффициент децимации. 74 | */ 75 | ALWAYS_INLINE static size_t decim_avg_scale(decim_avg_t* decim) 76 | { 77 | return decim->scale; 78 | } 79 | 80 | /** 81 | * Получает смещение с последней выборки исходного сигнала. 82 | * @param decim Дециматор. 83 | * @return Смещение. 84 | */ 85 | ALWAYS_INLINE static size_t decim_avg_skew(decim_avg_t* decim) 86 | { 87 | return decim->index; 88 | } 89 | 90 | #endif /* DECIM_H_ */ 91 | -------------------------------------------------------------------------------- /dsp/edge_detect.c: -------------------------------------------------------------------------------- 1 | #include "edge_detect.h" 2 | 3 | //! Маска детектора фронта. 4 | #define EDGE_DETECT_MASK 0x3 5 | 6 | 7 | 8 | void edge_detect_init(edge_detect_t* edge_detect) 9 | { 10 | edge_detect->data = EDGE_DETECT_LOW; 11 | } 12 | 13 | void edge_detect_reset(edge_detect_t* edge_detect) 14 | { 15 | edge_detect->data = EDGE_DETECT_LOW; 16 | } 17 | 18 | void edge_detect_reset_value(edge_detect_t* edge_detect, bool value) 19 | { 20 | edge_detect->data = value ? EDGE_DETECT_HIGH : EDGE_DETECT_LOW; 21 | } 22 | 23 | edge_detect_state_t edge_detect_put(edge_detect_t* edge_detect, bool value) 24 | { 25 | uint32_t data = edge_detect->data; 26 | uint32_t bit = value & 0x1; 27 | 28 | data = ((data << 1) | bit); 29 | 30 | edge_detect->data = (uint8_t)(data & EDGE_DETECT_MASK); 31 | 32 | return (edge_detect_state_t)edge_detect->data; 33 | } 34 | 35 | edge_detect_state_t edge_detect_state(edge_detect_t* edge_detect) 36 | { 37 | return (edge_detect_state_t)edge_detect->data; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /dsp/edge_detect.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file edge_detect.h Детектор фронта сигнала. 3 | */ 4 | 5 | #ifndef EDGE_DETECT_H_ 6 | #define EDGE_DETECT_H_ 7 | 8 | #include "errors/errors.h" 9 | #include 10 | #include 11 | 12 | //!< Перечисление состояния детектора. 13 | typedef enum _Edge_Detect_State { 14 | EDGE_DETECT_LOW = 0, //!< Низкий уровень. 15 | EDGE_DETECT_RISING = 1, //!< Уровень изменился с низкого на высокий - передний фронт. 16 | EDGE_DETECT_FALLING = 2, //!< Уровень изменился с высокого на низкий - задний фронт. 17 | EDGE_DETECT_HIGH = 3 //!< Высокий уровень. 18 | } edge_detect_state_t; 19 | 20 | //! Структура детектора фронта. 21 | typedef struct _Edge_Detect { 22 | uint8_t data; //!< Данные детектора (два последних семпла сигнала. 23 | } edge_detect_t; 24 | 25 | 26 | /** 27 | * Инициализирует детектор фронта. 28 | * @param edge_detect Детектор фронта. 29 | */ 30 | extern void edge_detect_init(edge_detect_t* edge_detect); 31 | 32 | /** 33 | * Сбрасывает детектор фронта. 34 | * @param edge_detect Детектор фронта. 35 | */ 36 | extern void edge_detect_reset(edge_detect_t* edge_detect); 37 | 38 | /** 39 | * Сбрасывает детектор фронта на заданное значение. 40 | * @param edge_detect Детектор фронта. 41 | * @param value Значение. 42 | */ 43 | extern void edge_detect_reset_value(edge_detect_t* edge_detect, bool value); 44 | 45 | /** 46 | * Обрабатывает очередное значение. 47 | * @param edge_detect Детектор фронта. 48 | * @param value Значение. 49 | * @return Состояние детектора. 50 | */ 51 | extern edge_detect_state_t edge_detect_put(edge_detect_t* edge_detect, bool value); 52 | 53 | /** 54 | * Получает состояние детектора. 55 | * @param edge_detect Детектор фронта. 56 | * @return Состояние детектора. 57 | */ 58 | extern edge_detect_state_t edge_detect_state(edge_detect_t* edge_detect); 59 | 60 | 61 | #endif /* EDGE_DETECT_H_ */ 62 | -------------------------------------------------------------------------------- /dsp/fir.c: -------------------------------------------------------------------------------- 1 | #include "fir.h" 2 | #include 3 | 4 | 5 | err_t fir_init(fir_t* fir, q15_t* coefs, q15_t* data, size_t size) 6 | { 7 | if(coefs == NULL) return E_NULL_POINTER; 8 | if(data == NULL) return E_NULL_POINTER; 9 | if(size == 0) return E_INVALID_VALUE; 10 | 11 | fir->coefs = coefs; 12 | fir->data = data; 13 | fir->size = size; 14 | fir->index = 0; 15 | 16 | return E_NO_ERROR; 17 | } 18 | 19 | void fir_reset(fir_t* fir) 20 | { 21 | memset(fir->data, 0x0, sizeof(q15_t) * fir->size); 22 | fir->index = 0; 23 | } 24 | 25 | ALWAYS_INLINE static size_t fir_next_index(fir_t* fir, size_t index) 26 | { 27 | size_t next_index = index + 1; 28 | 29 | if(next_index >= fir->size) next_index = 0; 30 | 31 | return next_index; 32 | } 33 | 34 | void fir_put(fir_t* fir, q15_t data) 35 | { 36 | fir->data[fir->index] = data; 37 | fir->index = fir_next_index(fir, fir->index); 38 | } 39 | 40 | // Прямая версия. 41 | q15_t fir_calc(fir_t* fir) 42 | { 43 | int32_t res; 44 | 45 | register int32_t c; 46 | register int32_t d; 47 | 48 | size_t index = fir->index; 49 | 50 | register int64_t acc = 0; 51 | 52 | size_t i; 53 | for(i = 0; i < fir->size; i ++){ 54 | c = fir->coefs[i]; 55 | d = fir->data[index]; 56 | 57 | //acc += c * d; 58 | acc = iq15_mlal(c, d, acc); 59 | 60 | index = fir_next_index(fir, index); 61 | } 62 | 63 | res = acc >> 15; 64 | res = q15_sat(res); 65 | 66 | return res; 67 | } 68 | 69 | // Версия с загрузкой по два элемента. 70 | /*q15_t fir_calc(fir_t* fir) 71 | { 72 | int32_t res; 73 | 74 | union _U_DATA32 { 75 | struct _S_DATA32{ 76 | int16_t _0; 77 | int16_t _1; 78 | } _16; 79 | int32_t _32; 80 | }; 81 | 82 | register union _U_DATA32 c; 83 | register union _U_DATA32 d; 84 | 85 | register int64_t acc = 0; 86 | 87 | size_t last_i = fir->size - 1; 88 | 89 | int16_t* coefs = fir->coefs; 90 | int16_t* data = &fir->data[fir->index]; 91 | 92 | int16_t* data_beg = fir->data; 93 | int16_t* data32_end = (int16_t*)(&((int32_t*)fir->data)[fir->size >> 1]); 94 | int16_t* data_end = &fir->data[fir->size]; 95 | 96 | size_t i; 97 | for(i = 0; i < fir->size;){ 98 | 99 | if(data < data32_end && i < last_i){ 100 | c._32 = *(int32_t*)coefs; 101 | d._32 = *(int32_t*)data; 102 | 103 | //acc += c * d; 104 | acc = iq15_mlal(c._16._0, d._16._0, acc); 105 | acc = iq15_mlal(c._16._1, d._16._1, acc); 106 | 107 | coefs += 2; 108 | data += 2; 109 | 110 | i += 2; 111 | }else{ 112 | c._16._0 = *(int16_t*)coefs; 113 | d._16._0 = *(int16_t*)data; 114 | 115 | //acc += c * d; 116 | acc = iq15_mlal(c._16._0, d._16._0, acc); 117 | 118 | coefs += 1; 119 | data += 1; 120 | 121 | i += 1; 122 | } 123 | 124 | if(data == data_end) data = data_beg; 125 | } 126 | 127 | res = acc >> 15; 128 | res = q15_sat(res); 129 | 130 | return res; 131 | }*/ 132 | 133 | q15_t fir_filter(fir_t* fir, q15_t data) 134 | { 135 | int32_t res; 136 | 137 | register int32_t c; 138 | register int32_t d = data; 139 | register int32_t tmp; 140 | 141 | register int64_t acc = 0; 142 | 143 | size_t i; 144 | for(i = 0; i < fir->size; i ++){ 145 | 146 | c = fir->coefs[i]; 147 | 148 | //acc += c * d; 149 | acc = iq15_mlal(c, d, acc); 150 | 151 | tmp = fir->data[i]; 152 | fir->data[i] = d; 153 | d = tmp; 154 | } 155 | 156 | res = acc >> 15; 157 | res = q15_sat(res); 158 | 159 | return res; 160 | } 161 | 162 | -------------------------------------------------------------------------------- /dsp/fir.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file fir.h Библиотека КИХ-фильтра. 3 | */ 4 | 5 | #ifndef FIR_H_ 6 | #define FIR_H_ 7 | 8 | #include "errors/errors.h" 9 | #include 10 | #include 11 | #include "q15/q15.h" 12 | 13 | //! Структура КИХ-фильтра. 14 | typedef struct _Fir { 15 | size_t size; //!< Число элементов фильтра (Размер буфера данных). 16 | q15_t* coefs; //!< Коэффициенты. 17 | q15_t* data; //!< Данные. 18 | size_t index; //!< Индекс. 19 | } fir_t; 20 | 21 | /** 22 | * Инициализирует фильтр. 23 | * @param fir Фильтр. 24 | * @param coefs Коэффициенты фильтра. 25 | * @param data Буфер данных, проходящих фильтр. 26 | * @param size Число коэффициентов и размер буфера данных фильтра. 27 | * @return Код ошибк. 28 | */ 29 | extern err_t fir_init(fir_t* fir, q15_t* coefs, q15_t* data, size_t size); 30 | 31 | /** 32 | * Сбрасывает фильтр. 33 | * @param fir Фильтр. 34 | */ 35 | extern void fir_reset(fir_t* fir); 36 | 37 | /** 38 | * Вставляет данные в фильтр. 39 | * Использует индекс. 40 | * @param fir Фильтр. 41 | * @param data Данные. 42 | */ 43 | extern void fir_put(fir_t* fir, q15_t data); 44 | 45 | /** 46 | * Вычисляет значение фильтра. 47 | * Использует 64 бит аккумулятор. 48 | * Использует индекс. 49 | * @param fir Фильтр. 50 | * @return Отфильтрованное значение. 51 | */ 52 | extern q15_t fir_calc(fir_t* fir); 53 | 54 | /** 55 | * Добавляет данные в фильтр 56 | * и вычисляет значение фильтра. 57 | * Не использует индекс, 58 | * сдвигает данные в массиве 59 | * одновременно с вычислением. 60 | * @param fir Фильтр. 61 | * @param data Данные. 62 | * @return Отфильтрованное значение. 63 | */ 64 | extern q15_t fir_filter(fir_t* fir, q15_t data); 65 | 66 | #endif /* FIR_H_ */ 67 | -------------------------------------------------------------------------------- /dsp/maj.c: -------------------------------------------------------------------------------- 1 | #include "maj.h" 2 | 3 | 4 | err_t maj_init(maj_t* maj) 5 | { 6 | maj->ones = 0; 7 | maj->zeros = 0; 8 | maj->value = false; 9 | 10 | return E_NO_ERROR; 11 | } 12 | 13 | void maj_reset(maj_t* maj) 14 | { 15 | maj->ones = 0; 16 | maj->zeros = 0; 17 | maj->value = false; 18 | } 19 | 20 | void maj_put(maj_t* maj, bool value) 21 | { 22 | if(value) maj->ones ++; 23 | else maj->zeros ++; 24 | } 25 | 26 | bool maj_calc(maj_t* maj) 27 | { 28 | maj->value = maj->ones > maj->zeros; 29 | 30 | maj->ones = 0; 31 | maj->zeros = 0; 32 | 33 | return maj->value; 34 | } 35 | -------------------------------------------------------------------------------- /dsp/maj.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file maj.h Библиотека мажоритара. 3 | */ 4 | 5 | #ifndef MAJ_H_ 6 | #define MAJ_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "errors/errors.h" 12 | #include "defs/defs.h" 13 | 14 | 15 | //! Структура мажоритара. 16 | typedef struct _Maj { 17 | size_t ones; //!< Число единиц. 18 | size_t zeros; //!< Число нулей. 19 | bool value; //!< Значение наибольшего. 20 | } maj_t; 21 | 22 | 23 | /** 24 | * Инициализирует мажоритар. 25 | * @param maj Мажоритар. 26 | * @return Код ошибки. 27 | */ 28 | extern err_t maj_init(maj_t* maj); 29 | 30 | /** 31 | * Сбрасывает мажоритар. 32 | * @param maj Мажоритар. 33 | */ 34 | extern void maj_reset(maj_t* maj); 35 | 36 | /** 37 | * Помещает значение в мажоритар. 38 | * @param maj Мажоритар. 39 | * @param value Значение. 40 | */ 41 | extern void maj_put(maj_t* maj, bool value); 42 | 43 | /** 44 | * Вычисляет мажоритар. 45 | * @param maj Мажоритар. 46 | * @return Последние данные. 47 | */ 48 | extern bool maj_calc(maj_t* maj); 49 | 50 | /** 51 | * Получает значение. 52 | * @param maj Мажоритар. 53 | * @return Значение. 54 | */ 55 | ALWAYS_INLINE static bool maj_value(maj_t* maj) 56 | { 57 | return maj->value; 58 | } 59 | 60 | #endif /* MAJ_H_ */ 61 | -------------------------------------------------------------------------------- /dsp/mwin.c: -------------------------------------------------------------------------------- 1 | #include "mwin.h" 2 | #include 3 | 4 | 5 | 6 | err_t mwin_init(mwin_t* mwin, mwin_data_t* data, size_t size) 7 | { 8 | if(data == NULL) return E_NULL_POINTER; 9 | if(size == 0) return E_INVALID_VALUE; 10 | 11 | mwin->data = data; 12 | mwin->size = size; 13 | mwin->sum = 0; 14 | mwin->index = 0; 15 | mwin->count = 0; 16 | 17 | return E_NO_ERROR; 18 | } 19 | 20 | void mwin_reset(mwin_t* mwin) 21 | { 22 | mwin->index = 0; 23 | mwin->sum = 0; 24 | mwin->count = 0; 25 | } 26 | 27 | void mwin_put(mwin_t* mwin, mwin_data_t data) 28 | { 29 | size_t next = 0; 30 | mwin_data_t old = 0; 31 | 32 | if(mwin->count >= mwin->size){ 33 | old = mwin->data[mwin->index]; 34 | }else if(mwin->count > 0){ 35 | old = mwin->data[0]; 36 | } 37 | 38 | mwin->data[mwin->index] = data; 39 | 40 | next = mwin->index + 1; 41 | if(next >= mwin->size) next = 0; 42 | mwin->index = next; 43 | 44 | next = mwin->count + 1; 45 | if(next > mwin->size) next = mwin->size; 46 | mwin->count = next; 47 | 48 | mwin->sum = iq15_sub(mwin->sum, old); 49 | mwin->sum = iq15_add(mwin->sum, data); 50 | } 51 | -------------------------------------------------------------------------------- /dsp/mwin.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mwin.h Библиотека скользящего окна. 3 | */ 4 | 5 | #ifndef MWIN_H_ 6 | #define MWIN_H_ 7 | 8 | #include 9 | #include "errors/errors.h" 10 | #include "defs/defs.h" 11 | #include "q15/q15.h" 12 | 13 | 14 | //! Тип данных скользящего окна. 15 | typedef q15_t mwin_data_t; 16 | 17 | //! Тип суммы данных скользящего окна. 18 | typedef iq15_t mwin_sum_t; 19 | 20 | //! Структура скользящего окна. 21 | typedef struct _MWin { 22 | mwin_data_t* data; //!< Данные. 23 | size_t size; //!< Размер данных. 24 | size_t count; //!< Число данных. 25 | size_t index; //!< Индекс. 26 | mwin_sum_t sum; //!< Сумма. 27 | } mwin_t; 28 | 29 | /** 30 | * Инициализирует скользящее окно. 31 | * @param mwin Скользящее окно. 32 | * @param data Буфер данных. 33 | * @param size Размер буфера данных. 34 | * @return Код ошибки. 35 | */ 36 | extern err_t mwin_init(mwin_t* mwin, mwin_data_t* data, size_t size); 37 | 38 | /** 39 | * Сбрасывает скользящее окно. 40 | * @param mwin Скользящее окно. 41 | */ 42 | extern void mwin_reset(mwin_t* mwin); 43 | 44 | /** 45 | * Помещает данные в скользящее окно. 46 | * @param mwin Скользящее окно. 47 | * @param data Данные. 48 | */ 49 | extern void mwin_put(mwin_t* mwin, mwin_data_t data); 50 | 51 | /** 52 | * Получает сумму данных в скользящем окне. 53 | * @param mwin Скользящее окно. 54 | * @return Сумма данных. 55 | */ 56 | ALWAYS_INLINE static mwin_sum_t mwin_sum(mwin_t* mwin) 57 | { 58 | return mwin->sum; 59 | } 60 | 61 | /** 62 | * Получает размер скользящего окна. 63 | * @param mwin Скользящее окно. 64 | * @return Размер скользящего окна. 65 | */ 66 | ALWAYS_INLINE static size_t mwin_size(mwin_t* mwin) 67 | { 68 | return mwin->size; 69 | } 70 | 71 | /** 72 | * Получает число данных в скользящем окне. 73 | * @param mwin Скользящее окно. 74 | * @return Число данных в скользящем окне. 75 | */ 76 | ALWAYS_INLINE static size_t mwin_count(mwin_t* mwin) 77 | { 78 | return mwin->count; 79 | } 80 | 81 | #endif /* MWIN_H_ */ 82 | -------------------------------------------------------------------------------- /errors/errors.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file errors.h 3 | * Тип и общие коды ошибок. 4 | */ 5 | 6 | #ifndef ERRORS_H 7 | #define ERRORS_H 8 | 9 | #include 10 | 11 | //! Тип ошибки. 12 | typedef uint8_t err_t; 13 | 14 | //! Отсутствие ошибки. 15 | #define E_NO_ERROR 0 16 | //! Нулевой указатель. 17 | #define E_NULL_POINTER 1 18 | //! Неправильное значение. 19 | #define E_INVALID_VALUE 2 20 | //! Выход за допустимые пределы. 21 | #define E_OUT_OF_RANGE 3 22 | //! Занято. 23 | #define E_BUSY 4 24 | //! Ошибка ввода-вывода. 25 | #define E_IO_ERROR 5 26 | //! Нехватка памяти. 27 | #define E_OUT_OF_MEMORY 6 28 | //! Нереализованный функционал. 29 | #define E_NOT_IMPLEMENTED 7 30 | //! Ошибка контрольной суммы. 31 | #define E_CRC 8 32 | //! Ошибка состояния. 33 | #define E_STATE 9 34 | //! Ошибка тайм-аута. 35 | #define E_TIME_OUT 10 36 | //! Неправильная операция. 37 | #define E_INVALID_OPERATION 11 38 | //! Операция выполняется. 39 | #define E_IN_PROGRESS 12 40 | //! Операция отменена. 41 | #define E_CANCELED 13 42 | 43 | //! Начальный код для пользовательских ошибок. 44 | #define E_USER 100 45 | 46 | #endif /* ERRORS_H */ 47 | 48 | -------------------------------------------------------------------------------- /filter_ab/filter_ab.c: -------------------------------------------------------------------------------- 1 | #include "filter_ab.h" 2 | 3 | 4 | 5 | void filter_ab_init(filter_ab_t* filter) 6 | { 7 | filter->value = 0; 8 | filter->weight = 0; 9 | } 10 | 11 | void filter_ab_reset(filter_ab_t* filter) 12 | { 13 | filter->value = 0; 14 | } 15 | 16 | void filter_ab_set_value(filter_ab_t* filter, filter_ab_value_t value) 17 | { 18 | filter->value = value; 19 | } 20 | 21 | void filter_ab_set_weight(filter_ab_t* filter, filter_ab_weight_t weight) 22 | { 23 | filter->weight = weight; 24 | } 25 | 26 | void filter_ab_put(filter_ab_t* filter, filter_ab_value_t value) 27 | { 28 | filter_ab_value_t delta = filter->value - value; 29 | delta = ((int64_t)delta * (int32_t)((uint32_t)filter->weight)) >> FILTER_AB_WEIGHT_BITS; 30 | filter->value = value + delta; 31 | } 32 | 33 | filter_ab_value_t filter_ab_value(filter_ab_t* filter) 34 | { 35 | return filter->value; 36 | } 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /filter_ab/filter_ab.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file filter_ab.h Библиотека цифрового фильтра первого порядка (альфа-бета фильтр). 3 | */ 4 | 5 | #ifndef FILTER_AB_H 6 | #define FILTER_AB_H 7 | 8 | #include 9 | #include 10 | #include "defs/defs.h" 11 | 12 | //! Тип значения фильтра. 13 | typedef int32_t filter_ab_value_t; 14 | //! Тип веса фильтра. 15 | typedef uint16_t filter_ab_weight_t; 16 | //! Число значащих бит веса фильтра. 17 | #define FILTER_AB_WEIGHT_BITS 16 18 | 19 | typedef struct _Filter_AB { 20 | filter_ab_value_t value; //!< Значение фильтра. 21 | /** 22 | * Вес фильтра 23 | * в формате Q16 24 | * (беззнаковое число с фиксированной запятой 25 | * от 0 до 0xffff - [0, 0.99999]). 26 | */ 27 | filter_ab_weight_t weight; 28 | } filter_ab_t; 29 | 30 | /** 31 | * Инициализирует фильтр. 32 | * @param filter Фильтр. 33 | */ 34 | EXTERN void filter_ab_init(filter_ab_t* filter); 35 | 36 | /** 37 | * Сбрасывает фильтр. 38 | * @param filter Фильтр. 39 | */ 40 | EXTERN void filter_ab_reset(filter_ab_t* filter); 41 | 42 | /** 43 | * Устанавливает значение фильтра. 44 | * @param filter Фильтр. 45 | * @param value Значение. 46 | */ 47 | EXTERN void filter_ab_set_value(filter_ab_t* filter, filter_ab_value_t value); 48 | 49 | /** 50 | * Устанавливает вес фильтра. 51 | * @param filter Фильтра. 52 | * @param weight Вес фильтра. 53 | */ 54 | EXTERN void filter_ab_set_weight(filter_ab_t* filter, filter_ab_weight_t weight); 55 | 56 | /** 57 | * Помещает значение в фильтр. 58 | * @param filter Фильтр. 59 | * @param value Значение. 60 | */ 61 | EXTERN void filter_ab_put(filter_ab_t* filter, filter_ab_value_t value); 62 | 63 | /** 64 | * Вычисляет значение фильтра. 65 | * @param filter Фильтр. 66 | * @return Значение фильтра. 67 | */ 68 | EXTERN filter_ab_value_t filter_ab_value(filter_ab_t* filter); 69 | 70 | #endif /* FILTER_AB_H */ 71 | -------------------------------------------------------------------------------- /fixed/fixed_vec2.c: -------------------------------------------------------------------------------- 1 | #include "fixed_vec2.h" 2 | #include "utils/utils.h" 3 | 4 | 5 | 6 | bool vec2_equal(const vec2_t* v1, const vec2_t* v2) 7 | { 8 | return v1->x == v2->x && v1->y == v2->y; 9 | } 10 | 11 | void vec2_add(vec2_t* v, const vec2_t* v1, const vec2_t* v2) 12 | { 13 | v->x = add_f32(v1->x, v2->x); 14 | v->y = add_f32(v1->y, v2->y); 15 | } 16 | 17 | void vec2_sub(vec2_t* v, const vec2_t* v1, const vec2_t* v2) 18 | { 19 | v->x = sub_f32(v1->x, v2->x); 20 | v->y = sub_f32(v1->y, v2->y); 21 | } 22 | 23 | void vec2_mul(vec2_t* v, const vec2_t* v1, const vec2_t* v2) 24 | { 25 | v->x = mul_f32(v1->x, v2->x); 26 | v->y = mul_f32(v1->y, v2->y); 27 | } 28 | 29 | void vec2_mul_n(vec2_t* v, const vec2_t* v1, f32_t n) 30 | { 31 | v->x = mul_f32(v1->x, n); 32 | v->y = mul_f32(v1->y, n); 33 | } 34 | 35 | void vec2_div(vec2_t* v, const vec2_t* v1, const vec2_t* v2) 36 | { 37 | v->x = div_f32(v1->x, v2->x); 38 | v->y = div_f32(v1->y, v2->y); 39 | } 40 | 41 | void vec2_div_n(vec2_t* v, const vec2_t* v1, f32_t n) 42 | { 43 | v->x = div_f32(v1->x, n); 44 | v->y = div_f32(v1->y, n); 45 | } 46 | 47 | f32_t vec2_length(const vec2_t* v) 48 | { 49 | f32_t xx = mul_f32(v->x, v->x); 50 | f32_t yy = mul_f32(v->y, v->y); 51 | 52 | f32_t s = add_f32(xx, yy); 53 | f32_t l = sqrt_f32(s); 54 | 55 | return l; 56 | } 57 | 58 | f32_t vec2_distance(const vec2_t* v1, const vec2_t* v2) 59 | { 60 | vec2_t v; 61 | 62 | vec2_sub(&v, v1, v2); 63 | 64 | return vec2_length(&v); 65 | } 66 | 67 | f32_t vec2_normalize(vec2_t* v, const vec2_t* v1) 68 | { 69 | f32_t l = vec2_length(v1); 70 | 71 | if(l != 0) vec2_div_n(v, v1, l); 72 | 73 | return l; 74 | } 75 | 76 | f32_t vec2_dot(const vec2_t* v1, const vec2_t* v2) 77 | { 78 | f32_t xx = mul_f32(v1->x, v2->x); 79 | f32_t yy = mul_f32(v1->y, v2->y); 80 | 81 | f32_t s = add_f32(xx, yy); 82 | 83 | return s; 84 | } 85 | 86 | void vec2_clamp(vec2_t* v, const vec2_t* v1, const vec2_t* v_min, const vec2_t* v_max) 87 | { 88 | v->x = CLAMP(v1->x, v_min->x, v_max->x); 89 | v->y = CLAMP(v1->y, v_min->y, v_max->y); 90 | } 91 | -------------------------------------------------------------------------------- /fixed/fixed_vec3.c: -------------------------------------------------------------------------------- 1 | #include "fixed_vec3.h" 2 | #include "utils/utils.h" 3 | 4 | 5 | 6 | bool vec3_equal(const vec3_t* v1, const vec3_t* v2) 7 | { 8 | return v1->x == v2->x && v1->y == v2->y && v1->z == v2->z; 9 | } 10 | 11 | void vec3_add(vec3_t* v, const vec3_t* v1, const vec3_t* v2) 12 | { 13 | v->x = add_f32(v1->x, v2->x); 14 | v->y = add_f32(v1->y, v2->y); 15 | v->z = add_f32(v1->z, v2->z); 16 | } 17 | 18 | void vec3_sub(vec3_t* v, const vec3_t* v1, const vec3_t* v2) 19 | { 20 | v->x = sub_f32(v1->x, v2->x); 21 | v->y = sub_f32(v1->y, v2->y); 22 | v->z = sub_f32(v1->z, v2->z); 23 | } 24 | 25 | void vec3_mul(vec3_t* v, const vec3_t* v1, const vec3_t* v2) 26 | { 27 | v->x = mul_f32(v1->x, v2->x); 28 | v->y = mul_f32(v1->y, v2->y); 29 | v->z = mul_f32(v1->z, v2->z); 30 | } 31 | 32 | void vec3_mul_n(vec3_t* v, const vec3_t* v1, f32_t n) 33 | { 34 | v->x = mul_f32(v1->x, n); 35 | v->y = mul_f32(v1->y, n); 36 | v->z = mul_f32(v1->z, n); 37 | } 38 | 39 | void vec3_div(vec3_t* v, const vec3_t* v1, const vec3_t* v2) 40 | { 41 | v->x = div_f32(v1->x, v2->x); 42 | v->y = div_f32(v1->y, v2->y); 43 | v->z = div_f32(v1->z, v2->z); 44 | } 45 | 46 | void vec3_div_n(vec3_t* v, const vec3_t* v1, f32_t n) 47 | { 48 | v->x = div_f32(v1->x, n); 49 | v->y = div_f32(v1->y, n); 50 | v->z = div_f32(v1->z, n); 51 | } 52 | 53 | f32_t vec3_length(const vec3_t* v) 54 | { 55 | f32_t xx = mul_f32(v->x, v->x); 56 | f32_t yy = mul_f32(v->y, v->y); 57 | f32_t zz = mul_f32(v->z, v->z); 58 | 59 | f32_t s = add_f32(xx, yy); 60 | s = add_f32(s, zz); 61 | f32_t l = sqrt_f32(s); 62 | 63 | return l; 64 | } 65 | 66 | f32_t vec3_distance(const vec3_t* v1, const vec3_t* v2) 67 | { 68 | vec3_t v; 69 | 70 | vec3_sub(&v, v1, v2); 71 | 72 | return vec3_length(&v); 73 | } 74 | 75 | f32_t vec3_normalize(vec3_t* v, const vec3_t* v1) 76 | { 77 | f32_t l = vec3_length(v1); 78 | 79 | if(l != 0) vec3_div_n(v, v1, l); 80 | 81 | return l; 82 | } 83 | 84 | f32_t vec3_dot(const vec3_t* v1, const vec3_t* v2) 85 | { 86 | f32_t xx = mul_f32(v1->x, v2->x); 87 | f32_t yy = mul_f32(v1->y, v2->y); 88 | f32_t zz = mul_f32(v1->z, v2->z); 89 | 90 | f32_t s = add_f32(xx, yy); 91 | s = add_f32(s, zz); 92 | 93 | return s; 94 | } 95 | 96 | void vec3_cross(vec3_t* v, const vec3_t* v1, const vec3_t* v2) 97 | { 98 | f32_t yz = mul_f32(v1->y, v2->z); 99 | f32_t zy = mul_f32(v1->z, v2->y); 100 | f32_t x = sub_f32(yz, zy); 101 | 102 | f32_t zx = mul_f32(v1->z, v2->x); 103 | f32_t xz = mul_f32(v1->x, v2->z); 104 | f32_t y = sub_f32(zx, xz); 105 | 106 | f32_t xy = mul_f32(v1->x, v2->y); 107 | f32_t yx = mul_f32(v1->y, v2->x); 108 | f32_t z = sub_f32(xy, yx); 109 | 110 | v->x = x; 111 | v->y = y; 112 | v->z = z; 113 | } 114 | 115 | void vec3_clamp(vec3_t* v, const vec3_t* v1, const vec3_t* v_min, const vec3_t* v_max) 116 | { 117 | v->x = CLAMP(v1->x, v_min->x, v_max->x); 118 | v->y = CLAMP(v1->y, v_min->y, v_max->y); 119 | v->z = CLAMP(v1->z, v_min->z, v_max->z); 120 | } 121 | -------------------------------------------------------------------------------- /fixed/fixed_vec4.c: -------------------------------------------------------------------------------- 1 | #include "fixed_vec4.h" 2 | #include "utils/utils.h" 3 | 4 | 5 | 6 | bool vec4_equal(const vec4_t* v1, const vec4_t* v2) 7 | { 8 | return v1->x == v2->x && v1->y == v2->y && 9 | v1->z == v2->z && v1->w == v2->w; 10 | } 11 | 12 | void vec4_add(vec4_t* v, const vec4_t* v1, const vec4_t* v2) 13 | { 14 | v->x = add_f32(v1->x, v2->x); 15 | v->y = add_f32(v1->y, v2->y); 16 | v->z = add_f32(v1->z, v2->z); 17 | v->w = add_f32(v1->w, v2->w); 18 | } 19 | 20 | void vec4_sub(vec4_t* v, const vec4_t* v1, const vec4_t* v2) 21 | { 22 | v->x = sub_f32(v1->x, v2->x); 23 | v->y = sub_f32(v1->y, v2->y); 24 | v->z = sub_f32(v1->z, v2->z); 25 | v->w = sub_f32(v1->w, v2->w); 26 | } 27 | 28 | void vec4_mul(vec4_t* v, const vec4_t* v1, const vec4_t* v2) 29 | { 30 | v->x = mul_f32(v1->x, v2->x); 31 | v->y = mul_f32(v1->y, v2->y); 32 | v->z = mul_f32(v1->z, v2->z); 33 | v->w = mul_f32(v1->w, v2->w); 34 | } 35 | 36 | void vec4_mul_n(vec4_t* v, const vec4_t* v1, f32_t n) 37 | { 38 | v->x = mul_f32(v1->x, n); 39 | v->y = mul_f32(v1->y, n); 40 | v->z = mul_f32(v1->z, n); 41 | v->w = mul_f32(v1->w, n); 42 | } 43 | 44 | void vec4_div(vec4_t* v, const vec4_t* v1, const vec4_t* v2) 45 | { 46 | v->x = div_f32(v1->x, v2->x); 47 | v->y = div_f32(v1->y, v2->y); 48 | v->z = div_f32(v1->z, v2->z); 49 | v->w = div_f32(v1->w, v2->w); 50 | } 51 | 52 | void vec4_div_n(vec4_t* v, const vec4_t* v1, f32_t n) 53 | { 54 | v->x = div_f32(v1->x, n); 55 | v->y = div_f32(v1->y, n); 56 | v->z = div_f32(v1->z, n); 57 | v->w = div_f32(v1->w, n); 58 | } 59 | 60 | f32_t vec4_length(const vec4_t* v) 61 | { 62 | f32_t xx = mul_f32(v->x, v->x); 63 | f32_t yy = mul_f32(v->y, v->y); 64 | f32_t zz = mul_f32(v->z, v->z); 65 | f32_t ww = mul_f32(v->w, v->w); 66 | 67 | f32_t s = add_f32(xx, yy); 68 | s = add_f32(s, zz); 69 | s = add_f32(s, ww); 70 | f32_t l = sqrt_f32(s); 71 | 72 | return l; 73 | } 74 | 75 | f32_t vec4_distance(const vec4_t* v1, const vec4_t* v2) 76 | { 77 | vec4_t v; 78 | 79 | vec4_sub(&v, v1, v2); 80 | 81 | return vec4_length(&v); 82 | } 83 | 84 | f32_t vec4_normalize(vec4_t* v, const vec4_t* v1) 85 | { 86 | f32_t l = vec4_length(v1); 87 | 88 | if(l != 0) vec4_div_n(v, v1, l); 89 | 90 | return l; 91 | } 92 | 93 | f32_t vec4_dot(const vec4_t* v1, const vec4_t* v2) 94 | { 95 | f32_t xx = mul_f32(v1->x, v2->x); 96 | f32_t yy = mul_f32(v1->y, v2->y); 97 | f32_t zz = mul_f32(v1->z, v2->z); 98 | f32_t ww = mul_f32(v1->w, v2->w); 99 | 100 | f32_t s = add_f32(xx, yy); 101 | s = add_f32(s, zz); 102 | s = add_f32(s, ww); 103 | 104 | return s; 105 | } 106 | 107 | void vec4_clamp(vec4_t* v, const vec4_t* v1, const vec4_t* v_min, const vec4_t* v_max) 108 | { 109 | v->x = CLAMP(v1->x, v_min->x, v_max->x); 110 | v->y = CLAMP(v1->y, v_min->y, v_max->y); 111 | v->z = CLAMP(v1->z, v_min->z, v_max->z); 112 | v->w = CLAMP(v1->w, v_min->w, v_max->w); 113 | } 114 | -------------------------------------------------------------------------------- /flash/flash.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file flash.h Библиотека работы со встроенной FLASH-памятью. 3 | */ 4 | 5 | #ifndef FLASH_H 6 | #define FLASH_H 7 | 8 | #include "defs/defs.h" 9 | #include "errors/errors.h" 10 | #include 11 | #include 12 | 13 | /** 14 | * Получает размер флеш-памяти в килобайтах. 15 | * @return Размер флеш-памяти. 16 | */ 17 | EXTERN uint32_t flash_size(void); 18 | 19 | /** 20 | * Получение размера страницы флеш-памяти в килобайтах. 21 | * @return Размер страницы флеш-памяти. 22 | */ 23 | EXTERN uint32_t flash_page_size(void); 24 | 25 | /** 26 | * Получение размера страницы флеш-памяти в байтах. 27 | * @return Размер страницы флеш-памяти. 28 | */ 29 | EXTERN uint32_t flash_page_size_bytes(void); 30 | 31 | /** 32 | * Получает количество страниц флеш-памяти. 33 | * @return Количество страниц. 34 | */ 35 | EXTERN uint32_t flash_pages(void); 36 | 37 | /** 38 | * Получает первую страницу флеш-памяти. 39 | * @return Первую страница флеш-памяти. 40 | */ 41 | EXTERN uint32_t flash_first_page(void); 42 | 43 | /** 44 | * Получает последнюю страницу флеш-памяти. 45 | * @return Последняя страница флеш-памяти. 46 | */ 47 | EXTERN uint32_t flash_last_page(void); 48 | 49 | /** 50 | * Получает адрес начала флеш-памяти. 51 | * @return Адрес начала флеш-памяти. 52 | */ 53 | EXTERN uint32_t flash_begin_address(void); 54 | 55 | /** 56 | * Получает адрес конца флеш-памяти. 57 | * @return Адрес конца флеш-памяти. 58 | */ 59 | EXTERN uint32_t flash_end_address(void); 60 | 61 | /** 62 | * Получает адрес заданной страницы флеш-памяти. 63 | * @param page Номер страницы флеш-памяти. 64 | * @return Адрес страницы флеш-памяти. 65 | */ 66 | EXTERN uint32_t flash_page_address(uint32_t page); 67 | 68 | /** 69 | * Получает флаг блокировки флеш-памяти. 70 | * @return Флаг блокировки флеш-памяти. 71 | */ 72 | EXTERN bool flash_locked(void); 73 | 74 | /** 75 | * Разблокирует флеш-память. 76 | * @return Флаг успеха. 77 | */ 78 | EXTERN bool flash_unlock(void); 79 | 80 | /** 81 | * Блокирует флеш-память. 82 | */ 83 | EXTERN void flash_lock(void); 84 | 85 | /** 86 | * Стирает страницу памяти. 87 | * @param address Адрес страницы памяти. 88 | * @return Флаг успеха. 89 | */ 90 | EXTERN bool flash_page_erase(uint32_t address); 91 | 92 | /** 93 | * Стирает все страницы памяти. 94 | * @return Флаг успеха. 95 | */ 96 | EXTERN bool flash_mass_erase(void); 97 | 98 | /** 99 | * Записывает полуслово в память. 100 | * @param address Адрес. 101 | * @param data Данные. 102 | * @return Флаг успеха. 103 | */ 104 | EXTERN bool flash_program(uint32_t address, uint16_t data); 105 | 106 | /** 107 | * Читает значение во флеш-памяти по заданному адресу. 108 | * @param address Адрес. 109 | * @return Значение. 110 | */ 111 | EXTERN uint16_t flash_read(uint32_t address); 112 | 113 | #endif /* FLASH_H */ 114 | 115 | -------------------------------------------------------------------------------- /future/future.c: -------------------------------------------------------------------------------- 1 | #include "future.h" 2 | #include 3 | #include "utils/utils.h" 4 | 5 | void future_init(future_t* future) 6 | { 7 | future->result = NULL; 8 | future->done = false; 9 | future->running = false; 10 | } 11 | 12 | void* future_result(const future_t* future) 13 | { 14 | return future->result; 15 | } 16 | 17 | void future_set_result(future_t* future, void* result) 18 | { 19 | future->result = result; 20 | } 21 | 22 | bool future_done(const future_t* future) 23 | { 24 | return future->done; 25 | } 26 | 27 | void future_set_done(future_t* future, bool done) 28 | { 29 | future->done = done; 30 | } 31 | 32 | bool future_running(const future_t* future) 33 | { 34 | return future->running; 35 | } 36 | 37 | void future_set_running(future_t* future, bool running) 38 | { 39 | future->running = running; 40 | } 41 | 42 | void future_start(future_t* future) 43 | { 44 | future->done = false; 45 | future->running = true; 46 | } 47 | 48 | void future_finish(future_t* future, void* result) 49 | { 50 | future->done = true; 51 | future->running = false; 52 | future->result = result; 53 | } 54 | 55 | void future_wait(const future_t* future) 56 | { 57 | WAIT_WHILE_TRUE(future_running(future)); 58 | } 59 | -------------------------------------------------------------------------------- /future/future.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file future.h 3 | * Библиотека для работы с ещё не наступившем событием. 4 | */ 5 | 6 | #ifndef FUTURE_H 7 | #define FUTURE_H 8 | 9 | #include 10 | #include "defs/defs.h" 11 | 12 | /** 13 | * Структура будущего. 14 | */ 15 | typedef struct _Future { 16 | //! Результат. 17 | void * volatile result; 18 | //! Флаг окончания. 19 | volatile bool done; 20 | //! Флаг выполнения. 21 | volatile bool running; 22 | }future_t; 23 | 24 | /** 25 | * Инициализирует будущее. 26 | * Незавершённое, невыполняющееся, с нулевым результатом. 27 | * @param future Будущее. 28 | */ 29 | EXTERN void future_init(future_t* future); 30 | 31 | /** 32 | * Получает результат будущего. 33 | * @param future Будущее. 34 | * @return Результат. 35 | */ 36 | EXTERN void* future_result(const future_t* future); 37 | 38 | /** 39 | * Устанавливает результат. 40 | * @param future Будущее. 41 | * @param result Результат. 42 | */ 43 | EXTERN void future_set_result(future_t* future, void* result); 44 | 45 | /** 46 | * Получает флаг завершения. 47 | * @param future Будущее. 48 | * @return Флаг завершения. 49 | */ 50 | EXTERN bool future_done(const future_t* future); 51 | 52 | /** 53 | * Устанавливает флаг завершения. 54 | * @param future Будущее. 55 | * @param done Флаг завершения. 56 | */ 57 | EXTERN void future_set_done(future_t* future, bool done); 58 | 59 | /** 60 | * Получает флаг выполнения. 61 | * @param future Будущее. 62 | * @return Флаг выполнения. 63 | */ 64 | EXTERN bool future_running(const future_t* future); 65 | 66 | /** 67 | * Устанавливает флаг выполнения. 68 | * @param future Будущее. 69 | * @param running Флаг выполнения. 70 | */ 71 | EXTERN void future_set_running(future_t* future, bool running); 72 | 73 | /** 74 | * Запускает выполнение будущего (done = false; running = true;). 75 | * @param future Будущее. 76 | */ 77 | EXTERN void future_start(future_t* future); 78 | 79 | /** 80 | * Завершает выполнение будущего (done = true; running = false;). 81 | * @param future Будущее. 82 | * @param result Результат. 83 | */ 84 | EXTERN void future_finish(future_t* future, void* result); 85 | 86 | /** 87 | * Ждёт окончания выполнения будущего. 88 | * @param future Будущее. 89 | */ 90 | EXTERN void future_wait(const future_t* future); 91 | 92 | #endif /* FUTURE_H */ 93 | 94 | -------------------------------------------------------------------------------- /gpio/gpio.c: -------------------------------------------------------------------------------- 1 | #include "gpio.h" 2 | 3 | //! Степень оптимизации установки параметров пина. 4 | #define GPIO_INIT_OPTIMIZE 2 5 | 6 | //! Реализация установки параметров одного пина. 7 | //! Жалко выкидывать разные варианты, в т.ч. на assembler. 8 | ALWAYS_INLINE static void gpio_init_pin_impl(GPIO_TypeDef* GPIO, gpio_pin_t pin, gpio_mode_t mode, gpio_conf_t conf) 9 | { 10 | #if GPIO_INIT_OPTIMIZE == 0 11 | // Вычисление номера пина. 12 | uint32_t pin_n = __CLZ(__RBIT((uint32_t)pin)); 13 | // Регистр конфигурации пина. 14 | __IO uint32_t* cr = (pin_n & 0x8) ? &GPIO->CRH : &GPIO->CRL; 15 | // Номер первого бита полей пина в регистре. 16 | uint32_t num = ((pin_n & 0x7) << 2); 17 | // Значение конфигурации для установки. 18 | uint32_t val = ((mode | (conf << 2)) << num); 19 | // Маска для сброса конфигурации. 20 | uint32_t msk = ~((GPIO_CRL_MODE0 | GPIO_CRL_CNF0) << num); 21 | // Сбросим параметры пина. 22 | *cr &= msk; 23 | // Установим новые параметры пина. 24 | *cr |= val; 25 | #elif GPIO_INIT_OPTIMIZE == 1 26 | // Вычисление номера пина. 27 | uint32_t pin_n = __CLZ(__RBIT((uint32_t)pin)); 28 | // Регистр конфигурации пина. 29 | __IO uint32_t* cr = (pin_n & 0x8) ? &GPIO->CRH : &GPIO->CRL; 30 | // Номер первого бита полей пина в регистре. 31 | uint32_t num = ((pin_n & 0x7) << 2); 32 | // Значение конфигурации для установки. 33 | uint32_t val = ((mode | (conf << 2)) << num); 34 | // Маска для сброса конфигурации. 35 | uint32_t msk = ~((GPIO_CRL_MODE0 | GPIO_CRL_CNF0) << num); 36 | // Сбросим параметры пина. 37 | // Установим новые параметры пина. 38 | *cr = (*cr & msk) | val; 39 | #elif GPIO_INIT_OPTIMIZE == 2 40 | // Вычисление номера пина. 41 | uint32_t pin_n = __CLZ(__RBIT((uint32_t)pin)); 42 | // Регистр конфигурации пина. 43 | __IO uint32_t* cr = &GPIO->CRL + ((pin_n & 0x8) >> 3); 44 | // Номер первого бита полей пина в регистре. 45 | uint32_t num = ((pin_n & 0x7) << 2); 46 | // Значение конфигурации для установки. 47 | uint32_t val = ((mode | (conf << 2)) << num); 48 | // Маска для сброса конфигурации. 49 | uint32_t msk = ~((GPIO_CRL_MODE0 | GPIO_CRL_CNF0) << num); 50 | // Сбросим параметры пина. 51 | // Установим новые параметры пина. 52 | *cr = (*cr & msk) | val; 53 | #elif GPIO_INIT_OPTIMIZE == 3 54 | __asm__ volatile( 55 | "rbit %1, %1\n\t" // pin = __RBIT(pin); 56 | "clz %1, %1\n\t" // pin = __CLZ(pin); 57 | "ubfx r4, %1, #3, #1\n\t" // tmp = (pin & 0x8) >> 3; 58 | "add %0, %0, r4, lsl #2\n\t" // cr* = cr* + tmp; 59 | "and %1, %1, #7\n\t" // pin = pin & 0x7; 60 | "lsl %1, %1, #2\n\t" // pin = pin << 2; 61 | "orr %2, %2, %3, lsl #2\n\t" // mode = mode | (conf << 2); 62 | "lsl %2, %2, %1\n\t" // mode = mode << pin; 63 | "mov %3, #15\n\t" // conf = 15; 64 | "lsl %3, %3, %1\n\t" // conf = 15 << pin; 65 | "ldr r4, [%0]\n\t" // tmp = *cr; 66 | "bic r4, r4, %3\n\t" // tmp = tmp & conf; 67 | "orr r4, r4, %2\n\t" // tmp = tmp | mode; 68 | "str r4, [%0]\n\t" // *cr = tmp; 69 | //"\n\t" 70 | ::"r"(GPIO), "r"(pin), "r"(mode), "r"(conf):"r4" 71 | ); 72 | #else 73 | #error Unknown GPIO_INIT_OPTIMIZE 74 | #endif 75 | } 76 | 77 | void gpio_init(GPIO_TypeDef* GPIO, gpio_pin_t pins, gpio_mode_t mode, gpio_conf_t conf) 78 | { 79 | // Текущий пин. 80 | gpio_pin_t pin; 81 | // Цикл по пинам. 82 | while(pins){ 83 | // Следующий номер пина. 84 | pin = __RBIT(BIT(__CLZ((uint32_t)pins))); 85 | // Инициализируем. 86 | gpio_init_pin_impl(GPIO, pin, mode, conf); 87 | // Очищаем номер инициализированного пина. 88 | pins &= ~pin; 89 | } 90 | } 91 | 92 | -------------------------------------------------------------------------------- /graphics/font_ascii_5x8.h: -------------------------------------------------------------------------------- 1 | #ifndef FONT_ASCII_5X8 2 | #define FONT_ASCII_5X8 3 | 4 | #include 5 | 6 | #define FONT_ASCII_5X8_WIDTH 475 7 | #define FONT_ASCII_5X8_HEIGHT 8 8 | 9 | static const uint8_t font_ascii_5x8_data[] = { 10 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x00, 11 | 0x00, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x14, 0x7F, 0x14, 12 | 0x7F, 0x14, 0x04, 0x2A, 0x7F, 0x2A, 0x10, 0x00, 0x16, 13 | 0x08, 0x34, 0x00, 0x36, 0x49, 0x36, 0x40, 0x00, 0x00, 14 | 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x00, 0x00, 15 | 0x00, 0x42, 0x3C, 0x00, 0x00, 0x54, 0x38, 0x38, 0x54, 16 | 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x80, 0x60, 17 | 0x20, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x40, 18 | 0xE0, 0x40, 0x00, 0x60, 0x10, 0x08, 0x06, 0x00, 0x00, 19 | 0x3C, 0x42, 0x3C, 0x00, 0x00, 0x44, 0x7E, 0x40, 0x00, 20 | 0x64, 0x52, 0x52, 0x4C, 0x00, 0x22, 0x4A, 0x4E, 0x32, 21 | 0x00, 0x18, 0x14, 0x7E, 0x10, 0x00, 0x2E, 0x4A, 0x4A, 22 | 0x32, 0x00, 0x3C, 0x4A, 0x4A, 0x30, 0x00, 0x02, 0x62, 23 | 0x1A, 0x06, 0x00, 0x34, 0x4A, 0x4A, 0x34, 0x00, 0x0C, 24 | 0x52, 0x52, 0x3C, 0x00, 0x00, 0x6C, 0x6C, 0x00, 0x00, 25 | 0x00, 0x80, 0x6C, 0x2C, 0x00, 0x00, 0x18, 0x24, 0x42, 26 | 0x00, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x42, 0x24, 27 | 0x18, 0x00, 0x00, 0x04, 0x52, 0x0C, 0x00, 0x3C, 0x42, 28 | 0x99, 0xA5, 0x1E, 0x7C, 0x12, 0x12, 0x7C, 0x00, 0x7E, 29 | 0x4A, 0x4A, 0x34, 0x00, 0x3C, 0x42, 0x42, 0x24, 0x00, 30 | 0x7E, 0x42, 0x42, 0x3C, 0x00, 0x7E, 0x4A, 0x4A, 0x42, 31 | 0x00, 0x7E, 0x0A, 0x0A, 0x02, 0x00, 0x3C, 0x42, 0x52, 32 | 0x34, 0x00, 0x7E, 0x08, 0x08, 0x7E, 0x00, 0x00, 0x42, 33 | 0x7E, 0x42, 0x00, 0x20, 0x42, 0x3E, 0x02, 0x00, 0x7E, 34 | 0x08, 0x34, 0x42, 0x00, 0x7E, 0x40, 0x40, 0x40, 0x00, 35 | 0x7E, 0x0C, 0x0C, 0x7E, 0x00, 0x7E, 0x0C, 0x38, 0x7E, 36 | 0x00, 0x3C, 0x42, 0x42, 0x3C, 0x00, 0x7E, 0x12, 0x12, 37 | 0x0C, 0x00, 0x3C, 0x52, 0x62, 0xBC, 0x00, 0x7E, 0x12, 38 | 0x12, 0x6C, 0x00, 0x24, 0x4A, 0x52, 0x24, 0x00, 0x00, 39 | 0x02, 0x7E, 0x02, 0x00, 0x3E, 0x40, 0x40, 0x3E, 0x00, 40 | 0x1E, 0x60, 0x60, 0x1E, 0x00, 0x7E, 0x30, 0x30, 0x7E, 41 | 0x00, 0x66, 0x18, 0x18, 0x66, 0x00, 0x06, 0x08, 0x70, 42 | 0x08, 0x06, 0x62, 0x52, 0x4A, 0x46, 0x00, 0x00, 0x7E, 43 | 0x42, 0x42, 0x00, 0x06, 0x08, 0x10, 0x60, 0x00, 0x00, 44 | 0x42, 0x42, 0x7E, 0x00, 0x00, 0x04, 0x02, 0x04, 0x00, 45 | 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x02, 0x04, 0x00, 46 | 0x00, 0x30, 0x48, 0x48, 0x78, 0x00, 0x7E, 0x48, 0x48, 47 | 0x30, 0x00, 0x00, 0x30, 0x48, 0x48, 0x00, 0x30, 0x48, 48 | 0x48, 0x7E, 0x00, 0x30, 0x68, 0x58, 0x10, 0x00, 0x10, 49 | 0x7C, 0x12, 0x04, 0x00, 0x10, 0xA8, 0xA8, 0x70, 0x00, 50 | 0x7E, 0x08, 0x08, 0x70, 0x00, 0x00, 0x48, 0x7A, 0x40, 51 | 0x00, 0x00, 0x40, 0x80, 0x7A, 0x00, 0x7E, 0x10, 0x10, 52 | 0x68, 0x00, 0x00, 0x42, 0x7E, 0x40, 0x00, 0x78, 0x08, 53 | 0x70, 0x08, 0x70, 0x78, 0x08, 0x08, 0x70, 0x00, 0x30, 54 | 0x48, 0x48, 0x30, 0x00, 0xF8, 0x28, 0x28, 0x10, 0x00, 55 | 0x10, 0x28, 0x28, 0xF8, 0x00, 0x78, 0x10, 0x08, 0x10, 56 | 0x00, 0x00, 0x50, 0x58, 0x28, 0x00, 0x08, 0x3E, 0x48, 57 | 0x20, 0x00, 0x38, 0x40, 0x40, 0x78, 0x00, 0x00, 0x38, 58 | 0x40, 0x38, 0x00, 0x38, 0x40, 0x30, 0x40, 0x38, 0x48, 59 | 0x30, 0x30, 0x48, 0x00, 0x58, 0xA0, 0xA0, 0x78, 0x00, 60 | 0x48, 0x68, 0x58, 0x48, 0x00, 0x08, 0x2A, 0x55, 0x41, 61 | 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x41, 0x55, 0x2A, 62 | 0x08, 0x00, 0x04, 0x02, 0x04, 0x02, 0x00, }; 63 | #endif /* FONT_ASCII_5X8 */ 64 | -------------------------------------------------------------------------------- /graphics/point.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file rect.h Библиотека точки. 3 | */ 4 | 5 | #ifndef POINT_H 6 | #define POINT_H 7 | 8 | #include "graphics.h" 9 | #include "defs/defs.h" 10 | #include 11 | 12 | //! Структура точки. 13 | typedef struct _Point { 14 | graphics_pos_t x; //!< Координата X. 15 | graphics_pos_t y; //!< Координата Y. 16 | } point_t; 17 | 18 | //! Инициализирует структуру точки. 19 | #define MAKE_POINT(arg_x, arg_y)\ 20 | { .x = arg_x, .y = arg_y } 21 | 22 | /** 23 | * Инициализирует точку. 24 | * @param point Точка. 25 | */ 26 | ALWAYS_INLINE static void point_init(point_t* point) 27 | { 28 | point->x = 0; 29 | point->y = 0; 30 | } 31 | 32 | /** 33 | * Инициализирует точку с заданной позицией. 34 | * @param point Точка. 35 | * @param x Координата X. 36 | * @param y Координата Y. 37 | */ 38 | ALWAYS_INLINE static void point_init_position(point_t* point, graphics_pos_t x, graphics_pos_t y) 39 | { 40 | point->x = x; 41 | point->y = y; 42 | } 43 | 44 | /** 45 | * Копирует одну точку в другую. 46 | * @param dst Точка - назначение. 47 | * @param src Точка - источник. 48 | */ 49 | ALWAYS_INLINE static void point_copy(point_t* dst, const point_t* src) 50 | { 51 | dst->x = src->x; 52 | dst->y = src->y; 53 | } 54 | 55 | /** 56 | * Устанавливает позицию точки. 57 | * @param point Точка. 58 | * @param x Координата X. 59 | * @param y Координата Y. 60 | */ 61 | ALWAYS_INLINE static void point_set_position(point_t* point, graphics_pos_t x, graphics_pos_t y) 62 | { 63 | point->x = x; 64 | point->y = y; 65 | } 66 | 67 | /** 68 | * Получает координату X точки. 69 | * @param point Точка. 70 | * @return Координата X. 71 | */ 72 | ALWAYS_INLINE static graphics_pos_t point_x(const point_t* point) 73 | { 74 | return point->x; 75 | } 76 | 77 | /** 78 | * Устанавливает координату X точки. 79 | * @param point Точка. 80 | * @param x Координата X. 81 | */ 82 | ALWAYS_INLINE static void point_set_x(point_t* point, graphics_pos_t x) 83 | { 84 | point->x = x; 85 | } 86 | 87 | /** 88 | * Получает координату Y точки. 89 | * @param point Точка. 90 | * @return Координата Y. 91 | */ 92 | ALWAYS_INLINE static graphics_pos_t point_y(const point_t* point) 93 | { 94 | return point->y; 95 | } 96 | 97 | /** 98 | * Устанавливает координату Y точки. 99 | * @param point Точка. 100 | * @param y Координата Y. 101 | */ 102 | ALWAYS_INLINE static void point_set_y(point_t* point, graphics_pos_t y) 103 | { 104 | point->y = y; 105 | } 106 | 107 | /** 108 | * Перемещает точку в заданную позицию. 109 | * @param point Точка. 110 | * @param x Координата X. 111 | * @param y Координата Y. 112 | */ 113 | ALWAYS_INLINE static void point_move(point_t* point, graphics_pos_t x, graphics_pos_t y) 114 | { 115 | point->x = x; 116 | point->y = y; 117 | } 118 | 119 | #endif /* POINT_H */ 120 | -------------------------------------------------------------------------------- /gui/gui_button.c: -------------------------------------------------------------------------------- 1 | #include "gui_button.h" 2 | #include "utils/utils.h" 3 | #include "graphics/painter.h" 4 | #include "input/keys.h" 5 | 6 | err_t gui_button_init(gui_button_t* button, gui_t* gui) 7 | { 8 | return gui_button_init_parent(button, gui, NULL); 9 | } 10 | 11 | err_t gui_button_init_parent(gui_button_t* button, gui_t* gui, gui_widget_t* parent) 12 | { 13 | RETURN_ERR_IF_FAIL(gui_widget_init_parent(GUI_WIDGET(button), gui, parent)); 14 | 15 | gui_theme_t* theme = gui_theme(gui_object_gui(GUI_OBJECT(button))); 16 | 17 | GUI_WIDGET(button)->type_id = GUI_BUTTON_TYPE_ID; 18 | GUI_WIDGET(button)->on_repaint = GUI_WIDGET_ON_REPAINT_PROC(gui_button_on_repaint); 19 | GUI_WIDGET(button)->on_key_press = GUI_WIDGET_ON_KEY_PRESS_PROC(gui_button_on_key_press); 20 | GUI_WIDGET(button)->on_key_release = GUI_WIDGET_ON_KEY_RELEASE_PROC(gui_button_on_key_release); 21 | GUI_WIDGET(button)->focusable = true; 22 | GUI_WIDGET(button)->back_color = theme->widget_color; 23 | GUI_WIDGET(button)->border = GUI_BORDER_SOLID; 24 | button->text = NULL; 25 | button->pressing = false; 26 | button->on_clicked = NULL; 27 | 28 | return E_NO_ERROR; 29 | } 30 | 31 | void gui_button_set_text(gui_button_t* button, const char* text) 32 | { 33 | button->text = text; 34 | gui_widget_repaint(GUI_WIDGET(button), NULL); 35 | } 36 | 37 | void gui_button_on_repaint(gui_button_t* button, const rect_t* rect) 38 | { 39 | gui_theme_t* theme = gui_theme(gui_object_gui(GUI_OBJECT(button))); 40 | 41 | painter_t painter; 42 | 43 | gui_widget_begin_paint(GUI_WIDGET(button), &painter, rect); 44 | 45 | painter_set_pen(&painter, PAINTER_PEN_SOLID); 46 | painter_set_brush(&painter, PAINTER_BRUSH_SOLID); 47 | 48 | if(!button->pressing){ 49 | painter_set_brush_color(&painter, GUI_WIDGET(button)->back_color); 50 | }else{ 51 | painter_set_brush_color(&painter, theme->pressed_color); 52 | } 53 | 54 | if(gui_widget_has_focus(GUI_WIDGET(button))){ 55 | painter_set_pen_color(&painter, theme->focus_color); 56 | }else{ 57 | painter_set_pen_color(&painter, theme->border_color); 58 | } 59 | 60 | if(GUI_WIDGET(button)->border == GUI_BORDER_NONE && !gui_widget_has_focus(GUI_WIDGET(button))){ 61 | painter_draw_fillrect(&painter, 0, 0, rect_width(&GUI_WIDGET(button)->rect) - 1, rect_height(&GUI_WIDGET(button)->rect) - 1); 62 | }else{ 63 | painter_draw_rect(&painter, 0, 0, rect_width(&GUI_WIDGET(button)->rect) - 1, rect_height(&GUI_WIDGET(button)->rect) - 1); 64 | } 65 | 66 | if(button->text != NULL){ 67 | painter_set_pen_color(&painter, theme->font_color); 68 | painter_set_font(&painter, theme->widget_font); 69 | painter_set_source_image_mode(&painter, PAINTER_SOURCE_IMAGE_MODE_BITMAP); 70 | 71 | graphics_pos_t text_x, text_y; 72 | painter_string_size(&painter, button->text, (graphics_size_t*)&text_x, (graphics_size_t*)&text_y); 73 | 74 | text_x = ((graphics_pos_t)gui_widget_width(GUI_WIDGET(button)) - text_x) / 2; 75 | text_y = ((graphics_pos_t)gui_widget_height(GUI_WIDGET(button)) - text_y) / 2; 76 | 77 | painter_draw_string(&painter, text_x, text_y, button->text); 78 | } 79 | 80 | gui_widget_end_paint(GUI_WIDGET(button), &painter); 81 | } 82 | 83 | void gui_button_on_key_press(gui_button_t* button, keycode_t key) 84 | { 85 | if(key == KEY_ENTER || key == KEY_SPACE){ 86 | if(!button->pressing){ 87 | button->pressing = true; 88 | gui_widget_repaint(GUI_WIDGET(button), NULL); 89 | } 90 | } 91 | } 92 | 93 | void gui_button_on_key_release(gui_button_t* button, keycode_t key) 94 | { 95 | if(key == KEY_ENTER || key == KEY_SPACE){ 96 | if(button->pressing){ 97 | button->pressing = false; 98 | 99 | if(button->on_clicked) button->on_clicked(button); 100 | 101 | gui_widget_repaint(GUI_WIDGET(button), NULL); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /gui/gui_button.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file gui_button.h Реализация виджета кнопки графического интерфейса. 3 | */ 4 | 5 | #ifndef GUI_BUTTON_H 6 | #define GUI_BUTTON_H 7 | 8 | #include "gui.h" 9 | #include "gui_widget.h" 10 | #include "errors/errors.h" 11 | #include "defs/defs.h" 12 | #include 13 | 14 | typedef struct _Gui_Button gui_button_t; 15 | 16 | //! Зеначение идентификатора типа кнопки. 17 | #define GUI_BUTTON_TYPE_ID 4 18 | 19 | struct _Gui_Button { 20 | gui_widget_t super; //!< Суперкласс. 21 | const char* text; //!< Текст кнопки. 22 | bool pressing; //!< Флаг нажимания на кнопку. 23 | void (*on_clicked)(gui_button_t* button); //!< Каллбэк при изменении флага. 24 | }; 25 | 26 | typedef void (*gui_button_on_clicked_t)(gui_button_t*); 27 | 28 | //! Приводит указатель button к типу кнопки. 29 | #define GUI_BUTTON(button) ((gui_button_t*)(button)) 30 | 31 | /** 32 | * Инициализирует кнопку. 33 | * @param button Кнопка. 34 | * @param gui Графический интерфейс. 35 | * @return Код ошибки. 36 | */ 37 | EXTERN err_t gui_button_init(gui_button_t* button, gui_t* gui); 38 | 39 | /** 40 | * Инициализирует кнопку как потомок заданного родителя. 41 | * @param button Кнопка. 42 | * @param gui Графический интерфейс. 43 | * @param parent Родитель. 44 | * @return Код ошибки. 45 | */ 46 | EXTERN err_t gui_button_init_parent(gui_button_t* button, gui_t* gui, gui_widget_t* parent); 47 | 48 | /** 49 | * Получает текст кнопки. 50 | * @param button Кнопка. 51 | * @return Текст кнопки. 52 | */ 53 | ALWAYS_INLINE static const char* gui_button_text(gui_button_t* button) 54 | { 55 | return button->text; 56 | } 57 | 58 | /** 59 | * Устанавливает текст кнопки. 60 | * @param button Кнопка. 61 | * @param text Текст кнопки. 62 | */ 63 | EXTERN void gui_button_set_text(gui_button_t* button, const char* text); 64 | 65 | /** 66 | * Получает каллбэк нажатия кнопки. 67 | * @param button Кнопка. 68 | * @return Каллбэк нажатия кнопки. 69 | */ 70 | ALWAYS_INLINE static gui_button_on_clicked_t gui_button_on_clicked(gui_button_t* button) 71 | { 72 | return button->on_clicked; 73 | } 74 | 75 | /** 76 | * Устанавливает каллбэк нажатия кнопки. 77 | * @param button Кнопка. 78 | * @param on_clicked Каллбэк нажатия кнопки. 79 | */ 80 | ALWAYS_INLINE static void gui_button_set_on_clicked(gui_button_t* button, gui_button_on_clicked_t on_clicked) 81 | { 82 | button->on_clicked = on_clicked; 83 | } 84 | 85 | /** 86 | * Обработчик перерисовки. 87 | * @param button Кнопка. 88 | * @param rect Область перерисовки. 89 | */ 90 | EXTERN void gui_button_on_repaint(gui_button_t* button, const rect_t* rect); 91 | 92 | /** 93 | * Обработчик нажатия клавиши. 94 | * @param button Кнопка. 95 | * @param key Код клавиши. 96 | */ 97 | EXTERN void gui_button_on_key_press(gui_button_t* button, keycode_t key); 98 | 99 | /** 100 | * Обработчик отпускания клавиши. 101 | * @param button Кнопка. 102 | * @param key Код клавиши. 103 | */ 104 | EXTERN void gui_button_on_key_release(gui_button_t* button, keycode_t key); 105 | 106 | #endif /* GUI_BUTTON_H */ 107 | 108 | -------------------------------------------------------------------------------- /gui/gui_checkbox.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file gui_checkbox.h Реализация виджета флажка графического интерфейса. 3 | */ 4 | 5 | #ifndef GUI_CHECKBOX_H 6 | #define GUI_CHECKBOX_H 7 | 8 | #include "gui.h" 9 | #include "gui_widget.h" 10 | #include "errors/errors.h" 11 | #include "defs/defs.h" 12 | #include 13 | #include 14 | 15 | typedef struct _Gui_Checkbox gui_checkbox_t; 16 | 17 | //! Зеначение идентификатора типа флажка. 18 | #define GUI_CHECKBOX_TYPE_ID 3 19 | 20 | struct _Gui_Checkbox { 21 | gui_widget_t super; //!< Суперкласс. 22 | const char* text; //!< Текст флажка. 23 | bool checked; //!< Флаг. 24 | size_t check_size; //!< Размер флажка. 25 | void (*on_toggled)(gui_checkbox_t* checkbox, bool checked); //!< Каллбэк при изменении флага. 26 | }; 27 | 28 | typedef void (*gui_checkbox_on_toggled_t)(gui_checkbox_t*, bool); 29 | 30 | //! Приводит указатель checkbox к типу флажка. 31 | #define GUI_CHECKBOX(checkbox) ((gui_checkbox_t*)(checkbox)) 32 | 33 | // Размер флажка по-умолчанию, 34 | #define GUI_CHECKBOX_DEFAULT_CHECK_SIZE 12 35 | 36 | /** 37 | * Инициализирует флажок. 38 | * @param checkbox Флажок. 39 | * @param gui Графический интерфейс. 40 | * @return Код ошибки. 41 | */ 42 | EXTERN err_t gui_checkbox_init(gui_checkbox_t* checkbox, gui_t* gui); 43 | 44 | /** 45 | * Инициализирует флажок как потомок заданного родителя. 46 | * @param checkbox Флажок. 47 | * @param gui Графический интерфейс. 48 | * @param parent Родитель. 49 | * @return Код ошибки. 50 | */ 51 | EXTERN err_t gui_checkbox_init_parent(gui_checkbox_t* checkbox, gui_t* gui, gui_widget_t* parent); 52 | 53 | /** 54 | * Получает текст флажка. 55 | * @param checkbox Флажок. 56 | * @return Текст флажка. 57 | */ 58 | ALWAYS_INLINE static const char* gui_checkbox_text(gui_checkbox_t* checkbox) 59 | { 60 | return checkbox->text; 61 | } 62 | 63 | /** 64 | * Устанавливает текст флажка. 65 | * @param checkbox Флажок. 66 | * @param text Текст флажка. 67 | */ 68 | EXTERN void gui_checkbox_set_text(gui_checkbox_t* checkbox, const char* text); 69 | 70 | /** 71 | * Получает установленность флажка. 72 | * @param checkbox Флажок. 73 | * @return Установленность флажка. 74 | */ 75 | ALWAYS_INLINE static bool gui_checkbox_checked(gui_checkbox_t* checkbox) 76 | { 77 | return checkbox->checked; 78 | } 79 | 80 | /** 81 | * Устанавливает установленность флажка. 82 | * @param checkbox Флажок. 83 | * @param checked Установленность флажка. 84 | */ 85 | EXTERN void gui_checkbox_set_checked(gui_checkbox_t* checkbox, bool checked); 86 | 87 | /** 88 | * Получает каллбэк изменения флага. 89 | * @param checkbox Флажок. 90 | * @return Каллбэк изменения флага. 91 | */ 92 | ALWAYS_INLINE static gui_checkbox_on_toggled_t gui_checkbox_on_toggled(gui_checkbox_t* checkbox) 93 | { 94 | return checkbox->on_toggled; 95 | } 96 | 97 | /** 98 | * Устанавливает каллбэк изменения флага. 99 | * @param checkbox Флажок. 100 | * @param on_toggled Каллбэк изменения флага. 101 | */ 102 | ALWAYS_INLINE static void gui_checkbox_set_on_toggled(gui_checkbox_t* checkbox, gui_checkbox_on_toggled_t on_toggled) 103 | { 104 | checkbox->on_toggled = on_toggled; 105 | } 106 | 107 | /** 108 | * Получает размер флажка. 109 | * @param checkbox Флажок. 110 | * @return Размер флажка. 111 | */ 112 | ALWAYS_INLINE static size_t gui_checkbox_check_size(gui_checkbox_t* checkbox) 113 | { 114 | return checkbox->check_size; 115 | } 116 | 117 | /** 118 | * Устанавливает размер флажка. 119 | * @param checkbox Флажок. 120 | * @param size Размер флажка. 121 | */ 122 | EXTERN void gui_checkbox_set_check_size(gui_checkbox_t* checkbox, size_t size); 123 | 124 | /** 125 | * Обработчик перерисовки. 126 | * @param checkbox Флажок. 127 | * @param rect Область перерисовки. 128 | */ 129 | EXTERN void gui_checkbox_on_repaint(gui_checkbox_t* checkbox, const rect_t* rect); 130 | 131 | /** 132 | * Обработчик нажатия клавиши. 133 | * @param checkbox Флажок. 134 | * @param key Код клавиши. 135 | */ 136 | EXTERN void gui_checkbox_on_key_press(gui_checkbox_t* checkbox, keycode_t key); 137 | 138 | #endif /* GUI_CHECKBOX_H */ 139 | 140 | -------------------------------------------------------------------------------- /gui/gui_event.c: -------------------------------------------------------------------------------- 1 | #include "gui_event.h" 2 | -------------------------------------------------------------------------------- /gui/gui_label.c: -------------------------------------------------------------------------------- 1 | #include "gui_label.h" 2 | #include "utils/utils.h" 3 | #include "graphics/painter.h" 4 | 5 | err_t gui_label_init(gui_label_t* label, gui_t* gui) 6 | { 7 | return gui_label_init_parent(label, gui, NULL); 8 | } 9 | 10 | err_t gui_label_init_parent(gui_label_t* label, gui_t* gui, gui_widget_t* parent) 11 | { 12 | RETURN_ERR_IF_FAIL(gui_widget_init_parent(GUI_WIDGET(label), gui, parent)); 13 | 14 | GUI_WIDGET(label)->type_id = GUI_LABEL_TYPE_ID; 15 | GUI_WIDGET(label)->on_repaint = GUI_WIDGET_ON_REPAINT_PROC(gui_label_on_repaint); 16 | 17 | return E_NO_ERROR; 18 | } 19 | 20 | void gui_label_set_text(gui_label_t* label, const char* text) 21 | { 22 | label->text = text; 23 | gui_widget_repaint(GUI_WIDGET(label), NULL); 24 | } 25 | 26 | void gui_label_on_repaint(gui_label_t* label, const rect_t* rect) 27 | { 28 | gui_widget_on_repaint(GUI_WIDGET(label), rect); 29 | 30 | if(label->text == NULL) return; 31 | 32 | gui_theme_t* theme = gui_theme(gui_object_gui(GUI_OBJECT(label))); 33 | 34 | painter_t painter; 35 | 36 | gui_widget_begin_paint(GUI_WIDGET(label), &painter, rect); 37 | 38 | painter_set_pen(&painter, PAINTER_PEN_SOLID); 39 | painter_set_pen_color(&painter, theme->font_color); 40 | painter_set_font(&painter, theme->widget_font); 41 | painter_set_source_image_mode(&painter, PAINTER_SOURCE_IMAGE_MODE_BITMAP); 42 | 43 | graphics_pos_t text_x, text_y; 44 | painter_string_size(&painter, label->text, (graphics_size_t*)&text_x, (graphics_size_t*)&text_y); 45 | 46 | text_x = ((graphics_pos_t)gui_widget_width(GUI_WIDGET(label)) - text_x) / 2; 47 | text_y = ((graphics_pos_t)gui_widget_height(GUI_WIDGET(label)) - text_y) / 2; 48 | 49 | painter_draw_string(&painter, text_x, text_y, label->text); 50 | 51 | gui_widget_end_paint(GUI_WIDGET(label), &painter); 52 | } 53 | -------------------------------------------------------------------------------- /gui/gui_label.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file gui_label.h Реализация виджета метки графического интерфейса. 3 | */ 4 | 5 | #ifndef GUI_LABEL_H 6 | #define GUI_LABEL_H 7 | 8 | #include "gui.h" 9 | #include "gui_widget.h" 10 | #include "errors/errors.h" 11 | #include "defs/defs.h" 12 | 13 | typedef struct _Gui_Label gui_label_t; 14 | 15 | //! Зеначение идентификатора типа метки. 16 | #define GUI_LABEL_TYPE_ID 1 17 | 18 | struct _Gui_Label { 19 | gui_widget_t super; //!< Суперкласс. 20 | const char* text; //!< Отображаемый текст. 21 | }; 22 | 23 | //! Приводит указатель label к типу метки. 24 | #define GUI_LABEL(label) ((gui_label_t*)(label)) 25 | 26 | /** 27 | * Инициализирует метку. 28 | * @param label Метка. 29 | * @param gui Графический интерфейс. 30 | * @return Код ошибки. 31 | */ 32 | EXTERN err_t gui_label_init(gui_label_t* label, gui_t* gui); 33 | 34 | /** 35 | * Инициализирует метку как потомок заданного родителя. 36 | * @param label Метка. 37 | * @param gui Графический интерфейс. 38 | * @param parent Родитель. 39 | * @return Код ошибки. 40 | */ 41 | EXTERN err_t gui_label_init_parent(gui_label_t* label, gui_t* gui, gui_widget_t* parent); 42 | 43 | /** 44 | * Получает текст метки. 45 | * @param label Метка. 46 | * @return Текст метки. 47 | */ 48 | ALWAYS_INLINE static const char* gui_label_text(gui_label_t* label) 49 | { 50 | return label->text; 51 | } 52 | 53 | /** 54 | * Устанавливает текст метки. 55 | * @param label Метка. 56 | * @param text Текст метки. 57 | */ 58 | EXTERN void gui_label_set_text(gui_label_t* label, const char* text); 59 | 60 | /** 61 | * Обработчик перерисовки. 62 | * @param label Метка. 63 | * @param rect Область перерисовки. 64 | */ 65 | EXTERN void gui_label_on_repaint(gui_label_t* label, const rect_t* rect); 66 | 67 | #endif /* GUI_LABEL_H */ 68 | -------------------------------------------------------------------------------- /gui/gui_number_label.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file gui_number_label.h Реализация виджета числовой метки графического интерфейса. 3 | */ 4 | 5 | #ifndef GUI_NUMBER_LABEL_H 6 | #define GUI_NUMBER_LABEL_H 7 | 8 | #include "gui.h" 9 | #include "gui_widget.h" 10 | #include "errors/errors.h" 11 | #include "defs/defs.h" 12 | 13 | 14 | typedef enum _Gui_Number_Label_Format { 15 | GUI_NUMBER_LABEL_DEC = 0, //!< Десятичный формат числа. 16 | GUI_NUMBER_LABEL_HEX, //!< Шестнадцатиричный формат числа. 17 | GUI_NUMBER_LABEL_FIX, //!< Формат числа с фиксированной запятой (fixed32_t). 18 | } gui_number_label_format_t; 19 | 20 | typedef struct _Gui_Number_Label gui_number_label_t; 21 | 22 | //! Зеначение идентификатора типа числовой метки. 23 | #define GUI_NUMBER_LABEL_TYPE_ID 2 24 | 25 | struct _Gui_Number_Label { 26 | gui_widget_t super; //!< Суперкласс. 27 | int number; //!< Отображаемое число. 28 | gui_number_label_format_t format; //!< Формат числа. 29 | size_t decimals; //!< Число знаков дробной части для формата с фиксированной запятой. 30 | }; 31 | 32 | //! Приводит указатель label к типу числовой метки. 33 | #define GUI_NUMBER_LABEL(label) ((gui_number_label_t*)(label)) 34 | 35 | //! Максимальное число знаков после запятой. 36 | #define GUI_NUMBER_LABEL_DECIMALS_MAX 6 37 | 38 | /** 39 | * Инициализирует метку. 40 | * @param label Метка. 41 | * @param gui Графический интерфейс. 42 | * @return Код ошибки. 43 | */ 44 | EXTERN err_t gui_number_label_init(gui_number_label_t* label, gui_t* gui); 45 | 46 | /** 47 | * Инициализирует метку как потомок заданного родителя. 48 | * @param label Метка. 49 | * @param gui Графический интерфейс. 50 | * @param parent Родитель. 51 | * @return Код ошибки. 52 | */ 53 | EXTERN err_t gui_number_label_init_parent(gui_number_label_t* label, gui_t* gui, gui_widget_t* parent); 54 | 55 | /** 56 | * Получает число метки. 57 | * @param label Метка. 58 | * @return Число метки. 59 | */ 60 | ALWAYS_INLINE static int gui_number_label_number(gui_number_label_t* label) 61 | { 62 | return label->number; 63 | } 64 | 65 | /** 66 | * Устанавливает число метки. 67 | * @param label Метка. 68 | * @param number Число метки. 69 | */ 70 | EXTERN void gui_number_label_set_number(gui_number_label_t* label, int number); 71 | 72 | /** 73 | * Получает формат числа метки. 74 | * @param label Метка. 75 | * @return Формат числа метки. 76 | */ 77 | ALWAYS_INLINE static gui_number_label_format_t gui_number_label_format(gui_number_label_t* label) 78 | { 79 | return label->format; 80 | } 81 | 82 | /** 83 | * Устанавливает формат числа метки. 84 | * @param label Метка. 85 | * @param format Формат числа метки. 86 | */ 87 | EXTERN void gui_number_label_set_format(gui_number_label_t* label, gui_number_label_format_t format); 88 | 89 | /** 90 | * Получает число знаков дробной части метки. 91 | * @param label Метка. 92 | * @return Число знаков дробной части метки. 93 | */ 94 | ALWAYS_INLINE static int gui_number_label_decimals(gui_number_label_t* label) 95 | { 96 | return label->decimals; 97 | } 98 | 99 | /** 100 | * Устанавливает число знаков дробной части метки. 101 | * @param label Метка. 102 | * @param decimal Число знаков дробной части метки. 103 | */ 104 | EXTERN void gui_number_label_set_decimals(gui_number_label_t* label, int decimals); 105 | 106 | /** 107 | * Обработчик перерисовки. 108 | * @param label Метка. 109 | * @param rect Область перерисовки. 110 | */ 111 | EXTERN void gui_number_label_on_repaint(gui_number_label_t* label, const rect_t* rect); 112 | 113 | #endif /* GUI_NUMBER_LABEL_H */ 114 | -------------------------------------------------------------------------------- /gui/gui_object.c: -------------------------------------------------------------------------------- 1 | #include "gui_object.h" 2 | #include "utils/utils.h" 3 | 4 | err_t gui_object_init(gui_object_t* object, gui_t* gui) 5 | { 6 | if(gui == NULL) return E_NULL_POINTER; 7 | 8 | RETURN_ERR_IF_FAIL(list_init(&object->childs)); 9 | RETURN_ERR_IF_FAIL(list_item_init_data(&object->child, object)); 10 | 11 | object->gui = gui; 12 | object->parent = NULL; 13 | 14 | return E_NO_ERROR; 15 | } 16 | 17 | err_t gui_object_init_parent(gui_object_t* object, gui_t* gui, gui_object_t* parent) 18 | { 19 | RETURN_ERR_IF_FAIL(gui_object_init(object, gui)); 20 | 21 | gui_object_set_parent(object, parent); 22 | 23 | return E_NO_ERROR; 24 | } 25 | 26 | static bool gui_object_add_child_impl(gui_object_t* object, gui_object_t* child) 27 | { 28 | if(!list_contains(&object->childs, &child->child)){ 29 | list_append(&object->childs, &child->child); 30 | return true; 31 | } 32 | return false; 33 | } 34 | 35 | static bool gui_object_remove_child_impl(gui_object_t* object, gui_object_t* child) 36 | { 37 | if(list_contains(&object->childs, &child->child)){ 38 | list_remove(&object->childs, &child->child); 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | static bool gui_object_set_parent_impl(gui_object_t* object, gui_object_t* parent) 45 | { 46 | if(object->parent == parent) return false; 47 | 48 | if(object->parent) gui_object_remove_child_impl(object->parent, object); 49 | 50 | object->parent = parent; 51 | 52 | return true; 53 | } 54 | 55 | void gui_object_set_parent(gui_object_t* object, gui_object_t* parent) 56 | { 57 | if(!gui_object_set_parent_impl(object, parent)) return; 58 | 59 | if(parent) gui_object_add_child_impl(parent, object); 60 | } 61 | 62 | void gui_object_add_child(gui_object_t* object, gui_object_t* child) 63 | { 64 | if(gui_object_add_child_impl(object, child)){ 65 | gui_object_set_parent_impl(child, object); 66 | } 67 | } 68 | 69 | void gui_object_remove_child(gui_object_t* object, gui_object_t* child) 70 | { 71 | if(gui_object_remove_child_impl(object, child)){ 72 | gui_object_set_parent_impl(child, NULL); 73 | } 74 | } 75 | 76 | gui_object_t* gui_object_first_child(gui_object_t* object) 77 | { 78 | list_item_t* child_item = list_first(&object->childs); 79 | 80 | if(child_item == NULL) return NULL; 81 | 82 | return (gui_object_t*)child_item->data; 83 | } 84 | 85 | gui_object_t* gui_object_next_child(gui_object_t* cur_child) 86 | { 87 | list_item_t* child_item = list_next(&cur_child->child); 88 | 89 | if(child_item == NULL) return NULL; 90 | 91 | return (gui_object_t*)child_item->data; 92 | } 93 | 94 | gui_object_t* gui_object_last_child(gui_object_t* object) 95 | { 96 | list_item_t* child_item = list_last(&object->childs); 97 | 98 | if(child_item == NULL) return NULL; 99 | 100 | return (gui_object_t*)child_item->data; 101 | } 102 | 103 | gui_object_t* gui_object_prev_child(gui_object_t* cur_child) 104 | { 105 | list_item_t* child_item = list_prev(&cur_child->child); 106 | 107 | if(child_item == NULL) return NULL; 108 | 109 | return (gui_object_t*)child_item->data; 110 | } 111 | -------------------------------------------------------------------------------- /input/key_layout_en.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file key_layout_en.h Английская раскладка клавиатуры. 3 | */ 4 | 5 | #ifndef KEY_LAYOUT_EN_H 6 | #define KEY_LAYOUT_EN_H 7 | 8 | #include "key_input.h" 9 | 10 | #ifndef KEY_LAYOUT_EN_ID 11 | #define KEY_LAYOUT_EN_ID 0 12 | #endif 13 | 14 | static const key_layout_t key_layout_en = { 15 | .name = "en", 16 | .id = KEY_LAYOUT_EN_ID, 17 | .map_normal = { 18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07: 19 | 0x00, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0f: TAB, ENTER 20 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17: 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1f: 22 | 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, // 0x20 - 0x27: ' ', '\'' 23 | 0x00, 0x00, 0x00, 0x00, 0x2c, 0x2d, 0x2e, 0x2f, // 0x28 - 0x2f: ',', '-', '.', '/' 24 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // 0x30 - 0x37: '0', '1', '2', '3', '4', '5', '6', '7' 25 | 0x38, 0x39, 0x00, 0x3b, 0x00, 0x3d, 0x00, 0x00, // 0x38 - 0x3f: '8', '9', ';', '=', 26 | 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // 0x40 - 0x47: 'a', 'b', 'c', 'd', 'e', 'f', 'g' 27 | 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, // 0x48 - 0x4f: 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o' 28 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // 0x50 - 0x57: 'p', 'q', 'r', 's', 't', 'u', 'v', 'w' 29 | 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x00, 0x00, // 0x58 - 0x5f: 'x', 'y', 'z', '[', '\', ']', 30 | 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 - 0x67: '`' 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6f: 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77: 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7f: 34 | 0x2f, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87: '/', '*' 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x2b, 0x0a, // 0x88 - 0x8f: '-', '+', ENTER 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97: 37 | 0x00, 0x00, 0x00, 0x00 // 0x98 - 0x9b: 38 | }, 39 | 40 | .map_shifted = { 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07: 42 | 0x00, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0f: TAB, ENTER 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17: 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1f: 45 | 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, // 0x20 - 0x27: ' ', '"' 46 | 0x00, 0x00, 0x00, 0x00, 0x3c, 0x5f, 0x3e, 0x3f, // 0x28 - 0x2f: '<', '_', '>', '?' 47 | 0x29, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5e, 0x26, // 0x30 - 0x37: ')', '!', '@', '#', '$', '%', '^', '&' 48 | 0x2a, 0x28, 0x00, 0x3a, 0x00, 0x2b, 0x00, 0x00, // 0x38 - 0x3f: '*', '(', ':', '+', 49 | 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // 0x40 - 0x47: 'A', 'B', 'C', 'D', 'E', 'F', 'G' 50 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, // 0x48 - 0x4f: 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O' 51 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // 0x50 - 0x57: 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W' 52 | 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x00, 0x00, // 0x58 - 0x5f: 'X', 'Y', 'Z', '{', '|', '}', 53 | 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 - 0x67: '~' 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6f: 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77: 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7f: 57 | 0x2f, 0x2a, 0x00, 0x30, 0x31, 0x32, 0x33, 0x34, // 0x80 - 0x87: '/', '*', '0', '1', '2', '3', '4' 58 | 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x2b, 0x0a, // 0x88 - 0x8f: '5', '6', '7', '8', '9', '-', '+', ENTER 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97: 60 | 0x00, 0x00, 0x00, 0x00 // 0x98 - 0x9b: 61 | } 62 | }; 63 | 64 | #endif //KEY_LAYOUT_EN_H 65 | -------------------------------------------------------------------------------- /input/key_layout_ru.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file key_layout_ru.h Русская раскладка клавиатуры (UTF-8). 3 | */ 4 | 5 | #ifndef KEY_LAYOUT_RU_H 6 | #define KEY_LAYOUT_RU_H 7 | 8 | #include "key_input.h" 9 | 10 | #ifndef KEY_LAYOUT_RU_ID 11 | #define KEY_LAYOUT_RU_ID 1 12 | #endif 13 | 14 | static const key_layout_t key_layout_ru = { 15 | .name = "ru", 16 | .id = KEY_LAYOUT_RU_ID, 17 | .map_normal = { 18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07: 19 | 0x00, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0f: TAB, ENTER 20 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17: 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1f: 22 | 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44D, // 0x20 - 0x27: ' ', 'э' 23 | 0x00, 0x00, 0x00, 0x00, 0x431, 0x2d, 0x44E, 0x2f, // 0x28 - 0x2f: 'б', '-', 'ю', '/' 24 | 0x30, 0x31, 0x32, 0x33 , 0x34, 0x35, 0x36, 0x37, // 0x30 - 0x37: '0', '1', '2', '3', '4', '5', '6', '7' 25 | 0x38, 0x39, 0x00, 0x436, 0x00, 0x3d, 0x00, 0x00, // 0x38 - 0x3f: '8', '9', 'ж', '=', 26 | 0x00 , 0x444, 0x438, 0x441, 0x432, 0x443, 0x430, 0x43F, // 0x40 - 0x47: 'ф', 'и', 'с', 'в', 'у', 'а', 'п' 27 | 0x440, 0x448, 0x43E, 0x43B, 0x434, 0x44C, 0x442, 0x449, // 0x48 - 0x4f: 'р', 'ш', 'о', 'л', 'д', 'ь', 'т', 'щ' 28 | 0x437, 0x439, 0x43A, 0x44B, 0x435, 0x433, 0x43C, 0x446, // 0x50 - 0x57: 'з', 'й', 'к', 'ы', 'е', 'г', 'м', 'ц' 29 | 0x447, 0x43D, 0x44F, 0x445, 0x5c , 0x44A, 0x00 , 0x00 , // 0x58 - 0x5f: 'ч', 'н', 'я', 'х', '\', 'ъ', 30 | 0x451, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 - 0x67: 'ё' 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6f: 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77: 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7f: 34 | 0x2e, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87: '.', '*' 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x2b, 0x0a, // 0x88 - 0x8f: '-', '+', ENTER 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97: 37 | 0x00, 0x00, 0x00, 0x00 // 0x98 - 0x9b: 38 | }, 39 | 40 | .map_shifted = { 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07: 42 | 0x00, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0f: TAB, ENTER 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17: 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1f: 45 | 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42D, // 0x20 - 0x27: ' ', 'Э' 46 | 0x00, 0x00, 0x00, 0x00, 0x411, 0x5f, 0x42E, 0x2c, // 0x28 - 0x2f: 'Б', '_', 'Ю', ',' 47 | 0x29, 0x21, 0x40, 0x23 , 0x24, 0x25, 0x5e, 0x26, // 0x30 - 0x37: ')', '!', '@', '#', '$', '%', '^', '&' 48 | 0x2a, 0x28, 0x00, 0x416, 0x00, 0x2b, 0x00, 0x00, // 0x38 - 0x3f: '*', '(', 'Ж', '+', 49 | 0x00 , 0x424, 0x418, 0x421, 0x412, 0x423, 0x410, 0x41F, // 0x40 - 0x47: 'Ф', 'И', 'С', 'В', 'У', 'А', 'П' 50 | 0x420, 0x428, 0x41E, 0x41B, 0x414, 0x42C, 0x422, 0x429, // 0x48 - 0x4f: 'Р', 'Ш', 'О', 'Л', 'Д', 'Ь', 'Т', 'Щ' 51 | 0x417, 0x419, 0x41A, 0x42B, 0x415, 0x413, 0x41C, 0x426, // 0x50 - 0x57: 'З', 'Й', 'К', 'Ы', 'Е', 'Г', 'М', 'Ц' 52 | 0x427, 0x41D, 0x42F, 0x425, 0x7c , 0x42A, 0x00 , 0x00 , // 0x58 - 0x5f: 'Ч', 'Н', 'Я', 'Х', '|', 'Ъ', 53 | 0x401, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 - 0x67: 'Ё' 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6f: 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77: 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7f: 57 | 0x2f, 0x2a, 0x00, 0x30, 0x31, 0x32, 0x33, 0x34, // 0x80 - 0x87: '/', '*', '0', '1', '2', '3', '4' 58 | 0x35, 0x36, 0x37, 0x38, 0x39, 0x2d, 0x2b, 0x0a, // 0x88 - 0x8f: '5', '6', '7', '8', '9', '-', '+', ENTER 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97: 60 | 0x00, 0x00, 0x00, 0x00 // 0x98 - 0x9b: 61 | } 62 | }; 63 | 64 | #endif //KEY_LAYOUT_RU_H 65 | -------------------------------------------------------------------------------- /ld-scripts/stm32f103c8.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания адресов и областей памяти. 4 | */ 5 | 6 | /* Точка входа. */ 7 | ENTRY(Reset_Handler) 8 | 9 | /* Память. */ 10 | MEMORY 11 | { 12 | BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 0K /* Загрузчик. */ 13 | APP (rx) : ORIGIN = 0x08000000 + LENGTH(BOOT), LENGTH = 64K - LENGTH(BOOT) /* Флеш-память. */ 14 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K /* ОЗУ */ 15 | } 16 | 17 | /* Синоним региона. */ 18 | REGION_ALIAS("FLASH", APP); 19 | 20 | /* Минимальный размер стека. */ 21 | _min_stack_size = 0x200; 22 | 23 | /* Конец стека. */ 24 | _estack = ORIGIN(RAM) + LENGTH(RAM); 25 | 26 | /* Адрес начала сегмента основного приложения. */ 27 | _app_origin = ORIGIN(APP); 28 | 29 | /* Декларация секций. */ 30 | INCLUDE "stm32f10x_sections.ld" 31 | -------------------------------------------------------------------------------- /ld-scripts/stm32f103rb.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания адресов и областей памяти. 4 | */ 5 | 6 | /* Точка входа. */ 7 | ENTRY(Reset_Handler) 8 | 9 | /* Память. */ 10 | MEMORY 11 | { 12 | BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 0K /* Загрузчик. */ 13 | APP (rx) : ORIGIN = 0x08000000 + LENGTH(BOOT), LENGTH = 128K - LENGTH(BOOT) /* Флеш-память. */ 14 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K /* ОЗУ */ 15 | } 16 | 17 | /* Синоним региона. */ 18 | REGION_ALIAS("FLASH", APP); 19 | 20 | /* Минимальный размер стека. */ 21 | _min_stack_size = 0x200; 22 | 23 | /* Конец стека. */ 24 | _estack = ORIGIN(RAM) + LENGTH(RAM); 25 | 26 | /* Адрес начала сегмента основного приложения. */ 27 | _app_origin = ORIGIN(APP); 28 | 29 | /* Декларация секций. */ 30 | INCLUDE "stm32f10x_sections.ld" 31 | -------------------------------------------------------------------------------- /ld-scripts/stm32f103rb_bld_app.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания адресов и областей памяти. 4 | */ 5 | 6 | /* Точка входа. */ 7 | ENTRY(Reset_Handler) 8 | 9 | /* Память. */ 10 | MEMORY 11 | { 12 | BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 8K /* Загрузчик. */ 13 | APP (rx) : ORIGIN = 0x08000000 + LENGTH(BOOT), LENGTH = 128K - LENGTH(BOOT) /* Флеш-память. */ 14 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K /* ОЗУ */ 15 | } 16 | 17 | /* Синоним региона. */ 18 | REGION_ALIAS("FLASH", APP); 19 | 20 | /* Минимальный размер стека. */ 21 | _min_stack_size = 0x200; 22 | 23 | /* Конец стека. */ 24 | _estack = ORIGIN(RAM) + LENGTH(RAM); 25 | 26 | /* Адрес начала сегмента основного приложения. */ 27 | _app_origin = ORIGIN(APP); 28 | 29 | /* Декларация секций. */ 30 | INCLUDE "stm32f10x_sections.ld" 31 | -------------------------------------------------------------------------------- /ld-scripts/stm32f103rb_bld_boot.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания адресов и областей памяти. 4 | */ 5 | 6 | /* Точка входа. */ 7 | ENTRY(Reset_Handler) 8 | 9 | /* Память. */ 10 | MEMORY 11 | { 12 | BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 8K /* Загрузчик. */ 13 | APP (rx) : ORIGIN = 0x08000000 + LENGTH(BOOT), LENGTH = 128K - LENGTH(BOOT) /* Флеш-память. */ 14 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K /* ОЗУ */ 15 | } 16 | 17 | /* Синоним региона. */ 18 | REGION_ALIAS("FLASH", BOOT); 19 | 20 | /* Минимальный размер стека. */ 21 | _min_stack_size = 0x200; 22 | 23 | /* Конец стека. */ 24 | _estack = ORIGIN(RAM) + LENGTH(RAM); 25 | 26 | /* Адрес начала сегмента основного приложения. */ 27 | _app_origin = ORIGIN(APP); 28 | 29 | /* Декларация секций. */ 30 | INCLUDE "stm32f10x_sections.ld" 31 | -------------------------------------------------------------------------------- /ld-scripts/stm32f103vc.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания адресов и областей памяти. 4 | */ 5 | 6 | /* Точка входа. */ 7 | ENTRY(Reset_Handler) 8 | 9 | /* Память. */ 10 | MEMORY 11 | { 12 | BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 0K /* Загрузчик. */ 13 | APP (rx) : ORIGIN = 0x08000000 + LENGTH(BOOT), LENGTH = 256K - LENGTH(BOOT) /* Флеш-память. */ 14 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 48K /* ОЗУ */ 15 | } 16 | 17 | /* Синоним региона. */ 18 | REGION_ALIAS("FLASH", APP); 19 | 20 | /* Минимальный размер стека. */ 21 | _min_stack_size = 0x200; 22 | 23 | /* Конец стека. */ 24 | _estack = ORIGIN(RAM) + LENGTH(RAM); 25 | 26 | /* Адрес начала сегмента основного приложения. */ 27 | _app_origin = ORIGIN(APP); 28 | 29 | /* Декларация секций. */ 30 | INCLUDE "stm32f10x_sections.ld" 31 | -------------------------------------------------------------------------------- /ld-scripts/stm32f103ze.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания адресов и областей памяти. 4 | */ 5 | 6 | /* Точка входа. */ 7 | ENTRY(Reset_Handler) 8 | 9 | /* Память. */ 10 | MEMORY 11 | { 12 | BOOT (rx) : ORIGIN = 0x08000000, LENGTH = 0K /* Загрузчик. */ 13 | APP (rx) : ORIGIN = 0x08000000 + LENGTH(BOOT), LENGTH = 512K - LENGTH(BOOT) /* Флеш-память. */ 14 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K /* ОЗУ */ 15 | } 16 | 17 | /* Синоним региона. */ 18 | REGION_ALIAS("FLASH", APP); 19 | 20 | /* Минимальный размер стека. */ 21 | _min_stack_size = 0x200; 22 | 23 | /* Конец стека. */ 24 | _estack = ORIGIN(RAM) + LENGTH(RAM); 25 | 26 | /* Адрес начала сегмента основного приложения. */ 27 | _app_origin = ORIGIN(APP); 28 | 29 | /* Декларация секций. */ 30 | INCLUDE "stm32f10x_sections.ld" 31 | -------------------------------------------------------------------------------- /ld-scripts/stm32f10x_sections.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Скрипт компоновщика для stm32. 3 | * Часть задания секций. 4 | */ 5 | 6 | /* Секции. */ 7 | SECTIONS 8 | { 9 | /* Вектора прерываний. */ 10 | .isr_vector : ALIGN(4) 11 | { 12 | _sisr = .; 13 | 14 | KEEP(*(.isr_vector)) 15 | 16 | . = ALIGN(4); 17 | _eisr = .; 18 | } > FLASH 19 | 20 | /* Код. */ 21 | .text : ALIGN(4) 22 | { 23 | _stext = .; 24 | 25 | *(.text) 26 | *(.text.*) 27 | *(.glue_7) 28 | *(.glue_7t) 29 | 30 | . = ALIGN(4); 31 | _etext = .; 32 | } > FLASH 33 | 34 | /* Данные только для чтения. */ 35 | .rodata : ALIGN(4) 36 | { 37 | _srodata = .; 38 | 39 | *(.rodata) 40 | *(.rodata.*) 41 | 42 | . = ALIGN(4); 43 | _erodata = .; 44 | } > FLASH 45 | 46 | /* Массив предварительной инициализации. */ 47 | .preinit : ALIGN(4) 48 | { 49 | _spreinit_array = .; 50 | 51 | KEEP(*(SORT(.preinit_array.*))) 52 | KEEP(*(.preinit_array)) 53 | 54 | . = ALIGN(4); 55 | _epreinit_array = .; 56 | } > FLASH 57 | 58 | /* Массив инициализации. */ 59 | .init : ALIGN(4) 60 | { 61 | _sinit_array = .; 62 | 63 | KEEP(*(SORT(.init_array.*))) 64 | KEEP(*(.init_array)) 65 | 66 | . = ALIGN(4); 67 | _einit_array = .; 68 | } > FLASH 69 | 70 | /* Массив деинициализации. */ 71 | .fini : ALIGN(4) 72 | { 73 | _sfini_array = .; 74 | 75 | KEEP(*(SORT(.fini_array.*))) 76 | KEEP(*(.fini_array)) 77 | 78 | . = ALIGN(4); 79 | _efini_array = .; 80 | } > FLASH 81 | 82 | /* ARM magic sections */ 83 | .ARM.extab : ALIGN(4) 84 | { 85 | *(.ARM.extab* .gnu.linkonce.armextab.*) 86 | } > FLASH 87 | 88 | .ARM.exidx : ALIGN(4) 89 | { 90 | __exidx_start = .; 91 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 92 | __exidx_end = .; 93 | } > FLASH 94 | 95 | . = ALIGN(4); 96 | /* Адрес инициализированных данных. */ 97 | _sidata = .; 98 | 99 | /* Инициализированные данные. */ 100 | .data : AT(_sidata) ALIGN(4) 101 | { 102 | _sdata = .; 103 | 104 | *(.data) 105 | *(.data.*) 106 | 107 | . = ALIGN(4); 108 | _edata = .; 109 | } > RAM 110 | 111 | /* Неинициализированные данные. */ 112 | .bss : ALIGN(4) 113 | { 114 | _sbss = .; 115 | 116 | *(.bss) 117 | *(.bss.*) 118 | *(COMMON) 119 | 120 | . = ALIGN(4); 121 | _ebss = .; 122 | } > RAM 123 | 124 | /* Куча. */ 125 | PROVIDE(_heap = _ebss); 126 | 127 | /* Стек минимального размера. */ 128 | .min_stack : ALIGN(4) 129 | { 130 | _smin_stack = .; 131 | 132 | . = . + _min_stack_size; 133 | 134 | . = ALIGN(4); 135 | _emin_stack = .; 136 | } > RAM 137 | 138 | /* Отладочная информация стандартных библиотек. */ 139 | /DISCARD/ : 140 | { 141 | libc.a ( * ) 142 | libm.a ( * ) 143 | libgcc.a ( * ) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /localization/localization.c: -------------------------------------------------------------------------------- 1 | #include "localization.h" 2 | #include 3 | 4 | 5 | //! Тип локализации. 6 | typedef struct _Localization { 7 | const translation_t* trs; //!< Переводы. 8 | size_t trs_count; //!< Число переводов. 9 | size_t cur_tr; //!< Индекс текущего перевода. 10 | size_t def_tr; //!< Индекс перевода по-умолчанию. 11 | const char* default_text; //!< Возвращаемый текст по-умолчанию. 12 | } localization_t; 13 | 14 | 15 | static localization_t loc; 16 | 17 | 18 | err_t localization_init(const translation_t* trs, size_t trs_count) 19 | { 20 | if(trs == NULL) return E_NULL_POINTER; 21 | if(trs_count == 0) return E_INVALID_VALUE; 22 | 23 | loc.trs = trs; 24 | loc.trs_count = trs_count; 25 | loc.cur_tr = 0; 26 | loc.def_tr = 0; 27 | loc.default_text = NULL; 28 | 29 | return E_NO_ERROR; 30 | } 31 | 32 | /** 33 | * Проверяет равенство двух идентификаторов языков. 34 | * @param l_lang Идентификатор языка. 35 | * @param r_lang Идентификатор языка. 36 | * @return Флаг равенства двух идентификаторов изыков. 37 | */ 38 | ALWAYS_INLINE static bool localization_langs_equals(lang_id_t l_lang, lang_id_t r_lang) 39 | { 40 | return l_lang == r_lang; 41 | } 42 | 43 | /** 44 | * Ищет перевод по идентификатору языка. 45 | * @param lang_id Идентификатор языка. 46 | * @param index Возвращаемый индекс перевода. 47 | * @return Наличие перевода для заданного языка. 48 | */ 49 | static bool localization_tr_index_by_lang_id(lang_id_t lang_id, size_t* index) 50 | { 51 | size_t i = 0; 52 | 53 | for(; i < loc.trs_count; i ++){ 54 | if(localization_langs_equals(loc.trs[i].lang_id, lang_id)){ 55 | if(index) *index = i; 56 | return true; 57 | } 58 | } 59 | 60 | return false; 61 | } 62 | 63 | bool localization_set_default_lang(lang_id_t lang_id) 64 | { 65 | size_t index = 0; 66 | if(localization_tr_index_by_lang_id(lang_id, &index)){ 67 | loc.def_tr = index; 68 | return true; 69 | } 70 | return false; 71 | } 72 | 73 | void localization_set_default_text(const char* text) 74 | { 75 | loc.default_text = text; 76 | } 77 | 78 | bool localization_set_lang(lang_id_t lang_id) 79 | { 80 | size_t index = 0; 81 | if(localization_tr_index_by_lang_id(lang_id, &index)){ 82 | loc.cur_tr = index; 83 | return true; 84 | } 85 | return false; 86 | } 87 | 88 | lang_id_t localization_lang(void) 89 | { 90 | if(loc.cur_tr >= loc.trs_count) return 0; 91 | 92 | return loc.trs[loc.cur_tr].lang_id; 93 | } 94 | 95 | /** 96 | * Функция сравнения перевода текста и идентификатора. 97 | * @param id Идентификатор перевода текста. 98 | * @param text_tr Перевод. 99 | * @return Результат сравнения. 100 | */ 101 | static int localization_compare_text_trs (const void * id, const void * text_tr) 102 | { 103 | trid_t id_tr = ((const text_tr_t*)text_tr)->id; 104 | 105 | if((trid_t)id > id_tr) return 1; 106 | if((trid_t)id < id_tr) return -1; 107 | 108 | return 0; 109 | } 110 | 111 | /** 112 | * Ищет текст перевода по идентификатору в заданном переводе. 113 | * @param id Идентификатор перевода текста. 114 | * @param search_tr Перевод. 115 | * @return Текст перевода. 116 | */ 117 | static const char* localization_translate_impl(trid_t id, const translation_t* search_tr) 118 | { 119 | const text_tr_t* text_tr = bsearch((const void*)id, search_tr->text_trs, search_tr->text_trs_count, 120 | sizeof(text_tr_t), localization_compare_text_trs); 121 | 122 | if(text_tr) return text_tr->text; 123 | 124 | return NULL; 125 | } 126 | 127 | const char* localization_translate(trid_t id) 128 | { 129 | const char* cur_text = localization_translate_impl(id, &loc.trs[loc.cur_tr]); 130 | 131 | if(!cur_text){ 132 | cur_text = localization_translate_impl(id, &loc.trs[loc.def_tr]); 133 | } 134 | 135 | if(cur_text) return cur_text; 136 | 137 | return loc.default_text; 138 | } 139 | -------------------------------------------------------------------------------- /mid_filter/mid_filter3i.c: -------------------------------------------------------------------------------- 1 | #include "mid_filter3i.h" 2 | #include 3 | 4 | 5 | 6 | void mid_filter3i_init(mid_filter3i_t* filter) 7 | { 8 | memset(filter, 0x0, sizeof(mid_filter3i_t)); 9 | } 10 | 11 | void mid_filter3i_reset(mid_filter3i_t* filter) 12 | { 13 | filter->index = 0; 14 | filter->count = 0; 15 | } 16 | 17 | bool mid_filter3i_full(mid_filter3i_t* filter) 18 | { 19 | return filter->count == MID_FILTER3I_SIZE; 20 | } 21 | 22 | bool mid_filter3i_empty(mid_filter3i_t* filter) 23 | { 24 | return filter->count == 0; 25 | } 26 | 27 | void mid_filter3i_put(mid_filter3i_t* filter, mid_filter3i_value_t value) 28 | { 29 | filter->buffer[filter->index] = value; 30 | 31 | if(++ filter->index >= MID_FILTER3I_SIZE) filter->index = 0; 32 | if(filter->count < MID_FILTER3I_SIZE) filter->count ++; 33 | } 34 | 35 | mid_filter3i_value_t mid_filter3i_value(mid_filter3i_t* filter) 36 | { 37 | if(filter->count == 0) return 0; 38 | 39 | mid_filter3i_value_t a = filter->buffer[0]; 40 | 41 | if(filter->count == 1) return a; 42 | 43 | mid_filter3i_value_t b = filter->buffer[1]; 44 | 45 | if(filter->count == 2) return (a + b) >> 1; 46 | 47 | mid_filter3i_value_t c = filter->buffer[2]; 48 | 49 | if(a >= b){ 50 | if(b >= c){ 51 | return b; 52 | }else if(a >= c){ 53 | return c; 54 | }else{ 55 | return a; 56 | } 57 | }else{//b > a 58 | if(a >= c){ 59 | return a; 60 | }else if(b >= c){ 61 | return c; 62 | }else{ 63 | return b; 64 | } 65 | } 66 | } 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /mid_filter/mid_filter3i.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mid_filter3i.h Библиотека медианного фильтра по трём знаковым целочисленным элементам. 3 | */ 4 | 5 | #ifndef MID_FILTER3I_H 6 | #define MID_FILTER3I_H 7 | 8 | #include 9 | #include 10 | #include "defs/defs.h" 11 | 12 | //! Тип значения фильтра. 13 | typedef int32_t mid_filter3i_value_t; 14 | 15 | //! Размер медианного фильтра. 16 | #define MID_FILTER3I_SIZE 3 17 | typedef struct _Mid_Filter3i { 18 | mid_filter3i_value_t buffer[MID_FILTER3I_SIZE]; //!< Буфер на три элемента. 19 | int8_t index; //!< Индекс текущего элемента. 20 | int8_t count; //!< Количество элементов. 21 | } mid_filter3i_t; 22 | 23 | /** 24 | * Инициализирует фильтр. 25 | * @param filter Фильтр. 26 | */ 27 | EXTERN void mid_filter3i_init(mid_filter3i_t* filter); 28 | 29 | /** 30 | * Сбрасывает фильтр. 31 | * @param filter Фильтр. 32 | */ 33 | EXTERN void mid_filter3i_reset(mid_filter3i_t* filter); 34 | 35 | /** 36 | * Получает флаг заполненности фильтра. 37 | * @param filter Фильтр. 38 | * @return Флаг заполненности фильтра. 39 | */ 40 | EXTERN bool mid_filter3i_full(mid_filter3i_t* filter); 41 | 42 | /** 43 | * Получает флаг пустоты фильтра. 44 | * @param filter Фильтр. 45 | * @return Флаг пустоты фильтра. 46 | */ 47 | EXTERN bool mid_filter3i_empty(mid_filter3i_t* filter); 48 | 49 | /** 50 | * Помещает значение в фильтр. 51 | * @param filter Фильтр. 52 | * @param value Значение. 53 | */ 54 | EXTERN void mid_filter3i_put(mid_filter3i_t* filter, mid_filter3i_value_t value); 55 | 56 | /** 57 | * Вычисляет значение фильтра. 58 | * @param filter Фильтр. 59 | * @return Значение фильтра. 60 | */ 61 | EXTERN mid_filter3i_value_t mid_filter3i_value(mid_filter3i_t* filter); 62 | 63 | #endif /* MID_FILTER3I_H */ 64 | -------------------------------------------------------------------------------- /mutex/mutex.c: -------------------------------------------------------------------------------- 1 | #include "mutex.h" 2 | #include 3 | 4 | void mutex_init(mutex_t* mutex) 5 | { 6 | *mutex = MUTEX_UNLOCKED; 7 | } 8 | 9 | bool mutex_trylock(mutex_t* mutex) 10 | { 11 | for(;;){ 12 | if(__LDREXB(mutex) == MUTEX_LOCKED) return false; 13 | if(__STREXB(MUTEX_LOCKED, mutex) == 0) break; 14 | } 15 | __DMB(); 16 | return true; 17 | } 18 | 19 | void mutex_lock(mutex_t* mutex) 20 | { 21 | for(;;){ 22 | if(__LDREXB(mutex) == MUTEX_LOCKED) continue; 23 | if(__STREXB(MUTEX_LOCKED, mutex) == 0) break; 24 | } 25 | __DMB(); 26 | } 27 | 28 | void mutex_unlock(mutex_t* mutex) 29 | { 30 | __DMB(); 31 | *mutex = MUTEX_UNLOCKED; 32 | } 33 | -------------------------------------------------------------------------------- /mutex/mutex.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mutex.h Реализация мютекса. 3 | */ 4 | #ifndef MUTEX_H 5 | #define MUTEX_H 6 | 7 | #include 8 | #include 9 | #include "defs/defs.h" 10 | 11 | //! Состояния мютекса. 12 | //! Мютекс не заблокирован. 13 | #define MUTEX_UNLOCKED 0 14 | //! Мютекс заблокирован. 15 | #define MUTEX_LOCKED 1 16 | 17 | //! Тип мютекса. 18 | typedef uint8_t mutex_t; 19 | 20 | /** 21 | * Инициализирует мютекс. 22 | * @param mutex Мютекс. 23 | */ 24 | EXTERN void mutex_init(mutex_t* mutex); 25 | 26 | /** 27 | * Пытается захватить мютекс. 28 | * @param mutex Мютекс. 29 | * @return Истина в случае успешного захвата мютекса, иначе false. 30 | */ 31 | EXTERN bool mutex_trylock(mutex_t* mutex); 32 | 33 | /** 34 | * Ждёт освобождения мютекса и блокирует его. 35 | * @param mutex Мютекс. 36 | */ 37 | EXTERN void mutex_lock(mutex_t* mutex); 38 | 39 | /** 40 | * Освобождает мютекс. 41 | * @param mutex Мютекс. 42 | */ 43 | EXTERN void mutex_unlock(mutex_t* mutex); 44 | 45 | #endif /* MUTEX_H */ 46 | 47 | -------------------------------------------------------------------------------- /mvsources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sources=$(ls *.h); 4 | 5 | for file in $sources 6 | do 7 | name=$(expr $file : '\(.*\)\.' \| $file); 8 | mkdir $name; 9 | mv "$name.c" $name 10 | mv "$name.h" $name 11 | done 12 | -------------------------------------------------------------------------------- /orientation/orientation.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file orientation.h 3 | * Библиотека для вычисления ориентации. 4 | */ 5 | 6 | #ifndef ORIENTATION_H 7 | #define ORIENTATION_H 8 | 9 | #include 10 | #include "defs/defs.h" 11 | #include "fixed/fixed32.h" 12 | #include "counter/counter.h" 13 | #include "gyro6050/gyro6050.h" 14 | #include "hmc5883l/hmc5883l.h" 15 | 16 | /** 17 | * Структура ориентации. 18 | */ 19 | typedef struct _Orientation { 20 | //! Гироскоп. 21 | const gyro6050_t* gyro; 22 | //! Компас. 23 | const hmc5883l_t* compass; 24 | //! Предыдущее значение угловой скорости по оси X. 25 | fixed32_t gyro_w_x_prev; 26 | //! Предыдущее значение угловой скорости по оси Y. 27 | fixed32_t gyro_w_y_prev; 28 | //! Предыдущее значение угловой скорости по оси Z. 29 | fixed32_t gyro_w_z_prev; 30 | 31 | //! Счётчик времени. 32 | counter_t counter; 33 | 34 | //! Вес угла по данным акселерометра. 35 | uint8_t accel_angle_weight; 36 | 37 | //! Угол по оси X. 38 | fixed32_t angle_x; 39 | //! Угол по оси Y. 40 | fixed32_t angle_y; 41 | //! Угол по оси Z. 42 | fixed32_t angle_z; 43 | 44 | //! Угол на север. 45 | fixed32_t north_azimuth; 46 | } orientation_t; 47 | 48 | #define ORIENTATION_ACCEL_ANGLE_WEIGHT_MAX 100 49 | #define ORIENTATION_ACCEL_ANGLE_WEIGHT_DEFAULT 4 50 | 51 | /** 52 | * Инициализирует ориентацию. 53 | * @param orientation Ориентация. 54 | */ 55 | EXTERN void orientation_init(orientation_t* orientation, const gyro6050_t* gyro, const hmc5883l_t* compass); 56 | 57 | /** 58 | * Получает вес угла по данным акселерометра. 59 | * @param orientation Ориентация. 60 | * @return Вес угла по данным акселерометра. 61 | */ 62 | EXTERN uint8_t orientation_accel_angle_weight(orientation_t* orientation); 63 | 64 | /** 65 | * Устанавливает вес угла по данным акселерометра. 66 | * @param orientation Ориентация. 67 | * @param weight Вес, значение осекается в промежуток от 0 до 100. 68 | */ 69 | EXTERN void orientation_set_accel_angle_weight(orientation_t* orientation, uint8_t weight); 70 | 71 | /** 72 | * Вычисляет ориентацию. 73 | * @param orientation Ориентация. 74 | */ 75 | EXTERN void orientation_calculate(orientation_t* orientation); 76 | 77 | /** 78 | * Получает угол по оси X. 79 | * @param orientation Ориентация. 80 | * @return Угол по оси X. 81 | */ 82 | static ALWAYS_INLINE fixed32_t orientation_angle_x(orientation_t* orientation) 83 | { 84 | return orientation->angle_x; 85 | } 86 | 87 | /** 88 | * Получает угол по оси Y. 89 | * @param orientation Ориентация. 90 | * @return Угол по оси Y. 91 | */ 92 | static ALWAYS_INLINE fixed32_t orientation_angle_y(orientation_t* orientation) 93 | { 94 | return orientation->angle_y; 95 | } 96 | 97 | /** 98 | * Получает угол по оси Z. 99 | * @param orientation Ориентация. 100 | * @return Угол по оси Z. 101 | */ 102 | static ALWAYS_INLINE fixed32_t orientation_angle_z(orientation_t* orientation) 103 | { 104 | return orientation->angle_z; 105 | } 106 | 107 | static ALWAYS_INLINE fixed32_t orientation_north_azimuth(orientation_t* orientation) 108 | { 109 | return orientation->north_azimuth; 110 | } 111 | 112 | #endif /* ORIENTATION_H */ 113 | 114 | -------------------------------------------------------------------------------- /pca9555/pca9555_mem.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file pca9555_mem.h Структура памяти pca9555. 3 | */ 4 | 5 | #ifndef PCA9555_MEM_H 6 | #define PCA9555_MEM_H 7 | 8 | #include 9 | 10 | //Структура памяти в pca9555. 11 | 12 | //Полная память. 13 | #pragma pack(push, 1) 14 | typedef struct _Pca9555_mem { 15 | // Входа 0-7. 16 | uint8_t idr0; 17 | // Входа 8-15. 18 | uint8_t idr1; 19 | // Выхода 0-7. 20 | uint8_t odr0; 21 | // Выхода 8-15. 22 | uint8_t odr1; 23 | // Инверсия 0-7. 24 | uint8_t pir0; 25 | // Инверсия 8-15. 26 | uint8_t pir1; 27 | // Конфигурация 0-7. 28 | uint8_t cr0; 29 | // Конфигурация 8-15. 30 | uint8_t cr1; 31 | } pca9555_mem_t; 32 | #pragma pack(pop) 33 | 34 | #endif /* PCA9555_MEM_H */ 35 | 36 | -------------------------------------------------------------------------------- /pid_controller/pid_controller.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "utils/utils.h" 3 | #include "pid_controller.h" 4 | 5 | 6 | void pid_controller_init(pid_controller_t* controller, fixed32_t kp, fixed32_t ki, fixed32_t kd) 7 | { 8 | controller->kp = kp; 9 | controller->ki = ki; 10 | controller->kd = kd; 11 | controller->prev_e = 0; 12 | controller->prev_i = 0; 13 | controller->value = 0; 14 | controller->clamp_min = INT32_MIN; 15 | controller->clamp_max = INT32_MAX; 16 | controller->clamp_width = INT32_MAX; 17 | } 18 | 19 | void pid_controller_reset(pid_controller_t* controller) 20 | { 21 | controller->prev_e = 0; 22 | controller->prev_i = 0; 23 | controller->value = 0; 24 | } 25 | 26 | bool pid_controller_calculate(pid_controller_t* controller, fixed32_t e, fixed32_t dt) 27 | { 28 | if(dt == 0) return false; 29 | // P = Kp * e; 30 | fixed32_t p = ((int64_t)controller->kp * e) >> FIXED32_FRACT_BITS; 31 | 32 | // I = Ki * e(t) * dt + I(t-1); 33 | fixed32_t i = ((int64_t)controller->ki * e) >> FIXED32_FRACT_BITS; 34 | i = ((int64_t)i * dt) >> FIXED32_FRACT_BITS; 35 | i = i + controller->prev_i; 36 | 37 | // D = Kd * (e(t) - e(t-1)) / dt; 38 | fixed32_t d = ((int64_t)controller->kd * (e - controller->prev_e)) / dt; 39 | 40 | int32_t delta_min = -controller->clamp_width; 41 | int32_t delta_max = controller->clamp_width; 42 | 43 | p = CLAMP(p, delta_min, delta_max); 44 | d = CLAMP(d, delta_min, delta_max); 45 | i = CLAMP(i, controller->clamp_min, controller->clamp_max); 46 | 47 | controller->prev_e = e; 48 | controller->prev_i = i; 49 | 50 | controller->value = p + i + d; 51 | 52 | controller->value = CLAMP(controller->value, controller->clamp_min, controller->clamp_max); 53 | 54 | return true; 55 | } 56 | -------------------------------------------------------------------------------- /q15/q15_str.c: -------------------------------------------------------------------------------- 1 | #include "q15_str.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #define STRTOL_DEFAULT 0 12 | #define STRTOL_BASE 10 13 | #define IQ15_STR_DP '.' 14 | #define IQ15_STR_e 'e' 15 | #define IQ15_STR_E 'E' 16 | #define IQ15_STR_PLUS '+' 17 | #define IQ15_STR_MINUS '-' 18 | #define IQ15_TOSTR_DIVIDER 100000 19 | 20 | 21 | //! Пропускает пробельные символы. 22 | static char* iq15_str_skip_spaces(char* str) 23 | { 24 | while(isspace((unsigned char)*str)) str ++; 25 | return str; 26 | } 27 | 28 | //! Преобразует целое число дробной части в фиксированную запятую. 29 | static q15_t iq15_str_fract_to_q(int32_t fract) 30 | { 31 | int32_t dec_div = STRTOL_BASE; 32 | while(fract >= dec_div) dec_div *= STRTOL_BASE; 33 | return (q15_t)LQ15F(fract, dec_div); 34 | } 35 | 36 | iq15_t iq15_fromstr(const char* str, const char** endp) 37 | { 38 | if(str == NULL){ 39 | if(endp) *endp = str; 40 | return STRTOL_DEFAULT; 41 | } 42 | 43 | char* ptr = (char*)str; 44 | 45 | lq15_t res = STRTOL_DEFAULT; 46 | 47 | bool is_neg = false; 48 | 49 | long int_part = 0; 50 | long fract_part = 0; 51 | long exp_part = 0; 52 | 53 | ptr = iq15_str_skip_spaces(ptr); 54 | 55 | // Знак. 56 | if(*ptr == IQ15_STR_MINUS){ 57 | is_neg = true; 58 | } 59 | 60 | // Целая часть. 61 | int_part = strtol(ptr, &ptr, STRTOL_BASE); 62 | if(errno != 0){ 63 | if(endp) *endp = ptr; 64 | return STRTOL_DEFAULT; 65 | } 66 | 67 | // Если после целой части следует точка. 68 | if(*ptr == IQ15_STR_DP){ 69 | // Пропуск разделителя дробной части. 70 | ptr ++; 71 | // Если следующий символ - цифра. 72 | if(isdigit((unsigned char)*ptr)){ 73 | // Дробная часть. 74 | fract_part = strtol(ptr, &ptr, STRTOL_BASE); 75 | if(errno != 0){ 76 | if(endp) *endp = ptr; 77 | return STRTOL_DEFAULT; 78 | } 79 | } 80 | } 81 | 82 | // Если после целой и/или дробной части следует экспонента. 83 | if(*ptr == IQ15_STR_e || *ptr == IQ15_STR_E){ 84 | // Пропуск экспоненты. 85 | ptr ++; 86 | // Экспонента. 87 | exp_part = strtol(ptr, &ptr, STRTOL_BASE); 88 | if(errno != 0){ 89 | if(endp) *endp = ptr; 90 | return STRTOL_DEFAULT; 91 | } 92 | } 93 | 94 | // Разбор строки закончен. 95 | if(endp) *endp = ptr; 96 | 97 | // Переведём целое число дробной части в фиксированную запятую. 98 | fract_part = iq15_str_fract_to_q(fract_part); 99 | 100 | // Целая часть. 101 | res = LQ15I(int_part); 102 | // Прибавим согласно знаку дробную часть. 103 | if(is_neg == false) res += fract_part; 104 | else res -= fract_part; 105 | // Обработаем экспоненту. 106 | while(exp_part > 0) { res *= 10; exp_part --; } 107 | while(exp_part < 0) { res /= 10; exp_part ++; } 108 | 109 | // Пределы. 110 | if(res > INT32_MAX || res < INT32_MIN){ 111 | errno = ERANGE; 112 | return 0; 113 | } 114 | 115 | errno = 0; 116 | 117 | return (iq15_t)res; 118 | } 119 | 120 | int iq15_tostr(char* str, size_t size, iq15_t q) 121 | { 122 | if(str == NULL) return -1; 123 | if(size == 0) return -1; 124 | 125 | const char* fmt = (q >= 0) ? "%u.%05u" : "-%u.%05u"; 126 | 127 | // Абсолютное значение. 128 | q = iq15_abs(q); 129 | 130 | // Целая часть. 131 | uint32_t int_part = (uint32_t)iq15_int(q); 132 | // Фиксированная дробная часть. 133 | uint32_t fract_part = (uint32_t)iq15_fract(q); 134 | // Преобразуем в числовое представление. 135 | // fract_part = fract_part * 100000 / 32768 136 | fract_part = fract_part * IQ15_TOSTR_DIVIDER / Q15_BASE; 137 | 138 | int cnt = snprintf(str, size, fmt, (unsigned int)int_part, (unsigned int)fract_part); 139 | 140 | return cnt; 141 | } 142 | 143 | -------------------------------------------------------------------------------- /q15/q15_str.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file q15_str.h Библиотека строковых функций для чисел с фиксированной запятой. 3 | */ 4 | 5 | #ifndef Q15_STR_H_ 6 | #define Q15_STR_H_ 7 | 8 | #include "q15.h" 9 | #include 10 | 11 | 12 | /** 13 | * Преобразует строку в число с фиксированной запятой с целой частью. 14 | * Устанавливает ERRNO. 15 | * @param str Строка. 16 | * @param endp Окончание числа в строке. 17 | * @return Число с фиксированной запятой. 18 | */ 19 | extern iq15_t iq15_fromstr(const char* str, const char** endp); 20 | 21 | /** 22 | * Преобразует число с фиксированной запятой с целой частью в строку. 23 | * @param str Строка. 24 | * @param size Размер строки. 25 | * @param q Число с фиксированной запятой. 26 | * @return Число записанных символов. 27 | */ 28 | extern int iq15_tostr(char* str, size_t size, iq15_t q); 29 | 30 | #endif /* Q15_STR_H_ */ 31 | -------------------------------------------------------------------------------- /scheduler/scheduler.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file scheduler.h Библиотека планировщика задач. 3 | * Используются приоритеты и кооперативная многозадачность. 4 | */ 5 | 6 | #ifndef SCHEDULER_H 7 | #define SCHEDULER_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include "future/future.h" 13 | #include "errors/errors.h" 14 | #include "list/list.h" 15 | #include "defs/defs.h" 16 | 17 | 18 | //! Ошибочный идентификатор задачи. 19 | #define INVALID_TASK_ID 0 20 | 21 | 22 | //! Тип идентификатора задачи. 23 | typedef uint32_t task_id_t; 24 | 25 | //! Тип приоритета задачи. 26 | typedef uint32_t task_priority_t; 27 | 28 | //! Тип функции задачи. 29 | typedef void* (*task_proc_t)(void*); 30 | 31 | typedef enum _Task_Flag { 32 | TASK_RUN_ONCE = 1 33 | } task_flag_t; 34 | 35 | //! Тип флагов задачи. 36 | typedef uint32_t task_flags_t; 37 | 38 | //! Тип дескриптора задачи. 39 | typedef struct _Task_Descr_t { 40 | list_item_t list_item; //!< Элемент списка задач. 41 | task_id_t tid; //!< Идентификатор задачи. 42 | task_priority_t priority; //!< Приоритет задачи. 43 | task_proc_t proc; //!< Функция задачи. 44 | void* arg; //!< Аргумент задачи. 45 | future_t* future; //!< Будущее задачи. 46 | task_flags_t flags; //!< Флаги задачи. 47 | } task_descr_t; 48 | 49 | //! Декларация буфера задач. 50 | #define TASKS_BUFFER(name, size) task_descr_t name[size] 51 | 52 | /** 53 | * Инициализирует планеровщик. 54 | * Планеровщик использует буфер дескрипторов 55 | * заданного размера для добавления задач. 56 | * Размер буфера определяет максимальное число 57 | * добавленных задач. 58 | * @param buffer Массив дескрипторов задач. 59 | * @param count Число дескрипторов. 60 | * @return Код ошибки. 61 | */ 62 | EXTERN err_t scheduler_init(task_descr_t* buffer, size_t count); 63 | 64 | /** 65 | * Получает идентификатор текущей задачи. 66 | * @return Идентификатор текущей задачи. 67 | */ 68 | EXTERN task_id_t scheduler_current_task_id(void); 69 | 70 | /** 71 | * Добавляет задачу. 72 | * @param proc Функция задачи. 73 | * @param priority Приоритет задачи. 74 | * @param arg Аргумент задачи. 75 | * @return Идентификатор задачи, при ошибке возвращает INVALID_TASK_ID. 76 | */ 77 | EXTERN task_id_t scheduler_add_task(task_proc_t proc, task_priority_t priority, void* arg, task_flags_t flags, future_t* future); 78 | 79 | /** 80 | * Удаляет задачу. 81 | * @param tid Идентификатор задачи. 82 | * @return Флаг удаления задачи. 83 | */ 84 | EXTERN bool scheduler_remove_task(task_id_t tid); 85 | 86 | /** 87 | * Главный цикл планеровщика. 88 | * Запускает очередную задачу. 89 | * @return Флаг запуска задачи, false если задач нет. 90 | */ 91 | EXTERN bool scheduler_process(void); 92 | 93 | #endif /* SCHEDULER_H */ 94 | -------------------------------------------------------------------------------- /sdcard/sdcard_diskio.c: -------------------------------------------------------------------------------- 1 | #include "sdcard_diskio.h" 2 | 3 | 4 | DSTATUS sdcard_disk_initialize(sdcard_t* sdcard) 5 | { 6 | sdcard_init_card(sdcard); 7 | 8 | if(sdcard_initialized(sdcard)) return 0; 9 | if(sdcard_identified(sdcard)) return STA_NOINIT; 10 | 11 | return STA_NODISK; 12 | } 13 | 14 | DSTATUS sdcard_disk_status(sdcard_t* sdcard) 15 | { 16 | if(sdcard_initialized(sdcard)) return 0; 17 | if(sdcard_identified(sdcard)) return STA_NOINIT; 18 | 19 | return STA_NODISK; 20 | } 21 | 22 | DRESULT sdcard_disk_read(sdcard_t* sdcard, BYTE* buff, DWORD sector, UINT count) 23 | { 24 | if(!sdcard_initialized(sdcard)) return RES_NOTRDY; 25 | 26 | err_t err = E_NO_ERROR; 27 | 28 | err = sdcard_select(sdcard); 29 | if(err != E_NO_ERROR) return RES_ERROR; 30 | 31 | err = sdcard_read_sector(sdcard, sector, count, buff, NULL); 32 | 33 | sdcard_deselect(sdcard); 34 | if(err != E_NO_ERROR) return RES_ERROR; 35 | 36 | return RES_OK; 37 | } 38 | 39 | #if _USE_WRITE 40 | DRESULT sdcard_disk_write(sdcard_t* sdcard, const BYTE* buff, DWORD sector, UINT count) 41 | { 42 | if(!sdcard_initialized(sdcard)) return RES_NOTRDY; 43 | 44 | err_t err = E_NO_ERROR; 45 | 46 | err = sdcard_select(sdcard); 47 | if(err != E_NO_ERROR) return RES_ERROR; 48 | 49 | err = sdcard_write_sector(sdcard, sector, count, buff, NULL); 50 | sdcard_deselect(sdcard); 51 | if(err != E_NO_ERROR) return RES_ERROR; 52 | 53 | return RES_OK; 54 | } 55 | 56 | #endif // _USE_WRITE 57 | 58 | #if _USE_IOCTL 59 | DRESULT sdcard_disk_ioctl(sdcard_t* sdcard, BYTE cmd, void* buff) 60 | { 61 | if(!sdcard_initialized(sdcard)) return RES_NOTRDY; 62 | 63 | DRESULT res = RES_ERROR; 64 | err_t err = E_NO_ERROR; 65 | 66 | uint32_t start_erase_block = 0; 67 | uint32_t end_erase_block = 0; 68 | 69 | switch(cmd){ 70 | case CTRL_SYNC: 71 | err = sdcard_select(sdcard); 72 | if(err != E_NO_ERROR) break; 73 | 74 | err = sdcard_wait_busy(sdcard); 75 | if(err == E_NO_ERROR) res = RES_OK; 76 | 77 | sdcard_deselect(sdcard); 78 | 79 | break; 80 | case GET_SECTOR_COUNT: 81 | *((DWORD*)buff) = sdcard_sectors_count(sdcard); 82 | res = RES_OK; 83 | break; 84 | case GET_SECTOR_SIZE: 85 | *((DWORD*)buff) = sdcard_sector_size(sdcard); 86 | res = RES_OK; 87 | break; 88 | case GET_BLOCK_SIZE: 89 | *((DWORD*)buff) = sdcard_erase_block_len(sdcard); 90 | res = RES_OK; 91 | break; 92 | case CTRL_TRIM: 93 | err = sdcard_select(sdcard); 94 | if(err != E_NO_ERROR) break; 95 | 96 | start_erase_block = ((DWORD*)buff)[0]; 97 | end_erase_block = ((DWORD*)buff)[1]; 98 | 99 | err = sdcard_erase_sector(sdcard, start_erase_block, 100 | end_erase_block - start_erase_block + 1); 101 | if(err == E_NO_ERROR) res = RES_OK; 102 | 103 | sdcard_deselect(sdcard); 104 | 105 | break; 106 | default: 107 | res = RES_PARERR; 108 | } 109 | 110 | return res; 111 | } 112 | #endif // _USE_IOCTL 113 | -------------------------------------------------------------------------------- /sdcard/sdcard_diskio.h: -------------------------------------------------------------------------------- 1 | #ifndef SDCARD_DISKIO_H 2 | #define SDCARD_DISKIO_H 3 | 4 | #include "sdcard.h" 5 | #include "defs/defs.h" 6 | 7 | #ifndef _DISKIO_DEFINED 8 | #include "fatfs/diskio.h" 9 | #endif 10 | 11 | 12 | /** 13 | * Инициализирует диск. 14 | * @param sdcard SD-карта. 15 | * @return Статус. 16 | */ 17 | EXTERN DSTATUS sdcard_disk_initialize(sdcard_t* sdcard); 18 | 19 | /** 20 | * Получает статус диска. 21 | * @param sdcard SD-карта. 22 | * @return Статус. 23 | */ 24 | EXTERN DSTATUS sdcard_disk_status(sdcard_t* sdcard); 25 | 26 | /** 27 | * Читает сектор диска. 28 | * @param sdcard SD-карта. 29 | * @param buff Буфер. 30 | * @param sector Сектор. 31 | * @param count Число секторов. 32 | * @return Результат. 33 | */ 34 | EXTERN DRESULT sdcard_disk_read(sdcard_t* sdcard, BYTE* buff, DWORD sector, UINT count); 35 | 36 | #if _USE_WRITE 37 | /** 38 | * Записывает сектор диска. 39 | * @param sdcard SD-карта. 40 | * @param buff Буфер. 41 | * @param sector Сектор. 42 | * @param count Число секторов. 43 | * @return Результат. 44 | */ 45 | EXTERN DRESULT sdcard_disk_write(sdcard_t* sdcard, const BYTE* buff, DWORD sector, UINT count); 46 | 47 | #endif // _USE_WRITE 48 | 49 | #if _USE_IOCTL 50 | /** 51 | * Управляет диском. 52 | * @param sdcard SD-карта. 53 | * @param cmd Команда. 54 | * @param buff Буфер. 55 | * @return Результат. 56 | */ 57 | EXTERN DRESULT sdcard_disk_ioctl(sdcard_t* sdcard, BYTE cmd, void* buff); 58 | #endif // _USE_IOCTL 59 | 60 | #endif // SDCARD_DISKIO_H 61 | -------------------------------------------------------------------------------- /sdcard/sdcard_token.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sdcard_token.h Декларация маркеров данных. 3 | */ 4 | 5 | #ifndef SDCARD_TOKEN_H_ 6 | #define SDCARD_TOKEN_H_ 7 | 8 | #include 9 | 10 | 11 | //! Размер контрольного маркера. 12 | #define SDCARD_CONTROL_TOKEN_SIZE 1 13 | 14 | //! Тип контрольного маркера. 15 | typedef uint8_t sdcard_control_token_t; 16 | 17 | // Маркер принятия данных картой при записи. 18 | //! Маска полезных данных. 19 | #define SDCARD_DATA_RESP_TOKEN_MASK 0x1f 20 | //! Сброшенный бит. 21 | #define SDCARD_DATA_RESP_TOKEN_BIT_ZERO 0x10 22 | //! Состояние. 23 | #define SDCARD_DATA_RESP_TOKEN_STATUS_MASK 0xe 24 | #define SDCARD_DATA_RESP_TOKEN_STATUS_OFFSET 1 25 | //! Установленный бит. 26 | #define SDCARD_DATA_RESP_TOKEN_BIT_ONE 0x1 27 | // Поле состояния. 28 | //! Данные приняты. 29 | #define SDCARD_DATA_RESP_TOKEN_STATUS_DATA_ACCEPTED 0x2 30 | //! Данные отброшены из-за ошибки CRC. 31 | #define SDCARD_DATA_RESP_TOKEN_STATUS_CRC_ERROR 0x5 32 | //! Данные отброшены из-за ошибки записи. 33 | #define SDCARD_DATA_RESP_TOKEN_STATUS_WRITE_ERROR 0x6 34 | 35 | // Маркеры при одиночном чтении или записи 36 | // и при множественном чтении. 37 | //! Маркер начала блока данных. 38 | #define SDCARD_START_BLOCK_TOKEN 0xfe 39 | 40 | // Маркеры начала при множественной записи 41 | // (Multiple Block Write). 42 | //! Маркер начала блока данных. 43 | #define SDCARD_MBW_START_BLOCK_TOKEN 0xfc 44 | //! Маркер окончания передачи. 45 | #define SDCARD_MBW_STOP_TRAN_TOKEN 0xfd 46 | 47 | // Маркеры ошибки. 48 | // Чтение. 49 | //! Маска полезных данных. 50 | #define SDCARD_DATA_ERROR_TOKEN_MASK 0xf 51 | //! Сброшенные биты. 52 | #define SDCARD_DATA_ERROR_TOKEN_ZERO_MASK 0xf0 53 | #define SDCARD_DATA_ERROR_TOKEN_ZERO_OFFSET 4 54 | //! Выход за пределы. 55 | #define SDCARD_DATA_ERROR_TOKEN_OUT_OF_RANGE 0x8 56 | //! Ошибка ECC. 57 | #define SDCARD_DATA_ERROR_TOKEN_CARD_ECC_FAILED 0x4 58 | //! Ошибка контроллера карты. 59 | #define SDCARD_DATA_ERROR_TOKEN_CC_ERROR 0x2 60 | //! Общая ошибка. 61 | #define SDCARD_DATA_ERROR_TOKEN_ERROR 0x1 62 | 63 | 64 | #endif /* SDCARD_TOKEN_H_ */ 65 | -------------------------------------------------------------------------------- /system/system.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | #include 3 | 4 | 5 | /** 6 | * Определение переменной со значением частоты ядра. 7 | * Частота по-умолчанию при включении равна 8 МГц. 8 | */ 9 | uint32_t SystemCoreClock = 8000000; 10 | 11 | 12 | /** 13 | * Инициализация тактирования на 72 МГц 14 | * при частоте кварца 8 МГц. 15 | */ 16 | void init_clock_72_hse_8(void) 17 | { 18 | // Предделители шин. 19 | // AHB - нет предделителя. 20 | RCC->CFGR &= ~RCC_CFGR_HPRE; 21 | // APB1 - делитель на 2. 22 | RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; 23 | // APB2 - нет предделителя. 24 | RCC->CFGR &= ~RCC_CFGR_PPRE2; 25 | // ADC - делитель на 6. 26 | RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6; 27 | // USB - делитель на 1.5. 28 | RCC->CFGR &= ~RCC_CFGR_USBPRE; 29 | 30 | // ФАПЧ. 31 | // Источник. 32 | RCC->CFGR |= RCC_CFGR_PLLSRC_HSE; 33 | // Делитель частоты внешнего осциллятора. 34 | RCC->CFGR &= ~RCC_CFGR_PLLXTPRE; 35 | // Умножитель частоты. 36 | RCC->CFGR |= RCC_CFGR_PLLMULL9; 37 | 38 | // Переход на тактирование от PLL. 39 | // Включение внешнего осциллятора. 40 | RCC->CR |= RCC_CR_HSEON; 41 | // Подождём запуска внешнего осциллятора. 42 | while(!(RCC->CR & RCC_CR_HSERDY)); 43 | // Запустим ФАПЧ. 44 | RCC->CR |= RCC_CR_PLLON; 45 | // Подождём запуска ФАПЧ. 46 | while(!(RCC->CR & RCC_CR_PLLRDY)); 47 | 48 | // Настройка чтения флеш-памяти. 49 | // Запретим доступ по половине цикла тактирования. 50 | // Доступ по половине цикла тактирования запрещён при загрузке. 51 | //FLASH->ACR &= ~FLASH_ACR_HLFCYA; 52 | // Установим задержку чтения из флеш-памяти в 2 такта. 53 | FLASH->ACR |= FLASH_ACR_LATENCY_2; 54 | 55 | // Разрешим буфер предвыборки. 56 | // Буфер предвыборки включен после загрузки. 57 | //FLASH->ACR |= FLASH_ACR_PRFTBE; 58 | // Подождём включения предвыборки. 59 | //while(!(FLASH->ACR & FLASH_ACR_PRFTBS)); 60 | 61 | // Перейдём на тактирование от ФАПЧ. 62 | RCC->CFGR |= RCC_CFGR_SW_PLL; 63 | // Подождём перехода на ФАПЧ. 64 | while(!(RCC->CFGR & RCC_CFGR_SWS_PLL)); 65 | 66 | // Установим значение частоты ядра. 67 | SystemCoreClock = 72000000; 68 | } 69 | 70 | /** 71 | * Сбрасывает тактирование на состояние после сброса - 72 | * 8 МГц внутренний RC-осциллятор. 73 | */ 74 | static void deinit_clock(void) 75 | { 76 | // Тактирование. 77 | // Перейдём на тактирование от внутреннего RC-осциллятора. 78 | RCC->CFGR &= ~RCC_CFGR_SW; 79 | // Подождём перехода на внутренний RC-осциллятор. 80 | while((RCC->CFGR & RCC_CFGR_SWS)); 81 | 82 | // Флеш-память. 83 | // Сбросим задержку чтения из флеш-памяти. 84 | FLASH->ACR &= ~FLASH_ACR_LATENCY; 85 | 86 | // ФАПЧ и внешний осциллятор. 87 | // Остановим ФАПЧ. 88 | RCC->CR &= ~RCC_CR_PLLON; 89 | // Подождём остановки ФАПЧ. 90 | while((RCC->CR & RCC_CR_PLLRDY)); 91 | // Выключим внешний осциллятор. 92 | RCC->CR &= ~RCC_CR_HSEON; 93 | // Подождём выключения внешнего осциллятора. 94 | while((RCC->CR & RCC_CR_HSERDY)); 95 | 96 | // Сброс настроек ФАПЧ. 97 | // Источник. 98 | RCC->CFGR &= ~RCC_CFGR_PLLSRC; 99 | // Делитель частоты внешнего осциллятора. 100 | RCC->CFGR &= ~RCC_CFGR_PLLXTPRE; 101 | // Умножитель частоты. 102 | RCC->CFGR &= ~RCC_CFGR_PLLMULL; 103 | 104 | // Предделители шин. 105 | // AHB. 106 | RCC->CFGR &= ~RCC_CFGR_HPRE; 107 | // APB1. 108 | RCC->CFGR &= ~RCC_CFGR_PPRE1; 109 | // APB2. 110 | RCC->CFGR &= ~RCC_CFGR_PPRE2; 111 | // ADC. 112 | RCC->CFGR &= ~RCC_CFGR_ADCPRE; 113 | // USB. 114 | RCC->CFGR &= ~RCC_CFGR_USBPRE; 115 | 116 | // Установим значение частоты ядра. 117 | SystemCoreClock = 8000000; 118 | } 119 | 120 | void SystemInit(void) 121 | { 122 | init_clock_72_hse_8(); 123 | } 124 | 125 | void SystemDeInit(void) 126 | { 127 | deinit_clock(); 128 | } 129 | -------------------------------------------------------------------------------- /system/system.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file system.h Библиотека инициализации дерева тактирования. 3 | */ 4 | 5 | #ifndef _SYSTEM_H_ 6 | #define _SYSTEM_H_ 7 | 8 | #include 9 | 10 | //! Значение частоты ядра. 11 | extern uint32_t SystemCoreClock; 12 | 13 | /** 14 | * Инициализирует дерево тактирования. 15 | */ 16 | extern void SystemInit(void); 17 | 18 | /** 19 | * Сбрасывает дерево тактирования. 20 | */ 21 | extern void SystemDeInit(void); 22 | 23 | #endif //_SYSTEM_H_ 24 | -------------------------------------------------------------------------------- /template/gdbinit.txt: -------------------------------------------------------------------------------- 1 | # Файл инициализации GDB. 2 | 3 | # Тайм-аут 10 сек. 4 | set remotetimeout 10 5 | 6 | # Лимиты. 7 | set remote hardware-watchpoint-limit 4 8 | set remote hardware-breakpoint-limit 6 9 | 10 | # Цель. 11 | target extended-remote | openocd -f "interface/stlink-v2.cfg" -f "target/stm32f1x.cfg" -c "gdb_port pipe" 12 | #; log_output openocd.log 13 | 14 | # Сброс. 15 | monitor reset halt 16 | 17 | # Файл отладки 18 | file main 19 | 20 | ## Раскомментировать, если необходимо 21 | ## каждый раз загружать прошивку. 22 | ## Загрузка прошивки. 23 | #load 24 | # 25 | ## Сброс. 26 | #monitor reset halt 27 | 28 | # Удалить точки останова. 29 | delete 30 | 31 | # Точка останова на main 32 | break main 33 | 34 | # Запуск 35 | continue 36 | -------------------------------------------------------------------------------- /template/main.c: -------------------------------------------------------------------------------- 1 | #include "stm32f10x.h" 2 | 3 | int main(void) 4 | { 5 | for(;;){ 6 | } 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /template/stm32f10x_conf.h: -------------------------------------------------------------------------------- 1 | #ifndef STM32F10X_CONF_H 2 | #define STM32F10X_CONF_H 3 | 4 | // #include "misc.h" 5 | // #include "stm32f10x_adc.h" 6 | // #include "stm32f10x_bkp.h" 7 | // #include "stm32f10x_can.h" 8 | // #include "stm32f10x_cec.h" 9 | // #include "stm32f10x_crc.h" 10 | // #include "stm32f10x_dac.h" 11 | // #include "stm32f10x_dbgmcu.h" 12 | // #include "stm32f10x_dma.h" 13 | // #include "stm32f10x_exti.h" 14 | // #include "stm32f10x_flash.h" 15 | // #include "stm32f10x_fsmc.h" 16 | // #include "stm32f10x_gpio.h" 17 | // #include "stm32f10x_i2c.h" 18 | // #include "stm32f10x_iwdg.h" 19 | // #include "stm32f10x_pwr.h" 20 | // #include "stm32f10x_rcc.h" 21 | // #include "stm32f10x_rtc.h" 22 | // #include "stm32f10x_sdio.h" 23 | // #include "stm32f10x_spi.h" 24 | // #include "stm32f10x_tim.h" 25 | // #include "stm32f10x_usart.h" 26 | // #include "stm32f10x_wwdg.h" 27 | 28 | #ifndef USE_FULL_ASSERT 29 | #define assert_param(param) 30 | #endif 31 | 32 | #endif //STM32F10X_CONF_H -------------------------------------------------------------------------------- /template_freertos/FreeRTOS-openocd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer 3 | * present in the kernel, so it has to be supplied by other means for 4 | * OpenOCD's threads awareness. 5 | * 6 | * Add this file to your project, and, if you're using --gc-sections, 7 | * ``--undefined=uxTopUsedPriority'' (or 8 | * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final 9 | * linking) to your LDFLAGS; same with all the other symbols you need. 10 | */ 11 | 12 | #include "FreeRTOS.h" 13 | 14 | #ifdef __GNUC__ 15 | #define USED __attribute__((used)) 16 | #else 17 | #define USED 18 | #endif 19 | 20 | const int USED uxTopUsedPriority = configMAX_PRIORITIES; 21 | -------------------------------------------------------------------------------- /template_freertos/gdbinit.txt: -------------------------------------------------------------------------------- 1 | # Файл инициализации GDB. 2 | 3 | # Тайм-аут 10 сек. 4 | set remotetimeout 10 5 | 6 | # Лимиты. 7 | set remote hardware-watchpoint-limit 4 8 | set remote hardware-breakpoint-limit 6 9 | 10 | # События потоков. 11 | #set print thread-events 12 | 13 | # Цель. 14 | target extended-remote | openocd -f "interface/stlink-v2.cfg" -f "target/stm32f1x.cfg"\ 15 | -c "stm32f1x.cpu configure -rtos auto" -c "gdb_port pipe" 16 | #; log_output openocd.log 17 | 18 | # Сброс. 19 | monitor reset halt 20 | 21 | # Файл отладки 22 | file build/main 23 | 24 | ## Раскомментировать, если необходимо 25 | ## каждый раз загружать прошивку. 26 | ## Загрузка прошивки. 27 | #load 28 | # 29 | ## Сброс. 30 | #monitor reset halt 31 | 32 | # Удалить точки останова. 33 | delete 34 | 35 | # Точка останова на main 36 | break main 37 | 38 | # Запуск 39 | continue 40 | -------------------------------------------------------------------------------- /template_freertos/main.c: -------------------------------------------------------------------------------- 1 | #include "stm32f10x.h" 2 | #define USART_STDIO 3 | #include "usart/usart_buf.h" 4 | #include 5 | #include "FreeRTOS.h" 6 | #include "task.h" 7 | 8 | 9 | #define USART_WRITE_BUFFER_SIZE 128 10 | static uint8_t usart_write_buffer[USART_WRITE_BUFFER_SIZE]; 11 | 12 | #define USART_READ_BUFFER_SIZE 128 13 | static uint8_t usart_read_buffer[USART_READ_BUFFER_SIZE]; 14 | 15 | static usart_buf_t usart_buf; 16 | 17 | 18 | #define BLINK_TASK_PRIORITY 1 19 | #define PRINT_TASK_PRIORITY 1 20 | 21 | 22 | #define LED_GPIO GPIOA 23 | #define LED0 GPIO_Pin_1 24 | #define LED1 GPIO_Pin_1 25 | 26 | static void init_leds(void) 27 | { 28 | GPIO_InitTypeDef gpio_led = 29 | {.GPIO_Pin = LED0 | LED1, .GPIO_Speed = GPIO_Speed_10MHz, .GPIO_Mode = GPIO_Mode_Out_PP}; 30 | 31 | GPIO_Init(GPIOA, &gpio_led); 32 | LED_GPIO->ODR |= LED0 | LED1; 33 | } 34 | 35 | static void led_off(uint16_t led) 36 | { 37 | LED_GPIO->ODR |= led; 38 | } 39 | 40 | static void led_on(uint16_t led) 41 | { 42 | LED_GPIO->ODR &= ~led; 43 | } 44 | 45 | static void led_toggle(uint16_t led) 46 | { 47 | LED_GPIO->ODR ^= led; 48 | } 49 | 50 | static bool led_status(uint16_t led) 51 | { 52 | return LED_GPIO->IDR & led; 53 | } 54 | 55 | 56 | void USART1_IRQHandler(void) 57 | { 58 | usart_buf_irq_handler(&usart_buf); 59 | } 60 | 61 | 62 | static void init_periph_clock(void) 63 | { 64 | // AFIO. 65 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 66 | // USART. 67 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 68 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); 69 | } 70 | 71 | static void init_usart(void) 72 | { 73 | GPIO_InitTypeDef gpio_tx = 74 | {.GPIO_Pin = GPIO_Pin_9, .GPIO_Speed = GPIO_Speed_10MHz, .GPIO_Mode = GPIO_Mode_AF_PP}; 75 | GPIO_InitTypeDef gpio_rx = 76 | {.GPIO_Pin = GPIO_Pin_10, .GPIO_Speed = GPIO_Speed_10MHz, .GPIO_Mode = GPIO_Mode_IN_FLOATING}; 77 | GPIO_Init(GPIOA, &gpio_tx); 78 | GPIO_Init(GPIOA, &gpio_rx); 79 | 80 | USART_InitTypeDef usart_is = 81 | {.USART_BaudRate = 9600, .USART_WordLength = USART_WordLength_8b, .USART_StopBits = USART_StopBits_1, 82 | .USART_Parity = USART_Parity_No, .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, .USART_HardwareFlowControl = USART_HardwareFlowControl_None}; 83 | USART_Init(USART1, &usart_is); 84 | USART_Cmd(USART1, ENABLE); 85 | 86 | usart_buf_init_t usartb_is = {.usart = USART1, 87 | .write_buffer = usart_write_buffer, .write_buffer_size = USART_WRITE_BUFFER_SIZE, 88 | .read_buffer = usart_read_buffer, .read_buffer_size = USART_READ_BUFFER_SIZE}; 89 | usart_buf_init(&usart_buf, &usartb_is); 90 | usart_setup_stdio(&usart_buf); 91 | 92 | NVIC_SetPriority(USART1_IRQn, 12); 93 | NVIC_EnableIRQ(USART1_IRQn); 94 | } 95 | 96 | void blink_led_task(void* param) 97 | { 98 | for(;;){ 99 | vTaskDelay(500 / portTICK_RATE_MS); 100 | led_toggle(LED0); 101 | } 102 | } 103 | 104 | void print_msg_task(void* param) 105 | { 106 | for(;;){ 107 | vTaskDelay(1000 / portTICK_RATE_MS); 108 | printf("ticks: %d\r\n", (int)xTaskGetTickCount()); 109 | } 110 | } 111 | 112 | int main(void) 113 | { 114 | NVIC_SetPriorityGrouping(0x3); 115 | 116 | init_periph_clock(); 117 | init_usart(); 118 | init_leds(); 119 | 120 | printf("STM32 MCU\r\n"); 121 | 122 | xTaskCreate(blink_led_task, "blink", configMINIMAL_STACK_SIZE, NULL, BLINK_TASK_PRIORITY, NULL); 123 | xTaskCreate(print_msg_task, "print", configMINIMAL_STACK_SIZE, NULL, PRINT_TASK_PRIORITY, NULL); 124 | 125 | vTaskStartScheduler(); 126 | 127 | for(;;){ 128 | } 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /template_freertos/stm32f10x_conf.h: -------------------------------------------------------------------------------- 1 | #ifndef STM32F10X_CONF_H 2 | #define STM32F10X_CONF_H 3 | 4 | // #include "misc.h" 5 | // #include "stm32f10x_adc.h" 6 | // #include "stm32f10x_bkp.h" 7 | // #include "stm32f10x_can.h" 8 | // #include "stm32f10x_cec.h" 9 | // #include "stm32f10x_crc.h" 10 | // #include "stm32f10x_dac.h" 11 | // #include "stm32f10x_dbgmcu.h" 12 | // #include "stm32f10x_dma.h" 13 | // #include "stm32f10x_exti.h" 14 | // #include "stm32f10x_flash.h" 15 | // #include "stm32f10x_fsmc.h" 16 | #include "stm32f10x_gpio.h" 17 | // #include "stm32f10x_i2c.h" 18 | // #include "stm32f10x_iwdg.h" 19 | // #include "stm32f10x_pwr.h" 20 | #include "stm32f10x_rcc.h" 21 | // #include "stm32f10x_rtc.h" 22 | // #include "stm32f10x_sdio.h" 23 | // #include "stm32f10x_spi.h" 24 | // #include "stm32f10x_tim.h" 25 | #include "stm32f10x_usart.h" 26 | // #include "stm32f10x_wwdg.h" 27 | 28 | #ifndef USE_FULL_ASSERT 29 | #define assert_param(param) 30 | #endif 31 | 32 | #endif //STM32F10X_CONF_H -------------------------------------------------------------------------------- /tft9341/tft9341_cache_vbuf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tft9341_cache_vbuf.h 3 | * Библиотека функций виртуального буфера для кэша экрана TFT на контроллере ILI9341. 4 | */ 5 | 6 | #ifndef TFT9341_CACHE_VBUF_H 7 | #define TFT9341_CACHE_VBUF_H 8 | 9 | #include "graphics/graphics.h" 10 | #include "tft9341/tft9341_cache.h" 11 | 12 | #ifdef USE_GRAPHICS_VIRTUAL_BUFFER 13 | 14 | /** 15 | * Устанавливает цвет пиксела. 16 | * @param graphics Изображение. 17 | * @param x Координата X. 18 | * @param y Координата Y. 19 | * @param color Цвет пиксела. 20 | * @return true в случае успеха, иначе false. 21 | */ 22 | static bool tft9341_cache_vbuf_set_pixel(graphics_t* graphics, graphics_pos_t x, graphics_pos_t y, graphics_color_t color) 23 | { 24 | tft9341_cache_t* tft_cache = (tft9341_cache_t*)graphics_data(graphics); 25 | if(tft_cache == NULL) return false; 26 | 27 | return tft9341_cache_set_pixel(tft_cache, x, y, color) == E_NO_ERROR; 28 | } 29 | 30 | /** 31 | * Сбрасывает буфер в устройство. 32 | * @param graphics Изображение. 33 | * @return true в случае успеха, иначе false. 34 | */ 35 | static bool tft9341_cache_vbuf_flush(graphics_t* graphics) 36 | { 37 | tft9341_cache_t* tft_cache = (tft9341_cache_t*)graphics_data(graphics); 38 | if(tft_cache == NULL) return false; 39 | 40 | return tft9341_cache_flush(tft_cache) == E_NO_ERROR; 41 | } 42 | 43 | /** 44 | * Быстро выводит залитый прямоугольник. 45 | * @param graphics Изображение. 46 | * @param left Лево. 47 | * @param top Верх. 48 | * @param right Право. 49 | * @param bottom Низ. 50 | * @param color Цвет. 51 | * @return true в случае успеха, иначе false. 52 | */ 53 | static bool tft9341_cache_vbuf_fast_fillrect(graphics_t* graphics, graphics_pos_t left, graphics_pos_t top, graphics_pos_t right, graphics_pos_t bottom, graphics_color_t color) 54 | { 55 | tft9341_cache_t* tft_cache = (tft9341_cache_t*)graphics_data(graphics); 56 | if(tft_cache == NULL) return false; 57 | 58 | return tft9341_cache_fill_region(tft_cache, left, top, right, bottom, color) == E_NO_ERROR; 59 | } 60 | 61 | /** 62 | * Заполняет структуру виртуального буфера, 63 | * используюзего функции кэша TFT по месту объявления. 64 | */ 65 | #define make_tft9341_cache_vbuf()\ 66 | make_graphics_vbuf(NULL, tft9341_cache_vbuf_set_pixel, NULL, NULL, NULL,\ 67 | tft9341_cache_vbuf_flush, tft9341_cache_vbuf_fast_fillrect); 68 | 69 | /** 70 | * Заполняет структуру изображение, 71 | * используюзего виртуальный буфер и 72 | * функции кэша TFT по месту объявления. 73 | */ 74 | #define make_tft9341_cache_graphics(arg_tft_cache, arg_vbuf, arg_width, arg_height, arg_format)\ 75 | make_graphics_virtual(arg_tft_cache, arg_width, arg_height, arg_format, arg_vbuf); 76 | 77 | 78 | #else 79 | #error tft9341_cache_vbuf need defined USE_GRAPHICS_VIRTUAL_BUFFER! 80 | #endif 81 | 82 | #endif /* TFT9341_CACHE_VBUF_H */ 83 | 84 | -------------------------------------------------------------------------------- /timers/timers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file timers.h Библиотека таймеров. 3 | */ 4 | 5 | #ifndef TIMERS_H 6 | #define TIMERS_H 7 | 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "future/future.h" 15 | #include "errors/errors.h" 16 | #include "list/list.h" 17 | #include "defs/defs.h" 18 | 19 | 20 | //! Ошибочный идентификатор таймера. 21 | #define INVALID_TIMER_ID 0 22 | 23 | 24 | //! Тип идентификатора таймера. 25 | typedef uint32_t timer_id_t; 26 | 27 | //! Тип функции таймера. 28 | typedef void* (*timer_proc_t)(void*); 29 | 30 | //! Тип дескриптора таймера. 31 | typedef struct _Timer_Descr_t { 32 | list_item_t list_item; //!< Элемент списка таймеров. 33 | timer_id_t tid; //!< Идентификатор таймера. 34 | timer_proc_t proc; //!< Функция таймера. 35 | struct timeval t_interval; //!< Интервал таймера. 36 | struct timeval t_value; //!< Следующее время срабатывания таймера. 37 | void* arg; //!< Аргумент таймера. 38 | future_t* future; //!< Будущее таймера. 39 | } timer_descr_t; 40 | 41 | //! Декларация буфера таймеров. 42 | #define TIMERS_BUFFER(name, size) timer_descr_t name[size] 43 | 44 | /** 45 | * Функция обратного вызова однократного запуска таймера для отсчёта времени. 46 | * @param tv_time Время, через которое должен сработать таймер. 47 | */ 48 | typedef void (*timers_setup_timer_callback_t)(const struct timeval* tv_time); 49 | 50 | //! Структура инициализации таймеров. 51 | typedef struct _Timers_Init_Struct { 52 | timer_descr_t* buffer; //!< Массив дескрипторов таймеров. 53 | size_t count; //!< Число дескрипторов. 54 | timers_setup_timer_callback_t setup_timer_callback; //!< Функция обратного вызова запуска таймера. 55 | } timers_init_t; 56 | 57 | /** 58 | * Инициализирует таймеры. 59 | * Таймеры используют буфер дескрипторов 60 | * заданного размера для добавления таймеров. 61 | * Размер буфера определяет максимальное число 62 | * добавленных таймеров. 63 | * @param timers_is Структура инициализации таймеров. 64 | * @return Код ошибки. 65 | */ 66 | EXTERN err_t timers_init(timers_init_t* timers_is); 67 | 68 | /** 69 | * Получает идентификатор текущего таймера. 70 | * @return Идентификатор текущего таймера. 71 | */ 72 | EXTERN timer_id_t timers_current_timer_id(void); 73 | 74 | /** 75 | * Добавляет таймер. 76 | * @param proc Функция таймера. 77 | * @param t_start Время срабатывания таймера. 78 | * Не может быть NULL или 0. 79 | * @param t_int Интервал периодического срабатывания таймера. 80 | * NULL или 0 для однократного запуска. 81 | * @param arg Аргумент таймера. 82 | * @return Идентификатор таймера, при ошибке возвращает INVALID_TIMER_ID. 83 | */ 84 | EXTERN timer_id_t timers_add_timer(timer_proc_t proc, struct timeval* t_start, struct timeval* t_int, void* arg, future_t* future); 85 | 86 | /** 87 | * Удаляет таймер. 88 | * @param tid Идентификатор таймера. 89 | * @return Флаг удаления таймера. 90 | */ 91 | EXTERN bool timers_remove_timer(timer_id_t tid); 92 | 93 | /** 94 | * Обработчик срабатывания таймера отсчёта времени. 95 | */ 96 | EXTERN void timers_timer_handler(void); 97 | 98 | #endif /* TIMERS_H */ 99 | -------------------------------------------------------------------------------- /usart/usart.c: -------------------------------------------------------------------------------- 1 | #include "usart_buf.c" 2 | #include "usart_bus.c" 3 | 4 | #warning This file is deprecated! Use usart_buf.c or usart_bus.c instead! 5 | -------------------------------------------------------------------------------- /usart/usart.h: -------------------------------------------------------------------------------- 1 | #include "usart_buf.h" 2 | #include "usart_bus.h" 3 | 4 | #warning This file is deprecated! Use usart_buf.h or usart_bus.h instead! 5 | -------------------------------------------------------------------------------- /utils/critical.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file critical.h Библиотека критических секций. 3 | */ 4 | #ifndef CRITICAL_H 5 | #define CRITICAL_H 6 | 7 | #define CRITICAL_ENTER() __asm__ volatile ("cpsid i") 8 | #define CRITICAL_EXIT() __asm__ volatile ("cpsie i") 9 | 10 | #endif /* CRITICAL_H */ 11 | 12 | -------------------------------------------------------------------------------- /utils/delay.c: -------------------------------------------------------------------------------- 1 | #include "delay.h" 2 | 3 | 4 | #ifndef INLINE_DELAY 5 | 6 | void delay_cycles(uint32_t cycles_count) 7 | { 8 | #define _DELAY_CYCLES_GETTING_LATENCY (14 + 2) // 2 - вызов функции. 9 | #define _DELAY_CYCLES_COUNT_PER_LOOP_MIN 5 10 | 11 | register uint32_t cycles_per_loop = _DELAY_CYCLES_COUNT_PER_LOOP_MIN; 12 | 13 | if(FLASH->ACR & FLASH_ACR_PRFTBE){ 14 | cycles_per_loop += FLASH->ACR & FLASH_ACR_LATENCY; 15 | } 16 | 17 | if(cycles_count > _DELAY_CYCLES_GETTING_LATENCY){ 18 | 19 | cycles_count -= _DELAY_CYCLES_GETTING_LATENCY; 20 | 21 | asm volatile( 22 | "2:\n\t" 23 | "cmp %1, %0\n\t" 24 | "bhs 1f\n\t" 25 | "add %1, %2\n\t" 26 | "b 2b\n\t" 27 | "1:" 28 | ::"r"(cycles_count), "r"(0), "r"(cycles_per_loop) 29 | ); 30 | } 31 | #undef _DELAY_CYCLES_COUNT_PER_LOOP_MIN 32 | #undef _DELAY_CYCLES_GETTING_LATENCY 33 | } 34 | 35 | 36 | void delay_ns(uint32_t ns) 37 | { 38 | #define _DELAY_NS_CALCULATING_CYCLES (35 + 2) // 2 - вызов функции. 39 | 40 | register uint32_t cycles_to_delay = (SystemCoreClock / 1000000UL) * ns / 1000UL; 41 | 42 | if(cycles_to_delay > _DELAY_NS_CALCULATING_CYCLES){ 43 | cycles_to_delay -= _DELAY_NS_CALCULATING_CYCLES; 44 | delay_cycles(cycles_to_delay); 45 | } 46 | #undef _DELAY_NS_CALCULATING_CYCLES 47 | } 48 | 49 | 50 | void delay_us(uint32_t us) 51 | { 52 | #define _DELAY_US_CALCULATING_CYCLES (21 + 2) // 2 - вызов функции. 53 | 54 | register uint32_t cycles_to_delay = SystemCoreClock / 1000000UL * us; 55 | 56 | if(cycles_to_delay > _DELAY_US_CALCULATING_CYCLES){ 57 | cycles_to_delay -= _DELAY_US_CALCULATING_CYCLES; 58 | delay_cycles(cycles_to_delay); 59 | } 60 | #undef _DELAY_US_CALCULATING_CYCLES 61 | } 62 | 63 | 64 | void delay_ms(uint32_t ms) 65 | { 66 | #define _DELAY_MS_CALCULATING_CYCLES (20 + 2) // 2 - вызов функции. 67 | 68 | register uint32_t cycles_to_delay = SystemCoreClock / 1000UL * ms; 69 | 70 | if(cycles_to_delay > _DELAY_MS_CALCULATING_CYCLES){ 71 | cycles_to_delay -= _DELAY_MS_CALCULATING_CYCLES; 72 | delay_cycles(cycles_to_delay); 73 | } 74 | #undef _DELAY_MS_CALCULATING_CYCLES 75 | } 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /utils/delay.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file delay.h Функции задержки выполнения. 3 | */ 4 | 5 | #ifndef DELAY_H 6 | #define DELAY_H 7 | 8 | #include 9 | #include "stm32f10x.h" 10 | #include "defs/defs.h" 11 | 12 | 13 | /** 14 | * Выполняет задержку выполнения на 15 | * заданное число тактов процессора. 16 | * Подстраивается под задержку FLASH памяти. 17 | * Длительность цикла ожидания в зависимости от частоты: 18 | * 8 MHz - 5 тактов. 19 | * 36 MHz - 6 тактов. 20 | * 72 MHz - 7 тактов. 21 | * @param cycles_count Число тактов. 22 | */ 23 | #ifdef INLINE_DELAY 24 | static inline void delay_cycles(uint32_t cycles_count) 25 | { 26 | #define _DELAY_CYCLES_GETTING_LATENCY (14 + 2) // 2 - вызов функции. 27 | #define _DELAY_CYCLES_COUNT_PER_LOOP_MIN 5 28 | 29 | register uint32_t cycles_per_loop = _DELAY_CYCLES_COUNT_PER_LOOP_MIN; 30 | 31 | if(FLASH->ACR & FLASH_ACR_PRFTBE){ 32 | cycles_per_loop += FLASH->ACR & FLASH_ACR_LATENCY; 33 | } 34 | 35 | if(cycles_count > _DELAY_CYCLES_GETTING_LATENCY){ 36 | 37 | cycles_count -= _DELAY_CYCLES_GETTING_LATENCY; 38 | 39 | asm volatile( 40 | "2:\n\t" 41 | "cmp %1, %0\n\t" 42 | "bhs 1f\n\t" 43 | "add %1, %2\n\t" 44 | "b 2b\n\t" 45 | "1:" 46 | ::"r"(cycles_count), "r"(0), "r"(cycles_per_loop) 47 | ); 48 | } 49 | #undef _DELAY_CYCLES_COUNT_PER_LOOP_MIN 50 | #undef _DELAY_CYCLES_GETTING_LATENCY 51 | } 52 | #else 53 | EXTERN void delay_cycles(uint32_t cycles_count); 54 | #endif 55 | 56 | /** 57 | * Выполняет задержку выполнения на 58 | * заданное число наносекунд. 59 | * @param ns Время в наносекундах. 60 | */ 61 | #ifdef INLINE_DELAY 62 | static inline void delay_ns(uint32_t ns) 63 | { 64 | #define _DELAY_NS_CALCULATING_CYCLES (35 + 2) // 2 - вызов функции. 65 | 66 | register uint32_t cycles_to_delay = (SystemCoreClock / 1000000UL) * ns / 1000UL; 67 | 68 | if(cycles_to_delay > _DELAY_NS_CALCULATING_CYCLES){ 69 | cycles_to_delay -= _DELAY_NS_CALCULATING_CYCLES; 70 | delay_cycles(cycles_to_delay); 71 | } 72 | #undef _DELAY_NS_CALCULATING_CYCLES 73 | } 74 | #else 75 | EXTERN void delay_ns(uint32_t ns); 76 | #endif 77 | 78 | /** 79 | * Выполняет задержку выполнения на 80 | * заданное число микросекунд. 81 | * @param us Время в микросекундах. 82 | */ 83 | #ifdef INLINE_DELAY 84 | static inline void delay_us(uint32_t us) 85 | { 86 | #define _DELAY_US_CALCULATING_CYCLES (21 + 2) // 2 - вызов функции. 87 | 88 | register uint32_t cycles_to_delay = SystemCoreClock / 1000000UL * us; 89 | 90 | if(cycles_to_delay > _DELAY_US_CALCULATING_CYCLES){ 91 | cycles_to_delay -= _DELAY_US_CALCULATING_CYCLES; 92 | delay_cycles(cycles_to_delay); 93 | } 94 | #undef _DELAY_US_CALCULATING_CYCLES 95 | } 96 | #else 97 | EXTERN void delay_us(uint32_t us); 98 | #endif 99 | 100 | /** 101 | * Выполняет задержку выполнения на 102 | * заданное число миллисекунд. 103 | * @param us Время в миллисекундах. 104 | */ 105 | #ifdef INLINE_DELAY 106 | static inline void delay_ms(uint32_t ms) 107 | { 108 | #define _DELAY_MS_CALCULATING_CYCLES (20 + 2) // 2 - вызов функции. 109 | 110 | register uint32_t cycles_to_delay = SystemCoreClock / 1000UL * ms; 111 | 112 | if(cycles_to_delay > _DELAY_MS_CALCULATING_CYCLES){ 113 | cycles_to_delay -= _DELAY_MS_CALCULATING_CYCLES; 114 | delay_cycles(cycles_to_delay); 115 | } 116 | #undef _DELAY_MS_CALCULATING_CYCLES 117 | } 118 | #else 119 | EXTERN void delay_ms(uint32_t ms); 120 | #endif 121 | 122 | #endif /* DELAY_H */ 123 | 124 | -------------------------------------------------------------------------------- /utils/net.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file net.h Функции преобразования порядка байт. 3 | */ 4 | 5 | #ifndef NET_H 6 | #define NET_H 7 | 8 | #include 9 | #include "defs/defs.h" 10 | 11 | /** 12 | * Преобразует узловой порядок расположения байтов 13 | * положительного короткого целого в 14 | * сетевой порядок расположения байтов. 15 | * @param hostshort Целое для преобразования. 16 | * @return Целое в сетевом порядке байт. 17 | */ 18 | ALWAYS_INLINE static uint16_t htons(uint16_t hostshort) 19 | { 20 | uint16_t res; 21 | 22 | __asm__ __volatile__ ("rev16 %0, %1" : "=r"(res) : "r"(hostshort)); 23 | 24 | return res; 25 | } 26 | 27 | /** 28 | * Преобразует сетевой порядок расположения байтов 29 | * положительного короткого целого в 30 | * узловой порядок расположения байтов. 31 | * @param netshort Целое для преобразования. 32 | * @return Целое в узловом порядке байт. 33 | */ 34 | ALWAYS_INLINE static uint16_t ntohs(uint16_t netshort) 35 | { 36 | uint16_t res; 37 | 38 | __asm__ __volatile__ ("rev16 %0, %1" : "=r"(res) : "r"(netshort)); 39 | 40 | return res; 41 | } 42 | 43 | /** 44 | * Преобразует узловой порядок расположения байтов 45 | * положительного целого в 46 | * сетевой порядок расположения байтов. 47 | * @param hostshort Целое для преобразования. 48 | * @return Целое в сетевом порядке байт. 49 | */ 50 | ALWAYS_INLINE static uint32_t htonl(uint32_t hostlong) 51 | { 52 | uint32_t res; 53 | 54 | __asm__ __volatile__ ("rev %0, %1" : "=r"(res) : "r"(hostlong)); 55 | 56 | return res; 57 | } 58 | 59 | /** 60 | * Преобразует сетевой порядок расположения байтов 61 | * положительного целого в 62 | * узловой порядок расположения байтов. 63 | * @param netshort Целое для преобразования. 64 | * @return Целое в узловом порядке байт. 65 | */ 66 | ALWAYS_INLINE static uint32_t ntohl(uint32_t netlong) 67 | { 68 | uint32_t res; 69 | 70 | __asm__ __volatile__ ("rev %0, %1" : "=r"(res) : "r"(netlong)); 71 | 72 | return res; 73 | } 74 | 75 | #endif //NET_H 76 | -------------------------------------------------------------------------------- /utils/utf8.c: -------------------------------------------------------------------------------- 1 | #include "utf8.h" 2 | 3 | 4 | 5 | size_t utf8_str_char_size(const char* str_c) 6 | { 7 | size_t res = 0; 8 | unsigned char c = str_c[0]; 9 | 10 | while(c & 0x80){ 11 | res ++; 12 | c <<= 0x1; 13 | } 14 | 15 | return res == 0 ? 1 : res; 16 | } 17 | 18 | size_t utf8_char_size(wchar_t c) 19 | { 20 | if(c > 0x001fffff) return 0; 21 | 22 | if(c >= 0x00010000) return 4; 23 | if(c >= 0x00000800) return 3; 24 | if(c >= 0x00000080) return 2; 25 | 26 | return 1; 27 | } 28 | 29 | /* 30 | 0000 0000-0000 007F 0xxxxxxx 31 | 0000 0080-0000 07FF 110xxxxx 10xxxxxx 32 | 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 33 | 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 34 | */ 35 | wchar_t utf8_char_decode(const char* str_c) 36 | { 37 | wchar_t res = 0; 38 | size_t s = utf8_str_char_size(str_c); 39 | 40 | switch(s){ 41 | case 1: 42 | default: 43 | res = (wchar_t)(*str_c); 44 | break; 45 | case 2: 46 | res = (res | (str_c[0] & 0x1f)) << 6; 47 | res = (res | (str_c[1] & 0x3f)); 48 | break; 49 | case 3: 50 | res = (res | (str_c[0] & 0xf )) << 6; 51 | res = (res | (str_c[1] & 0x3f)) << 6; 52 | res = (res | (str_c[2] & 0x3f)); 53 | break; 54 | case 4: 55 | res = (res | (str_c[0] & 0x7 )) << 6; 56 | res = (res | (str_c[1] & 0x3f)) << 6; 57 | res = (res | (str_c[2] & 0x3f)) << 6; 58 | res = (res | (str_c[3] & 0x3f)); 59 | break; 60 | } 61 | 62 | return res; 63 | } 64 | 65 | size_t utf8_char_encode(char* str_c, wchar_t c) 66 | { 67 | size_t s = utf8_char_size(c); 68 | 69 | switch(s){ 70 | case 1: 71 | default: 72 | *str_c = (char)(c); 73 | break; 74 | case 2://0x1f 0x3f <<6 75 | str_c[0] = (char)(((c >> 6 ) | 0xc0)); 76 | str_c[1] = (char)(((c ) & 0x3f) | 0x80); 77 | break; 78 | case 3://0xf 79 | str_c[0] = (char)(((c >> 12) | 0xe0)); 80 | str_c[1] = (char)(((c >> 6 ) & 0x3f) | 0x80); 81 | str_c[2] = (char)(((c ) & 0x3f) | 0x80); 82 | break; 83 | case 4://0x7 84 | str_c[0] = (char)(((c >> 18) | 0xf0)); 85 | str_c[1] = (char)(((c >> 12) & 0x3f) | 0x80); 86 | str_c[2] = (char)(((c >> 6 ) & 0x3f) | 0x80); 87 | str_c[3] = (char)(((c ) & 0x3f) | 0x80); 88 | break; 89 | } 90 | 91 | return s; 92 | } 93 | 94 | bool utf8_char_validate(const char* str_c) 95 | { 96 | size_t s = utf8_str_char_size(str_c); 97 | 98 | if(s > 4) return false; 99 | 100 | switch(s){ 101 | case 1: 102 | if(str_c[0] & 0x80) return false; 103 | break; 104 | case 2: 105 | if((str_c[0] & 0xe0) != 0xc0) return false; 106 | if((str_c[1] & 0xc0) != 0x80) return false; 107 | break; 108 | case 3: 109 | if((str_c[0] & 0xf0) != 0xe0) return false; 110 | if((str_c[1] & 0xc0) != 0x80) return false; 111 | if((str_c[2] & 0xc0) != 0x80) return false; 112 | break; 113 | case 4: 114 | if((str_c[0] & 0xf8) != 0xf0) return false; 115 | if((str_c[1] & 0xc0) != 0x80) return false; 116 | if((str_c[2] & 0xc0) != 0x80) return false; 117 | if((str_c[3] & 0xc0) != 0x80) return false; 118 | break; 119 | default: 120 | return false; 121 | } 122 | 123 | return true; 124 | } 125 | -------------------------------------------------------------------------------- /utils/utf8.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file utf.h Библиотека работы с utf8. 3 | */ 4 | 5 | #ifndef UTF8_H 6 | #define UTF8_H 7 | 8 | #include 9 | #include 10 | #include "defs/defs.h" 11 | 12 | 13 | /** 14 | * Получает размер символа строки utf8. 15 | * @param str_c Символ utf8. 16 | * @return Размер символа строки utf8. 17 | */ 18 | EXTERN size_t utf8_str_char_size(const char* str_c); 19 | 20 | /** 21 | * Получает размер символа utf8. 22 | * @param c Код символа utf8. 23 | * @return Размер символа utf8. 24 | */ 25 | EXTERN size_t utf8_char_size(wchar_t c); 26 | 27 | /** 28 | * Декодирует символ строки utf8. 29 | * @param str_c Символ строки utf8. 30 | * @return Код символа utf8. 31 | */ 32 | EXTERN wchar_t utf8_char_decode(const char* str_c); 33 | 34 | /** 35 | * Кодирует символ в строку utf8. 36 | * @param str_c Строка utf8. 37 | * @param c Код символа utf8. 38 | * @return Размер символа utf8. 39 | */ 40 | EXTERN size_t utf8_char_encode(char* str_c, wchar_t c); 41 | 42 | /** 43 | * Верифицирует символа строки utf8. 44 | * @param str_c Символ utf8. 45 | * @return true если символ валиден, иначе false. 46 | */ 47 | EXTERN bool utf8_char_validate(const char* str_c); 48 | 49 | #endif /* UTF8_H */ 50 | -------------------------------------------------------------------------------- /utils/utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file utils.h 3 | * Различные функции. 4 | */ 5 | 6 | #ifndef UTILS_H 7 | #define UTILS_H 8 | 9 | #include "defs/defs.h" 10 | 11 | /** 12 | * Каст void*. 13 | */ 14 | #define int_to_pvoid(I) ((void*)(ptrdiff_t)I) 15 | #define pvoid_to_int(I_TYPE, P) ((I_TYPE)(ptrdiff_t)P) 16 | #define pvoid_cast(T, PV) ((T)PV) 17 | 18 | /** 19 | * Максимальное значение из двух. 20 | */ 21 | #ifndef MAX 22 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 23 | #endif 24 | 25 | /** 26 | * Минимальное значнеие из двух. 27 | */ 28 | #ifndef MIN 29 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 30 | #endif 31 | 32 | /** 33 | * Абсолютное значение числа. 34 | */ 35 | #ifndef ABS 36 | #define ABS(a) ((a) < 0 ? -(a) : (a)) 37 | #endif 38 | 39 | /** 40 | * Значение в границах. 41 | */ 42 | #ifndef CLAMP 43 | #define CLAMP(v, min_v, max_v) (MIN(MAX(v, min_v), max_v)) 44 | #endif 45 | 46 | /** 47 | * Меняет значения в переменных A и B, используя переменную TMP 48 | */ 49 | #define SWAP(A, B, TMP) do{ (TMP) = (A); (A) = (B); (B) = (TMP); }while(0) 50 | 51 | /** 52 | * Цикличный инкремент/декремент на заданное значение. 53 | */ 54 | #define CYCLIC_ADD(VAL, ADD, MIN, MAX) do{VAL += (ADD); if(VAL >= (MAX)) VAL = (MIN);}while(0) 55 | #define CYCLIC_SUB(VAL, SUB, MIN, MAX) do{VAL -= (SUB); if(VAL <= (MIN)) VAL = (MAX);}while(0) 56 | 57 | /** 58 | * Цикличный инкремент/декремент на 1. 59 | */ 60 | #define CYCLIC_INC(VAL, MIN, MAX) CYCLIC_ADD(VAL, 1, MIN, MAX) 61 | #define CYCLIC_DEC(VAL, MIN, MAX) CYCLIC_SUB(VAL, 1, MIN, MAX) 62 | 63 | /** 64 | * Ограничительный инкремент/декремент на заданное значение. 65 | */ 66 | #define CLAMP_ADD(VAL, ADD, MAX) do{VAL += (ADD); if(VAL > (MAX)) VAL = (MAX);}while(0) 67 | #define CLAMP_SUB(VAL, SUB, MIN) do{VAL -= (SUB); if(VAL < (MIN)) VAL = (MIN);}while(0) 68 | 69 | /** 70 | * Ограничительный инкремент/декремент на 1. 71 | */ 72 | #define CLAMP_INC(VAL, MAX) CLAMP_ADD(VAL, 1, MAX) 73 | #define CLAMP_DEC(VAL, MIN) CLAMP_SUB(VAL, 1, MIN) 74 | 75 | /** 76 | * Ожидание пока условие C истинно. 77 | */ 78 | #define WAIT_WHILE_TRUE(C) do{}while((C)) 79 | 80 | /** 81 | * Ожидание пока условие C ложно. 82 | */ 83 | #define WAIT_WHILE_FALSE(C) do{}while(!(C)) 84 | 85 | /** 86 | * Если функция F возвратила ошибку, отличную от E_NO_ERROR - возвращает эту ошибку. 87 | */ 88 | #define RETURN_ERR_IF_FAIL(F) do{\ 89 | err_t CONCAT(err, __LINE__) = F;\ 90 | if(CONCAT(err, __LINE__) != E_NO_ERROR)\ 91 | { return CONCAT(err, __LINE__); }\ 92 | }while(0) 93 | 94 | #endif /* UTILS_H */ 95 | --------------------------------------------------------------------------------