瀏覽代碼

Пишу скрипт калибровки. Меняю IAP под MDIO

unknown 7 月之前
父節點
當前提交
a7afcc9aec

+ 23 - 4
fw/modules/io/analog_input.c

@@ -20,6 +20,8 @@
 #if defined (MAI_12)  
 
 #define VOLTAGE_FACTOR      0.182382
+#define VOLTAGE_FACTOR_0_10 0.1083
+#define VOLTAGE_FACTOR_0_1  0.9812
 #define CURRENT_FACTOR      0.00091191
 #define CRNT_LIM_V_FACTOR   0.0476
 #define VOLT_ALARM_LIMIT    10000.0
@@ -235,19 +237,35 @@ void ai_processing(void)
         // ---------------------------------------------------------------------
         // Фильтрованные данные
         
-#if 1 
+#if 1
         // Отключил на время теста уставок
         filter_factor = settings.ai[i].mode == 0 ? VOLTAGE_FACTOR : CURRENT_FACTOR;
           
         adc_com_data[i] = (float)adc_com_raw_data[i]*filter_factor*
                           settings.ai[i].k_factor + settings.ai[i].b_factor;
         
+        if (settings.ai[i].mode == MEAS_VOLTAGE) {
+            if (settings.ai[i].voltage_mode == 0)
+                adc_com_data[i] /= VOLTAGE_FACTOR_0_10*10000;
+            else
+                adc_com_data[i] /= VOLTAGE_FACTOR_0_1*10000;
+        }
+        
+        
         filter_factor = settings.ai[i + 6].mode == 0 ? VOLTAGE_FACTOR : CURRENT_FACTOR;
         
         adc_com_data[i + 6] = (float)adc_com_raw_data[i + 6]*filter_factor*
                               settings.ai[i + 6].k_factor + settings.ai[i + 6].b_factor;
+        
+        if (settings.ai[i + 6].mode == MEAS_VOLTAGE) {
+            if (settings.ai[i + 6].voltage_mode == 0)
+                adc_com_data[i + 6] /= VOLTAGE_FACTOR_0_10*10000;
+            else
+                adc_com_data[i + 6] /= VOLTAGE_FACTOR_0_1*10000;
+        }
 #endif
         
+        
 #if 0        
         // Подменяем реальные сигналы не тестовые
         for (int i = 0; i < 12; i++)
@@ -611,14 +629,15 @@ void ai_connect_channel(uint8_t channel)
         
         switch (channel)
         {
-            case AN_INP_7: ai_mux |= (0x04 << 4); break; // U401 Y4
-            case AN_INP_8: ai_mux |= (0x06 << 4); break; // U401 Y6
+            case AN_INP_7: ai_mux |= (0x01 << 4); break; // U401 Y4
+            case AN_INP_8: ai_mux |= (0x03 << 4); break; // U401 Y6
             case AN_INP_9: ai_mux |= (0x07 << 4); break; // U401 Y7
             case AN_INP_10:ai_mux |= (0x05 << 4); break; // U401 Y5
             case AN_INP_11:ai_mux |= (0x02 << 4); break; // U401 Y2
-            case AN_INP_12:ai_mux |= (0x01 << 4); break; // U401 Y1
+            case AN_INP_12:ai_mux |= (0x04 << 4); break; // U401 Y1
             case CRNT_LIM_U_BFR_R: ai_mux  |= (0x00 << 4); break; // U401 Y0
             case CRNT_LIM_U_ABFR_R: ai_mux |= (0x03 << 4); break; // U401 Y3
+          
             default: break;
         }
     }

+ 5 - 1
fw/modules/io/analog_input.h

@@ -29,7 +29,11 @@ typedef struct
 typedef enum
 {
     MEAS_VOLTAGE = 0,
-    MEAS_CURRENT,  
+    MEAS_CURRENT = 1,
+    MEAS_VOLTAGE_0_10,
+    MEAS_VOLTAGE_0_1,
+    MEAS_CURRENT_4_20,
+    MEAS_CURRENT_0_20,
     
 } MEAS_CHAN_MODE_t;
 

+ 1 - 1
fw/modules/io/io.h

@@ -28,7 +28,7 @@
 
 #define AI_COMMON_NUMBER    12  // Основные 12
 
-#define AI_ADD_NUMBER       2   // Дополнительные входы
+#define AI_ADD_NUMBER       4   // Дополнительные входы
 
 // -------------------------------------------------------------------------- //
 // Аналоговые выходы. 

+ 340 - 0
iap/modules/io/digital_output.c

@@ -0,0 +1,340 @@
+#include "at32f403a_407.h"
+#include "digital_output.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "settings_api.h"
+#include "io_utils.h"
+#include "mux.h"
+#include <stdio.h>
+
+
+
+uint16_t output_state_bit;
+uint16_t output_state_save_bit;
+uint16_t output_value_bit;
+uint16_t output_value_save_bit;
+uint16_t output_mode_bit;
+uint16_t output_mode_save_bit;
+uint16_t output_pwm[DO_NUMBER];
+uint16_t output_pwm_save[DO_NUMBER];
+uint16_t output_pwm_period[DO_NUMBER];
+uint16_t output_pwm_period_save[DO_NUMBER];
+
+
+out_t outputs[DO_NUMBER] = {
+    {GPIOC, GPIO_PINS_12, 0, 0, 0, false, 0, 0},   // -
+    {GPIOD, GPIO_PINS_2,  0, 0, 0, false, 0, 0},   // -
+    {GPIOE, GPIO_PINS_6,  0, 0, 0, false, 0, 0},   // TMR9_CH2 (remap)
+    {GPIOC, GPIO_PINS_1,  0, 0, 0, false, 0, 0},   // -
+    {GPIOC, GPIO_PINS_11, 0, 0, 0, false, 0, 0},   // -
+    {GPIOD, GPIO_PINS_3,  0, 0, 0, false, 0, 0},   // -
+    {GPIOE, GPIO_PINS_5,  0, 0, 0, false, 0, 0},   // TMR9_CH1 (remap)
+    {GPIOC, GPIO_PINS_2,  0, 0, 0, false, 0, 0}    // -
+};
+
+
+//
+void do_init(void)
+{
+    // Таймер для выходов в режиме PWM
+    di_out_pwm_tim_init();
+    
+    // Актуализация битовых полей (используюся для управления по modbus)
+    
+    // Состояние выходов вкл/выкл.
+    do_update_field(&settings.dout[0].state, &output_state_bit);
+    do_update_field(&settings.dout_save[0].state, &output_state_save_bit);
+    
+    // Режим работы выходов
+    do_update_field(&settings.dout[0].mode, &output_mode_bit);
+    do_update_field(&settings.dout_save[0].mode, &output_mode_save_bit);
+    
+    // Значение на выходах
+    do_update_field(&settings.dout[0].value, &output_value_bit);
+    do_update_field(&settings.dout_save[0].value, &output_value_save_bit);
+    
+    // Установить режим работы и состояние на всех выходах
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        do_gpio_init(&outputs[i], i);
+
+        // Актуализация параметров PWM для modbus
+        output_pwm[i] = settings.dout[i].pwm_duty;
+        output_pwm_period[i] = settings.dout[i].pwm_period;
+        
+        output_pwm_save[i] = settings.dout_save[i].pwm_duty;
+        output_pwm_period_save[i] = settings.dout_save[i].pwm_period;
+        
+        do_update(&settings.dout_save[i], i);
+    }
+}
+
+
+// Заполняет битовые поля по значения в массивах
+void do_update_field(uint8_t *param, uint16_t *field)
+{
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        if (*param)
+            *field |= 1 << i;
+        else 
+            *field &= ~(1 << i);
+        
+        param += sizeof(do_t);
+    }  
+}
+
+
+// Настройка GPIO выходов
+void do_gpio_init(out_t *out, uint8_t index)
+{
+    gpio_init_type gpio_init_struct;
+    
+    gpio_default_para_init(&gpio_init_struct);
+    
+    gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;  
+    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
+    gpio_init_struct.gpio_mode           = GPIO_MODE_OUTPUT;  
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init_struct.gpio_pins           = out->pin;
+    gpio_init(out->port, &gpio_init_struct); 
+}
+
+
+
+
+//
+void do_set_common(void)
+{
+    bool flag = false;
+    
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        // Изменилось состояние выходов
+        if (settings.dout[i].state != (output_state_bit & (1 << i))) {
+            settings.dout[i].state = (output_state_bit >> i) & 1;
+        }
+      
+        // Изменилось значение на выходе
+        if (settings.dout[i].value != (output_value_bit & (1 << i))) {
+            settings.dout[i].value = (output_value_bit >> i) & 1;
+            flag = true;
+        }
+        
+        // Изменился режим работы
+        if (settings.dout[i].mode != (output_mode_bit & (1 << i))) {
+            settings.dout[i].mode = (output_mode_bit >> i) & 1;
+            flag = true;
+        }
+                
+        // Изменилось заполнение PWM
+        if (settings.dout[i].pwm_duty != output_pwm[i]) {
+            settings.dout[i].pwm_duty = output_pwm[i];
+            flag = true;
+        }
+        
+        // Изменился период PWM
+        if (settings.dout[i].pwm_period != output_pwm_period[i]) {
+            settings.dout[i].pwm_period = output_pwm_period[i];
+            flag = true;
+        }
+        
+        // Значение на выходе в безопасном режиме. Обновляем значения в настройках.
+        settings.dout_save[i].value = (output_value_save_bit >> i) & 1;
+        
+        // Режим работы в безопасном режиме. Обновляем значения в настройках.
+        settings.dout_save[i].mode = (output_mode_save_bit >> i) & 1;
+        
+        // Состояние выходов в безопасном режиме. Обновляем значения в настройках.
+        settings.dout_save[i].state = (output_state_save_bit >> i) & 1;
+
+        // Заполнение PWM в безопасном режие. Обновляем значение в настройках.
+        settings.dout_save[i].pwm_duty = output_pwm_save[i];
+        
+        // Период PWM в безопасном режие. Обновляем значение в настройках.
+        settings.dout_save[i].pwm_period = output_pwm_period_save[i];
+        
+        if (flag)
+            do_update(&settings.dout[i], i);
+    }
+}
+
+
+// Установка режима и значения на выходе
+void do_update(do_t *out, uint8_t i)
+{
+    // Если выход выключен - ничего не меняем
+    if (!out->state)
+        return;
+  
+    uint8_t led_index = 0;
+  
+    // Режим ШИМ
+    if (out->mode) {
+        do_set_pwm(out->pwm_period, out->pwm_duty, i);
+    }
+    // Режим обычного выхода
+    else {
+        outputs[i].mode = 0;
+        do_set_out(&outputs[i], out->value);
+        
+        if (i < 4)
+            led_index = i + 8;
+        else
+            led_index = i - 4 + 24;
+          
+        if (out->value == 1)
+            leds[led_index].state = LED_ON;
+        else
+            leds[led_index].state = LED_OFF;
+    }
+}
+
+
+//
+void do_set_pwm(uint16_t period, uint16_t duty, uint8_t index)
+{
+    uint16_t duty_calc;
+  
+    if (duty == 0)
+        duty_calc = 0;
+    else
+        duty_calc = (duty*period/100 < 1) ? 1 : duty*period/100;
+    
+    outputs[index].pwm_flag = false;
+    outputs[index].pwm_period_cnt = 0;
+    outputs[index].pwm_duty_cnt = 0;
+    outputs[index].pwm_period = period;
+    outputs[index].pwm_duty = duty_calc;
+    outputs[index].mode = 1;
+}
+
+
+// Дергает пином.
+void do_set_out(out_t *out, uint8_t val)
+{
+    if (val) {
+        gpio_bits_set(out->port, out->pin);
+    }    
+    else {
+        gpio_bits_reset(out->port, out->pin);
+    }
+}
+
+
+//
+void out_as_pwm(void)
+{
+    uint32_t timer_period;
+    uint16_t pwm_pulse;
+    crm_clocks_freq_type crm_clocks_freq_struct = {0};
+    tmr_output_config_type tmr_output_struct;
+    
+    crm_periph_clock_enable(CRM_TMR9_PERIPH_CLOCK, TRUE);
+    
+    crm_clocks_freq_get(&crm_clocks_freq_struct);
+    
+    //timer_period = (crm_clocks_freq_struct.sclk_freq / 10 ) - 1;
+    
+    timer_period = 24000 - 1;
+    pwm_pulse = 125*timer_period/1000;
+    
+    tmr_base_init(TMR9, 24000 - 1, 1000 - 1);
+    tmr_cnt_dir_set(TMR9, TMR_COUNT_UP);
+
+    tmr_output_default_para_init(&tmr_output_struct);
+    tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
+    tmr_output_struct.oc_output_state = TRUE;
+    tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH;
+    tmr_output_struct.oc_idle_state = TRUE;
+    
+    tmr_output_channel_config(TMR9, TMR_SELECT_CHANNEL_1, &tmr_output_struct);
+    tmr_channel_value_set(TMR9, TMR_SELECT_CHANNEL_1, pwm_pulse);
+    
+    tmr_flag_clear(TMR9, TMR_OVF_FLAG);
+    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
+    nvic_irq_enable(TMR1_BRK_TMR9_IRQn, 5, 0);
+    
+    //tmr_interrupt_enable(TMR9, TMR_OVF_INT, TRUE);
+    tmr_interrupt_enable(TMR9, TMR_C1_INT, TRUE);
+    
+    tmr_counter_enable(TMR9, TRUE);
+}
+
+
+
+// -------------------------------------------------------------------------- //
+//                              PWM
+
+// Таймер для выходов в режиме PWM. Частота 10Гц.
+void di_out_pwm_tim_init(void)
+{
+    uint16_t prescaler_value = 0;
+    uint16_t timer_period = 1000 - 1;
+    gpio_init_type gpio_init_struct;
+    
+    gpio_default_para_init(&gpio_init_struct);
+        
+    gpio_init_struct.gpio_pins = GPIO_PINS_15;
+    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
+    gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init(GPIOB, &gpio_init_struct);
+
+    crm_periph_clock_enable(CRM_TMR9_PERIPH_CLOCK, TRUE);
+    
+    prescaler_value = (uint16_t)(system_core_clock / 10000) - 1;
+    tmr_base_init(TMR9, timer_period, prescaler_value);
+    
+    tmr_cnt_dir_set(TMR9, TMR_COUNT_UP);
+    tmr_clock_source_div_set(TMR9, TMR_CLOCK_DIV1);
+    
+    nvic_irq_enable(TMR1_BRK_TMR9_IRQn, 5, 0);
+
+    tmr_interrupt_enable(TMR9, TMR_OVF_INT, TRUE);
+    
+    tmr_counter_enable(TMR9, TRUE);
+}
+
+
+// Реализация программного PWM для цифровых выходов
+inline void pwm_proc(void)
+{
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        if (outputs[i].mode)    // режим PWM
+        {
+            if (outputs[i].pwm_period_cnt == outputs[i].pwm_period /*PWM_PERIOD_TEST*/) {
+                outputs[i].pwm_period_cnt = 0;
+            }
+            if (outputs[i].pwm_period_cnt == 0) {
+                outputs[i].pwm_flag = false;
+                gpio_bits_set(outputs[i].port, outputs[i].pin);
+                //gpio_bits_set(GPIOB, GPIO_PINS_15);
+            }
+            if (outputs[i].pwm_duty_cnt == outputs[i].pwm_duty /*PWM_DUTY_TEST*/) {
+                outputs[i].pwm_duty_cnt = 0;
+                gpio_bits_reset(outputs[i].port, outputs[i].pin);
+                //gpio_bits_reset(GPIOB, GPIO_PINS_15);
+                outputs[i].pwm_flag = true;
+            }
+            outputs[i].pwm_period_cnt++;
+            if (outputs[i].pwm_flag == false) {
+                outputs[i].pwm_duty_cnt++;
+            }
+        }
+    }
+}
+
+// Реализация программного PWM для цифровых выходов
+void TMR1_BRK_TMR9_IRQHandler(void)
+{
+    if(tmr_flag_get(TMR9, TMR_OVF_FLAG) != RESET)
+    {
+        tmr_flag_clear(TMR9, TMR_OVF_FLAG);
+        //GPIOB->odt ^= GPIO_PINS_15;
+        pwm_proc();
+    }
+}
+

+ 38 - 0
iap/modules/io/digital_output.h

@@ -0,0 +1,38 @@
+#ifndef __DIGITAL_OUTPUT_H
+#define __DIGITAL_OUTPUT_H
+
+#include <stdbool.h>
+#include "io.h"
+
+
+//
+void do_init(void);
+
+//
+void do_update_field(uint8_t *param, uint16_t *field);
+
+//
+void do_gpio_init(out_t *out, uint8_t index);
+
+//
+void do_set_common(void);
+
+//
+void do_update(do_t *out, uint8_t i);
+
+//
+void do_set_pwm(uint16_t period, uint16_t duty, uint8_t index);
+
+//
+void do_set_out(out_t *out, uint8_t val);
+
+//
+void out_as_pwm(void);
+
+// 
+void di_out_pwm_tim_init(void);
+
+
+
+#endif  // __DIGITAL_OUTPUT_H
+

+ 0 - 331
iap/modules/io/input.c

@@ -1,331 +0,0 @@
-#include "at32f403a_407.h"
-#include "input.h"
-#include "settings_api.h"
-#include "FreeRTOS.h"
-#include "task.h"
-#include "mux.h"
-#include <stdio.h>
-
-
-// *port; pin; mode; port_source; pin_source; deb_counter; p_flag; cnt;
-din_t 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
-};
-
-
-//
-void in_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);
-
-#if 0    
-    // Вход
-    if (input->mode == 0)
-    {
-        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); 
-    }
-    // Счетный вход
-    else if (input->mode == 1)
-    {
-    }
-#endif
-}
-
-//
-void in_exint_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 in_set(void)
-{
-    for (int i = 0; i < DI_NUMBER; i++)
-    {
-        if ((settings.di_mode_bits & (1 << i)) != inputs[i].mode) 
-        {
-            inputs[i].mode = settings.di_mode_bits & (1 << i);
-            if (inputs[i].mode == 0) 
-            {
-                inputs[i].cnt = 0;
-                inputs[i].p_flag = false;
-                input_cnt[i] = 0;
-            }
-            else
-            {
-                input_state_bit &= ~(1 << i);
-            }
-        }
-    }
-}
-
-//
-void io_test(void)
-{
-#if 0  
-    printf("IN_1: %u IN_2: %u IN_3: %u IN_4: %u IN_5: %u IN_6: %u IN_7: %u IN_8: %u\r\n", 
-           gpio_input_data_bit_read(inputs[0].port, inputs[0].pin),
-           gpio_input_data_bit_read(inputs[1].port, inputs[1].pin),
-           gpio_input_data_bit_read(inputs[2].port, inputs[2].pin),
-           gpio_input_data_bit_read(inputs[3].port, inputs[3].pin),
-           gpio_input_data_bit_read(inputs[4].port, inputs[4].pin),
-           gpio_input_data_bit_read(inputs[5].port, inputs[5].pin),
-           gpio_input_data_bit_read(inputs[6].port, inputs[6].pin), 
-           gpio_input_data_bit_read(inputs[7].port, inputs[7].pin));
-#endif    
-    
-    printf("IN_1: %u IN_2: %u IN_3: %u IN_4: %u IN_5: %u IN_6: %u IN_7: %u IN_8: %u\r\n", 
-           input_cnt[0], input_cnt[1], input_cnt[2], input_cnt[3], 
-           input_cnt[4], input_cnt[5], input_cnt[6], input_cnt[7]);
-    
-}
-
-//
-void input_task(void *params)
-{
-    for (;;)
-    {
-        
-        for (int i = 0; i < DI_NUMBER; i++)
-        {
-            // Режим обычного входа
-            if (inputs[i].mode == 0)
-            {
-                input_state[i] = (uint16_t)gpio_input_data_bit_read(inputs[i].port, inputs[i].pin);
-                
-                if (!input_state[i]) {
-                    input_state_bit &= ~(1 << i); // снять бит
-                    leds[i].state = LED_OFF;
-                }
-                else {
-                    input_state_bit |= input_state[i] << i;
-                    leds[i].state = LED_ON;
-                }
-            }
-        }
-            
-        vTaskDelay(100);
-    }
-}
-
-//
-inline void debounce(void)
-{
-    for (int i = 0; i < DI_NUMBER; i++)
-    {
-        if ((inputs[i].p_flag) && (inputs[i].mode == 0)){
-            if (++inputs[i].cnt == settings.di_debounce[i]) {
-                inputs[i].cnt = 0;
-                inputs[i].p_flag = false;
-                
-                input_state[i] = (uint16_t)gpio_input_data_bit_read(inputs[i].port, inputs[i].pin);
-                
-                if (!input_state[i]) {
-                    input_state_bit &= ~(1 << i); // снять бит
-                    leds[i].state = LED_OFF;
-                }
-                else {
-                    input_state_bit |= input_state[i] << i;
-                    leds[i].state = LED_ON;
-                }
-            }
-        }
-    }
-}
-
-// IN_8 GPIOA_0
-void EXINT0_IRQHandler(void)
-{
-    if (exint_flag_get(EXINT_LINE_0) != RESET) 
-    {
-        exint_flag_clear(EXINT_LINE_0);
-        if (inputs[7].mode == 0)
-            inputs[7].p_flag = true;
-        else { 
-            if (inputs[7].cnt_flag) {
-                input_cnt[7]++;
-                inputs[7].cnt_flag = false;
-            }
-            else
-                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 (inputs[6].mode == 0)
-            inputs[6].p_flag = true;
-        else { 
-            if (inputs[6].cnt_flag) {
-                input_cnt[6]++;
-                inputs[6].cnt_flag = false;
-            }
-            else
-                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 (inputs[5].mode == 0)
-            inputs[5].p_flag = true;
-        else { 
-            if (inputs[5].cnt_flag) {
-                input_cnt[5]++;
-                inputs[5].cnt_flag = false;
-            }
-            else
-                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 (inputs[4].mode == 0)
-            inputs[4].p_flag = true;
-        else { 
-            if (inputs[4].cnt_flag) {
-                input_cnt[4]++;
-                inputs[4].cnt_flag = false;
-            }
-            else
-                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 (inputs[1].mode == 0)
-            inputs[1].p_flag = true;
-        else { 
-            if (inputs[1].cnt_flag) {
-                input_cnt[1]++;
-                inputs[1].cnt_flag = false;
-            }
-            else
-                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 (inputs[0].mode == 0)
-            inputs[0].p_flag = true;
-        else { 
-            if (inputs[0].cnt_flag) {
-                input_cnt[0]++;
-                inputs[0].cnt_flag = false;
-            }
-            else
-                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 (inputs[2].mode == 0)
-            inputs[2].p_flag = true;
-        else { 
-            if (inputs[2].cnt_flag) {
-                input_cnt[2]++;
-                inputs[2].cnt_flag = false;
-            }
-            else
-                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 (inputs[3].mode == 0)
-            inputs[3].p_flag = true;
-        else { 
-            if (inputs[3].cnt_flag) {
-                input_cnt[3]++;
-                inputs[3].cnt_flag = false;
-            }
-            else
-                inputs[3].cnt_flag = true;
-        }
-    }    
-}

+ 0 - 30
iap/modules/io/input.h

@@ -1,30 +0,0 @@
-#ifndef __INPUT_H
-#define __INPUT_H
-
-
-#include "io.h"
-
-
-extern din_t inputs[];
-
-//
-void in_init(din_t *input);
-
-//
-void in_exint_init(void);
-
-//
-void in_set(void);
-
-//
-void io_test(void);
-
-//
-void input_task(void *params);
-
-//
-void debounce(void);
-
-
-#endif  // __INPUT_H
-

+ 1 - 105
iap/modules/io/io.c

@@ -2,34 +2,13 @@
 #include "io.h"
 #include "FreeRTOS.h"
 #include "task.h"
-#include "input.h"
-#include "output.h"
 #include "settings_api.h"
 #include "io_utils.h"
 #include <stdio.h>
 
 
-uint16_t input_state[DI_NUMBER];     // состояние входа
-uint16_t input_state_bit;
-
-
-//uint16_t output_state[DO_NUMBER];     // состояние входа
-uint16_t output_state_bit;
-uint16_t output_mode_bit;
-uint16_t output_pwm[DO_NUMBER];
-uint16_t output_pwm_save[DO_NUMBER];
-uint16_t output_pwm_period[DO_NUMBER];
-uint16_t output_pwm_period_save[DO_NUMBER];
-
-// -------------------------------------------------------------------------- //
-// Текущие параметры
-
-//uint16_t input_state[DI_NUMBER];     // состояние входа
-uint32_t input_cnt[DI_NUMBER];       // счетчики входов
-
-
 //
-void io_port_init(void)
+void io_port_enable(void)
 {
     crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
     crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
@@ -42,87 +21,4 @@ void io_port_init(void)
     crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
     crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
     pwc_battery_powered_domain_access(TRUE);
-    
-    io_tim_init();
-}
-
-//
-void io_init(void)
-{
-    for (int i = 0; i < DI_NUMBER; i++)
-    {
-        in_init(&inputs[i]);
-    }
-
-    output_state_bit = settings.do_bits;
-    output_mode_bit = settings.do_mode_bits;
-    
-    // Таймер для выходов в режиме PWM
-    out_pwm_tim_init();
-    
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        output_pwm[i] = settings.do_pwm[i];
-        output_pwm_save[i] = settings.do_pwm_save[i];
-        output_pwm_period[i] = settings.do_pwm_period[i];
-        output_pwm_period_save[i] = settings.do_pwm_period_save[i];
-
-        if (save_mode_get()) {
-            outputs[i].pwm_duty = settings.do_pwm_save[i];
-            outputs[i].pwm_period = settings.do_pwm_period_save[i];
-        }
-        else {
-            outputs[i].pwm_duty = settings.do_pwm[i];
-            outputs[i].pwm_period = settings.do_pwm_period[i];
-        }
-        
-        out_gpio_init(&outputs[i], i);
-        load_sens_init(&load_sens[i]);
-    }
 }
-
-// Таймер для антидребезга
-void io_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        
-    }
-}
-

+ 42 - 44
iap/modules/io/io.h

@@ -3,39 +3,43 @@
 
 #include <stdbool.h>
 
-// Период опроса входов 100 мс
 
 // -------------------------------------------------------------------------- //
 // Дискретые входы
 
-#define DI_NUMBER       8   // Количество входов
+#define DI_NUMBER           8   // Количество входов
 
-#define DI_MODE_IN      0   // Режим обычного входа
+#define DI_MODE_IN          0   // Режим обычного входа
 
-#define DI_MODE_CNT     1   // Режим счетного входа
+#define DI_MODE_CNT         1   // Режим счетного входа
 
 
 // -------------------------------------------------------------------------- //
-// Выходы
-#define DO_NUMBER       8    // Количество выходов
+// Дискретные выходы
 
-#define DEBOUNCE_CNT    50
+#define DO_NUMBER           8   // Количество выходов
 
-// Прочие параметры из других модулей для передачи по modbus
+#define DEBOUNCE_CNT        50
 
-//uint32_t uptime;
+// -------------------------------------------------------------------------- //
+// Аналоговые входы. 
+
+#define AI_ALL_NUMBER       16  // Общее количество
 
+#define AI_COMMON_NUMBER    12  // Основные 12
+
+#define AI_ADD_NUMBER       4   // Дополнительные входы
 
 // -------------------------------------------------------------------------- //
+// Аналоговые выходы. 
 
-//
-void io_port_init(void);
+#define AO_NUMBER           4   // Количество выходов
 
-//
-void io_init(void);
+// -------------------------------------------------------------------------- //
 
 //
-void io_tim_init(void);
+void io_port_enable(void);
+
 
 // -------------------------------------------------------------------------- //
 
@@ -46,6 +50,26 @@ typedef struct
     
 } simple_gpio_t;
 
+//
+typedef struct
+{
+    uint8_t state;          // 0 - выкл, 1 - вкл
+    
+} di_t;
+
+
+//
+typedef struct
+{
+    uint8_t state;          // 0 - выкл, 1 - вкл
+    uint8_t mode;           // режим работы, 0 - вход, 1 - счетчик импульсов
+    uint8_t value;          // значение на выходе в режиме обычного выхода
+    uint16_t pwm_duty;      // значение заполнения ШИМ
+    uint16_t pwm_period;    // период ШИМ в [0.1с (10..1000)]
+    
+} do_t;
+
+
 
 typedef struct 
 {
@@ -74,29 +98,17 @@ typedef struct
 } out_t;
 
 
-
-
-// -------------------------------------------------------------------------- //
-// Текущие параметры
-
-extern uint16_t input_state[DI_NUMBER];      // состояние входа
-extern uint16_t input_state_bit;             // битовое поле
-
-extern uint32_t input_cnt[DI_NUMBER];       // счетчики входов
-
 extern uint16_t output_state_bit;
+extern uint16_t output_state_save_bit;
+extern uint16_t output_value_bit;
+extern uint16_t output_value_save_bit;
 extern uint16_t output_mode_bit;
+extern uint16_t output_mode_save_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[];
 
-//uint16_t output_state[DI_NUMBER];    // состояние выхода, 0 - норма, 1 - обрыв, 2 - КЗ
-
-
-// -------------------------------------------------------------------------- //
-// Структуры настроек. Хранятся во внутренней памяти контроллера.
-
 
 //
 // контроль состояний - обрыв, КЗ, норма
@@ -120,20 +132,6 @@ typedef struct
 } system_t;
 
 
-// Структура системных настроек
-/*
-typedef struct 
-{
-	uint16_t        model;			// Модель
-	uint32_t        proddate;		// Дата производства
-	uint32_t        serial;			// Серийный номер
-	uint8_t         fw_version[8];	// Версия ПО
-	uint8_t         test_state;		// Статус тестирования
-	
-} sys_settings_t;
-
-*/
-
 
 
 #endif  // __IO_H

+ 41 - 46
iap/modules/io/io_utils.c

@@ -1,46 +1,41 @@
-#include "at32f403a_407.h"
-#include "io_utils.h"
-#include "FreeRTOS.h"
-#include "task.h"
-#include "input.h"
-#include "output.h"
-#include "settings_api.h"
-#include "mux.h"
-#include <stdio.h>
-
-
-bool save_mode = false;
-static uint16_t counter = 0;
-
-//
-void save_mode_init(void)
-{
-    save_mode = settings.save_mode;
-    save_mode ? mux_led_status(false) : mux_led_status(true);
-}
-
-//
-void save_mode_set(bool state)
-{
-    save_mode = state;
-    save_mode ? mux_led_status(false) : mux_led_status(true);
-}
-
-//
-bool save_mode_get(void)
-{
-    return save_mode;
-}
-
-// Должна вызываться раз в секунду
-void save_mode_inc_cnt(void)
-{
-    bool foo = counter++ > settings.save_delay ? true : false;
-    save_mode_set(foo);
-}
-
-//
-void save_mode_reset_cnt(void)
-{
-    counter = 0;
-}
+#include "at32f403a_407.h"
+#include "io_utils.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "settings_api.h"
+#include "mux.h"
+#include <stdio.h>
+
+
+bool save_mode = false;
+static uint16_t counter = 0;
+
+//
+void save_mode_init(void)
+{
+    save_mode = (bool)settings.save_mode;
+    save_mode ? mux_led_status(false) : mux_led_status(true);
+}
+
+//
+void save_mode_set(bool state)
+{
+    save_mode = state;
+    save_mode ? mux_led_status(false) : mux_led_status(true);
+}
+
+//
+bool save_mode_get(void)
+{
+    return save_mode;
+}
+
+// Должна вызываться раз в секунду
+void save_mode_inc_cnt(void)
+{
+    if (settings.save_mode)
+        return;
+
+    bool foo = counter++ > settings.save_delay ? true : false;
+    save_mode_set(foo);
+}

+ 21 - 23
iap/modules/io/io_utils.h

@@ -1,23 +1,21 @@
-#ifndef __IO_UTILS_H
-#define __IO_UTILS_H
-
-#include <stdbool.h>
-
-
-//
-void save_mode_init(void);
-
-//
-void save_mode_set(bool state);
-
-//
-bool save_mode_get(void);
-
-//
-void save_mode_inc_cnt(void);
-
-//
-void save_mode_reset_cnt(void);
-
-#endif  // __IO_UTILS_H
-
+#ifndef __IO_UTILS_H
+#define __IO_UTILS_H
+
+#include <stdbool.h>
+
+
+//
+void save_mode_init(void);
+
+//
+void save_mode_set(bool state);
+
+//
+bool save_mode_get(void);
+
+//
+void save_mode_inc_cnt(void);
+
+
+#endif  // __IO_UTILS_H
+

+ 32 - 1
iap/modules/io/mux.h

@@ -30,14 +30,45 @@
 
 typedef enum
 {
-    STATUS_G = 0,
+    INP_1 = 0, 
+    INP_2, 
+    INP_3, 
+    INP_4,
+    
+    INP_5, 
+    INP_6, 
+    INP_7, 
+    INP_8,
+    
+    OUT_1_G,
+    OUT_2_G,
+    OUT_3_G,
+    OUT_4_G,
+    
+    OUT_1_R,
+    OUT_2_R,
+    OUT_3_R,
+    OUT_4_R,
+    
+    STATUS_G,
     STATUS_R,
     RX_G,
     TX_R,
+    
+    OUT_5_R,
+    OUT_6_R,
+    OUT_7_R,
+    OUT_8_R,
+    
+    OUT_5_G,
+    OUT_6_G,
+    OUT_7_G,
+    OUT_8_G,
       
 } led_t;
 
 
+
 typedef enum
 {
     LED_OFF = 0, 

+ 0 - 369
iap/modules/io/output.c

@@ -1,369 +0,0 @@
-#include "at32f403a_407.h"
-#include "output.h"
-#include "FreeRTOS.h"
-#include "task.h"
-#include "settings_api.h"
-#include "io_utils.h"
-#include <stdio.h>
-
-
-out_t outputs[DO_NUMBER] = {
-    {GPIOC, GPIO_PINS_12, 0, 0, 0, false, 0, 0},   // -
-    {GPIOD, GPIO_PINS_2,  0, 0, 0, false, 0, 0},   // -
-    {GPIOE, GPIO_PINS_6,  0, 0, 0, false, 0, 0},   // TMR9_CH2 (remap)
-    {GPIOC, GPIO_PINS_1,  0, 0, 0, false, 0, 0},   // -
-    {GPIOC, GPIO_PINS_11, 0, 0, 0, false, 0, 0},   // -
-    {GPIOD, GPIO_PINS_3,  0, 0, 0, false, 0, 0},   // -
-    {GPIOE, GPIO_PINS_5,  0, 0, 0, false, 0, 0},   // TMR9_CH1 (remap)
-    {GPIOC, GPIO_PINS_2,  0, 0, 0, false, 0, 0}    // -
-};
-
-
-simple_gpio_t load_sens[DO_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}
-};
-
-
-
-//
-void out_gpio_init(out_t *out, uint8_t index)
-{
-    gpio_init_type gpio_init_struct;
-
-    
-    // Выход
-    if (out->mode == 0)
-    {
-        gpio_default_para_init(&gpio_init_struct);
-        
-        gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;  
-        gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
-        gpio_init_struct.gpio_mode           = GPIO_MODE_OUTPUT;  
-        gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
-        gpio_init_struct.gpio_pins           = out->pin;
-        gpio_init(out->port, &gpio_init_struct); 
-    }
-    
-    do_update(out, index) ;
-}
-
-//
-void do_set_common(void)
-{
-    bool flag = false;
-    
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        // 
-        if ((settings.do_bits & (1 << i)) != (output_state_bit & (1 << i))) {
-            settings.do_bits = output_state_bit;
-            flag = true;
-        } 
-        else if ((settings.do_mode_bits & (1 << i)) != (output_mode_bit & (1 << i))) {
-            settings.do_mode_bits ^= (1 << i);
-            settings.do_mode_bits = output_mode_bit;
-            flag = true;
-        }  
-        else if (settings.do_pwm[i] != output_pwm[i]) {
-            settings.do_pwm[i] = output_pwm[i];
-            flag = true;
-        }
-        else if (settings.do_pwm_save[i] != output_pwm_save[i]) {
-            settings.do_pwm_save[i] = output_pwm_save[i];
-            flag = true;
-        }
-        else if (settings.do_pwm_period [i] != output_pwm_period[i]) {
-            settings.do_pwm_period[i] = output_pwm_period[i];
-            flag = true;
-        }
-        else if (settings.do_pwm_period_save[i] != output_pwm_period_save[i]) {
-            settings.do_pwm_period_save[i] = output_pwm_period_save[i];
-            flag = true;
-        }
- 
-        if (flag)
-            do_update(&outputs[i], i);
-    }
-}
-
-//
-void do_set(void)
-{
-    if (output_state_bit == settings.do_bits) 
-        return;
-    
-    // Состояние выхода/выходов изменилось
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        if ((settings.do_bits & (1 << i)) != (output_state_bit & (1 << i))) 
-        {
-            do_update(&outputs[i], i);
-        }
-    }
-    
-    // Сохраним новое значение выходов в настройках
-    settings.do_bits = output_state_bit;
-}
-
-// Установка значения на выходе 
-void do_update(out_t *out, uint8_t i)
-{
-    // Режим ШИМ
-    if (settings.do_mode_bits & (1 << i)) {
-        // Безопасный режим включен
-        if (save_mode_get())
-            do_set_pwm(settings.do_pwm_period_save[i], settings.do_pwm_save[i], i);
-        else
-            do_set_pwm(settings.do_pwm_period[i], settings.do_pwm[i], i);
-    }
-    // Режим обычного выхода
-    else {
-        out->mode = 0;
-        // Безопасный режим включен
-        if (save_mode_get())
-            do_set_out(out, settings.do_save_bits & (1 << i));
-        else
-            do_set_out(out, settings.do_bits & (1 << i));
-    }
-}
-
-//
-void do_set_mode(void)
-{
-    if (output_mode_bit == settings.do_mode_bits)
-        return;
-  
-    // Состояние выхода/выходов изменилось
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        if ((settings.do_mode_bits & (1 << i)) != (output_mode_bit & (1 << i)))
-        {
-            settings.do_mode_bits ^= (1 << i);
-            do_update(&outputs[i], i);
-        }
-    }
-  
-    settings.do_mode_bits = output_mode_bit;
-}
-
-//#define PWM_PERIOD_TEST     20
-//#define PWM_DUTY_TEST       10
-void do_set_pwm(uint16_t period, uint16_t duty, uint8_t index)
-{
-    uint16_t duty_calc;
-  
-    if (duty == 0)
-        duty_calc = 0;
-    else
-        duty_calc = (duty*period/100 < 1) ? 1 : duty*period/100;
-    
-    outputs[index].pwm_flag = false;
-    outputs[index].pwm_period_cnt = 0;
-    outputs[index].pwm_duty_cnt = 0;
-    outputs[index].pwm_period = period;
-    outputs[index].pwm_duty = duty_calc;
-    outputs[index].mode = 1;
-}
-
-//
-void do_set_out(out_t *out, uint8_t val)
-{
-    if (val) {
-        gpio_bits_set(GPIOB, GPIO_PINS_15);
-        gpio_bits_set(out->port, out->pin);
-    }
-    else {
-        gpio_bits_reset(GPIOB, GPIO_PINS_15);
-        gpio_bits_reset(out->port, out->pin);
-    }
-}
-
-//
-void out_as_pwm(void)
-{
-    uint32_t timer_period;
-    uint16_t pwm_pulse;
-    crm_clocks_freq_type crm_clocks_freq_struct = {0};
-    tmr_output_config_type tmr_output_struct;
-    
-    crm_periph_clock_enable(CRM_TMR9_PERIPH_CLOCK, TRUE);
-    
-    crm_clocks_freq_get(&crm_clocks_freq_struct);
-    
-    //timer_period = (crm_clocks_freq_struct.sclk_freq / 10 ) - 1;
-    
-    timer_period = 24000 - 1;
-    pwm_pulse = 125*timer_period/1000;
-    
-    tmr_base_init(TMR9, 24000 - 1, 1000 - 1);
-    tmr_cnt_dir_set(TMR9, TMR_COUNT_UP);
-
-    tmr_output_default_para_init(&tmr_output_struct);
-    tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
-    tmr_output_struct.oc_output_state = TRUE;
-    tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH;
-    tmr_output_struct.oc_idle_state = TRUE;
-    
-    tmr_output_channel_config(TMR9, TMR_SELECT_CHANNEL_1, &tmr_output_struct);
-    tmr_channel_value_set(TMR9, TMR_SELECT_CHANNEL_1, pwm_pulse);
-    
-    tmr_flag_clear(TMR9, TMR_OVF_FLAG);
-    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
-    nvic_irq_enable(TMR1_BRK_TMR9_IRQn, 5, 0);
-    
-    //tmr_interrupt_enable(TMR9, TMR_OVF_INT, TRUE);
-    tmr_interrupt_enable(TMR9, TMR_C1_INT, TRUE);
-    
-    tmr_counter_enable(TMR9, TRUE);
-}
-
-// Таймер для выходов в режиме PWM. Частота 10Гц.
-void out_pwm_tim_init(void)
-{
-    uint16_t prescaler_value = 0;
-    uint16_t timer_period = 1000 - 1;
-    gpio_init_type gpio_init_struct;
-    
-    gpio_default_para_init(&gpio_init_struct);
-        
-    gpio_init_struct.gpio_pins = GPIO_PINS_15;
-    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
-    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
-    gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
-    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
-    gpio_init(GPIOB, &gpio_init_struct);
-
-    crm_periph_clock_enable(CRM_TMR9_PERIPH_CLOCK, TRUE);
-    
-    prescaler_value = (uint16_t)(system_core_clock / 10000) - 1;
-    tmr_base_init(TMR9, timer_period, prescaler_value);
-    
-    tmr_cnt_dir_set(TMR9, TMR_COUNT_UP);
-    tmr_clock_source_div_set(TMR9, TMR_CLOCK_DIV1);
-    
-    nvic_irq_enable(TMR1_BRK_TMR9_IRQn, 5, 0);
-
-    tmr_interrupt_enable(TMR9, TMR_OVF_INT, TRUE);
-    
-    tmr_counter_enable(TMR9, TRUE);
-}
-
-
-
-inline void pwm_proc(void)
-{
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        if (outputs[i].mode)    // режим PWM
-        {
-            if (outputs[i].pwm_period_cnt == outputs[i].pwm_period /*PWM_PERIOD_TEST*/) {
-                outputs[i].pwm_period_cnt = 0;
-            }
-            if (outputs[i].pwm_period_cnt == 0) {
-                outputs[i].pwm_flag = false;
-                gpio_bits_set(outputs[i].port, outputs[i].pin);
-                //gpio_bits_set(GPIOB, GPIO_PINS_15);
-            }
-            if (outputs[i].pwm_duty_cnt == outputs[i].pwm_duty /*PWM_DUTY_TEST*/) {
-                outputs[i].pwm_duty_cnt = 0;
-                gpio_bits_reset(outputs[i].port, outputs[i].pin);
-                //gpio_bits_reset(GPIOB, GPIO_PINS_15);
-                outputs[i].pwm_flag = true;
-            }
-            outputs[i].pwm_period_cnt++;
-            if (outputs[i].pwm_flag == false) {
-                outputs[i].pwm_duty_cnt++;
-            }
-        }
-    }
-}
-
-//
-void 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 out_test(void)
-{
-    for (int i = 0; i < DO_NUMBER; i++)
-    {
-        outputs[i].port->odt ^= outputs[i].pin;
-        
-        printf("LOAD_1: %u LOAD_2: %u LOAD_3: %u LOAD_4: %u LOAD_5: %u LOAD_6: %u LOAD_7: %u LOAD_8: %u\r\n", 
-           gpio_input_data_bit_read(load_sens[0].port, load_sens[0].pin),
-           gpio_input_data_bit_read(load_sens[1].port, load_sens[1].pin),
-           gpio_input_data_bit_read(load_sens[2].port, load_sens[2].pin),
-           gpio_input_data_bit_read(load_sens[3].port, load_sens[3].pin),
-           gpio_input_data_bit_read(load_sens[4].port, load_sens[4].pin),
-           gpio_input_data_bit_read(load_sens[5].port, load_sens[5].pin),
-           gpio_input_data_bit_read(load_sens[6].port, load_sens[6].pin), 
-           gpio_input_data_bit_read(load_sens[7].port, load_sens[7].pin));
-        
-        vTaskDelay(500);
-    }  
-}
-
-//
-void load_test(void)
-{
-    printf("LOAD_1: %u LOAD_2: %u LOAD_3: %u LOAD_4: %u LOAD_5: %u LOAD_6: %u LOAD_7: %u LOAD_8: %u\r\n", 
-           gpio_input_data_bit_read(load_sens[0].port, load_sens[0].pin),
-           gpio_input_data_bit_read(load_sens[1].port, load_sens[1].pin),
-           gpio_input_data_bit_read(load_sens[2].port, load_sens[2].pin),
-           gpio_input_data_bit_read(load_sens[3].port, load_sens[3].pin),
-           gpio_input_data_bit_read(load_sens[4].port, load_sens[4].pin),
-           gpio_input_data_bit_read(load_sens[5].port, load_sens[5].pin),
-           gpio_input_data_bit_read(load_sens[6].port, load_sens[6].pin), 
-           gpio_input_data_bit_read(load_sens[7].port, load_sens[7].pin));
-}
-
-
-//
-void TMR1_BRK_TMR9_IRQHandler(void)
-{
-    if(tmr_flag_get(TMR9, TMR_OVF_FLAG) != RESET)
-    {
-        tmr_flag_clear(TMR9, TMR_OVF_FLAG);
-        //GPIOB->odt ^= GPIO_PINS_15;
-        pwm_proc();
-    }
-}
-
-#if 0
-void TMR1_BRK_TMR9_IRQHandler(void)
-{
-    static uint32_t cnt1 = 0;
-    static uint32_t cnt2 = 0;
-    
-    if (tmr_flag_get(TMR9, TMR_OVF_FLAG) != RESET)
-    {
-        tmr_flag_clear(TMR9, TMR_OVF_FLAG);
-        cnt1++;
-        printf("Cnt1 %u\r\n", cnt1);
-    }
-    else if (tmr_flag_get(TMR9, TMR_C1_INT) != RESET)
-    {
-        tmr_flag_clear(TMR9, TMR_C1_INT);
-        cnt2++;
-        printf("Cnt2 %u\r\n", cnt2);
-    }
-}
-#endif

+ 0 - 58
iap/modules/io/output.h

@@ -1,58 +0,0 @@
-#ifndef __OUTPUT_H
-#define __OUTPUT_H
-
-
-#include "io.h"
-
-
-#define PWM_PERIOD_TEST     20
-#define PWM_DUTY_TEST       18
-
-
-extern out_t outputs[];
-
-extern simple_gpio_t load_sens[];
-
-
-//
-void out_gpio_init(out_t *out, uint8_t index);
-
-//
-void do_set_common(void);
-
-//
-void do_set(void);
-
-// Установка значения на выходе 
-void do_update(out_t *out, uint8_t index);
-
-//
-void do_set_mode(void);
-
-//
-void do_set_pwm(uint16_t period, uint16_t duty, uint8_t index);
-
-//
-void do_set_out(out_t *out, uint8_t val);
-
-// 
-void out_pwm_tim_init(void);
-
-//
-void out_as_pwm(void);
-
-//
-void pwm_proc(void);
-
-//
-void load_sens_init(simple_gpio_t *sens);
-
-//
-void out_test(void);
-
-//
-void load_test(void);
-
-
-#endif  // __OUTPUT_H
-

+ 454 - 0
iap/modules/log/log.c

@@ -0,0 +1,454 @@
+#include "log.h"
+#include "rtc.h"
+#include "ringfs.h"
+#include "spi_flash.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+#include "event_groups.h"
+#include "rtc.h"
+#include "settings_api.h"
+#include "digital_input.h"
+#include "log_ai.h"
+#include "log_dio.h"
+#include "ringfs_api.h"
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#undef DBG
+#define DBG if(0)
+
+static bool archive_state = true;
+static bool log_state = true;
+
+static bool log_init_f = false;
+static bool archive_init_f = false;
+
+struct ringfs fs_log;
+
+SemaphoreHandle_t log_mutex;
+xQueueHandle log_queue;
+//EventGroupHandle_t archive_event;
+
+uint16_t log_entries_capacity;
+uint16_t archive_entries_capacity;
+
+void archive_task(void *params);
+void log_task(void *params);
+
+
+
+//
+static struct ringfs_flash_partition ringfs_flash_log = 
+{
+	.sector_offset = LOG_FLASH_SECTOR_OFFSET,
+	.sector_erase = op_sector_erase,
+	.program = op_program,
+	.read = op_read,
+};
+
+
+//
+void log_init(bool format) 
+{
+	DBG printf("[LOG] Init...\r\n");
+    
+    // ---------------------------------------------------------------------- //
+    // Журнал
+        
+	ringfs_flash_log.sector_size = spi_flash_desc.sector_size;
+	ringfs_flash_log.sector_count = LOG_FLASH_SECTOR_COUNT;
+
+	ringfs_init(&fs_log, &ringfs_flash_log, LOG_ENTRY_VERSION, sizeof(log_entry_t));
+    
+	if (format || ringfs_scan(&fs_log) != 0) {
+		DBG printf("FAT1 false\r\n");
+		ringfs_format(&fs_log);
+	}
+	DBG printf("FAT1 true\r\n");
+    
+    
+#if defined (MDIO_88)    
+    log_dio_archive_init();
+#endif
+    
+#if defined (MAI_12)
+    log_ai_archive_init();
+#endif
+    
+    // ---------------------------------------------------------------------- //
+	log_mutex = xSemaphoreCreateMutex();
+
+    log_entries_capacity = ringfs_capacity(&fs_log);
+    
+#if defined (MDIO_88) || (MAI_12)     
+    archive_entries_capacity = ringfs_capacity(&fs_ch_arch[0]);
+    
+    // Event
+    archive_event = xEventGroupCreate();
+
+	xTaskCreate(archive_task, "archive_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+#endif
+    
+    log_queue = xQueueCreate(10, sizeof(log_entry_t));
+
+    xTaskCreate(log_task, "log_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    
+    log_init_f = true;
+    
+    archive_init_f = true;
+
+    // Таймер для ведения архива с разным периодом по разным каналам
+    log_init_archive_tim();  
+}
+
+// Настройка таймера на частоту 10 Гц
+void log_init_archive_tim(void)
+{
+    printf("Init log timer...\r\n");
+    
+    crm_clocks_freq_type crm_clocks_freq_struct = {0};
+    
+    crm_periph_clock_enable(CRM_TMR14_PERIPH_CLOCK, TRUE);
+
+    crm_clocks_freq_get(&crm_clocks_freq_struct);
+    tmr_base_init(TMR14, 999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
+    tmr_cnt_dir_set(TMR14, TMR_COUNT_UP);
+        
+    tmr_flag_clear(TMR14, TMR_OVF_FLAG);
+
+    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
+    nvic_irq_enable(TMR8_TRG_HALL_TMR14_IRQn, 5, 0);
+       
+    tmr_counter_enable(TMR14, TRUE);
+    
+    tmr_interrupt_enable(TMR14, TMR_OVF_INT, TRUE);
+}
+
+//
+void TMR8_TRG_HALL_TMR14_IRQHandler(void)
+{
+    if (tmr_flag_get(TMR14, TMR_OVF_FLAG) != RESET)
+    {
+        tmr_flag_clear(TMR14, TMR_OVF_FLAG);
+        
+        if (archive_state) 
+        {
+            log_check_archive_cnt();
+            //printf("TMR_14 irq\r\n");
+        }
+    }
+}
+
+//
+int log_fetch(void *entry, entry_type_t entry_type, uint8_t ch, uint32_t timeout) 
+{
+    int ret;
+    
+    ret = xSemaphoreTake(log_mutex, (TickType_t)timeout);
+    
+    if (ret == pdFALSE)
+        return ret;
+    if (entry_type == LOG_ENTRY)
+        ret = ringfs_fetch(&fs_log, entry);
+#if defined (MDIO_88) || (MAI_12)     
+    else if (entry_type == ARCHIVE_ENTRY)
+        ret = ringfs_fetch(&fs_ch_arch[ch], entry);
+#endif    
+    else ret = -1;
+
+    xSemaphoreGive(log_mutex);
+    return ret;   
+}
+
+//
+int log_discard(void *entry, entry_type_t entry_type, uint8_t ch, uint32_t timeout)
+{
+    int ret;
+      
+    ret = xSemaphoreTake(log_mutex, (TickType_t)timeout);
+    
+    if (ret == pdFALSE)
+        return ret;
+    if (entry_type == LOG_ENTRY)
+        ret = ringfs_discard(&fs_log);
+#if defined (MDIO_88) || (MAI_12)     
+    else if (entry_type == ARCHIVE_ENTRY)
+        ret = ringfs_discard(&fs_ch_arch[ch]);
+#endif    
+    else ret = -1;
+    
+    xSemaphoreGive(log_mutex);
+    return ret; 
+}
+
+//
+int log_append(void *entry, entry_type_t entry_type, uint8_t ch)
+{
+    int ret;
+    TM_RTC_t time;
+    common_entry_t *entry_ptr = entry;
+    log_entry_t *log_etnry_ptr;
+    archive_entry_t *archive_etnry_ptr;
+    
+    ret = xSemaphoreTake(log_mutex, portMAX_DELAY);
+    
+    if (ret == pdFALSE)
+        return ret;
+  
+    if (entry_ptr->timestamp == 0)
+        entry_ptr->timestamp = rtc_get_ms();
+    
+    if (entry_type == LOG_ENTRY) 
+    {
+        log_etnry_ptr = (log_entry_t*)entry;
+        log_etnry_ptr->crc = crc_8(entry, sizeof(log_entry_t) - 1);
+        ret = ringfs_append(&fs_log, entry);
+    }
+#if defined (MDIO_88) || (MAI_12)     
+    else if (entry_type == ARCHIVE_ENTRY) 
+    {
+        archive_etnry_ptr = (archive_entry_t*)entry;
+        archive_etnry_ptr->crc = crc_8(entry, sizeof(archive_entry_t) - 1);
+        ret = ringfs_append(&fs_ch_arch[ch], entry);
+    }
+#endif    
+    else ret = -1;
+    
+    xSemaphoreGive(log_mutex);
+    return ret;
+    
+}
+
+//
+uint16_t log_capacity(void)
+{
+    return ringfs_count_exact(&fs_log);
+}
+
+//
+uint16_t log_arch_capacity(uint8_t ch)
+{
+#if defined (MDIO_88) || (MAI_12)   
+    return ringfs_count_exact(&fs_ch_arch[ch]);
+#endif    
+}
+
+// -------------------------------------------------------------------------- //
+// misc
+
+uint8_t crc_8(uint8_t *data, int length)
+{
+    uint8_t crc = 0x00;
+    uint8_t extract;
+    uint8_t sum;
+    
+    for (int i = 0; i < length; i++) {
+        extract = *data;
+        for (uint8_t tmp = 8; tmp; tmp--) {
+            sum = (crc ^ extract) & 0x01;
+            crc >>= 1;
+            if (sum)
+                crc ^= 0x8C;
+            extract >>= 1;
+        }
+        data++;
+    }
+    return crc;
+}
+
+// -------------------------------------------------------------------------- //
+// Tests
+
+// val - 0 - журнал
+// val - 1 - архив
+// ch - номер канала архива
+void log_info(uint8_t val, uint8_t ch)
+{
+    if (val > 1)
+        return;
+#if defined (MDIO_88) || (MAI_12)   
+    struct ringfs *fs = val == 0 ? &fs_log : &fs_ch_arch[ch];
+#else
+    struct ringfs *fs = &fs_log;
+#endif    
+    
+    int capacity_flash = 0;
+    int count_flash = 0;
+    int count_estimate = 0;
+    
+    capacity_flash = ringfs_capacity(fs);
+    count_flash = ringfs_count_exact(fs);
+    count_estimate = ringfs_count_estimate(fs);
+    
+    if (val == 0)
+    {
+        DBG printf("Log partition capacity: %u\r\n", capacity_flash);
+        DBG printf("Count log entry: %u\r\n", count_flash);
+        DBG printf("Estimate count: %u\r\n", count_estimate);
+    }
+    else 
+    {
+        DBG printf("Archive partition capacity: %u\r\n", capacity_flash);
+        DBG printf("Count archive entry: %u\r\n", count_flash);
+        DBG printf("Estimate count: %u\r\n", count_estimate);
+    }
+}
+
+// val - 0 - журнал
+// val - 1 - архив
+// ch - номер канала архива
+void log_format(uint8_t val, uint8_t ch)
+{
+    if (val == 0) {
+        DBG printf("Formating log partition...\r\n");
+        ringfs_format(&fs_log);
+    } 
+#if defined (MDIO_88) || (MAI_12)       
+    else if (val == 1) {
+        DBG printf("Formating archive partition...\r\n");
+        ringfs_format(&fs_ch_arch[ch]);
+    }
+#endif    
+}
+
+// Добавить n записей журнала
+int log_add_random_entry(uint8_t val, uint32_t cnt_entry, uint8_t ch)
+{
+    int ret;
+    log_entry_t log_entry = {0};
+    archive_entry_t archive_entry = {0};
+    
+    static uint8_t log_index = 0;
+    static uint32_t archive_index = 0;
+    
+    if (val == 0)
+    {
+        DBG printf("Appending %u archive entries\r\n", cnt_entry);
+        
+        for (uint32_t i = 0; i < cnt_entry; i++)
+        {
+            log_entry.code_type = log_index;
+            log_entry.code_state = log_index;
+            log_entry.channel_number = log_index;
+            log_entry.value = (float)log_index++;
+            
+            ret = log_append((void*)&log_entry, LOG_ENTRY, 0);
+        }
+        DBG printf("Result: %u\r\n", ret);
+    }
+      
+    if (val == 1)
+    {
+        DBG printf("Appending %u archive entries\r\n", cnt_entry);
+
+        for (uint32_t i = 0; i < cnt_entry; i++)
+        {
+            archive_entry.input_value = archive_index++;
+
+            ret = log_append((void*)&archive_entry, ARCHIVE_ENTRY, ch);
+        }
+        DBG printf("Result: %u\r\n", ret);
+    }
+    return ret;
+}
+
+//
+int log_add_entry(log_event_type_t type, log_event_state_t state, 
+                  uint8_t channel_number, float value)
+{
+    log_entry_t entry;
+    
+    if (!log_init_f)
+        return -1;
+    
+    entry.timestamp = rtc_get_ms();
+    entry.code_type = (uint8_t)type;
+    entry.code_state = (uint8_t)state;
+    entry.channel_number = channel_number;
+    entry.value = value;
+    
+    xQueueSend(log_queue, &entry, 0);
+    
+    return 0;
+}
+
+
+//
+void test_fetch(void)
+{
+    archive_entry_t entry = {0};
+    log_fetch(&entry, ARCHIVE_ENTRY, 0, portMAX_DELAY);
+    //printf("\r\n%" PRId64 " [ms]\r\n", rtc_get_ms());
+    printf("[entry] timestamp = % " PRId64 ", value = %u, crc = %u\r\n", entry.timestamp, entry.input_value, entry.crc);
+}
+
+//
+void log_archive_state(bool state)
+{
+    archive_state = state;
+}
+
+//
+void log_log_state(bool state)
+{
+    log_state = state;
+}
+
+
+void archive_task(void *params)
+{
+    int ret = 0;
+    uint32_t event = 0;
+    archive_entry_t entry = {0};
+    EventBits_t bits;
+    uint8_t channel_number = log_get_arch_channel_number();
+        
+    for (;;)
+    {
+        log_archive_task_device();
+    }
+}
+
+//
+void log_task(void *params)
+{
+    int ret;
+    log_entry_t entry;
+      
+    for (;;)
+    {
+        if (xQueueReceive(log_queue, &entry, portMAX_DELAY) == pdTRUE)
+        {
+            DBG printf("Try append LOG entry... ");
+            ret = log_append((void*)&entry, LOG_ENTRY, 0);
+            DBG printf("Result: %i\r\n", ret);
+        }
+    }
+}
+
+// Вызывается в прерывании таймера с частотой 10 Гц 
+// TODO
+void log_check_archive_cnt(void)
+{
+#if defined (MDIO_88) || (MAI_12)   
+    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+    uint8_t channel_number = log_get_arch_channel_number();
+
+    for (uint8_t i = 0; i < channel_number; i++)
+    {
+        if (archive_cnt[i]++ >= 10*settings.period_archive[i])
+        {
+            archive_cnt[i] = 0;
+
+            if (log_is_channel_on(i)) 
+            {
+                DBG printf("Send event: %u\r\n", 1 << i);
+                xEventGroupSetBitsFromISR(archive_event, 1 << i, &xHigherPriorityTaskWoken);
+            }
+        }
+    }
+#endif    
+}
+

+ 192 - 0
iap/modules/log/log.h

@@ -0,0 +1,192 @@
+#ifndef __LOG_H
+#define __LOG_H
+
+#include "at32f403a_407.h"
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+
+#define LOG_ENTRY_VERSION               1
+
+#define ARCHIV_ENTRY_VERSION            1
+
+#define LOG_FLASH_SECTOR_OFFSET         4
+
+#define LOG_FLASH_SECTOR_COUNT          51
+
+#define ARCHIVE_FLASH_SECTOR_OFFSET     60
+
+#define ARCHIVE_FLASH_SECTOR_COUNT      30 //38
+
+#define ARCHIVE_CHANNEL_OFFSET          (ARCHIVE_FLASH_SECTOR_COUNT + 4)
+  
+#define SECTOR_COUNT (spi_flash_desc.sector_count/2 - LOG_FLASH_SECTOR_OFFSET)  
+
+
+  
+  
+#define MB_ARCHIVE_ENTRY                0x06
+  
+#define MB_LOG_ENTRY                    0x07
+
+  
+// -------------------------------------------------------------------------- //
+  
+  
+// События архивов
+typedef enum
+{
+    ARCH_CH_1 = 1 << 0,
+    ARCH_CH_2 = 1 << 1,
+    ARCH_CH_3 = 1 << 2,
+    ARCH_CH_4 = 1 << 3,
+    ARCH_CH_5 = 1 << 4,
+    ARCH_CH_6 = 1 << 5,
+    ARCH_CH_7 = 1 << 6,
+    ARCH_CH_8 = 1 << 7,
+    ARCH_CH_9 = 1 << 8,
+    ARCH_CH_10 = 1 << 9,
+    ARCH_CH_11 = 1 << 10,
+    ARCH_CH_12 = 1 << 11,
+    
+} arch_event_t;
+
+  
+//
+typedef enum 
+{
+    LOG_SYSTEM_BOOT = 1,    // включение питания/перезагрузка
+    LOG_CLOCK_CHANGE,       // перевод времени
+    LOG_UPDATE_FW,          // обновление FW
+    LOG_SYSTEM_ERR,         // самодиагностика/системная ошибка
+    LOG_CHANGE_CONFIG,      // изменение конфигурации
+    LOG_OUPUTS,             // диагностика выходов
+    LOG_SETPOINT,           // срабатывание уставок
+    LOG_SAVE_MODE,          // переход в безопасный режим
+    LOG_CLEAR,              // очистка журнала/архива
+    
+    LOG_NONE,
+
+} log_event_type_t;
+
+
+typedef enum
+{
+    LOG_EVENT_STATE_ERR = 0,
+    LOG_EVENT_STATE_OK,
+    
+} log_event_state_t;
+
+
+typedef enum
+{
+    LOG_ENTRY = 0,
+    ARCHIVE_ENTRY,
+    
+} entry_type_t;
+
+
+//
+typedef __packed struct 
+{
+    uint64_t timestamp;
+    
+} common_entry_t;
+
+
+// Структура записи журанала
+typedef __packed struct 
+{
+	uint64_t timestamp;
+    uint8_t code_type;  // код типа события
+    uint8_t code_state; // код состояния
+    uint8_t channel_number; // номер канала
+    float value;        // значение
+    uint8_t crc;
+    
+} log_entry_t;
+
+
+// Структура архивной записи
+typedef __packed struct
+{
+    uint64_t timestamp;
+    uint8_t input_value;
+    uint8_t crc;
+    
+} archive_entry_t;
+
+
+//
+void log_init(bool format);
+
+//
+void log_init_archive_tim(void);
+
+//
+int log_fetch(void *entry, entry_type_t entry_type, uint8_t ch, uint32_t timeout);
+
+//
+int log_discard(void *entry, entry_type_t entry_type, uint8_t ch, uint32_t timeout);
+
+// 
+int log_append(void *entry, entry_type_t entry_type, uint8_t ch);
+
+//
+uint16_t log_capacity(void);
+
+//
+uint16_t log_arch_capacity(uint8_t ch);
+
+// -------------------------------------------------------------------------- //
+// misc
+
+uint8_t crc_8(uint8_t *data, int length);
+
+// -------------------------------------------------------------------------- //
+// Tests
+
+//
+void log_info(uint8_t val, uint8_t ch);
+
+//
+void log_format(uint8_t val, uint8_t ch);
+
+//
+int log_add_random_entry(uint8_t val, uint32_t cnt_entry, uint8_t ch);
+
+//
+int log_add_entry(log_event_type_t type, log_event_state_t state, 
+                  uint8_t channel_number, float value);
+
+//
+void test_fetch(void);
+
+//
+void log_archive_state(bool state);
+
+//
+void log_log_state(bool state);
+
+//
+void test_archive_format(void);
+
+//
+void log_check_archive_cnt(void);
+
+// -------------------------------------------------------------------------- //
+
+extern uint16_t log_entries_capacity;
+extern uint16_t archive_entries_capacity;
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __LOG_H */

+ 114 - 0
iap/modules/preset/preset_ai.c

@@ -0,0 +1,114 @@
+#include "preset_ai.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "settings_api.h"
+#include "triggers.h"
+#include "mux.h"
+#include "log.h"
+#include <stdio.h>
+
+#if defined (MAI_12)
+
+#undef DBG
+#define DBG if(1)
+
+extern led_t ai_alarm_led[];
+
+
+hyst_state_t hyst_state[AI_COMMON_NUMBER];
+
+preset_cur_t preset_cur[AI_COMMON_NUMBER];
+
+
+// 
+void preset_init(void)
+{
+    for (int i = 0; i < AI_COMMON_NUMBER; i++)
+    {
+        hyst_state[i] = hyst_idle;
+        
+        preset_cur[i].max = false;
+        preset_cur[i].min = false;
+    }
+}
+
+
+//
+void preset_set_state(void)
+{
+    for (int i = 0; i < AI_COMMON_NUMBER; i++)
+    {
+        if (((settings.preset_state_bits >> i) & 1) != settings.preset[i].state)
+        {
+            settings.preset[i].state = ((settings.preset_state_bits >> 1) & 1);
+        }
+    }
+}
+
+
+//
+void preset_process(float *data)
+{
+    bool high = false;
+    bool low = false;
+
+    for (int i = 0; i < AI_COMMON_NUMBER; i++)
+    {
+        if ((settings.preset[i].state == 0) || (settings.ai[i].state == 0))
+            continue;
+        
+        // 0 - тип уставки - фиксированное значение
+        if (settings.preset[i].type == 0)
+        {
+            high = trig_high_value(data[i], 0, settings.preset[i].max, settings.preset[i].hyst, &hyst_state[i]);
+            low = trig_low_value(data[i], settings.preset[i].min, 0, settings.preset[i].hyst, &hyst_state[i]);
+            
+   
+            if (preset_cur[i].max != high) {
+                // Запись в журнал о срабатывании верхней уставки
+                if (high == true) {
+                    printf("LOG high level! [%f]\r\n", data[i]);
+                    //log_add_entry(LOG_SETPOINT, 1, i + 1, data[i]);
+                }
+                else {
+                    printf("LOF high norm [%f]\r\n", data[i]);
+                    //log_add_entry(LOG_SETPOINT, 1, i + 1, data[i]);
+                }
+            }
+
+            if (preset_cur[i].min != low) {
+                // Запись в журнал о срабатывании нижней уставки
+                if (low == true) {
+                    printf("LOG low level! [%f]\r\n", data[i]);
+                    
+                }
+                else {
+                    printf("LOF low norm [%f]\r\n", data[i]);
+                    
+                }
+            }  
+            
+            preset_cur[i].max = high;
+            preset_cur[i].min = low;
+            
+#if 0            
+            // 
+            if (high) {
+                DBG printf("Chan: %i, val: %f, HIGH\r\n", i, data[i]);
+            }
+            
+            if (low) {
+                DBG printf("Chan: %i, val: %f, LOW\r\n", i, data[i]);
+            }
+#endif            
+        }
+        
+        
+    }
+}
+
+
+
+
+
+#endif

+ 41 - 0
iap/modules/preset/preset_ai.h

@@ -0,0 +1,41 @@
+#ifndef __PRESET_AI_H
+#define __PRESET_AI_H
+
+#include "at32f403a_407.h"
+#include <stdbool.h>
+
+
+//
+typedef struct
+{
+    uint8_t state;  // 0 - выкл, 1 - вкл
+    uint8_t type;   // тип, 0 - фиксированное значение
+    float min;      // минимальное значение
+    float max;      // максимальное значение
+    float hyst;     // значение гистерезиса
+
+} preset_ai_t;
+
+
+// Структура для текущих значений уставок
+typedef struct 
+{
+    bool max;       // значение сигнала больше верхней уствки
+    bool min;       // значение сигнала меньше нижней уставки
+  
+} preset_cur_t;
+
+
+// 
+void preset_init(void);
+
+//
+void preset_set_state(void);
+
+//
+void preset_process(float *data);
+
+
+
+#endif  // __PRESET_AI_H
+

+ 296 - 367
iap/modules/settings/settings_api.c

@@ -1,367 +1,296 @@
-#include "at32f403a_407.h" 
-#include "settings_api.h"
-#include "sys_api.h"
-#include "FreeRTOS.h"
-#include "task.h"
-#include "queue.h"
-#include "semphr.h"
-#include "common_config.h"
-#include "common.h"
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-
-SemaphoreHandle_t flash_mutex;
-
-  
-// Системные настройки
-sys_settings_t sys_settings;
-
-// Общая структура настроек
-settings_t settings;
-
-modbus_t mb_port_settings;
-
-
-//
-void init_settings(void)
-{
-    flash_mutex = xSemaphoreCreateMutex();
-}
-
-// Загрузка структуры настроек из flesh
-void settings_load(settings_t *settings)
-{
-    uint32_t loadCRC;  // CRC из flash
-    uint32_t newCRC;   // CRC загруженной структуры настроек
-    bool need_default = false;
-    
-    settings_read_from_flash((uint8_t*)settings, sizeof(settings_t));
-    
-    // Считываем CRC из флеш памяти
-    loadCRC = settings->critical_section_crc;
-    
-    // Рассчитываем CRC для структуры настроек
-    newCRC = settings_get_crc(settings);
-
-    // Если CRC не совпадают нужно прошивать дефолтные настройки
-    if (loadCRC != newCRC) {
-        need_default = true;
-    }
-    
-    // Прошиваем дефолтные настройки если нужно
-    if (need_default) 
-    {
-        settings_set_all_default();
-        settings_save(settings);
-    }
-}
-
-//
-void settings_read_from_flash(uint8_t *data, uint32_t size)
-{
-    uint32_t baseAddress = SETTINGS_SECTOR;
-        
-    for (uint32_t i = 0; i < size; i++)
-        *data++ = (*(uint32_t*)baseAddress++);;
-}
-
-//
-uint32_t settings_get_crc(settings_t *settings)
-{
-    crc_data_reset();
-    return crc_block_calculate((uint32_t*)settings, sizeof(settings_t)/4 - 1);
-}
-
-//
-uint32_t settings_get_crit_sec_crc(settings_t *settings)
-{
-    crc_data_reset();
-    uint32_t critsec_len = (uint32_t)((uint8_t *)(&settings->critical_section_crc) - (uint8_t *)settings) / 4;
-    return crc_block_calculate((uint32_t *)settings, critsec_len);
-}
-
-// Сброс всех настроек в значения по умолчанию
-void settings_set_all_default(void)
-{
-    settings_set_modbus_def(&settings.com_settings.mb_port);
-    settings.critical_section_crc = settings_get_crit_sec_crc(&settings);
-}
-
-// -------------------------------------------------------------------------- //
-// Настройки по умолчанию
-
-//
-void settings_set_modbus_def(uint16_t *mb_port)
-{
-    modbus_t mb_settings;
-    
-    mb_settings.baud = BRD_115200;
-	mb_settings.parity = NO_PAR;
-	mb_settings.databits = DATABITS_8;
-	mb_settings.stopbits = STOP_1;
-    
-    settings_conv_modbus_def(&mb_settings, mb_port);
-}
-
-//
-void settings_conv_modbus_def(modbus_t *mb_settings, uint16_t *mb_port)
-{
-	uint16_t param = 0;
-
-	// Количестро стоп бит (0-1 биты)
-	if (mb_settings->stopbits == STOP_1)
-		param = 0x00;
-	else if (mb_settings->stopbits == STOP_2)
-		param = 0x02; 		
-
-	// Длина слова (2ой бит)
-	param |= 0x00 << 2;
-
-	// Контроль четности (3-4 биты)
-	if (mb_settings->parity == NO_PAR)
-		param |= 0x00 << 3;
-	else if (mb_settings->parity == EVEN_PAR)
-		param |= 0x02 << 3;
-	else if (mb_settings->parity == ODD_PAR)
-		param |= 0x03 << 3;
-
-	// Скорость (5 - 7 биты)
-	switch (mb_settings->baud)
-	{
-		case BRD_2400 :
-			param |= 0x00 << 5;
-		break;
-
-		case BRD_4800 :
-			param |= 0x01 << 5;
-		break;
-
-		case BRD_9600 :
-			param |= 0x02 << 5;
-		break;
-
-		case BRD_19200 :
-			param |= 0x03 << 5;
-		break;
-
-		case BRD_38400 :
-			param |= 0x04 << 5;
-		break;
-
-		case BRD_57600 :
-			param |= 0x05 << 5;
-		break;
-
-		case BRD_115200 :
-			param |= 0x06 << 5;
-		break;
-
-		default : break;
-	}
-
-	*mb_port = param;
-}
-
-// Установка параметров Modbus
-void settings_set_modbus_params(uint16_t mb_port)
-{
-	uint16_t param = 0;
-
-	// Количестро стоп бит (0-1 биты)
-	param = 0x0003 & mb_port; 
-
-	if (param == 0x00)
-		mb_port_settings.stopbits = STOP_1;
-	else if (param == 0x02)
-		mb_port_settings.stopbits = STOP_2;
-
-	// Длина слова (2ой бит)
-	param = (0x0004 & mb_port) >> 2;
-
-	mb_port_settings.databits = DATABITS_8;
-	
-	// Контроль четности (3-4 биты)
-	param = (0x0018 & mb_port) >> 3; 
-
-	if (param == 0x00)
-		mb_port_settings.parity = NO_PAR;
-	else if (param == 0x02)
-		mb_port_settings.parity = EVEN_PAR;
-	else if (param == 0x03)
-		mb_port_settings.parity = ODD_PAR;
-
-	// Скорость (5 - 7 биты)
-	param = (0x00E0 & mb_port) >> 5; 
-
-	switch (param)
-	{
-		case 0x00 :
-			mb_port_settings.baud = BRD_2400;
-		break;
-
-		case 0x01 :
-			mb_port_settings.baud = BRD_4800;
-		break;
-
-		case 0x02 :
-			mb_port_settings.baud = BRD_9600;
-		break;
-
-		case 0x03 :
-			mb_port_settings.baud = BRD_19200;
-		break;
-
-		case 0x04 :
-			mb_port_settings.baud = BRD_38400;
-		break;
-
-		case 0x05 :
-			mb_port_settings.baud = BRD_57600;
-		break;
-
-		case 0x06 :
-			mb_port_settings.baud = BRD_115200;
-		break;
-
-		default : break;
-	}
-}
-
-// -------------------------------------------------------------------------- //
-
-// Запись структуры настроек во flash
-void settings_save(settings_t *settings)
-{
-    xSemaphoreTake(flash_mutex, portMAX_DELAY);
-    
-    settings->critical_section_crc = settings_get_crit_sec_crc(settings);
-    
-    settings_write_to_flash((uint8_t*)settings, sizeof(settings_t));
-    xSemaphoreGive(flash_mutex);
-}
-
-//
-void settings_write_to_flash(uint8_t *data, uint32_t size)
-{
-    uint32_t baseAddress = SETTINGS_SECTOR;
-    uint32_t checkCrc = 0;
-    uint32_t crc = settings_get_crc((settings_t*)data);
-    flash_status_type status;
-    uint8_t *ptr = data;
-    
-    for (uint8_t i = 0; i < 3; i++)
-    {	
-        flash_unlock();
-    
-        settings_erase_flash_sector();
-
-        for (uint32_t i = 0; i < size; i++)
-            if ((status = flash_byte_program(baseAddress++, *data++)) != FLASH_OPERATE_DONE) {
-                DBG printf("FLASH_ProgramByte error: status = %d\r\n", status);
-                break;
-            }
-    
-        if ((status = flash_word_program((uint32_t)CRC_ADDRESS, crc)) != FLASH_OPERATE_DONE) {
-            DBG printf("FLASH_ProgramWord error: status = %d\r\n", status);
-        }
-    
-        flash_lock();
-    
-        /* Считываем что записали */
-        settings_read_from_flash(ptr, sizeof(settings_t));
-    
-        checkCrc = settings_get_crc((settings_t*)ptr);
-    
-        /* Проверяем  CRC того что было записано */
-        if (checkCrc == crc)
-            break;
-    }
-}
-
-// Очистка сектора настроек
-void settings_erase_flash_sector(void)
-{
-    flash_status_type status;
-
-    if ((status = flash_sector_erase(SETTINGS_SECTOR)) != FLASH_OPERATE_DONE) {
-        DBG printf("SETTINGS_EraseFlashSector error: status = %d/r/n", status);
-    }
-}
-
-//
-uint32_t settings_get_mb_baud(modbus_t *mb_settings)
-{
-    switch (mb_settings->baud)
-    {
-        case BRD_1200 :
-          return 1200;
-        break;
-        
-        case BRD_2400 :
-          return 2400;
-        break;
-        
-        case BRD_4800 :
-            return 4800;
-        break;
-        
-        case BRD_9600 :
-            return 9600;
-        break;
-        
-        case BRD_19200 :
-            return 19200;
-        break;
-        
-        case BRD_38400 :
-            return 38400;
-        break;
-        
-        case BRD_57600 :
-            return 57600;
-        break;
-        
-        case BRD_115200 :
-            return 115200;
-        break;
-        
-        case BRD_230400 :
-            return 230400;
-        break;
-        
-        case BRD_460800 :
-            return 460800;
-        break;
-        
-        default :
-            return 115200; 
-        break;
-    }
-}
-
-
-//
-eMBParity settings_get_mb_par(modbus_t *mb_settings)
-{
-    switch (mb_settings->parity)
-    {
-        case NO_PAR :
-            return MB_PAR_NONE;
-        break;
-        
-        case ODD_PAR :
-            return MB_PAR_ODD;
-        break;
-        
-        case EVEN_PAR :
-            return MB_PAR_EVEN;
-        break;
-        
-        default :
-            return MB_PAR_NONE;
-        break;
-    }
-}
-
+#include "at32f403a_407.h" 
+#include "settings_api.h"
+#include "sys_api.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+#include "common_config.h"
+#include "common.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+SemaphoreHandle_t flash_mutex;
+
+  
+// Системные настройки
+sys_settings_t sys_settings;
+
+// Общая структура настроек
+settings_t settings;
+
+modbus_t mb_port_settings;
+
+
+//
+void init_settings(void)
+{
+    flash_mutex = xSemaphoreCreateMutex();
+}
+
+// Загрузка структуры настроек из flesh
+bool settings_load(settings_t *settings)
+{
+    uint32_t loadCRC;  // CRC из flash
+    
+    settings_read_from_flash((uint8_t*)settings, sizeof(settings_t));
+    
+    loadCRC = settings->critical_section_crc;
+
+    if (loadCRC == 0xFFFFFFFF)
+        return false;
+    
+    return true;
+}
+
+//
+void settings_read_from_flash(uint8_t *data, uint32_t size)
+{
+    uint32_t baseAddress = SETTINGS_SECTOR;
+        
+    for (uint32_t i = 0; i < size; i++)
+        *data++ = (*(uint32_t*)baseAddress++);;
+}
+
+//
+uint32_t settings_get_crc(settings_t *settings)
+{
+    crc_data_reset();
+    return crc_block_calculate((uint32_t*)settings, sizeof(settings_t)/4 - 1);
+}
+
+//
+uint32_t settings_get_crit_sec_crc(settings_t *settings)
+{
+    crc_data_reset();
+    uint32_t critsec_len = (uint32_t)((uint8_t *)(&settings->critical_section_crc) - (uint8_t *)settings) / 4;
+    return crc_block_calculate((uint32_t *)settings, critsec_len);
+}
+
+// Сброс всех настроек в значения по умолчанию
+void settings_set_all_default(void)
+{
+    settings_set_modbus_def(&settings.com_settings.mb_port);
+    settings.critical_section_crc = settings_get_crit_sec_crc(&settings);
+}
+
+// -------------------------------------------------------------------------- //
+// Настройки по умолчанию
+
+//
+void settings_set_modbus_def(uint16_t *mb_port)
+{
+    modbus_t mb_settings;
+    
+    mb_settings.baud = BRD_115200;
+	mb_settings.parity = NO_PAR;
+	mb_settings.databits = DATABITS_8;
+	mb_settings.stopbits = STOP_1;
+    
+    settings_conv_modbus_def(&mb_settings, mb_port);
+}
+
+//
+void settings_conv_modbus_def(modbus_t *mb_settings, uint16_t *mb_port)
+{
+	uint16_t param = 0;
+
+	// Количестро стоп бит (0-1 биты)
+	if (mb_settings->stopbits == STOP_1)
+		param = 0x00;
+	else if (mb_settings->stopbits == STOP_2)
+		param = 0x02; 		
+
+	// Длина слова (2ой бит)
+	param |= 0x00 << 2;
+
+	// Контроль четности (3-4 биты)
+	if (mb_settings->parity == NO_PAR)
+		param |= 0x00 << 3;
+	else if (mb_settings->parity == EVEN_PAR)
+		param |= 0x02 << 3;
+	else if (mb_settings->parity == ODD_PAR)
+		param |= 0x03 << 3;
+
+	// Скорость (5 - 7 биты)
+	switch (mb_settings->baud)
+	{
+		case BRD_2400 :
+			param |= 0x00 << 5;
+		break;
+
+		case BRD_4800 :
+			param |= 0x01 << 5;
+		break;
+
+		case BRD_9600 :
+			param |= 0x02 << 5;
+		break;
+
+		case BRD_19200 :
+			param |= 0x03 << 5;
+		break;
+
+		case BRD_38400 :
+			param |= 0x04 << 5;
+		break;
+
+		case BRD_57600 :
+			param |= 0x05 << 5;
+		break;
+
+		case BRD_115200 :
+			param |= 0x06 << 5;
+		break;
+
+		default : break;
+	}
+
+	*mb_port = param;
+}
+
+// Установка параметров Modbus
+void settings_set_modbus_params(uint16_t mb_port)
+{
+	uint16_t param = 0;
+
+	// Количестро стоп бит (0-1 биты)
+	param = 0x0003 & mb_port; 
+
+	if (param == 0x00)
+		mb_port_settings.stopbits = STOP_1;
+	else if (param == 0x02)
+		mb_port_settings.stopbits = STOP_2;
+
+	// Длина слова (2ой бит)
+	param = (0x0004 & mb_port) >> 2;
+
+	mb_port_settings.databits = DATABITS_8;
+	
+	// Контроль четности (3-4 биты)
+	param = (0x0018 & mb_port) >> 3; 
+
+	if (param == 0x00)
+		mb_port_settings.parity = NO_PAR;
+	else if (param == 0x02)
+		mb_port_settings.parity = EVEN_PAR;
+	else if (param == 0x03)
+		mb_port_settings.parity = ODD_PAR;
+
+	// Скорость (5 - 7 биты)
+	param = (0x00E0 & mb_port) >> 5; 
+
+	switch (param)
+	{
+		case 0x00 :
+			mb_port_settings.baud = BRD_2400;
+		break;
+
+		case 0x01 :
+			mb_port_settings.baud = BRD_4800;
+		break;
+
+		case 0x02 :
+			mb_port_settings.baud = BRD_9600;
+		break;
+
+		case 0x03 :
+			mb_port_settings.baud = BRD_19200;
+		break;
+
+		case 0x04 :
+			mb_port_settings.baud = BRD_38400;
+		break;
+
+		case 0x05 :
+			mb_port_settings.baud = BRD_57600;
+		break;
+
+		case 0x06 :
+			mb_port_settings.baud = BRD_115200;
+		break;
+
+		default : break;
+	}
+}
+
+// -------------------------------------------------------------------------- //
+
+
+//
+uint32_t settings_get_mb_baud(modbus_t *mb_settings)
+{
+    switch (mb_settings->baud)
+    {
+        case BRD_1200 :
+          return 1200;
+        break;
+        
+        case BRD_2400 :
+          return 2400;
+        break;
+        
+        case BRD_4800 :
+            return 4800;
+        break;
+        
+        case BRD_9600 :
+            return 9600;
+        break;
+        
+        case BRD_19200 :
+            return 19200;
+        break;
+        
+        case BRD_38400 :
+            return 38400;
+        break;
+        
+        case BRD_57600 :
+            return 57600;
+        break;
+        
+        case BRD_115200 :
+            return 115200;
+        break;
+        
+        case BRD_230400 :
+            return 230400;
+        break;
+        
+        case BRD_460800 :
+            return 460800;
+        break;
+        
+        default :
+            return 115200; 
+        break;
+    }
+}
+
+
+//
+eMBParity settings_get_mb_par(modbus_t *mb_settings)
+{
+    switch (mb_settings->parity)
+    {
+        case NO_PAR :
+            return MB_PAR_NONE;
+        break;
+        
+        case ODD_PAR :
+            return MB_PAR_ODD;
+        break;
+        
+        case EVEN_PAR :
+            return MB_PAR_EVEN;
+        break;
+        
+        default :
+            return MB_PAR_NONE;
+        break;
+    }
+}
+

+ 123 - 23
iap/modules/settings/settings_api.h

@@ -2,20 +2,74 @@
 #define SETTINGS_API_H
 
 #include "at32f403a_407.h"
-#include <stdbool.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 "preset_ai.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 байт)                // +
+
+*/
 
-#define MODEL_LEN           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
 {
@@ -23,7 +77,7 @@ typedef struct
 	parity_t   parity;		// Четность 
 	databits_t databits;	// Число бит данных
 	stopbits_t stopbits;	// Число стоп-бит  
-
+    
 } modbus_t;
 
 
@@ -32,18 +86,8 @@ typedef struct
 {
     uint16_t    mb_port;    // Настройки порта для modbus
     //char model[MODEL_LEN];  // Модель
-      
 } com_settings_t;
 
-
-// Полная структура настроек
-typedef struct
-{
-    com_settings_t  com_settings;
-    uint32_t        critical_section_crc;
-    
-} settings_t;
-
 //
 typedef enum 
 {
@@ -59,8 +103,56 @@ typedef enum
 } mb_err_code_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;       // Слово для контроля целостности структуры настроек
+    
+   
+    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]; // дискретные входы
+    
+    do_t        dout[DO_NUMBER];        // параметры выходов в обычном режиме
+    do_t        dout_save[DO_NUMBER];   // параметры выходов в безопасном режиме
+    
+    uint16_t    period_archive[ARCH_DIO_CH_NUMBER]; // период архивирования
+
+    
+    uint16_t    save_mode;          // безопасный режим, 0 - выкл, 1 - вкл
+    uint16_t    save_delay;         // время ожидания опроса (сек.)
+      
+    uint8_t     info[32];           // Пользовательская информация. Текстовая строка.
+    
+    
+} settings_t;
+
+
+
 // Загрузка структуры настроек из flesh
-void settings_load(settings_t *settings);
+bool settings_load(settings_t *settings);
 
 //
 void init_settings(void);
@@ -90,29 +182,37 @@ 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);
 
-// Запись структуры настроек во flash
-void settings_save(settings_t *settings);
+//
+eMBParity settings_get_mb_par(modbus_t *mb_settings);
 
 //
-void settings_write_to_flash(uint8_t *data, uint32_t size);
+void settings_init_mb_port(uint8_t mb_addr);
+
+// -------------------------------------------------------------------------- //
 
-// Очистка сектора настроек
-void settings_erase_flash_sector(void);
 
 //
-uint32_t settings_get_mb_baud(modbus_t *mb_settings);
+bool settings_is_changed(settings_t *new_settings);
 
 //
-eMBParity settings_get_mb_par(modbus_t *mb_settings);
+void settings_print(void);
+
 
 // Системные настройки
 extern sys_settings_t sys_settings;
 
-//
+// Копия системных настроек
+extern sys_settings_t temp_sys_settings;
+
+// Общая структура настроек
 extern settings_t settings;
 
+//
+extern SemaphoreHandle_t flash_mutex;
+
 //
 extern modbus_t mb_port_settings;
 

+ 24 - 10
iap/user/main.c

@@ -1,5 +1,8 @@
 #include "main.h"
 #include "common_config.h"
+#include "utility.h"
+#include "model_cfg.h"
+#include "digital_output.h"
 
 
 void soft_wdt(void *params);
@@ -34,16 +37,14 @@ int main()
     system_clock_config();
     
     delay_init();
-
-    uart_print_init(115200);
     
     // Флаг - нужно ли обновляться
     load_mode = bpr_data_read(BACKUP_IAP_LOAD_MODE);
     
     // Число попыток загрузки основного ПО
     boot_try = bpr_data_read(BACKUP_IAP_BOOT_TRY);
-    
-    DBG printf("[IAP] load_mode: %u, boot_try: %u\r\n", load_mode, boot_try);
+#if 0    
+    //DBG printf("[IAP] load_mode: %u, boot_try: %u\r\n", load_mode, boot_try);
 
     // Если есть попытки, то пытаемся загрузить FW.
 	// Используем ограниченное число попыток загрузить основное FW.
@@ -57,13 +58,13 @@ int main()
             // Флеш пустая. Нечего загружать
             fw_invalid = 1;
             boot_failed = false;
-            DBG printf("FW empty! Bootloader starting...\n\r");
+            //DBG printf("FW empty! Bootloader starting...\n\r");
         }
     }
     else if (boot_try == 1)
     {
         boot_failed = true;
-        DBG printf("FW boot failed. Bootloader starting...\r\n");
+        //DBG printf("FW boot failed. Bootloader starting...\r\n");
         
         load_mode = 1;
         boot_try = 0;
@@ -73,15 +74,28 @@ int main()
     
     if  ((load_mode == 0) && (!fw_invalid))
     {
-        DBG printf("Run main FW\r\n");
+        //DBG printf("Run main FW\r\n");
         bpr_data_write(BACKUP_IAP_BOOT_TRY, BOOT_TRY);
-        DBG printf("Go to main FW...\r\n");
+        //DBG printf("Go to main FW...\r\n");
         jump_to_app(USER_FLASH_FIRST_PAGE_ADDRESS);
     }
-        
+#endif     
+    // Модуль MDIO_88 должен поддерживать работу выходов при работе в IAP
+    if (get_mode_from_flash() == MODEL_MDIO_88)
+    {
+        crm_periph_clock_enable(CRM_CRC_PERIPH_CLOCK, TRUE);
+        settings_load(&settings);
+        //settings_set_modbus_params(settings.com_settings.mb_port);
+        do_init();
+    }
+    
+    uart_print_init(115200);
+    
     DBG printf("IAP starting...\r\n");
 
-    // -------------------------------------------------------------------------- //    
+    
+    
+    // -------------------------------------------------------------------------    
     // Мультиплексор
     
     mux_gpio_init();

二進制
output/fw.bin


二進制
output/iap.bin


文件差異過大導致無法顯示
+ 557 - 490
project/ewarm/iap/iap.dep


+ 15 - 1
project/ewarm/iap/iap.ewp

@@ -376,6 +376,8 @@
                     <state>$PROJ_DIR$\..\..\..\iap\modules\settings</state>
                     <state>$PROJ_DIR$\..\..\..\iap\modules\iap</state>
                     <state>$PROJ_DIR$\..\..\..\iap\modules\io</state>
+                    <state>$PROJ_DIR$\..\..\..\iap\modules\log</state>
+                    <state>$PROJ_DIR$\..\..\..\iap\modules\preset</state>
                     <state>$PROJ_DIR$\..\..\..\iap\user</state>
                     <state>$PROJ_DIR$\..\..\..\libs\thirdparty\freertos\include</state>
                     <state>$PROJ_DIR$\..\..\..\libs\thirdparty\freertos\portable\IAR\ARM_CM4F</state>
@@ -445,7 +447,7 @@
                 </option>
                 <option>
                     <name>IccCppInlineSemantics</name>
-                    <state>0</state>
+                    <state>1</state>
                 </option>
                 <option>
                     <name>IccCmsis</name>
@@ -2144,10 +2146,19 @@
             </group>
             <group>
                 <name>io</name>
+                <file>
+                    <name>$PROJ_DIR$\..\..\..\iap\modules\io\digital_output.c</name>
+                </file>
+                <file>
+                    <name>$PROJ_DIR$\..\..\..\iap\modules\io\io_utils.c</name>
+                </file>
                 <file>
                     <name>$PROJ_DIR$\..\..\..\iap\modules\io\mux.c</name>
                 </file>
             </group>
+            <group>
+                <name>log</name>
+            </group>
             <group>
                 <name>misc</name>
             </group>
@@ -2160,6 +2171,9 @@
                     <name>$PROJ_DIR$\..\..\..\iap\modules\modbus\modbus_params.c</name>
                 </file>
             </group>
+            <group>
+                <name>preset</name>
+            </group>
             <group>
                 <name>settings</name>
                 <file>

+ 12 - 0
project/ewarm/iap/iap.ewt

@@ -2381,10 +2381,19 @@
             </group>
             <group>
                 <name>io</name>
+                <file>
+                    <name>$PROJ_DIR$\..\..\..\iap\modules\io\digital_output.c</name>
+                </file>
+                <file>
+                    <name>$PROJ_DIR$\..\..\..\iap\modules\io\io_utils.c</name>
+                </file>
                 <file>
                     <name>$PROJ_DIR$\..\..\..\iap\modules\io\mux.c</name>
                 </file>
             </group>
+            <group>
+                <name>log</name>
+            </group>
             <group>
                 <name>misc</name>
             </group>
@@ -2397,6 +2406,9 @@
                     <name>$PROJ_DIR$\..\..\..\iap\modules\modbus\modbus_params.c</name>
                 </file>
             </group>
+            <group>
+                <name>preset</name>
+            </group>
             <group>
                 <name>settings</name>
                 <file>

文件差異過大導致無法顯示
+ 657 - 655
project/ewarm/module_universal_io.dep


+ 1 - 1
project/ewarm/module_universal_io.ewp

@@ -225,7 +225,7 @@
                     <state>AT_START_F403A_V1</state>
                     <state>PRINTF_STDLIB</state>
                     <state>DEBUG</state>
-                    <state>MAI_12</state>
+                    <state>MDIO_88</state>
                 </option>
                 <option>
                     <name>CCPreprocFile</name>

+ 10 - 0
shared/model/model_cfg.h

@@ -20,6 +20,16 @@
 #endif
 
 
+typedef enum
+{
+    MODEL_EMPTY = 0,
+    MODEL_MDIO_88 = 0x0100,
+    MODEL_MAO_4 = 0x0200,
+    MODEL_MAI_12 = 0x0300,
+    
+} model_t;
+
+
 static const uint16_t model_code = MODEL_CODE;
 
 #define MODEL_ADDR          0x080211F0

+ 20 - 1
shared/utils/utility.c

@@ -125,4 +125,23 @@ void TMR4_GLOBAL_IRQHandler(void)
         ulHighFrequencyTimerTicks++;
 #endif        
     }
-}
+}
+
+// 
+model_t get_mode_from_flash(void)
+{
+    char model[MODEL_LEN] = {0};
+    
+    memcpy(model, (void const*)MODEL_ADDR, MODEL_LEN);
+    
+    if (strncmp(model, "MDIO_88", 7) == 0)
+        return MODEL_MDIO_88;
+    
+    if (strncmp(model, "MAI_12", 6) == 0)
+        return MODEL_MAI_12;
+    
+    if (strncmp(model, "MAO_4", 5) == 0)
+        return MODEL_MAO_4;
+    
+    return MODEL_EMPTY;
+}

+ 5 - 0
shared/utils/utility.h

@@ -1,6 +1,8 @@
 #ifndef __UTILITY_H_
 #define __UTILITY_H_
 
+#include "model_cfg.h"
+
 
 #define BIT_READ(value, bit) (((value) >> (bit)) & 0x01)
 #define BIT_SET(value, bit) ((value) |= (1UL << (bit)))
@@ -21,5 +23,8 @@ void utl_stat_timer_init(void);
 //
 void print_os_stat(void);
 
+// 
+model_t get_mode_from_flash(void);
+
 
 #endif /* __UTILITY_H_ */

+ 8 - 6
tools/analog_in.py

@@ -165,7 +165,7 @@ class IO_AnalogInput(IO_Module):
 
     def set_inputs_mode(self, val):
         'Режим измерения входов (0 - напряжение или 1 - ток. (битовое поле))'
-        self.modbus.write_holding_register(AiReg.IN_STATE.value, val)
+        self.modbus.write_holding_register(AiReg.IN_MODE.value, val)
 
 
     def set_voltage_range(self, val):
@@ -309,7 +309,7 @@ class IO_AnalogInput(IO_Module):
 def main():
     colorama.init(autoreset=True)
     
-    serial_port = Serial('COM10', 115200, timeout=0.05, parity='N', xonxoff=False)
+    serial_port = Serial('COM12', 115200, timeout=0.05, parity='N', xonxoff=False)
     
     modbus_tester = Modbus(serial_port, 1)
     modbus_tester.MB_DEBUG = False
@@ -317,8 +317,10 @@ def main():
     ai = IO_AnalogInput(modbus_tester) 
 
     '''Режим работы аналоговых входов'''
-    # ai.set_inputs_state(0b1111_1111_1111)
-    # ai.print_inputs()
+    ai.set_inputs_state(0b1111_1111_1111)
+    # ai.set_voltage_range(0b1111_1111_1111)
+    ai.set_voltage_range(0b0000_0000_0000)
+    ai.print_inputs()
         
     # ai.show_graph(ai.get_fil_inputs, 'AIN_FIL_1')
 
@@ -340,8 +342,8 @@ def main():
     # ai.print_inputs()
 
     '''Системное'''
-    print(ai.sys.get_uptime())
-    # ai.sys.save_settings()
+    # print(ai.sys.get_uptime())
+    ai.sys.save_settings()
 
     '''Установка коэффициентов усиления. Канал, коэффициент'''
     '''

+ 174 - 0
tools/calibration_analog_in.py

@@ -0,0 +1,174 @@
+from modbus import Modbus
+from analog_in import IO_AnalogInput
+from serial import Serial
+from colorama import Fore
+from mb_registers import *
+import inquirer
+from dataclasses import dataclass
+import time
+
+CALIBRATION_MODE = ['VOLT']
+
+
+@dataclass(frozen=True)
+class Const:
+    VOLTAGE_0_10 = 0
+    VOLTAGE_1_10 = 1
+
+    FIRST_POINT_VOLTAGE = 1.0
+    SECOND_POINT_VOLTAGE = 10.0
+    MIDLE_POINT_VOLTAGE = 5.0
+
+
+class Calibration_AI:
+
+    CHANNEL_NUMBER = 12
+
+    def __init__(self, mb_port):
+        serial_port = Serial(mb_port, 115200, timeout=0.05, parity='N', xonxoff=False)
+        self.modbus = Modbus(serial_port, 1)
+        self.dut = IO_AnalogInput(self.modbus)
+        self.mid_point_factors = [0]*self.CHANNEL_NUMBER
+        self.first_point_data = [0]*self.CHANNEL_NUMBER
+        self.second_point_data = [0]*self.CHANNEL_NUMBER
+
+        self.k_factors = [0]*self.CHANNEL_NUMBER
+        self.b_factors = [0]*self.CHANNEL_NUMBER
+
+    def voltage_0_10(self):
+        print("Калибровка напряжения в режиме 0-10 В")
+        self.setup_module(Const.VOLTAGE_0_10)
+
+
+    def get_filtered_data(self, sample_count: int):
+        raw_data = []
+
+        for i in range(sample_count):
+            raw = self.dut.get_fil_inputs()
+            raw_data.append(raw)
+            time.sleep(0.5)
+
+        tmp_data = [0]*self.CHANNEL_NUMBER
+        for j in range(self.CHANNEL_NUMBER):
+            for i in range(sample_count):
+                tmp_data[j] += raw_data[i][j]/sample_count
+
+        return tmp_data
+
+
+    def middle_point(self, point: float):
+        """Расчет коэффициента средней точки"""
+        print(f"Установите значение напряжения {point} и нажмите 'Enter'")
+        input()
+        raw_data = self.get_filtered_data(10)
+
+        print(raw_data)
+
+        for i in range(self.CHANNEL_NUMBER):
+            self.mid_point_factors[i] = (point - raw_data[i])/10.0
+
+
+    def point(self, point: float):
+        """Расчет коэффициентов для точки"""
+        print(f"Установите значения напряжения {point} и назмите 'Enter'")
+        input()
+        return self.get_filtered_data(10)
+
+
+    def test_factors(self, point:float):
+        """Проверка коэффициентов"""
+        print(f"Установите значения напряжения {point} и назмите 'Enter'")
+        input()
+        data = self.get_filtered_data(10)
+        for i in range(self.CHANNEL_NUMBER):
+            data[i] = (point - (data[i]*self.k_factors[i] + self.b_factors[i]))/10.0
+
+        return data
+
+
+    def calibration_mode(self, mode: int):
+        # Настройка входов
+        self.setup_module(mode)
+        # Средняя точка 5 В
+        self.middle_point(Const.MIDLE_POINT_VOLTAGE)
+        # Первая точка 1 В
+        self.first_point_data = self.point(Const.FIRST_POINT_VOLTAGE)
+        # Вторая точка 10 В
+        self.second_point_data = self.point(Const.SECOND_POINT_VOLTAGE)
+        # Расчет коэффициентов уравнения прямой
+        for i in range(self.CHANNEL_NUMBER):
+
+            self.k_factors[i] = ((self.second_point_data[i] - self.first_point_data[i]) / \
+                                (Const.SECOND_POINT_VOLTAGE - Const.FIRST_POINT_VOLTAGE))
+
+            self.b_factors[i] = self.second_point_data[i] - self.k_factors[i]*Const.SECOND_POINT_VOLTAGE
+
+            self.k_factors[i] = 1.0/self.k_factors[i]
+
+            # self.k_factors[i] = 1.0/((self.second_point_data[i] - self.first_point_data[i]) / \
+            #                     (Const.SECOND_POINT_VOLTAGE - Const.FIRST_POINT_VOLTAGE))
+            # self.b_factors[i] = Const.SECOND_POINT_VOLTAGE - self.second_point_data[i]
+
+        # Проверка коэффициентов
+        print(self.mid_point_factors)
+        print(self.test_factors(5.0))
+
+        # print("First point data")
+        # print(self.first_point_data)
+        # print("Secon point data")
+        # print(self.second_point_data)
+
+        # print("k, b factors")
+        # print(self.k_factors)
+        # print(self.b_factors)
+
+        
+
+
+
+
+
+    def setup_module(self, channel_mode: int):
+        """Настройка измеретельных каналов модуля в нужном режиме"""
+
+        # Настройка каналов в режиме измерения напряжения 0 - 10 В
+        if channel_mode == Const.VOLTAGE_0_10:
+            print("Настройка модуля в режиме измерения напряжения 0 - 10 В...", end='')
+            self.dut.set_inputs_state(0b1111_1111_1111)
+            self.dut.set_inputs_mode(0b0000_0000_0000)
+            self.dut.set_voltage_range(0b0000_0000_0000)
+            for i in range(1, 13):
+                self.dut.set_k_factor(i, 1.0)
+                self.dut.set_b_factor(i, 0.0)
+            # self.dut.sys.save_settings()
+            # self.dut.print_inputs()
+            print('OK')
+
+
+
+
+
+    def menu(self):
+        menu_items = [
+        inquirer.List('action',
+                message="Калибровка MAI_12",
+                choices=['Калибровка напряжения 0-10 В',
+                         'Завершить'],
+            ),
+        ]
+
+        while True:
+            answers = inquirer.prompt(menu_items)
+            if answers['action'] == 'Калибровка напряжения 0-10 В':
+                self.calibration_mode(Const.VOLTAGE_0_10)
+            elif answers['action'] == 'Завершить':
+                return
+
+
+def main():
+    calibration = Calibration_AI('COM12')
+    calibration.menu()
+
+
+if __name__ == '__main__':
+    main()

部分文件因文件數量過多而無法顯示