浏览代码

Добавляю параметры цифровых вх/вых.

dtelenkov 5 月之前
父节点
当前提交
b69cb5088d

+ 448 - 433
fw/modules/io/digital_input.c

@@ -1,433 +1,448 @@
-#include "at32f403a_407.h"
-#include "digital_input.h"
-#include "FreeRTOS.h"
-#include "task.h"
-#include "settings_api.h"
-#include "io_utils.h"
-#include "mux.h"
-#include <stdio.h>
-
-#if defined (MDIO_88)
-
-// Цифровые входы
-// *port; pin; mode; port_source; pin_source; deb_counter; p_flag; cnt;
-din_t d_inputs[DI_NUMBER] = {
-    {GPIOB, GPIO_PINS_11, 0, 0, 0, false, false}, // 1   
-    {GPIOB, GPIO_PINS_10, 0, 0, 0, false, false}, // 2
-    {GPIOE, GPIO_PINS_14, 0, 0, 0, false, false}, // 3 перенесли {GPIOB, GPIO_PINS_1,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE1,  0},
-    {GPIOE, GPIO_PINS_15, 0, 0, 0, false, false}, // 4 перенесли {GPIOB, GPIO_PINS_0,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE0,  0},
-    {GPIOA, GPIO_PINS_3,  0, 0, 0, false, false}, // 5
-    {GPIOA, GPIO_PINS_2,  0, 0, 0, false, false}, // 6
-    {GPIOA, GPIO_PINS_1,  0, 0, 0, false, false}, // 7
-    {GPIOA, GPIO_PINS_0,  0, 0, 0, false, false}  // 8
-};
-
-// Датчики обрыва нагрузки
-simple_gpio_t di_load[DI_NUMBER] = {
-    {GPIOD, GPIO_PINS_0},
-    {GPIOD, GPIO_PINS_1},
-    {GPIOC, GPIO_PINS_13},
-    {GPIOC, GPIO_PINS_0},
-    {GPIOC, GPIO_PINS_10},
-    {GPIOD, GPIO_PINS_4},
-    {GPIOE, GPIO_PINS_4},
-    {GPIOC, GPIO_PINS_3}
-};
-
-// -------------------------------------------------------------------------- //
-// Текущие параметры
-
-uint32_t di_cnt[DI_NUMBER];         // счетчики входов
-
-uint16_t di_state[DI_NUMBER];       // состояние входов
-uint16_t di_state_bit;
-
-uint16_t di_load_state[DO_NUMBER];  // состояние датчиков обрыва нагрузки
-uint16_t di_load_state_bit;
-
-uint16_t di_credibility_state[DO_NUMBER];  // достоверность состояния датчиков нагрузки
-uint16_t di_credibility_state_bit;         // достоверность состояния датчиков нагрузки
-
-//
-void di_init(void)
-{
-    // Входы
-    for (int i = 0; i < DI_NUMBER; i++) 
-    {
-        di_base_init(&d_inputs[i]);
-        di_load_sens_init(&di_load[i]);
-    }
-    
-    // EXTI
-    di_exti_init();
-    
-    // Таймер для антидребезга
-    di_tim_init();
-}
-
-//
-void di_base_init(din_t *input)
-{
-    gpio_init_type gpio_init_struct;
-
-    gpio_default_para_init(&gpio_init_struct);
-        
-    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
-    gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;  
-    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
-    gpio_init_struct.gpio_pins           = input->pin;
-    gpio_init(input->port, &gpio_init_struct);
-}
-
-//
-void di_exti_init(void)
-{
-    exint_init_type exint_init_struct;
-    
-    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE11); // 11
-    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE10); // 10
-    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOE, GPIO_PINS_SOURCE14); // 14
-    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOE, GPIO_PINS_SOURCE15); // 15
-    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE3);  // 3
-    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE2);  // 2
-    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE1);  // 1
-    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE0);  // 0
-    
-    exint_default_para_init(&exint_init_struct);
-    
-    exint_init_struct.line_enable = TRUE;
-    exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
-    exint_init_struct.line_select = EXINT_LINE_0 | EXINT_LINE_1 | EXINT_LINE_2 |
-                                    EXINT_LINE_3 | EXINT_LINE_10 | 
-                                    EXINT_LINE_11| EXINT_LINE_14 | EXINT_LINE_15; 
-    
-    exint_init_struct.line_polarity = EXINT_TRIGGER_BOTH_EDGE;
-    exint_init(&exint_init_struct);
-    
-    exint_flag_clear(EXINT_LINE_0);
-    exint_flag_clear(EXINT_LINE_1);
-    exint_flag_clear(EXINT_LINE_2);
-    exint_flag_clear(EXINT_LINE_3);
-    exint_flag_clear(EXINT_LINE_10);
-    exint_flag_clear(EXINT_LINE_11);
-    exint_flag_clear(EXINT_LINE_14);
-    exint_flag_clear(EXINT_LINE_15);
-    
-    nvic_irq_enable(EXINT0_IRQn, 5, 0);
-    nvic_irq_enable(EXINT1_IRQn, 5, 0);
-    nvic_irq_enable(EXINT2_IRQn, 5, 0);
-    nvic_irq_enable(EXINT3_IRQn, 5, 0);
-    nvic_irq_enable(EXINT15_10_IRQn, 5, 0);
-}
-
-//
-void di_load_sens_init(simple_gpio_t *sens)
-{
-    gpio_init_type gpio_init_struct;
-    
-    gpio_default_para_init(&gpio_init_struct);
-        
-    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
-    gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;  
-    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
-    gpio_init_struct.gpio_pins           = sens->pin;
-    gpio_init(sens->port, &gpio_init_struct); 
-}
-
-// Таймер для антидребезга
-void di_tim_init(void)
-{
-    crm_clocks_freq_type crm_clocks_freq_struct = {0};
-    
-    crm_clocks_freq_get(&crm_clocks_freq_struct);
-    
-    nvic_irq_disable(TMR8_BRK_TMR12_IRQn);
-    
-    crm_periph_clock_enable(CRM_TMR12_PERIPH_CLOCK, TRUE);
-
-    // 1 Hz
-    tmr_base_init(TMR12, 9, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
-    tmr_cnt_dir_set(TMR12, TMR_COUNT_UP);
-    
-    NVIC_ClearPendingIRQ(TMR8_BRK_TMR12_IRQn);
-    nvic_irq_enable(TMR8_BRK_TMR12_IRQn, 5, 0);
-    
-    tmr_flag_clear(TMR12, TMR_OVF_FLAG);
-    tmr_interrupt_enable(TMR12, TMR_OVF_INT, TRUE);
-    tmr_counter_value_set(TMR12, 0);
-    tmr_counter_enable(TMR12, TRUE);  
-}
-
-
-void TMR8_BRK_TMR12_IRQHandler(void)
-{
-    //static int i = 0;
-    //static int cnt = 0;
-
-    if(tmr_flag_get(TMR12, TMR_OVF_FLAG) != RESET)
-    {
-        tmr_flag_clear(TMR12, TMR_OVF_FLAG);
-
-        debounce();
-#if 0        
-        if (i++ == 1000) {
-            i = 0;
-            cnt++;
-            printf("CNT: %u\r\n");
-        }
-#endif        
-    }
-}
-
-// Пробегает по всему массиву структур цифровых входов.
-// Если режим входа изменился 
-void di_set(void)
-{
-    for (int i = 0; i < DI_NUMBER; i++)
-    {
-        if (((settings.di_mode_bits >> i) & 1) != d_inputs[i].mode) 
-        {
-            d_inputs[i].mode = ((settings.di_mode_bits >> i) & 1);
-            if (d_inputs[i].mode == 0) 
-            {
-                d_inputs[i].cnt = 0;
-                d_inputs[i].p_flag = false;
-                di_cnt[i] = 0;
-            }
-            else
-            {
-                di_state_bit &= ~(1 << i);
-            }
-        }
-    }
-}
-
-//
-uint8_t di_get(uint8_t channel)
-{
-    uint8_t ret = 0;
-    
-    ret = (uint8_t)(di_state_bit >> channel & 1);
-    
-    return  ret;
-}
-
-// Реализация функции антидребезка. Вызывается в прерывании таймера
-void debounce(void)
-{
-    for (int i = 0; i < DI_NUMBER; i++)
-    {
-        if ((d_inputs[i].p_flag) && (d_inputs[i].mode == 0)){
-            if (++d_inputs[i].cnt == settings.di_debounce[i]) {
-                d_inputs[i].cnt = 0;
-                d_inputs[i].p_flag = false;
-                
-                di_state[i] = (uint16_t)gpio_input_data_bit_read(d_inputs[i].port, d_inputs[i].pin);
-                
-                if (!di_state[i]) {
-                    di_state_bit &= ~(1 << i); // снять бит
-                    leds[i].state = LED_OFF;
-                }
-                else {
-                    di_state_bit |= di_state[i] << i;
-                    leds[i].state = LED_ON;
-                }
-            }
-        }
-    }
-}
-
-// Периодический опрос входов и датчиков обрыва нагрузки
-void di_task(void *params)
-{
-    for (;;)
-    {
-        
-        for (int i = 0; i < DI_NUMBER; i++)
-        {
-            // Режим обычного входа
-            if (d_inputs[i].mode == 0)
-            {
-                di_state[i] = (uint16_t)gpio_input_data_bit_read(d_inputs[i].port, d_inputs[i].pin);
-                
-                if (!di_state[i]) {
-                    di_state_bit &= ~(1 << i); // снять бит
-                    leds[i].state = LED_OFF;
-                }
-                else {
-                    di_state_bit |= di_state[i] << i;
-                    leds[i].state = LED_ON;
-                }
-            }
-        }
-        
-       
-        for (int i = 0; i < DI_NUMBER; i++)
-        {                           
-            di_load_state[i] = (uint16_t)gpio_input_data_bit_read(di_load[i].port, di_load[i].pin);
-            
-            // Текущее состояние датчиков нагрузки.
-            if (!di_load_state[i]) {
-                di_load_state_bit &= ~(1 << i);  // снять бит
-            }
-            else {
-                di_load_state_bit |= 1 << i;
-            }
-            
-            // Установка битов достоверности
-            // Если 0 (выход разомкнут), то состояние достоверно и нужно 
-            // выставить соответствующий бит
-            if (!(output_state_bit & (1 << i))) {
-                di_credibility_state_bit |= 1 << i;
-            }
-            else { 
-                di_credibility_state_bit &= ~(1 << i);
-            }  
-        }
-            
-        vTaskDelay(100);
-    }
-}
-
-// IN_8 GPIOA_0
-void EXINT0_IRQHandler(void)
-{
-    if (exint_flag_get(EXINT_LINE_0) != RESET) 
-    {
-        exint_flag_clear(EXINT_LINE_0);
-        if (d_inputs[7].mode == 0)
-            d_inputs[7].p_flag = true;
-        else { 
-            if (d_inputs[7].cnt_flag) {
-                di_cnt[7]++;
-                d_inputs[7].cnt_flag = false;
-            }
-            else
-                d_inputs[7].cnt_flag = true;
-        }
-    }
-}
-
-// IN_7 GPIOA_1
-void EXINT1_IRQHandler(void)
-{
-    if(exint_flag_get(EXINT_LINE_1) != RESET) 
-    {
-        exint_flag_clear(EXINT_LINE_1);
-        if (d_inputs[6].mode == 0)
-            d_inputs[6].p_flag = true;
-        else { 
-            if (d_inputs[6].cnt_flag) {
-                di_cnt[6]++;
-                d_inputs[6].cnt_flag = false;
-            }
-            else
-                d_inputs[6].cnt_flag = true;
-        }
-    }
-}
-
-// IN_6 GPIOA_2
-void EXINT2_IRQHandler(void)
-{
-    if(exint_flag_get(EXINT_LINE_2) != RESET) 
-    {
-        exint_flag_clear(EXINT_LINE_2);
-        if (d_inputs[5].mode == 0)
-            d_inputs[5].p_flag = true;
-        else { 
-            if (d_inputs[5].cnt_flag) {
-                di_cnt[5]++;
-                d_inputs[5].cnt_flag = false;
-            }
-            else
-                d_inputs[5].cnt_flag = true;
-        }
-    }
-}
-
-// IN_5 GPIOA_3
-void EXINT3_IRQHandler(void)
-{
-    if(exint_flag_get(EXINT_LINE_3) != RESET) 
-    {
-        exint_flag_clear(EXINT_LINE_3);
-        if (d_inputs[4].mode == 0)
-            d_inputs[4].p_flag = true;
-        else { 
-            if (d_inputs[4].cnt_flag) {
-                di_cnt[4]++;
-                d_inputs[4].cnt_flag = false;
-            }
-            else
-                d_inputs[4].cnt_flag = true;
-        }
-    }
-}
-
-// IN_1, IN_2, IN_3, IN_4
-void EXINT15_10_IRQHandler(void)
-{
-    // IN_2 GPIOB_10
-    if (exint_flag_get(EXINT_LINE_10) != RESET)  
-    {
-        exint_flag_clear(EXINT_LINE_10);
-        if (d_inputs[1].mode == 0)
-            d_inputs[1].p_flag = true;
-        else { 
-            if (d_inputs[1].cnt_flag) {
-                di_cnt[1]++;
-                d_inputs[1].cnt_flag = false;
-            }
-            else
-                d_inputs[1].cnt_flag = true;
-        }
-    }
-    // IN_1 GPIOB_11
-    else if (exint_flag_get(EXINT_LINE_11) != RESET)  
-    {
-        exint_flag_clear(EXINT_LINE_11);
-        if (d_inputs[0].mode == 0)
-            d_inputs[0].p_flag = true;
-        else { 
-            if (d_inputs[0].cnt_flag) {
-                di_cnt[0]++;
-                d_inputs[0].cnt_flag = false;
-            }
-            else
-                d_inputs[0].cnt_flag = true;
-        }
-    }
-    // IN_3 GPIOE_14
-    else if (exint_flag_get(EXINT_LINE_14) != RESET)  
-    {
-        exint_flag_clear(EXINT_LINE_14);
-        if (d_inputs[2].mode == 0)
-            d_inputs[2].p_flag = true;
-        else { 
-            if (d_inputs[2].cnt_flag) {
-                di_cnt[2]++;
-                d_inputs[2].cnt_flag = false;
-            }
-            else
-                d_inputs[2].cnt_flag = true;
-        }
-    }
-    // IN_4 GPIOE_15
-    else if (exint_flag_get(EXINT_LINE_15) != RESET) 
-    {
-        exint_flag_clear(EXINT_LINE_15);
-        if (d_inputs[3].mode == 0)
-            d_inputs[3].p_flag = true;
-        else { 
-            if (d_inputs[3].cnt_flag) {
-                di_cnt[3]++;
-                d_inputs[3].cnt_flag = false;
-            }
-            else
-                d_inputs[3].cnt_flag = true;
-        }
-    }    
-}
-
-#endif
+#include "at32f403a_407.h"
+#include "digital_input.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "settings_api.h"
+#include "io_utils.h"
+#include "mux.h"
+#include <stdio.h>
+
+#if defined (MDIO_88)
+
+// Цифровые входы
+// *port; pin; mode; port_source; pin_source; deb_counter; p_flag; cnt;
+din_t d_inputs[DI_NUMBER] = {
+    {GPIOB, GPIO_PINS_11, 0, 0, 0, false, false}, // 1   
+    {GPIOB, GPIO_PINS_10, 0, 0, 0, false, false}, // 2
+    {GPIOE, GPIO_PINS_14, 0, 0, 0, false, false}, // 3 перенесли {GPIOB, GPIO_PINS_1,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE1,  0},
+    {GPIOE, GPIO_PINS_15, 0, 0, 0, false, false}, // 4 перенесли {GPIOB, GPIO_PINS_0,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE0,  0},
+    {GPIOA, GPIO_PINS_3,  0, 0, 0, false, false}, // 5
+    {GPIOA, GPIO_PINS_2,  0, 0, 0, false, false}, // 6
+    {GPIOA, GPIO_PINS_1,  0, 0, 0, false, false}, // 7
+    {GPIOA, GPIO_PINS_0,  0, 0, 0, false, false}  // 8
+};
+
+// Датчики обрыва нагрузки
+simple_gpio_t di_load[DI_NUMBER] = {
+    {GPIOD, GPIO_PINS_0},
+    {GPIOD, GPIO_PINS_1},
+    {GPIOC, GPIO_PINS_13},
+    {GPIOC, GPIO_PINS_0},
+    {GPIOC, GPIO_PINS_10},
+    {GPIOD, GPIO_PINS_4},
+    {GPIOE, GPIO_PINS_4},
+    {GPIOC, GPIO_PINS_3}
+};
+
+// -------------------------------------------------------------------------- //
+// Текущие параметры
+
+uint32_t di_cnt[DI_NUMBER];         // счетчики входов
+
+uint16_t di_state[DI_NUMBER];       // состояние входов
+uint16_t di_state_bit;
+
+uint16_t di_load_state[DO_NUMBER];  // состояние датчиков обрыва нагрузки
+uint16_t di_load_state_bit;
+
+uint16_t di_credibility_state[DO_NUMBER];  // достоверность состояния датчиков нагрузки
+uint16_t di_credibility_state_bit;         // достоверность состояния датчиков нагрузки
+
+
+// Настройка периферии дискретных входов (GPIO, EXTI, TIM).
+// Настройка датчиков обрыва нагрузки (GPIO).
+// Вызывается единственный раз при старте контроллера.
+// Периферия настраивается однозначно и только один раз.
+void di_init(void)
+{
+    // Входы
+    for (int i = 0; i < DI_NUMBER; i++) {
+        di_base_init(&d_inputs[i]);
+        di_load_sens_init(&di_load[i]);
+    }
+    
+    // EXTI
+    di_exti_init();
+    
+    // Таймер для антидребезга
+    di_tim_init();
+}
+
+
+// Настройка GPIO дискретных входов
+void di_base_init(din_t *input)
+{
+    gpio_init_type gpio_init_struct;
+
+    gpio_default_para_init(&gpio_init_struct);
+        
+    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
+    gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;  
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init_struct.gpio_pins           = input->pin;
+    gpio_init(input->port, &gpio_init_struct);
+}
+
+
+// Настройка EXTI дискретных входов
+void di_exti_init(void)
+{
+    exint_init_type exint_init_struct;
+    
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE11); // 11
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE10); // 10
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOE, GPIO_PINS_SOURCE14); // 14
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOE, GPIO_PINS_SOURCE15); // 15
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE3);  // 3
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE2);  // 2
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE1);  // 1
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE0);  // 0
+    
+    exint_default_para_init(&exint_init_struct);
+    
+    exint_init_struct.line_enable = TRUE;
+    exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
+    exint_init_struct.line_select = EXINT_LINE_0 | EXINT_LINE_1 | EXINT_LINE_2 |
+                                    EXINT_LINE_3 | EXINT_LINE_10 | 
+                                    EXINT_LINE_11| EXINT_LINE_14 | EXINT_LINE_15; 
+    
+    exint_init_struct.line_polarity = EXINT_TRIGGER_BOTH_EDGE;
+    exint_init(&exint_init_struct);
+    
+    exint_flag_clear(EXINT_LINE_0);
+    exint_flag_clear(EXINT_LINE_1);
+    exint_flag_clear(EXINT_LINE_2);
+    exint_flag_clear(EXINT_LINE_3);
+    exint_flag_clear(EXINT_LINE_10);
+    exint_flag_clear(EXINT_LINE_11);
+    exint_flag_clear(EXINT_LINE_14);
+    exint_flag_clear(EXINT_LINE_15);
+    
+    nvic_irq_enable(EXINT0_IRQn, 5, 0);
+    nvic_irq_enable(EXINT1_IRQn, 5, 0);
+    nvic_irq_enable(EXINT2_IRQn, 5, 0);
+    nvic_irq_enable(EXINT3_IRQn, 5, 0);
+    nvic_irq_enable(EXINT15_10_IRQn, 5, 0);
+}
+
+
+// Настройка датчиков обрыва нагрузки (GPIO).
+void di_load_sens_init(simple_gpio_t *sens)
+{
+    gpio_init_type gpio_init_struct;
+    
+    gpio_default_para_init(&gpio_init_struct);
+        
+    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
+    gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;  
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init_struct.gpio_pins           = sens->pin;
+    gpio_init(sens->port, &gpio_init_struct); 
+}
+
+
+// Таймер антидребезга для дискретных входов
+void di_tim_init(void)
+{
+    crm_clocks_freq_type crm_clocks_freq_struct = {0};
+    
+    crm_clocks_freq_get(&crm_clocks_freq_struct);
+    
+    nvic_irq_disable(TMR8_BRK_TMR12_IRQn);
+    
+    crm_periph_clock_enable(CRM_TMR12_PERIPH_CLOCK, TRUE);
+
+    // 1 Hz
+    tmr_base_init(TMR12, 9, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
+    tmr_cnt_dir_set(TMR12, TMR_COUNT_UP);
+    
+    NVIC_ClearPendingIRQ(TMR8_BRK_TMR12_IRQn);
+    nvic_irq_enable(TMR8_BRK_TMR12_IRQn, 5, 0);
+    
+    tmr_flag_clear(TMR12, TMR_OVF_FLAG);
+    tmr_interrupt_enable(TMR12, TMR_OVF_INT, TRUE);
+    tmr_counter_value_set(TMR12, 0);
+    tmr_counter_enable(TMR12, TRUE);  
+}
+
+
+// IRQ таймера антидребезга дискретных входов
+void TMR8_BRK_TMR12_IRQHandler(void)
+{
+    if(tmr_flag_get(TMR12, TMR_OVF_FLAG) != RESET)
+    {
+        tmr_flag_clear(TMR12, TMR_OVF_FLAG);
+
+        debounce();
+    }
+}
+
+
+// Установка состояний дискретных входов (вкл./выкл.)
+void di_set_state(void)
+{
+    for (int i = 0; i < DI_NUMBER; i++)
+    {
+        settings.di[i].state = (uint8_t)((settings.di_state_bits >> i) & 1);
+    }
+}
+
+
+// Пробегает по всему массиву структур цифровых входов.
+// Если режим входа изменился 
+void di_set(void)
+{
+    for (int i = 0; i < DI_NUMBER; i++)
+    {
+        if (((settings.di_mode_bits >> i) & 1) != d_inputs[i].mode) 
+        {
+            d_inputs[i].mode = ((settings.di_mode_bits >> i) & 1);
+            if (d_inputs[i].mode == 0) 
+            {
+                d_inputs[i].cnt = 0;
+                d_inputs[i].p_flag = false;
+                di_cnt[i] = 0;
+            }
+            else
+            {
+                di_state_bit &= ~(1 << i);
+            }
+        }
+    }
+}
+
+//
+uint8_t di_get(uint8_t channel)
+{
+    uint8_t ret = 0;
+    
+    ret = (uint8_t)(di_state_bit >> channel & 1);
+    
+    return  ret;
+}
+
+
+// Функция антидребезка. Вызывается в прерывании таймера.
+void debounce(void)
+{
+    for (int i = 0; i < DI_NUMBER; i++)
+    {
+        if ((d_inputs[i].p_flag) && (d_inputs[i].mode == 0)){
+            if (++d_inputs[i].cnt == settings.di_debounce[i]) {
+                d_inputs[i].cnt = 0;
+                d_inputs[i].p_flag = false;
+                
+                di_state[i] = (uint16_t)gpio_input_data_bit_read(d_inputs[i].port, d_inputs[i].pin);
+                
+                if (!di_state[i]) {
+                    di_state_bit &= ~(1 << i); // снять бит
+                    leds[i].state = LED_OFF;
+                }
+                else {
+                    di_state_bit |= di_state[i] << i;
+                    leds[i].state = LED_ON;
+                }
+            }
+        }
+    }
+}
+
+
+// Периодический опрос дискретнрых входов и датчиков обрыва нагрузки
+void di_task(void *params)
+{
+    for (;;)
+    {
+        // Дискретные входы
+        for (int i = 0; i < DI_NUMBER; i++)
+        {
+            // Режим обычного входа
+            if (d_inputs[i].mode == 0)
+            {
+                di_state[i] = (uint16_t)gpio_input_data_bit_read(d_inputs[i].port, d_inputs[i].pin);
+                
+                if (!di_state[i]) {
+                    di_state_bit &= ~(1 << i); // снять бит
+                    leds[i].state = LED_OFF;
+                }
+                else {
+                    di_state_bit |= di_state[i] << i;
+                    leds[i].state = LED_ON;
+                }
+            }
+        }
+        
+       
+        // Датчики обрыва нагрузки
+        for (int i = 0; i < DI_NUMBER; i++)
+        {                           
+            di_load_state[i] = (uint16_t)gpio_input_data_bit_read(di_load[i].port, di_load[i].pin);
+            
+            // Текущее состояние датчиков нагрузки.
+            if (!di_load_state[i]) {
+                di_load_state_bit &= ~(1 << i);  // снять бит
+            }
+            else {
+                di_load_state_bit |= 1 << i;
+            }
+            
+            // Установка битов достоверности
+            // Если 0 (выход разомкнут), то состояние достоверно и нужно 
+            // выставить соответствующий бит
+            if (!(output_state_bit & (1 << i))) {
+                di_credibility_state_bit |= 1 << i;
+            }
+            else { 
+                di_credibility_state_bit &= ~(1 << i);
+            }  
+        }
+            
+        vTaskDelay(100);
+    }
+}
+
+// -------------------------------------------------------------------------- // 
+//        Обработчики прерываний EXTI для режима счетных входов
+
+// IN_8 GPIOA_0
+void EXINT0_IRQHandler(void)
+{
+    if (exint_flag_get(EXINT_LINE_0) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_0);
+        if (d_inputs[7].mode == 0)
+            d_inputs[7].p_flag = true;
+        else { 
+            if (d_inputs[7].cnt_flag) {
+                di_cnt[7]++;
+                d_inputs[7].cnt_flag = false;
+            }
+            else
+                d_inputs[7].cnt_flag = true;
+        }
+    }
+}
+
+// IN_7 GPIOA_1
+void EXINT1_IRQHandler(void)
+{
+    if(exint_flag_get(EXINT_LINE_1) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_1);
+        if (d_inputs[6].mode == 0)
+            d_inputs[6].p_flag = true;
+        else { 
+            if (d_inputs[6].cnt_flag) {
+                di_cnt[6]++;
+                d_inputs[6].cnt_flag = false;
+            }
+            else
+                d_inputs[6].cnt_flag = true;
+        }
+    }
+}
+
+// IN_6 GPIOA_2
+void EXINT2_IRQHandler(void)
+{
+    if(exint_flag_get(EXINT_LINE_2) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_2);
+        if (d_inputs[5].mode == 0)
+            d_inputs[5].p_flag = true;
+        else { 
+            if (d_inputs[5].cnt_flag) {
+                di_cnt[5]++;
+                d_inputs[5].cnt_flag = false;
+            }
+            else
+                d_inputs[5].cnt_flag = true;
+        }
+    }
+}
+
+// IN_5 GPIOA_3
+void EXINT3_IRQHandler(void)
+{
+    if(exint_flag_get(EXINT_LINE_3) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_3);
+        if (d_inputs[4].mode == 0)
+            d_inputs[4].p_flag = true;
+        else { 
+            if (d_inputs[4].cnt_flag) {
+                di_cnt[4]++;
+                d_inputs[4].cnt_flag = false;
+            }
+            else
+                d_inputs[4].cnt_flag = true;
+        }
+    }
+}
+
+// IN_1, IN_2, IN_3, IN_4
+void EXINT15_10_IRQHandler(void)
+{
+    // IN_2 GPIOB_10
+    if (exint_flag_get(EXINT_LINE_10) != RESET)  
+    {
+        exint_flag_clear(EXINT_LINE_10);
+        if (d_inputs[1].mode == 0)
+            d_inputs[1].p_flag = true;
+        else { 
+            if (d_inputs[1].cnt_flag) {
+                di_cnt[1]++;
+                d_inputs[1].cnt_flag = false;
+            }
+            else
+                d_inputs[1].cnt_flag = true;
+        }
+    }
+    // IN_1 GPIOB_11
+    else if (exint_flag_get(EXINT_LINE_11) != RESET)  
+    {
+        exint_flag_clear(EXINT_LINE_11);
+        if (d_inputs[0].mode == 0)
+            d_inputs[0].p_flag = true;
+        else { 
+            if (d_inputs[0].cnt_flag) {
+                di_cnt[0]++;
+                d_inputs[0].cnt_flag = false;
+            }
+            else
+                d_inputs[0].cnt_flag = true;
+        }
+    }
+    // IN_3 GPIOE_14
+    else if (exint_flag_get(EXINT_LINE_14) != RESET)  
+    {
+        exint_flag_clear(EXINT_LINE_14);
+        if (d_inputs[2].mode == 0)
+            d_inputs[2].p_flag = true;
+        else { 
+            if (d_inputs[2].cnt_flag) {
+                di_cnt[2]++;
+                d_inputs[2].cnt_flag = false;
+            }
+            else
+                d_inputs[2].cnt_flag = true;
+        }
+    }
+    // IN_4 GPIOE_15
+    else if (exint_flag_get(EXINT_LINE_15) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_15);
+        if (d_inputs[3].mode == 0)
+            d_inputs[3].p_flag = true;
+        else { 
+            if (d_inputs[3].cnt_flag) {
+                di_cnt[3]++;
+                d_inputs[3].cnt_flag = false;
+            }
+            else
+                d_inputs[3].cnt_flag = true;
+        }
+    }    
+}
+
+#endif

+ 54 - 49
fw/modules/io/digital_input.h

@@ -1,49 +1,54 @@
-#ifndef __DIGITAL_INPUT_H
-#define __DIGITAL_INPUT_H
-
-#include <stdbool.h>
-#include "io.h"
-
-//
-void di_init(void);
-
-//
-void di_base_init(din_t *input);
-
-//
-void di_exti_init(void);
-
-// 
-void di_tim_init(void);
-
-//
-void di_load_sens_init(simple_gpio_t *sens);
-
-//
-void di_set(void);
-
-//
-uint8_t di_get(uint8_t channel);
-
-//
-void debounce(void);
-
-// Периодический опрос входов и датчиков обрыва нагрузки
-void di_task(void *params);
-
-
-
-extern uint32_t di_cnt[DI_NUMBER];   // счетчики входов
-
-extern uint16_t di_state[DI_NUMBER]; // состояние входа
-extern uint16_t di_state_bit;        // битовое поле
-
-extern uint16_t di_load_state[DO_NUMBER];  // состояние датчиков нагрузки
-extern uint16_t di_load_state_bit;
-
-extern uint16_t di_credibility_state[DO_NUMBER];  // достоверность состояния датчиков нагрузки
-extern uint16_t di_credibility_state_bit;  // достоверность состояния датчиков нагрузки
-
-
-#endif  // __DIGITAL_INPUT_H
-
+#ifndef __DIGITAL_INPUT_H
+#define __DIGITAL_INPUT_H
+
+#include <stdbool.h>
+#include "io.h"
+
+
+
+//
+void di_init(void);
+
+//
+void di_base_init(din_t *input);
+
+//
+void di_exti_init(void);
+
+// 
+void di_tim_init(void);
+
+//
+void di_load_sens_init(simple_gpio_t *sens);
+
+//
+void di_set_state(void);
+
+//
+void di_set(void);
+
+//
+uint8_t di_get(uint8_t channel);
+
+//
+void debounce(void);
+
+// Периодический опрос входов и датчиков обрыва нагрузки
+void di_task(void *params);
+
+
+
+extern uint32_t di_cnt[DI_NUMBER];   // счетчики входов
+
+extern uint16_t di_state[DI_NUMBER]; // состояние входа
+extern uint16_t di_state_bit;        // битовое поле
+
+extern uint16_t di_load_state[DO_NUMBER];  // состояние датчиков нагрузки
+extern uint16_t di_load_state_bit;
+
+extern uint16_t di_credibility_state[DO_NUMBER];  // достоверность состояния датчиков нагрузки
+extern uint16_t di_credibility_state_bit;  // достоверность состояния датчиков нагрузки
+
+
+#endif  // __DIGITAL_INPUT_H
+

+ 121 - 114
fw/modules/io/io.h

@@ -1,114 +1,121 @@
-#ifndef __IO_H
-#define __IO_H
-
-#include <stdbool.h>
-
-
-// -------------------------------------------------------------------------- //
-// Дискретые входы
-
-#define DI_NUMBER           8   // Количество входов
-
-#define DI_MODE_IN          0   // Режим обычного входа
-
-#define DI_MODE_CNT         1   // Режим счетного входа
-
-
-// -------------------------------------------------------------------------- //
-// Дискретные выходы
-
-#define DO_NUMBER           8   // Количество выходов
-
-#define DEBOUNCE_CNT        50
-
-// -------------------------------------------------------------------------- //
-// Аналоговые входы. 
-
-#define AI_ALL_NUMBER       16  // Общее количество
-
-#define AI_COMMON_NUMBER    12  // Основные 12
-
-#define AI_ADD_NUMBER       4   // Дополнительные 4 входа
-
-// -------------------------------------------------------------------------- //
-// Аналоговые выходы. 
-
-#define AO_NUMBER           4   // Количество выходов
-
-// -------------------------------------------------------------------------- //
-
-//
-void io_port_enable(void);
-
-
-// -------------------------------------------------------------------------- //
-
-typedef struct
-{
-    gpio_type *port;
-    uint16_t pin;
-    
-} simple_gpio_t;
-
-
-typedef struct 
-{
-    gpio_type *port;
-    uint16_t pin;
-    uint16_t mode;  // 0 - обычный вход, 1 - счетный вход
-    uint32_t deb_counter;
-    uint32_t cnt;
-    bool p_flag;
-    bool cnt_flag;
-    
-} din_t;
-
-
-typedef struct
-{
-    gpio_type *port;
-    uint16_t pin;
-    uint16_t mode;  // 0 - обычный выход, 1 - режим ШИМ
-    uint16_t pwm_period_cnt;
-    uint16_t pwm_duty_cnt;
-    uint16_t pwm_flag;
-    uint16_t pwm_period;
-    uint16_t pwm_duty;
-    
-} out_t;
-
-
-extern uint16_t output_state_bit;
-extern uint16_t output_mode_bit;
-extern uint16_t output_pwm[];
-extern uint16_t output_pwm_save[];
-extern uint16_t output_pwm_period[];
-extern uint16_t output_pwm_period_save[];
-
-
-//
-// контроль состояний - обрыв, КЗ, норма
-typedef struct
-{
-    uint16_t state;         // состояние выхода
-    uint16_t pwm;           // 
-    uint16_t mode;          // режим работы, 0 - выход, 1 - PWM
-    uint16_t smode_state;   // значение в безопасном режиме,
-                            // 0 - разомкнут, 1 - замкнут
-    uint16_t smode_pwm;     // значение PWM в безопасном режиме (%)
-    uint16_t normal_state;  // нормальное состояние выхода
-                            // 0 - разомкнут, 1 - замкнут
-} output_t;
-
-
-typedef struct
-{
-    uint16_t smode;         // безопасный режим 0 - включен, 1 - выключен
-    uint16_t com_timeout;   // время ожидания запроса от мастера
-} system_t;
-
-
-
-
-#endif  // __IO_H
-
+#ifndef __IO_H
+#define __IO_H
+
+#include <stdbool.h>
+
+
+// -------------------------------------------------------------------------- //
+// Дискретые входы
+
+#define DI_NUMBER           8   // Количество входов
+
+#define DI_MODE_IN          0   // Режим обычного входа
+
+#define DI_MODE_CNT         1   // Режим счетного входа
+
+
+// -------------------------------------------------------------------------- //
+// Дискретные выходы
+
+#define DO_NUMBER           8   // Количество выходов
+
+#define DEBOUNCE_CNT        50
+
+// -------------------------------------------------------------------------- //
+// Аналоговые входы. 
+
+#define AI_ALL_NUMBER       16  // Общее количество
+
+#define AI_COMMON_NUMBER    12  // Основные 12
+
+#define AI_ADD_NUMBER       4   // Дополнительные 4 входа
+
+// -------------------------------------------------------------------------- //
+// Аналоговые выходы. 
+
+#define AO_NUMBER           4   // Количество выходов
+
+// -------------------------------------------------------------------------- //
+
+//
+void io_port_enable(void);
+
+
+// -------------------------------------------------------------------------- //
+
+typedef struct
+{
+    gpio_type *port;
+    uint16_t pin;
+    
+} simple_gpio_t;
+
+
+typedef struct
+{
+    uint8_t state;          // 0 - выкл, 1 - вкл
+    
+} di_t;
+
+
+typedef struct 
+{
+    gpio_type *port;
+    uint16_t pin;
+    uint16_t mode;  // 0 - обычный вход, 1 - счетный вход
+    uint32_t deb_counter;
+    uint32_t cnt;
+    bool p_flag;
+    bool cnt_flag;
+    
+} din_t;
+
+
+typedef struct
+{
+    gpio_type *port;
+    uint16_t pin;
+    uint16_t mode;  // 0 - обычный выход, 1 - режим ШИМ
+    uint16_t pwm_period_cnt;
+    uint16_t pwm_duty_cnt;
+    uint16_t pwm_flag;
+    uint16_t pwm_period;
+    uint16_t pwm_duty;
+    
+} out_t;
+
+
+extern uint16_t output_state_bit;
+extern uint16_t output_mode_bit;
+extern uint16_t output_pwm[];
+extern uint16_t output_pwm_save[];
+extern uint16_t output_pwm_period[];
+extern uint16_t output_pwm_period_save[];
+
+
+//
+// контроль состояний - обрыв, КЗ, норма
+typedef struct
+{
+    uint16_t state;         // состояние выхода
+    uint16_t pwm;           // 
+    uint16_t mode;          // режим работы, 0 - выход, 1 - PWM
+    uint16_t smode_state;   // значение в безопасном режиме,
+                            // 0 - разомкнут, 1 - замкнут
+    uint16_t smode_pwm;     // значение PWM в безопасном режиме (%)
+    uint16_t normal_state;  // нормальное состояние выхода
+                            // 0 - разомкнут, 1 - замкнут
+} output_t;
+
+
+typedef struct
+{
+    uint16_t smode;         // безопасный режим 0 - включен, 1 - выключен
+    uint16_t com_timeout;   // время ожидания запроса от мастера
+} system_t;
+
+
+
+
+#endif  // __IO_H
+

+ 146 - 145
fw/modules/log/log_dio.c

@@ -1,145 +1,146 @@
-#include "at32f403a_407.h"
-#include "log_dio.h"
-#include "settings_api.h"
-#include "ringfs.h"
-#include "ringfs_api.h"
-
-
-#if defined (MDIO_88)
-
-
-#undef DBG
-#define DBG if(1)
-
-
-EventGroupHandle_t archive_event;
-
-uint32_t archive_cnt[ARCH_DIO_CH_NUMBER] = {0};
-
-struct ringfs fs_ch_arch[ARCH_DIO_CH_NUMBER];
-
-
-static struct ringfs_flash_partition fingfs_flash_ch_arch[ARCH_DIO_CH_NUMBER] = 
-{
-    {
-        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET,
-        .sector_erase = op_sector_erase,
-        .program = op_program,
-        .read = op_read,
-    },
-    {
-        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*1,
-        .sector_erase = op_sector_erase,
-        .program = op_program,
-        .read = op_read,
-    },
-    {
-        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*2,
-        .sector_erase = op_sector_erase,
-        .program = op_program,
-        .read = op_read,
-    },
-    {
-        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*3,
-        .sector_erase = op_sector_erase,
-        .program = op_program,
-        .read = op_read,
-    },
-    {
-        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*4,
-        .sector_erase = op_sector_erase,
-        .program = op_program,
-        .read = op_read,
-    },
-    {
-        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*5,
-        .sector_erase = op_sector_erase,
-        .program = op_program,
-        .read = op_read,
-    },
-    {
-        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*6,
-        .sector_erase = op_sector_erase,
-        .program = op_program,
-        .read = op_read,
-    },
-    {
-        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*7,
-        .sector_erase = op_sector_erase,
-        .program = op_program,
-        .read = op_read,
-    },
-};
-
-
-// Архив. 8 буферов на каждый канал.
-void log_dio_archive_init(void)
-{
-    for (uint8_t i = 0; i < ARCH_DIO_CH_NUMBER; i ++) 
-    {
-        fingfs_flash_ch_arch[i].sector_size = spi_flash_desc.sector_size;
-        
-        fingfs_flash_ch_arch[i].sector_count = ARCHIVE_FLASH_SECTOR_COUNT;
-        
-        ringfs_init(&fs_ch_arch[i], &fingfs_flash_ch_arch[i], 
-                    ARCHIV_ENTRY_VERSION + i, sizeof(archive_entry_t));
-        
-        if (ringfs_scan(&fs_ch_arch[i]) != 0) {
-            DBG printf("FAT for channel %u is false\r\n", i + 1);
-            ringfs_format(&fs_ch_arch[i]);
-        }
-        DBG printf("FAT for channel %u is true\r\n", i + 1);
-    }
-}
-    
-    
-//
-uint8_t log_get_arch_channel_number(void)
-{
-    return (uint8_t)ARCH_DIO_CH_NUMBER;
-}
-
-
-//
-uint8_t log_is_channel_on(uint8_t channel)
-{
-    return true;
-}
-
-
-//
-void log_archive_task_device(void)
-{
-    int ret = 0;
-    EventBits_t bits;
-    archive_entry_t entry = {0};
-    
-    bits = xEventGroupWaitBits(archive_event, 
-                               ARCH_CH_1 | ARCH_CH_2 | ARCH_CH_3 | ARCH_CH_4 | 
-                               ARCH_CH_5 | ARCH_CH_6 | ARCH_CH_7 | ARCH_CH_8 |
-                               ARCH_CH_9 | ARCH_CH_10 | ARCH_CH_11 | ARCH_CH_12,
-                               pdTRUE, pdFALSE, portMAX_DELAY);
-     
-    for (uint32_t i = 0; i < ARCH_AI_CH_NUMBER; i++)
-    {
-        if (bits & (1 << i))
-        {
-            DBG printf("Archive event: %u\r\n", (1 << i));
-                
-            entry.timestamp = 0;
-            entry.input_value = di_get(i - 1);
-        
-            DBG printf("Append archive entry...");
-            ret = log_append((void*)&entry, ARCHIVE_ENTRY, i - 1);
-                
-            if (ret != 0) {
-                DBG printf("FAIL\r\n");
-            }
-            else {  
-                DBG printf("OK\r\n");
-            }
-        }
-    }
-}
-
-#endif
+#include "at32f403a_407.h"
+#include "log_dio.h"
+#include "settings_api.h"
+#include "ringfs.h"
+#include "ringfs_api.h"
+#include "digital_input.h"
+
+
+#if defined (MDIO_88)
+
+
+#undef DBG
+#define DBG if(1)
+
+
+EventGroupHandle_t archive_event;
+
+uint32_t archive_cnt[ARCH_DIO_CH_NUMBER] = {0};
+
+struct ringfs fs_ch_arch[ARCH_DIO_CH_NUMBER];
+
+
+static struct ringfs_flash_partition fingfs_flash_ch_arch[ARCH_DIO_CH_NUMBER] = 
+{
+    {
+        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET,
+        .sector_erase = op_sector_erase,
+        .program = op_program,
+        .read = op_read,
+    },
+    {
+        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*1,
+        .sector_erase = op_sector_erase,
+        .program = op_program,
+        .read = op_read,
+    },
+    {
+        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*2,
+        .sector_erase = op_sector_erase,
+        .program = op_program,
+        .read = op_read,
+    },
+    {
+        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*3,
+        .sector_erase = op_sector_erase,
+        .program = op_program,
+        .read = op_read,
+    },
+    {
+        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*4,
+        .sector_erase = op_sector_erase,
+        .program = op_program,
+        .read = op_read,
+    },
+    {
+        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*5,
+        .sector_erase = op_sector_erase,
+        .program = op_program,
+        .read = op_read,
+    },
+    {
+        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*6,
+        .sector_erase = op_sector_erase,
+        .program = op_program,
+        .read = op_read,
+    },
+    {
+        .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET + ARCHIVE_CHANNEL_OFFSET*7,
+        .sector_erase = op_sector_erase,
+        .program = op_program,
+        .read = op_read,
+    },
+};
+
+
+// Архив. 8 буферов на каждый канал.
+void log_dio_archive_init(void)
+{
+    for (uint8_t i = 0; i < ARCH_DIO_CH_NUMBER; i ++) 
+    {
+        fingfs_flash_ch_arch[i].sector_size = spi_flash_desc.sector_size;
+        
+        fingfs_flash_ch_arch[i].sector_count = ARCHIVE_FLASH_SECTOR_COUNT;
+        
+        ringfs_init(&fs_ch_arch[i], &fingfs_flash_ch_arch[i], 
+                    ARCHIV_ENTRY_VERSION + i, sizeof(archive_entry_t));
+        
+        if (ringfs_scan(&fs_ch_arch[i]) != 0) {
+            DBG printf("FAT for channel %u is false\r\n", i + 1);
+            ringfs_format(&fs_ch_arch[i]);
+        }
+        DBG printf("FAT for channel %u is true\r\n", i + 1);
+    }
+}
+    
+    
+//
+uint8_t log_get_arch_channel_number(void)
+{
+    return (uint8_t)ARCH_DIO_CH_NUMBER;
+}
+
+
+//
+uint8_t log_is_channel_on(uint8_t channel)
+{
+    return (bool)settings.di[channel].state;
+}
+
+
+//
+void log_archive_task_device(void)
+{
+    int ret = 0;
+    EventBits_t bits;
+    archive_entry_t entry = {0};
+    
+    bits = xEventGroupWaitBits(archive_event, 
+                               ARCH_CH_1 | ARCH_CH_2 | ARCH_CH_3 | ARCH_CH_4 | 
+                               ARCH_CH_5 | ARCH_CH_6 | ARCH_CH_7 | ARCH_CH_8 |
+                               ARCH_CH_9 | ARCH_CH_10 | ARCH_CH_11 | ARCH_CH_12,
+                               pdTRUE, pdFALSE, portMAX_DELAY);
+     
+    for (uint32_t i = 0; i < ARCH_AI_CH_NUMBER; i++)
+    {
+        if (bits & (1 << i))
+        {
+            DBG printf("Archive event: %u\r\n", (1 << i));
+                
+            entry.timestamp = 0;
+            entry.input_value = di_get(i - 1);
+        
+            DBG printf("Append archive entry...");
+            ret = log_append((void*)&entry, ARCHIVE_ENTRY, i - 1);
+                
+            if (ret != 0) {
+                DBG printf("FAIL\r\n");
+            }
+            else {  
+                DBG printf("OK\r\n");
+            }
+        }
+    }
+}
+
+#endif

+ 237 - 219
fw/modules/modbus/modbus_dio_params.c

@@ -1,219 +1,237 @@
-#include "at32f403a_407.h"
-#include "modbus_dio_params.h"
-#include "modbus_params.h"
-#include "digital_input.h"
-#include "digital_output.h"
-#include "settings_api.h"
-
-extern mb_param_t mb_param[];
-
-#if defined (MDIO_88)
-
-
-//
-uint16_t mb_init_dio_params(uint16_t i)
-{
-    uint16_t index = i;
-    uint16_t addr = 0;  
-  
-    mb_param[index].reg = 0x0100;
-	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&di_state_bit;  // Текущее состояние входов
-	mb_param[index].set = NULL;
-    mb_param[index].get = NULL;
-    mb_param[index].check_handler = mb_check_dummy;
-    
-    index++;
-    
-    // Счетчики импульсов. Регистры 0x0102 - 0x0111
-    addr = 0x0102;
-    for (int i = 0; i < DI_NUMBER; i++)
-    {
-        mb_param[index].reg = addr;
-        mb_param[index].size = 2;
-        mb_param[index].param = (uint8_t*)&di_cnt[i];  // Счетчик ипульсов
-        mb_param[index].set = NULL;
-        mb_param[index].get = NULL;
-        mb_param[index].check_handler = mb_check_dummy;
-        
-        addr += 2;
-        index++;
-    }
-    
-    // Режим работы входов
-    mb_param[index].reg = 0x0120;
-	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&settings.di_mode_bits;  
-	mb_param[index].set = mb_set_din_mode;
-    mb_param[index].get = NULL;
-    mb_param[index].check_handler = mb_check_dummy;
-    
-    index++;
-    
-    // Нормальное состояние входов
-    mb_param[index].reg = 0x0122;
-	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&settings.di_norm_state_bits;  
-	mb_param[index].set = NULL;
-    mb_param[index].get = NULL;
-    mb_param[index].check_handler = mb_check_dummy;
-    
-    index++;
- 
-    // Время антидребезга
-    addr = 0x0124;
-    for (int i = 0; i < DI_NUMBER; i++)
-    {
-        mb_param[index].reg = addr;
-        mb_param[index].size = 1;
-        mb_param[index].param = (uint8_t*)&settings.di_debounce[i];
-        mb_param[index].set = NULL;
-        mb_param[index].get = NULL;
-        mb_param[index].check_handler = mb_check_dummy;
-        
-        addr++;
-        index++;
-    }
-
-    // Текущее состояние датчиков нагрузки
-    mb_param[index].reg = 0x0130;
-	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&di_load_state_bit;
-	mb_param[index].set = NULL;
-    mb_param[index].get = NULL;
-    mb_param[index].check_handler = mb_check_dummy;
-    
-    index++;
-    
-    // Слово достоверности датчиков нагрузки [1 - показания достоверны, 0 - нет]
-    mb_param[index].reg = 0x0131;
-	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&di_credibility_state_bit;
-	mb_param[index].set = NULL;
-    mb_param[index].get = NULL;
-    mb_param[index].check_handler = mb_check_dummy;
-    
-    index++;
-    
-    // Текущее состояние выходов
-    mb_param[index].reg = 0x0200;
-	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&output_state_bit;  
-	mb_param[index].set = mb_set_do;
-    mb_param[index].get = NULL;
-    mb_param[index].check_handler = mb_check_dummy;
-    
-    index++;
-    
-    // Режим работы выходов
-    mb_param[index].reg = 0x0202;
-	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&output_mode_bit;  
-	mb_param[index].set = mb_set_do_mode;
-    mb_param[index].get = NULL;
-    mb_param[index].check_handler = mb_check_dummy;
-    
-    index++;
-    
-    // Состояние выходов в безопасном режиме
-    mb_param[index].reg = 0x0203;
-	mb_param[index].size = 1;
-	mb_param[index].param = (uint8_t*)&settings.do_save_bits;  
-	mb_param[index].set = mb_set_do;
-    mb_param[index].get = NULL;
-    mb_param[index].check_handler = mb_check_dummy;
-    
-    index++;
-    
-    // Заполнение PWM. Регистры 0x0210 - 0x0217
-    addr = 0x0210;
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        mb_param[index].reg = addr;
-        mb_param[index].size = 1;
-        mb_param[index].param = (uint8_t*)&output_pwm[i];  // Счетчик ипульсов
-        mb_param[index].set = mb_set_do;
-        mb_param[index].get = NULL;
-        mb_param[index].check_handler = mb_check_dummy;
-        
-        addr++;
-        index++;
-    }
-    
-    // Заполнение PWM в безопасном режиме. Регистры 0x0220 - 0x0227
-    addr = 0x0220;
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        mb_param[index].reg = addr;
-        mb_param[index].size = 1;
-        mb_param[index].param = (uint8_t*)&output_pwm_save[i];  // Счетчик ипульсов
-        mb_param[index].set = mb_set_do;
-        mb_param[index].get = NULL;
-        mb_param[index].check_handler = mb_check_dummy;
-        
-        addr++;
-        index++;
-    }
-    
-    // Период PWM. Регистры 0x0220 - 0x0227
-    addr = 0x0230;
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        mb_param[index].reg = addr;
-        mb_param[index].size = 1;
-        mb_param[index].param = (uint8_t*)&output_pwm_period[i];  // Счетчик ипульсов
-        mb_param[index].set = mb_set_do;
-        mb_param[index].get = NULL;
-        mb_param[index].check_handler = mb_check_dummy;
-        
-        addr++;
-        index++;
-    }
-    
-    // Период PWM. Регистры 0x0220 - 0x0227
-    addr = 0x0240;
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        mb_param[index].reg = addr;
-        mb_param[index].size = 1;
-        mb_param[index].param = (uint8_t*)&output_pwm_period_save[i];  // Счетчик ипульсов
-        mb_param[index].set = mb_set_do;
-        mb_param[index].get = NULL;
-        mb_param[index].check_handler = mb_check_dummy;
-        
-        addr++;
-        index++;
-    }
-    
-    return index;
-}
-
-
-
-// -------------------------------------------------------------------------- //
-//                          Установка параметров
-// -------------------------------------------------------------------------- //
-
-//
-mb_delay_action_t mb_set_din_mode(void)
-{
-    di_set();
-    return MB_NO_ACTION;
-}
-
-//
-mb_delay_action_t mb_set_do(void)
-{
-    do_set_common();
-    return MB_NO_ACTION;
-}
-
-//
-mb_delay_action_t mb_set_do_mode(void)
-{
-    do_set_mode();
-    return MB_NO_ACTION;
-}
-
-#endif
-
+#include "at32f403a_407.h"
+#include "modbus_dio_params.h"
+#include "modbus_params.h"
+#include "digital_input.h"
+#include "digital_output.h"
+#include "settings_api.h"
+
+extern mb_param_t mb_param[];
+
+#if defined (MDIO_88)
+
+
+//
+uint16_t mb_init_dio_params(uint16_t i)
+{
+    uint16_t index = i;
+    uint16_t addr = 0;  
+  
+    // Статус дискретных входов (вкл./выкл.)
+    mb_param[index].reg = 0x0100;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&settings.di_state_bits;  
+	mb_param[index].set = mb_set_di_state;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+  
+    // Текущее состояние входов
+    mb_param[index].reg = 0x0101;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&di_state_bit;  
+	mb_param[index].set = NULL;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // Счетчики импульсов. Регистры 0x0102 - 0x0111
+    addr = 0x0102;
+    for (int i = 0; i < DI_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 2;
+        mb_param[index].param = (uint8_t*)&di_cnt[i]; 
+        mb_param[index].set = NULL;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr += 2;
+        index++;
+    }
+    
+    // Режим работы входов
+    mb_param[index].reg = 0x0120;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&settings.di_mode_bits;  
+	mb_param[index].set = mb_set_din_mode;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // Нормальное состояние входов
+    mb_param[index].reg = 0x0122;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&settings.di_norm_state_bits;  
+	mb_param[index].set = NULL;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+ 
+    // Время антидребезга
+    addr = 0x0124;
+    for (int i = 0; i < DI_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 1;
+        mb_param[index].param = (uint8_t*)&settings.di_debounce[i];
+        mb_param[index].set = NULL;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr++;
+        index++;
+    }
+
+    // Текущее состояние датчиков нагрузки
+    mb_param[index].reg = 0x0130;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&di_load_state_bit;
+	mb_param[index].set = NULL;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // Слово достоверности датчиков нагрузки [1 - показания достоверны, 0 - нет]
+    mb_param[index].reg = 0x0131;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&di_credibility_state_bit;
+	mb_param[index].set = NULL;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // Текущее состояние выходов
+    mb_param[index].reg = 0x0200;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&output_state_bit;  
+	mb_param[index].set = mb_set_do;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // Режим работы выходов
+    mb_param[index].reg = 0x0202;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&output_mode_bit;  
+	mb_param[index].set = mb_set_do_mode;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // Состояние выходов в безопасном режиме
+    mb_param[index].reg = 0x0203;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&settings.do_save_bits;  
+	mb_param[index].set = mb_set_do;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // Заполнение PWM. Регистры 0x0210 - 0x0217
+    addr = 0x0210;
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 1;
+        mb_param[index].param = (uint8_t*)&output_pwm[i];  // Счетчик ипульсов
+        mb_param[index].set = mb_set_do;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr++;
+        index++;
+    }
+    
+    // Заполнение PWM в безопасном режиме. Регистры 0x0220 - 0x0227
+    addr = 0x0220;
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 1;
+        mb_param[index].param = (uint8_t*)&output_pwm_save[i];  // Счетчик ипульсов
+        mb_param[index].set = mb_set_do;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr++;
+        index++;
+    }
+    
+    // Период PWM. Регистры 0x0220 - 0x0227
+    addr = 0x0230;
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 1;
+        mb_param[index].param = (uint8_t*)&output_pwm_period[i];  // Счетчик ипульсов
+        mb_param[index].set = mb_set_do;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr++;
+        index++;
+    }
+    
+    // Период PWM. Регистры 0x0220 - 0x0227
+    addr = 0x0240;
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 1;
+        mb_param[index].param = (uint8_t*)&output_pwm_period_save[i];  // Счетчик ипульсов
+        mb_param[index].set = mb_set_do;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr++;
+        index++;
+    }
+    
+    return index;
+}
+
+
+
+// -------------------------------------------------------------------------- //
+//                          Установка параметров
+// -------------------------------------------------------------------------- //
+
+//
+mb_delay_action_t mb_set_di_state(void)
+{
+    di_set_state();
+    return MB_SAVE_SETTINGS;
+}
+
+//
+mb_delay_action_t mb_set_din_mode(void)
+{
+    di_set();
+    return MB_NO_ACTION;
+}
+
+//
+mb_delay_action_t mb_set_do(void)
+{
+    do_set_common();
+    return MB_NO_ACTION;
+}
+
+//
+mb_delay_action_t mb_set_do_mode(void)
+{
+    do_set_mode();
+    return MB_NO_ACTION;
+}
+
+#endif
+

+ 39 - 36
fw/modules/modbus/modbus_dio_params.h

@@ -1,37 +1,40 @@
-#ifndef __MODBUS_DIO_PARAMS_H
-#define __MODBUS_DIO_PARAMS_H
-
-#include "mb.h"
-#include "mbport.h"
-#include "modbus.h"
-#include <stdbool.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-  
-//
-uint16_t mb_init_dio_params(uint16_t i);
-  
-// -------------------------------------------------------------------------- //
-//                          Установка параметров
-// -------------------------------------------------------------------------- //
-
-//
-mb_delay_action_t mb_set_din_mode(void);
-
-//
-mb_delay_action_t mb_set_do(void);
-
-//
-mb_delay_action_t mb_set_do_mode(void);
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
+#ifndef __MODBUS_DIO_PARAMS_H
+#define __MODBUS_DIO_PARAMS_H
+
+#include "mb.h"
+#include "mbport.h"
+#include "modbus.h"
+#include <stdbool.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  
+//
+uint16_t mb_init_dio_params(uint16_t i);
+  
+// -------------------------------------------------------------------------- //
+//                          Установка параметров
+// -------------------------------------------------------------------------- //
+
+//
+mb_delay_action_t mb_set_di_state(void);
+
+//
+mb_delay_action_t mb_set_din_mode(void);
+
+//
+mb_delay_action_t mb_set_do(void);
+
+//
+mb_delay_action_t mb_set_do_mode(void);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif // __MODBUS_DIO_PARAMS_H
 #endif // __MODBUS_DIO_PARAMS_H

+ 244 - 238
fw/modules/settings/settings_api.h

@@ -1,238 +1,244 @@
-#ifndef SETTINGS_API_H
-#define SETTINGS_API_H
-
-#include "at32f403a_407.h"
-#include "model_cfg.h"
-#include "usart.h"
-#include "sys_api.h"
-#include "io.h"
-#include "mb.h"
-#include "mbport.h"
-#include "log.h"
-#include "analog_input.h"
-#include "analog_output.h"
-#include <stdbool.h>
-
-
-// Изменить версию если поменялась структура настроек
-#define SETTINGS_VERSION    0x01
-
-
-// ------------------------------------------------------------------- //
-//					 	Граничные значения
-// ------------------------------------------------------------------- //
-
-#define MAX_ARCHIVE_PERIOD  43200
-
-// ------------------------------------------------------------------- //
-//					 	Настройки лога и архива
-// ------------------------------------------------------------------- //
-
-#define ARCH_DIO_CH_NUMBER              8
-
-#define ARCH_AI_CH_NUMBER               12 //12  
-
-
-// ------------------------------------------------------------------- //
-//					 		Draft
-// ------------------------------------------------------------------- //
-
-/*
-1. Uptime (uint32_t)                    // +
-2. Realtime (unix timestamp, uint32_t)  // +
-3. Версия прошивки                      // +
-4. Модель (char 16 байт)                // +
-
-*/
-
-
-
-// ------------------------------------------------------------------- //
-//					 		Modbus
-// ------------------------------------------------------------------- //
-
-#define MB_STOP_BIT_MASK    0x03
-#define MB_STOP_BIT_1       0x00
-#define MB_STOP_BIT_2       0x02
-
-#define MB_PARITY_MASK      (0x03 << 3)
-#define MB_NO_PAR           (0x00 << 3)
-#define MB_EVEN_PAR         (0x02 << 3)
-#define MB_ODD_PAR          (0x03 << 3)
-
-#define MB_BRD_MASK         (0x07 << 5)
-#define MB_BRD_2400         (0x00 << 5)
-#define MB_BRD_4800         (0x01 << 5)
-#define MB_BRD_9600         (0x02 << 5)
-#define MB_BRD_19200        (0x03 << 5)
-#define MB_BRD_38400        (0x04 << 5)
-#define MB_BRD_57600        (0x05 << 5)
-#define MB_BRD_115200       (0x06 << 5)
-
-
-
-// Modbus 
-typedef struct
-{
-	rate_t     baud;		// Скорость порта 
-	parity_t   parity;		// Четность 
-	databits_t databits;	// Число бит данных
-	stopbits_t stopbits;	// Число стоп-бит  
-    
-} modbus_t;
-
-
-// Общая структура настроек для IAP и FW
-typedef struct
-{
-    uint16_t    mb_port;    // Настройки порта для modbus
-    //char model[MODEL_LEN];  // Модель
-} com_settings_t;
-
-
-#if 0
-// Дискретные входы
-typedef struct
-{
-    uint16_t debounce_time; // период антидребезга в мс (0 - 10 сек)
-} dinput_t;
-#endif
-
-
-// Полная структура настроек
-typedef struct
-{
-    com_settings_t  com_settings;
-    uint32_t    critical_section_crc;
-/* WARNING! До поля CritSecCRC включительно структура настроек должна быть
-* идентичной между бутлоадером и основным ПО и не должна изменяться при обновлении ПО.
-* Контроль целостности настроек внутри IAP выполняется только для критической секции,
-* т.к. контроль целостности всей структуры не имеет смысла
-* (структура настроек всегда будет отличаться внутри основного ПО).
-* В случае повреждения критического сектора, загружаются параметры по умолчанию. */    
-    
-    uint16_t    settings_version;   // Версия структуры настроек 
-    uint32_t    control_word;       // Слово для контроля целостности структуры настроек
-    
-#if defined (MDIO_88)          
-    uint16_t    di_mode_bits;          // режим работы, 0 - вход, 1 - счетчик импульсов
-    uint16_t    di_norm_state_bits;    // нормальное состояние (0 - разомкнут, 1 - замкнут)        
-    uint16_t    di_debounce[DI_NUMBER]; // Дискретные входы
-    
-    uint16_t    do_mode_bits;       // режим работы выхода 0 - выход, 1 - ШИМ
-    uint16_t    do_bits;            // последнее сохраненное значение на выходах
-    uint16_t    do_save_bits;       // значение на выходах в бесопасном режиме работы
-    uint16_t    do_pwm[DO_NUMBER];  // значение заполнения ШИМ
-    uint16_t    do_pwm_save[DO_NUMBER]; // значение заполнения ШИМ в безопасном режиме
-    uint16_t    do_pwm_period[DO_NUMBER];  // период ШИМ в [0.1с (10..1000)]
-    uint16_t    do_pwm_period_save[DO_NUMBER]; // период ШИМ в безопасном режиме [0.1с (10..1000)]
-    
-    uint16_t    period_archive[ARCH_DIO_CH_NUMBER]; // период архивирования
-#endif
-
-#if defined (MAI_12)
-    ai_t        ai[AI_COMMON_NUMBER];   // 
-    ai_t        ai_add[AI_ADD_NUMBER];  //
-     
-    uint16_t    ai_state_bits;      // статус входа (для 12 основных), 0 - выкл, 1 - вкл
-    uint16_t    ai_mode_bits;       // режим работы входов (для 12 основных), 0 - измерение напряжения, 1 - тока
-    uint16_t    ext_sens_power;     // питание внешних датчиков, 0 - выкл, 1 - вкл
-    
-    uint16_t    period_archive[ARCH_AI_CH_NUMBER]; // период архивирования
-#endif    
-
-#if defined (MAO_4)    
-    
-    ao_t        ao[AO_NUMBER];      // параметры выходов 
-    ao_t        ao_save[AO_NUMBER]; // параметры выходов в безопасном режиме
-    
-    uint16_t    ao_state_bits;      // статус выхода, 0 - выкл, 1 - вкл
-    uint16_t    ao_state_save_bits; // статус выхода в безопасном режиме, 0 - выкл, 1 - вкл
-    uint16_t    ao_mode_bits;       // режим работы выходов, 0 - напряжения, 1 - ток
-    uint16_t    ao_mode_save_bits;  // режим работы выходов в безопасном режиме, 0 - напряжения, 1 - ток
-    
-#endif    
-    
-    bool        save_mode;          // безопасный режим, 0 - выкл, 1 - вкл
-    uint16_t    save_delay;         // время ожидания опроса (сек.)
-      
-    uint8_t     info[32];           // Пользовательская информация. Текстовая строка.
-    
-    
-} settings_t;
-
-
-
-// Загрузка структуры настроек из flesh
-void settings_load(settings_t *settings);
-
-//
-void init_settings(void);
-
-//
-void settings_read_from_flash(uint8_t *data, uint32_t size);
-
-//
-uint32_t settings_get_crc(settings_t *settings);
-
-//
-uint32_t settings_get_crit_sec_crc(settings_t *settings);
-
-// Сброс всех настроек в значения по умолчанию
-void settings_set_all_default(void);
-
-
-// -------------------------------------------------------------------------- //
-// Настройки по умолчанию
-
-//
-void settings_set_modbus_def(uint16_t *mb_port);
-
-//
-void settings_conv_modbus_def(modbus_t *mb_settings, uint16_t *mb_port);
-
-// Установка параметров Modbus
-void settings_set_modbus_params(uint16_t mb_port);
-
-//
-uint32_t settings_get_mb_baud(modbus_t *mb_settings);
-
-//
-eMBParity settings_get_mb_par(modbus_t *mb_settings);
-
-//
-void settings_init_mb_port(uint8_t mb_addr);
-
-// -------------------------------------------------------------------------- //
-
-// Запись структуры настроек во flash
-bool settings_save(settings_t *settings);
-
-//
-bool settings_save_with_log(void);
-
-//
-bool settings_write_to_flash(uint8_t *data, uint32_t size);
-
-// Очистка сектора настроек
-void settings_erase_flash_sector(void);
-
-//
-bool settings_is_changed(settings_t *new_settings);
-
-//
-void settings_print(void);
-
-
-// Системные настройки
-extern sys_settings_t sys_settings;
-
-// Копия системных настроек
-extern sys_settings_t temp_sys_settings;
-
-// Общая структура настроек
-extern settings_t settings;
-
-
-#endif /* #ifndef SETTINGS_API_H */
-
+#ifndef SETTINGS_API_H
+#define SETTINGS_API_H
+
+#include "at32f403a_407.h"
+#include "model_cfg.h"
+#include "usart.h"
+#include "sys_api.h"
+#include "io.h"
+#include "mb.h"
+#include "mbport.h"
+#include "log.h"
+#include "analog_input.h"
+#include "analog_output.h"
+#include <stdbool.h>
+
+
+// Изменить версию если поменялась структура настроек
+#define SETTINGS_VERSION    0x01
+
+
+// ------------------------------------------------------------------- //
+//					 	Граничные значения
+// ------------------------------------------------------------------- //
+
+#define MAX_ARCHIVE_PERIOD  43200
+
+// ------------------------------------------------------------------- //
+//					 	Настройки лога и архива
+// ------------------------------------------------------------------- //
+
+#define ARCH_DIO_CH_NUMBER              8
+
+#define ARCH_AI_CH_NUMBER               12 //12  
+
+
+// ------------------------------------------------------------------- //
+//					 		Draft
+// ------------------------------------------------------------------- //
+
+/*
+1. Uptime (uint32_t)                    // +
+2. Realtime (unix timestamp, uint32_t)  // +
+3. Версия прошивки                      // +
+4. Модель (char 16 байт)                // +
+
+*/
+
+
+
+// ------------------------------------------------------------------- //
+//					 		Modbus
+// ------------------------------------------------------------------- //
+
+#define MB_STOP_BIT_MASK    0x03
+#define MB_STOP_BIT_1       0x00
+#define MB_STOP_BIT_2       0x02
+
+#define MB_PARITY_MASK      (0x03 << 3)
+#define MB_NO_PAR           (0x00 << 3)
+#define MB_EVEN_PAR         (0x02 << 3)
+#define MB_ODD_PAR          (0x03 << 3)
+
+#define MB_BRD_MASK         (0x07 << 5)
+#define MB_BRD_2400         (0x00 << 5)
+#define MB_BRD_4800         (0x01 << 5)
+#define MB_BRD_9600         (0x02 << 5)
+#define MB_BRD_19200        (0x03 << 5)
+#define MB_BRD_38400        (0x04 << 5)
+#define MB_BRD_57600        (0x05 << 5)
+#define MB_BRD_115200       (0x06 << 5)
+
+
+
+// Modbus 
+typedef struct
+{
+	rate_t     baud;		// Скорость порта 
+	parity_t   parity;		// Четность 
+	databits_t databits;	// Число бит данных
+	stopbits_t stopbits;	// Число стоп-бит  
+    
+} modbus_t;
+
+
+// Общая структура настроек для IAP и FW
+typedef struct
+{
+    uint16_t    mb_port;    // Настройки порта для modbus
+    //char model[MODEL_LEN];  // Модель
+} com_settings_t;
+
+
+#if 0
+// Дискретные входы
+typedef struct
+{
+    uint16_t debounce_time; // период антидребезга в мс (0 - 10 сек)
+} dinput_t;
+#endif
+
+
+// Полная структура настроек
+typedef struct
+{
+    com_settings_t  com_settings;
+    uint32_t    critical_section_crc;
+/* WARNING! До поля CritSecCRC включительно структура настроек должна быть
+* идентичной между бутлоадером и основным ПО и не должна изменяться при обновлении ПО.
+* Контроль целостности настроек внутри IAP выполняется только для критической секции,
+* т.к. контроль целостности всей структуры не имеет смысла
+* (структура настроек всегда будет отличаться внутри основного ПО).
+* В случае повреждения критического сектора, загружаются параметры по умолчанию. */    
+    
+    uint16_t    settings_version;   // Версия структуры настроек 
+    uint32_t    control_word;       // Слово для контроля целостности структуры настроек
+    
+#if defined (MDIO_88)          
+    
+    di_t        di[DI_NUMBER];      //
+    uint16_t    di_state_bits;      //
+    
+    
+    
+    uint16_t    di_mode_bits;          // режим работы, 0 - вход, 1 - счетчик импульсов
+    uint16_t    di_norm_state_bits;    // нормальное состояние (0 - разомкнут, 1 - замкнут)        
+    uint16_t    di_debounce[DI_NUMBER]; // Дискретные входы
+    
+    uint16_t    do_mode_bits;       // режим работы выхода 0 - выход, 1 - ШИМ
+    uint16_t    do_bits;            // последнее сохраненное значение на выходах
+    uint16_t    do_save_bits;       // значение на выходах в бесопасном режиме работы
+    uint16_t    do_pwm[DO_NUMBER];  // значение заполнения ШИМ
+    uint16_t    do_pwm_save[DO_NUMBER]; // значение заполнения ШИМ в безопасном режиме
+    uint16_t    do_pwm_period[DO_NUMBER];  // период ШИМ в [0.1с (10..1000)]
+    uint16_t    do_pwm_period_save[DO_NUMBER]; // период ШИМ в безопасном режиме [0.1с (10..1000)]
+    
+    uint16_t    period_archive[ARCH_DIO_CH_NUMBER]; // период архивирования
+#endif
+
+#if defined (MAI_12)
+    ai_t        ai[AI_COMMON_NUMBER];   // 
+    ai_t        ai_add[AI_ADD_NUMBER];  //
+     
+    uint16_t    ai_state_bits;      // статус входа (для 12 основных), 0 - выкл, 1 - вкл
+    uint16_t    ai_mode_bits;       // режим работы входов (для 12 основных), 0 - измерение напряжения, 1 - тока
+    uint16_t    ext_sens_power;     // питание внешних датчиков, 0 - выкл, 1 - вкл
+    
+    uint16_t    period_archive[ARCH_AI_CH_NUMBER]; // период архивирования
+#endif    
+
+#if defined (MAO_4)    
+    
+    ao_t        ao[AO_NUMBER];      // параметры выходов 
+    ao_t        ao_save[AO_NUMBER]; // параметры выходов в безопасном режиме
+    
+    uint16_t    ao_state_bits;      // статус выхода, 0 - выкл, 1 - вкл
+    uint16_t    ao_state_save_bits; // статус выхода в безопасном режиме, 0 - выкл, 1 - вкл
+    uint16_t    ao_mode_bits;       // режим работы выходов, 0 - напряжения, 1 - ток
+    uint16_t    ao_mode_save_bits;  // режим работы выходов в безопасном режиме, 0 - напряжения, 1 - ток
+    
+#endif    
+    
+    bool        save_mode;          // безопасный режим, 0 - выкл, 1 - вкл
+    uint16_t    save_delay;         // время ожидания опроса (сек.)
+      
+    uint8_t     info[32];           // Пользовательская информация. Текстовая строка.
+    
+    
+} settings_t;
+
+
+
+// Загрузка структуры настроек из flesh
+void settings_load(settings_t *settings);
+
+//
+void init_settings(void);
+
+//
+void settings_read_from_flash(uint8_t *data, uint32_t size);
+
+//
+uint32_t settings_get_crc(settings_t *settings);
+
+//
+uint32_t settings_get_crit_sec_crc(settings_t *settings);
+
+// Сброс всех настроек в значения по умолчанию
+void settings_set_all_default(void);
+
+
+// -------------------------------------------------------------------------- //
+// Настройки по умолчанию
+
+//
+void settings_set_modbus_def(uint16_t *mb_port);
+
+//
+void settings_conv_modbus_def(modbus_t *mb_settings, uint16_t *mb_port);
+
+// Установка параметров Modbus
+void settings_set_modbus_params(uint16_t mb_port);
+
+//
+uint32_t settings_get_mb_baud(modbus_t *mb_settings);
+
+//
+eMBParity settings_get_mb_par(modbus_t *mb_settings);
+
+//
+void settings_init_mb_port(uint8_t mb_addr);
+
+// -------------------------------------------------------------------------- //
+
+// Запись структуры настроек во flash
+bool settings_save(settings_t *settings);
+
+//
+bool settings_save_with_log(void);
+
+//
+bool settings_write_to_flash(uint8_t *data, uint32_t size);
+
+// Очистка сектора настроек
+void settings_erase_flash_sector(void);
+
+//
+bool settings_is_changed(settings_t *new_settings);
+
+//
+void settings_print(void);
+
+
+// Системные настройки
+extern sys_settings_t sys_settings;
+
+// Копия системных настроек
+extern sys_settings_t temp_sys_settings;
+
+// Общая структура настроек
+extern settings_t settings;
+
+
+#endif /* #ifndef SETTINGS_API_H */
+

+ 58 - 49
fw/modules/settings/settings_dio.c

@@ -1,49 +1,58 @@
-#include "at32f403a_407.h" 
-#include "settings_api.h"
-#include "settings_dio.h"
-
-#if defined (MDIO_88)
-
-//
-void settings_dio_set_all_default(void)
-{
-    // Дискретные/счетные входы
-    settings_din_def(&settings);
-    
-    // Выходы
-    settings_do_def(&settings);
-    
-    // Время ведения архива по каждому каналу (сек.)
-    for (uint8_t i = 0; i < ARCH_DIO_CH_NUMBER; i++) {
-        settings.period_archive[i] = 3600;
-    }
-}
-
-// Установить параметры дискретных входов по умолчанию
-void settings_din_def(settings_t *settings)
-{
-    settings->di_mode_bits = 0;
-    settings->di_norm_state_bits = 0;
-    
-    for (int i = 0; i < DI_NUMBER; i++) {
-        settings->di_debounce[i] = 50;
-    }
-}
-
-// Выходы
-void settings_do_def(settings_t *settings)
-{
-    settings->do_mode_bits = 0; // режим работы выхода (обычный выход)
-    settings->do_bits = 0;      // последнее сохраненное значение 
-    settings->do_save_bits = 0;
-    
-    for (uint8_t i = 0; i < DO_NUMBER; i++)
-    {
-        settings->do_pwm[i] = 30;
-        settings->do_pwm_save[i] = 30; // значение на выходах в бесопасном режиме работы
-        settings->do_pwm_period[i] = 50;
-        settings->do_pwm_period_save[i] = 50;
-    }
-}
-
-#endif
+#include "at32f403a_407.h" 
+#include "settings_api.h"
+#include "settings_dio.h"
+
+#if defined (MDIO_88)
+
+//
+void settings_dio_set_all_default(void)
+{
+    // Дискретные/счетные входы
+    settings_din_def(&settings);
+    
+    // Выходы
+    settings_do_def(&settings);
+    
+    // Время ведения архива по каждому каналу (сек.)
+    for (uint8_t i = 0; i < ARCH_DIO_CH_NUMBER; i++) {
+        settings.period_archive[i] = 3600;
+    }
+}
+
+// Установить параметры дискретных входов по умолчанию
+void settings_din_def(settings_t *settings)
+{
+    // Все входы выключены
+    settings->di_state_bits = 0;
+    
+    // Параметры входов в обычном режиме
+    for (int i = 0; i < DI_NUMBER; i++) {
+        settings->di[i].state = 0;
+    }
+  
+  
+    settings->di_mode_bits = 0;
+    settings->di_norm_state_bits = 0;
+    
+    for (int i = 0; i < DI_NUMBER; i++) {
+        settings->di_debounce[i] = 50;
+    }
+}
+
+// Выходы
+void settings_do_def(settings_t *settings)
+{
+    settings->do_mode_bits = 0; // режим работы выхода (обычный выход)
+    settings->do_bits = 0;      // последнее сохраненное значение 
+    settings->do_save_bits = 0;
+    
+    for (uint8_t i = 0; i < DO_NUMBER; i++)
+    {
+        settings->do_pwm[i] = 30;
+        settings->do_pwm_save[i] = 30; // значение на выходах в бесопасном режиме работы
+        settings->do_pwm_period[i] = 50;
+        settings->do_pwm_period_save[i] = 50;
+    }
+}
+
+#endif

+ 297 - 295
fw/user/main.cpp

@@ -1,295 +1,297 @@
-#include "at32f403a_407.h"
-#include "at32f403a_407_board.h"
-#include "at32f403a_407_clock.h"
-#include "common_config.h"
-#include "FreeRTOS.h"
-#include "task.h"
-#include "queue.h"
-#include "semphr.h"
-extern "C" {
-#include "usb_eth.h"
-#include "mux.h"
-#include "misc.h"
-#include "spi_common.h"
-#include "user_fatfs.h"
-#include "spi_flash.h"
-#include "usb_eth.h"
-#include "extended_sram.h"
-#include "modbus.h"
-#include "common_gpio.h"
-#include "io.h"
-#include "sys_api.h"
-#include "settings_api.h"
-#include "update.h"
-#include "uptime.h"
-#include "rtc.h"
-#include "mb.h"
-#include "io_utils.h"
-#include "digital_input.h"
-#include "digital_output.h"
-#include "buttons.h"
-#include "adc_transport.h"
-#include "shift_reg.h"
-#include "analog_input.h"
-#include "analog_output.h"
-#include "dac_transport.h"
-#include "log.h"
-#include "swap.h"
-#include "utility.h"
-#include "soft_test.h"
-#include "soft_wdt.h"
-#include "usb_clock.h"
-#include "filter.h"
-#include "modbus_ai_params.h"
-}
-#include "terminal_sbs.h"
-#include "terminal_usartbridge.h"
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdlib.h>
-
-
-void init_task(void *argument);
-
-
-//
-int main(void)
-{
-    __disable_irq();
-    nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x08021000);
-    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
-	__enable_irq();
-  
-    crm_periph_clock_enable(CRM_CRC_PERIPH_CLOCK, TRUE);
-    
-    extend_SRAM();
-  
-    system_clock_config();
-
-    delay_init();
-                    
-    xTaskCreate(init_task, "init_task", 10*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
-        
-    vTaskStartScheduler();
-     
-    while (1) {}
-}
-
-
-void init_task(void *argument)
-{
-// -------------------------------------------------------------------------- //    
-// Software watchdog
-  
-    gpio_wdt_init();
-    xTaskCreate(soft_wdt, "soft_wdt", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);    
-    
-// -------------------------------------------------------------------------
-// CLI
-    
-    sbsTerminal.configure();
-    terminalUsartBridge.configure();    
-    
-// -------------------------------------------------------------------------- //    
-// Настройки. Загрузка и проверка.
-
-    // Мьютекс для работы с настройками
-    init_settings(); 
-    
-    // Системные настройки и копия
-    sys_settings_load(&sys_settings);
-    memcpy(&temp_sys_settings, &sys_settings, sizeof(sys_settings_t));
-    
-    // Основные настройки
-    settings_load(&settings);
-    
-    // Настройки параметров порта Modbus
-    settings_set_modbus_params(settings.com_settings.mb_port);
-    
-#if 0
-// Только для теста    
-    settings_set_all_default();
-    settings_save(&settings);
-#endif
-    
-// -------------------------------------------------------------------------- //    
-// Безопасный режим, входы, выходы
-    
-#if defined (MDIO_88) || (MAO_4)
-    //settings.save_mode = false;
-    save_mode_init();
-#endif
-    
-// -------------------------------------------------------------------------- //
-// Включить тактирование портов
-    
-    io_port_enable();
-
-// -------------------------------------------------------------------------- //            
-// Цифровые входы/выходы
-
-#if defined (MDIO_88)
-    
-    di_init();
-    di_tim_init();
-    do_init();
-    xTaskCreate(di_task, "input_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
-    
-#endif
-    
-#if defined (MAI_12)    
-    
-    ai_init();    
-    xTaskCreate(adc_task, "adc_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
-    
-#endif    
-    
-#if defined (MAO_4)    
-    
-    ao_init();
-    xTaskCreate(dac_task, "dac_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
-    
-#endif 
-    
-// -------------------------------------------------------------------------- //
-// Кнопки [SET, RESET]
-    
-    button_init();
-    xTaskCreate(button_task, "button_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
-    
-// -------------------------------------------------------------------------- //
-// Uptime    
-    
-    uptime_init();
-    
-// -------------------------------------------------------------------------- //
-// RTC    
-    
-    TM_RTC_Init();
-    rtc_subtim_init();
-    
-// -------------------------------------------------------------------------- //    
-// Мультиплексор
-#if 1    
-    mux_gpio_init();
-    xTaskCreate(mux_task, "mux_task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
-#endif    
-// -------------------------------------------------------------------------- //        
-// Modbus    
-    
-    mb_init();
-    
-// -------------------------------------------------------------------------- //        
-// Сброс счетчика попыток загрузок
-    
-    update_reset_boot_try();    
-    
-// -------------------------------------------------------------------------- //    
-// Считать ревизию платы (состояние пинов)
-    
-    gpio_update_rev();
-    
-// -------------------------------------------------------------------------- //    
-// SPI flash, журнал событий, архив
-#if 0
-    common_spi_init();
-    spi_flash_init();
-    
-    log_init(false);
-#endif    
-// -------------------------------------------------------------------------- //
-// Статистика FreeRTOS
-    
-    utl_stat_timer_init();
-    
-// -------------------------------------------------------------------------- //
-// EVENT. Обновление FW.
-#if 0    
-    uint16_t update_status = bpr_data_read(BACKUP_UPDATE_STATUS);
-    
-    if (update_status == IAP_UPDATE_OK)
-        log_add_entry(LOG_UPDATE_FW, LOG_EVENT_STATE_OK, 0, atof(FW_VERSION));
-    else if (update_status == IAP_UPDATE_ERROR)
-        log_add_entry(LOG_UPDATE_FW, LOG_EVENT_STATE_ERR, 0, atof(FW_VERSION));
-        
-    bpr_data_write(BACKUP_UPDATE_STATUS, IAP_UPDATE_NO);
-
-// -------------------------------------------------------------------------- //
-// EVENT. Включение питания/перезагрузка.    
-    
-    log_add_entry(LOG_SYSTEM_BOOT, (log_event_state_t)0, 0, 0);
-#endif   
-// -------------------------------------------------------------------------- //    
-// USB (RNDIS class)
-#ifdef USB_RNDIS    
-    usb_clock48m_select(USB_CLK_HEXT);
-    crm_periph_clock_enable(CRM_USB_PERIPH_CLOCK, TRUE);
-    usb_init();
-    usb_eth_init();
-#endif 
-    
-
-    
-// -------------------------------------------------------------------------- //        
-// Тесты
-
-    //usb_eth_init();
-    //sys_clear();
-    //mux_led_test_init();
-    //pwm_test();
-    
-    // -------------------------------------------------------------------------- //    
-// Сдвиговые регистры и мультиплексоры    
-    //sh_init();
-    
-// Тесты аналоговых входов    
-    //ai_connect_test();
-    //ai_mode_test();
-    //ai_connect_channel(V_ISO);  
-    //ai_connect_channel(AN_INP_1);  
-    //ai_connect_channel(AN_INP_7);  
-    
-// -------------------------------------------------------------------------- //    
-// DAC    
-/*    
-    dac_gpio_init();
-    dac_test(CH_DAC_1, 30000);  
-*/    
-/*    
-    dac_test(CH_DAC_2, 10000);  
-    dac_test(CH_DAC_3, 10000);
-    dac_test(CH_DAC_4, 10000);  
-*/    
-/*    
-    dac_test(CH_DAC_1, 10000);  
-    dac_test(CH_DAC_2, 10000);  
-    dac_test(CH_DAC_3, 10000);
-    dac_test(CH_DAC_4, 10000);  
-*/  
-    
-#if 0
-    // Настройки по умолчанию 
-    settings_set_all_default();
-    settings_save(&settings);
-#endif    
-    
-// -------------------------------------------------------------------------- //        
-// Отдельный таск для предварительных тестов
-    
-    // Разное
-    //xTaskCreate(test_hw_task, "hw_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
-    
-    // Тесты GPIO
-    //xTaskCreate(test_gpio, "gpio_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
-    
-    //ai_processing();
-    
-    //average_filter_init();
-    
-// -------------------------------------------------------------------------- //
-// Удаляем стартовую задачу 
-           
-    vTaskDelete(NULL);
-}
-
+#include "at32f403a_407.h"
+#include "at32f403a_407_board.h"
+#include "at32f403a_407_clock.h"
+#include "common_config.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+extern "C" {
+#include "usb_eth.h"
+#include "mux.h"
+#include "misc.h"
+#include "spi_common.h"
+#include "user_fatfs.h"
+#include "spi_flash.h"
+#include "usb_eth.h"
+#include "extended_sram.h"
+#include "modbus.h"
+#include "common_gpio.h"
+#include "io.h"
+#include "sys_api.h"
+#include "settings_api.h"
+#include "update.h"
+#include "uptime.h"
+#include "rtc.h"
+#include "mb.h"
+#include "io_utils.h"
+#include "digital_input.h"
+#include "digital_output.h"
+#include "buttons.h"
+#include "adc_transport.h"
+#include "shift_reg.h"
+#include "analog_input.h"
+#include "analog_output.h"
+#include "dac_transport.h"
+#include "log.h"
+#include "swap.h"
+#include "utility.h"
+#include "soft_test.h"
+#include "soft_wdt.h"
+#include "usb_clock.h"
+#include "filter.h"
+#include "modbus_ai_params.h"
+}
+#include "terminal_sbs.h"
+#include "terminal_usartbridge.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+void init_task(void *argument);
+
+
+//
+int main(void)
+{
+    __disable_irq();
+    nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x08021000);
+    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
+	__enable_irq();
+  
+    crm_periph_clock_enable(CRM_CRC_PERIPH_CLOCK, TRUE);
+    
+    extend_SRAM();
+  
+    system_clock_config();
+
+    delay_init();
+                    
+    xTaskCreate(init_task, "init_task", 10*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+        
+    vTaskStartScheduler();
+     
+    while (1) {}
+}
+
+
+void init_task(void *argument)
+{
+// -------------------------------------------------------------------------- //    
+// Software watchdog
+  
+    gpio_wdt_init();
+    xTaskCreate(soft_wdt, "soft_wdt", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);    
+    
+// -------------------------------------------------------------------------
+// CLI
+    
+    sbsTerminal.configure();
+    terminalUsartBridge.configure();    
+    
+// -------------------------------------------------------------------------- //    
+// Настройки. Загрузка и проверка.
+
+    // Мьютекс для работы с настройками
+    init_settings(); 
+    
+    // Системные настройки и копия
+    sys_settings_load(&sys_settings);
+    memcpy(&temp_sys_settings, &sys_settings, sizeof(sys_settings_t));
+    
+    // Основные настройки
+    settings_load(&settings);
+    
+    // Настройки параметров порта Modbus
+    settings_set_modbus_params(settings.com_settings.mb_port);
+    
+#if 0
+// Только для теста    
+    settings_set_all_default();
+    settings_save(&settings);
+#endif
+    
+// -------------------------------------------------------------------------- //    
+// Безопасный режим, входы, выходы
+    
+#if defined (MDIO_88) || (MAO_4)
+    //settings.save_mode = false;
+    save_mode_init();
+#endif
+    
+// -------------------------------------------------------------------------- //
+// Включить тактирование портов
+    
+    io_port_enable();
+
+// -------------------------------------------------------------------------- //            
+// Цифровые входы/выходы
+
+#if defined (MDIO_88)
+    
+    // Инициализация GPIO, EXTI, TIM для цифровых входов
+    di_init();
+    
+    // 
+    do_init();
+    xTaskCreate(di_task, "input_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    
+#endif
+    
+#if defined (MAI_12)    
+    
+    ai_init();    
+    xTaskCreate(adc_task, "adc_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    
+#endif    
+    
+#if defined (MAO_4)    
+    
+    ao_init();
+    xTaskCreate(dac_task, "dac_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    
+#endif 
+    
+// -------------------------------------------------------------------------- //
+// Кнопки [SET, RESET]
+    
+    button_init();
+    xTaskCreate(button_task, "button_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    
+// -------------------------------------------------------------------------- //
+// Uptime    
+    
+    uptime_init();
+    
+// -------------------------------------------------------------------------- //
+// RTC    
+    
+    TM_RTC_Init();
+    rtc_subtim_init();
+    
+// -------------------------------------------------------------------------- //    
+// Мультиплексор
+#if 1    
+    mux_gpio_init();
+    xTaskCreate(mux_task, "mux_task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+#endif    
+// -------------------------------------------------------------------------- //        
+// Modbus    
+    
+    mb_init();
+    
+// -------------------------------------------------------------------------- //        
+// Сброс счетчика попыток загрузок
+    
+    update_reset_boot_try();    
+    
+// -------------------------------------------------------------------------- //    
+// Считать ревизию платы (состояние пинов)
+    
+    gpio_update_rev();
+    
+// -------------------------------------------------------------------------- //    
+// SPI flash, журнал событий, архив
+#if 0
+    common_spi_init();
+    spi_flash_init();
+    
+    log_init(false);
+#endif    
+// -------------------------------------------------------------------------- //
+// Статистика FreeRTOS
+    
+    utl_stat_timer_init();
+    
+// -------------------------------------------------------------------------- //
+// EVENT. Обновление FW.
+#if 0    
+    uint16_t update_status = bpr_data_read(BACKUP_UPDATE_STATUS);
+    
+    if (update_status == IAP_UPDATE_OK)
+        log_add_entry(LOG_UPDATE_FW, LOG_EVENT_STATE_OK, 0, atof(FW_VERSION));
+    else if (update_status == IAP_UPDATE_ERROR)
+        log_add_entry(LOG_UPDATE_FW, LOG_EVENT_STATE_ERR, 0, atof(FW_VERSION));
+        
+    bpr_data_write(BACKUP_UPDATE_STATUS, IAP_UPDATE_NO);
+
+// -------------------------------------------------------------------------- //
+// EVENT. Включение питания/перезагрузка.    
+    
+    log_add_entry(LOG_SYSTEM_BOOT, (log_event_state_t)0, 0, 0);
+#endif   
+// -------------------------------------------------------------------------- //    
+// USB (RNDIS class)
+#ifdef USB_RNDIS    
+    usb_clock48m_select(USB_CLK_HEXT);
+    crm_periph_clock_enable(CRM_USB_PERIPH_CLOCK, TRUE);
+    usb_init();
+    usb_eth_init();
+#endif 
+    
+
+    
+// -------------------------------------------------------------------------- //        
+// Тесты
+
+    //usb_eth_init();
+    //sys_clear();
+    //mux_led_test_init();
+    //pwm_test();
+    
+    // -------------------------------------------------------------------------- //    
+// Сдвиговые регистры и мультиплексоры    
+    //sh_init();
+    
+// Тесты аналоговых входов    
+    //ai_connect_test();
+    //ai_mode_test();
+    //ai_connect_channel(V_ISO);  
+    //ai_connect_channel(AN_INP_1);  
+    //ai_connect_channel(AN_INP_7);  
+    
+// -------------------------------------------------------------------------- //    
+// DAC    
+/*    
+    dac_gpio_init();
+    dac_test(CH_DAC_1, 30000);  
+*/    
+/*    
+    dac_test(CH_DAC_2, 10000);  
+    dac_test(CH_DAC_3, 10000);
+    dac_test(CH_DAC_4, 10000);  
+*/    
+/*    
+    dac_test(CH_DAC_1, 10000);  
+    dac_test(CH_DAC_2, 10000);  
+    dac_test(CH_DAC_3, 10000);
+    dac_test(CH_DAC_4, 10000);  
+*/  
+    
+#if 0
+    // Настройки по умолчанию 
+    settings_set_all_default();
+    settings_save(&settings);
+#endif    
+    
+// -------------------------------------------------------------------------- //        
+// Отдельный таск для предварительных тестов
+    
+    // Разное
+    //xTaskCreate(test_hw_task, "hw_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    
+    // Тесты GPIO
+    //xTaskCreate(test_gpio, "gpio_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    
+    //ai_processing();
+    
+    //average_filter_init();
+    
+// -------------------------------------------------------------------------- //
+// Удаляем стартовую задачу 
+           
+    vTaskDelete(NULL);
+}
+

二进制
output/fw.bin


文件差异内容过多而无法显示
+ 409 - 446
project/ewarm/iap/iap.dep


文件差异内容过多而无法显示
+ 1053 - 1052
project/ewarm/module_universal_io.dep


+ 18 - 2
tools/digital_io.py

@@ -16,9 +16,15 @@ class IO_Digital(IO_Module):
         self.modbus = modbus
         self.modbus = modbus
         super().__init__(self.modbus)
         super().__init__(self.modbus)
         self.log = DigitalLogReader(self.modbus)
         self.log = DigitalLogReader(self.modbus)
- 
+  
     '''Запрос параметров'''
     '''Запрос параметров'''
-    # 0x0100 - текущее состояние входов
+
+    # 0x0100 - Состояние входов (вкл./выкл.)
+    def get_inputs_state(self) -> str:
+        data = self.modbus.read_holding_registers(DioReg.IN_STATE.value , 1)
+        return format(data[0], '08b')
+
+    # 0x0101 - текущее состояние входов
     def get_inputs_bit(self) -> str:
     def get_inputs_bit(self) -> str:
         data = self.modbus.read_holding_registers(DioReg.IN_BITS.value , 1)
         data = self.modbus.read_holding_registers(DioReg.IN_BITS.value , 1)
         return format(data[0], '08b')
         return format(data[0], '08b')
@@ -66,6 +72,12 @@ class IO_Digital(IO_Module):
         return self.modbus.read_holding_registers(DIO_REGS['in_deb_start'], 8)
         return self.modbus.read_holding_registers(DIO_REGS['in_deb_start'], 8)
 
 
     '''Установка параметров'''
     '''Установка параметров'''
+
+    # 0x0100 - Состояние входов (вкл./выкл.)
+    def set_inputs_state(self, val):
+        self.modbus.write_holding_register(DioReg.IN_STATE.value, val)
+
+    #
     def set_inputs_mode(self, val):
     def set_inputs_mode(self, val):
         self.modbus.write_holding_register(DIO_REGS['in_mode'], val)
         self.modbus.write_holding_register(DIO_REGS['in_mode'], val)
 
 
@@ -93,6 +105,10 @@ class IO_Digital(IO_Module):
 
 
 
 
     def print_inputs(self):
     def print_inputs(self):
+
+        # Состояние входов (вкл./выкл.)
+        print('Inputs state [bit field]  :', Fore.GREEN + self.get_inputs_mode())
+
         # Значения входов (битовое поле)
         # Значения входов (битовое поле)
         print('Inputs values [bit field] :', Fore.GREEN + self.get_inputs_bit())
         print('Inputs values [bit field] :', Fore.GREEN + self.get_inputs_bit())
 
 

部分文件因为文件数量过多而无法显示