Browse Source

[BT-6710]add portgw module

balbekova 5 năm trước cách đây
mục cha
commit
9f58efe810

+ 70 - 41
config/board_bt6710.h

@@ -81,6 +81,7 @@ WDG_PIN(X)
 #define WEB_SERVER_ENABLE           //Веб сервер
 #define SNMP_ENABLE                 //SNMP протокол
 #define UPS_ENABLE                  //UPS
+#define PORTGW_ENABLE               //Прозрачный порт
 //#define DEBUG_FREERTOS            //Мониторинг FreeRtos
 
 
@@ -91,6 +92,7 @@ XSETTING( SNTP_t,	sSNTP, SETTINGS_SetSntpDef, ALL_DEFAULT ) \
 XSETTING( INOUTS_t,	sInOuts, SETTINGS_SetINOUTSDef, ALL_DEFAULT ) \
 XSETTING( UPS_Setting_t, UPS_Setting, SETTINGS_SetUPSSettingsDef, ALL_DEFAULT ) \
 XSETTING( ALARM_MNGR_t, sAlarmManager, SETTINGS_SetAlarmManagerDef, ALL_DEFAULT ) \
+XSETTING( PORTGW_t, sPortGw, SETTINGS_SetPortGwDef, ALL_DEFAULT ) \
 
 #define SNMP_DEV_ROOT_OID       9
 
@@ -126,8 +128,6 @@ XSETTING( ALARM_MNGR_t, sAlarmManager, SETTINGS_SetAlarmManagerDef, ALL_DEFAULT
   XJSON_SETTINGS_TAG("temp_high",          GetTemperatureAlarmHighRangeStr,           SetTemperatureAlarmHighRangeStr) \
   XJSON_SETTINGS_TAG("temp_low",           GetTemperatureAlarmLowRangeStr,            SetTemperatureAlarmLowRangeStr) \
   XJSON_SETTINGS_TAG("temp_hist",          GetTemperatureAlarmHisteStr,               SetTemperatureAlarmHisteStr) \
-  XJSON_SETTINGS_TAG("loadvolt_high",      GetLoadAlarmHighRangeStr,                  SetLoadAlarmHighRangeStr) \
-  XJSON_SETTINGS_TAG("loadvolt_hist",      GetLoadAlarmHisteStr,                      SetLoadAlarmHistStr) \
   XJSON_SETTINGS_TAG("netsettings_changed",GetWebReinitFlag,                          SetEmptyFuncStr) \
 
 #define WEB_PARAMS_TAGS_TABLE \
@@ -148,44 +148,73 @@ XSETTING( ALARM_MNGR_t, sAlarmManager, SETTINGS_SetAlarmManagerDef, ALL_DEFAULT
   XTRAP(FW_VERSION_UPDATE,                 1,      true,      GetVersionStr) \
   XTRAP(FW_VERSION_UPDATED,                1,      true,      GetVersionStr) \
   XTRAP(DEVICE_RESTORED,                   1,      true,      GetVersionStr) \
-  XTRAP(DI0_NORM,                          9,      true,      GetDIN0StatusStr) \
-  XTRAP(DI0_ALARM,                         9,      true,      GetDIN0StatusStr) \
-  XTRAP(BATTERY_HIGH_TEMPERATURE_NORM,     9,      true,      GetInternalTempStr) \
-  XTRAP(BATTERY_HIGH_TEMPERATURE_ALARM,    9,      true,      GetInternalTempStr) \
-  XTRAP(LINE_ALARM,                        9,      true,      GetInputVoltageStr) \
-  XTRAP(LINE_NORM,                         9,      true,      GetInputVoltageStr) \
-  XTRAP(LOW_BAT_ALARM,                     9,      true,      GetBatCapacityStr) \
-  XTRAP(LOW_BAT_NORM,                      9,      true,      GetBatCapacityStr) \
-  XTRAP(CONNECT_MONITOR_ALARM,             9,      true,      GetConnectMonitorStr) \
-  XTRAP(CONNECT_MONITOR_NORM,              9,      true,      GetConnectMonitorStr) \
-  XTRAP(BATTERY_CONNECT_ALARM,             9,      true,      GetBatCapacityStr) \
-  XTRAP(BATTERY_CONNECT_NORM,              9,      true,      GetBatCapacityStr) \
-  XTRAP(BATTERY_LOW_TEMPERATURE_NORM,      9,      true,      GetInternalTempStr) \
-  XTRAP(BATTERY_LOW_TEMPERATURE_ALARM,     9,      true,      GetInternalTempStr) \
-
-#if 0
-  const char* logsStrShortRu[] =
+  XTRAP(DI0_NORM,                          5,      true,      GetDIN0StatusStr) \
+  XTRAP(DI0_ALARM,                         5,      true,      GetDIN0StatusStr) \
+  XTRAP(DI1_NORM,                          6,      true,      GetDIN0StatusStr) \
+  XTRAP(DI1_ALARM,                         6,      true,      GetDIN0StatusStr) \
+  XTRAP(BATTERY_HIGH_TEMPERATURE_NORM,     10,     true,      GetInternalTempStr) \
+  XTRAP(BATTERY_HIGH_TEMPERATURE_ALARM,    10,     true,      GetInternalTempStr) \
+  XTRAP(LINE_ALARM,                        12,     true,      GetInputVoltageStr) \
+  XTRAP(LINE_NORM,                         12,     true,      GetInputVoltageStr) \
+  XTRAP(LOW_BAT_ALARM,                     15,     true,      GetBatCapacityStr) \
+  XTRAP(LOW_BAT_NORM,                      15,     true,      GetBatCapacityStr) \
+  XTRAP(CABINET_HIGH_TEMPERATURE_NORM,     9,      true,      GetInternalTempStr) \
+  XTRAP(CABINET_HIGH_TEMPERATURE_ALARM,    9,      true,      GetInternalTempStr) \
+  XTRAP(CONNECT_MONITOR_ALARM,             17,     true,      GetConnectMonitorStr) \
+  XTRAP(CONNECT_MONITOR_NORM,              17,     true,      GetConnectMonitorStr) \
+  XTRAP(BATTERY_CONNECT_ALARM,             15,     true,      GetBatCapacityStr) \
+  XTRAP(BATTERY_CONNECT_NORM,              15,     true,      GetBatCapacityStr) \
+
+typedef enum
 {
-	"Перезагрузка контроллера",
-    "Сброс настроек",
-    "Обновление ПО",
-    "Включение",
-    "Смена пароля",
-    "Сохранение настроек",
-    "Авторизация",
-    "Тест ИБП",
-    "Откл. нагрузки ИБП",
-    "Авария дискр. входа 1",
-    "Низкое вых. напряжение",
-    "Высокое вых. напряжение",
-    "Высокая температура",
-    "Низкая температура",
-    "Авария вх. напряжения",
-    "Низкий заряд АКБ",
-    "Авария нагрузки",
-    "Авария связи с ИБП",
-    "Авария отключения АКБ",
-	"Замена АКБ",
-};
-#endif
+  FW_VERSION_UPDATE = 1,
+  FW_VERSION_UPDATED,
+  DEVICE_RESTORED,
+  DEVICE_REBOOTED,
+  DI0_NORM,
+  DI0_ALARM,
+  DI1_NORM,
+  DI1_ALARM,
+  BATTERY_HIGH_TEMPERATURE_NORM,
+  BATTERY_HIGH_TEMPERATURE_ALARM,
+  LINE_ALARM,
+  LINE_NORM,
+  LOW_BAT_ALARM,
+  LOW_BAT_NORM,
+  CABINET_HIGH_TEMPERATURE_NORM,
+  CABINET_HIGH_TEMPERATURE_ALARM,
+  CONNECT_MONITOR_ALARM,
+  CONNECT_MONITOR_NORM,
+  BATTERY_CONNECT_ALARM,
+  BATTERY_CONNECT_NORM,
+  ALL_TRAPS
+} TRAP_LIST_t;
+
+typedef enum {
+	LOG_SYSTEM_BOOT = 0x00,			// device booted
+	LOG_SYSTEM_DEFCONFIG,	// default config applied
+	LOG_UPDATE_SOFT,
+	LOG_TURN_ON,		//
+	LOG_PSW_CHANGE,		//
+	LOG_SETTING_SAVE,		//
+	LOG_LOGIN,		//
+	LOG_TEST_UPS,		//
+	LOG_SHUTDOWN_UPS,
+	LOG_ALARM_DIO,
+  LOG_ALARM_DI1,
+	LOG_ALARM_VAC_LOW_OUTPUT,
+	LOG_ALARM_VAC_HIGH_OUTPUT,
+	LOG_ALARM_HIGH_AKB_TEMP,
+	LOG_ALARM_LOW_AKB_TEMP,
+  LOG_ALARM_HIGH_CABINET_TEMP,
+	LOG_ALARM_LOW_CABINET_TEMP,
+	LOG_ALARM_LINE,
+	LOG_ALARM_LOW_BAT,
+	LOG_ALARM_POWER,
+	LOG_ALARM_UPS,
+	LOG_ALARM_AKB,
+	LOG_VALUE,
+	LOG_NONE,
+} log_type_t;
+
 #endif /* BOARD_PRS_H */

+ 6 - 0
modules/Makefile

@@ -47,6 +47,9 @@ INCLUDES += -Icommon
 INCLUDES += -Imonitor
 INCLUDES += -Ilog
 INCLUDES += -Itesting
+ifeq ($(HARDWARE), bt6710)
+INCLUDES += -Iportgw
+endif
 ifeq ($(HARDWARE), bt6709)
 INCLUDES += -Iwhitelist
 endif
@@ -63,6 +66,9 @@ CSRC += $(wildcard common/*.c)
 CSRC += $(wildcard monitor/*.c)
 CSRC += $(wildcard log/*.c)
 CSRC += $(wildcard testing/*.c)
+ifeq ($(HARDWARE), bt6710)
+CSRC += $(wildcard portgw/*.c)
+endif
 ifeq ($(HARDWARE), bt6709)     
 CSRC += $(wildcard whitelist/*.c)
 endif

+ 632 - 0
modules/portgw/portgw.c

@@ -0,0 +1,632 @@
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+#include "queue.h"
+#include <errno.h>
+
+#include "common_config.h"
+
+#include "lwip/sockets.h"
+#include "lwip/inet.h"
+
+#include "settings_api.h"
+#include "portgw.h"
+#include "tinystdio.h"
+#include "usart.h"
+
+#define PORTGW_PORT_NUM         1001
+#define PORTGW_DATA_CHUNK_SIZE  512
+
+/* Set option to drop old connection if the new one is accepted */
+#define TCP_DROP_PREV_CONNECTION    1
+
+static int listen_sd;
+static struct sockaddr_in sa;
+static struct fd_set master_set, read_set, write_set;
+static int max_sd;
+
+static uint8_t data_buffer[PORTGW_DATA_CHUNK_SIZE];
+
+#undef DBG
+#define DBG if(0)
+
+
+/* (Re)init serial port */ 
+void serial_reinit()
+{
+    uint16_t parity, stop, wordlen;
+
+    /* Parity set */
+    switch (sSettings.sPortGw.parity) {
+        case GW_EVEN_PAR:
+            parity = USART_Parity_Even;
+            break;
+        case GW_ODD_PAR:
+            parity = USART_Parity_Odd;
+            break;
+        case GW_NO_PAR:
+        default:
+            parity = USART_Parity_No;
+            break;
+    }
+    /* Stop bits set */
+    switch (sSettings.sPortGw.stopbits) {
+        case 2:
+            stop = USART_StopBits_2;
+            break;
+        case 1:
+        default:
+            stop = USART_StopBits_1;
+            break;
+    }
+    /* Word length set */
+    switch (sSettings.sPortGw.databits) {
+        case 8:
+            if ((sSettings.sPortGw.parity == GW_EVEN_PAR) ||
+                (sSettings.sPortGw.parity == GW_ODD_PAR)) {
+                /* 8-bit data + Parity */
+                wordlen = 9;
+            } else {
+                wordlen = 8;
+            }
+            break;
+        case 7:
+        default:
+            /* 7-bit data + Parity */
+            wordlen = 8;
+            break;
+    }
+    uart_hw_init(RS485_USART, sSettings.sPortGw.baud, wordlen, parity, stop);
+}
+
+/* Stop server */
+static void stop_server(void) {
+    /* Clean up all of the sockets that are open */
+    for (int i = 0; i <= max_sd; ++i)
+    {
+        if (FD_ISSET(i, &master_set)) {
+            DBG printf("Close sock %d\n", i);
+            closesocket(i);
+            FD_CLR(i, &master_set);
+        }
+    }
+    DBG printf("Portgw stopped\n");
+}
+
+/* Start TCP server */
+static bool start_tcp_server(uint16_t port)
+{
+    int res;
+
+    listen_sd = socket(PF_INET, SOCK_STREAM, 0);
+
+    if (listen_sd < 0) {
+        DBG printf("Socket create failed\r\n");
+        return false;
+    }
+
+    res = fcntl(listen_sd, F_SETFL, O_NONBLOCK);
+    if (res < 0) {
+        DBG printf("fcntl() failed");
+        closesocket(listen_sd);
+        return false;
+    }
+
+#if 0
+    /* Not used */
+    lwip_setsockopt(listen_sd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+    if (res < 0) {
+        printf("setsockopt() failed");
+        closesocket(listen_sd);
+        return false;
+    }
+
+    /* Not used (SO_REUSE==1 should be enabled) */
+    int on = 1;
+    res = setsockopt(listen_sd, SOL_SOCKET,  SO_REUSEADDR, (char *)&on, sizeof(on));
+    if (res < 0) {
+        printf("setsockopt() failed");
+        closesocket(listen_sd);
+        return false;
+    }
+#endif
+
+    memset(&sa, 0, sizeof(struct sockaddr_in));
+    sa.sin_family = AF_INET;
+    sa.sin_addr.s_addr = IPADDR_ANY;
+    sa.sin_port = htons(port);
+
+    if (bind(listen_sd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
+    {
+        DBG printf("Bind to port %d failed\n", port);
+        closesocket(listen_sd);
+        return false;
+    }
+
+    res = listen(listen_sd, 1);
+    if (res < 0) {
+        DBG printf("Listen failed failed\r\n");
+        closesocket(listen_sd);
+        return false;
+    }
+
+    FD_ZERO(&master_set);
+    max_sd = listen_sd;
+    FD_SET(listen_sd, &master_set);
+
+    printf("Port %d opened\n", port);
+
+    return true;
+}
+
+/* Start UDP server */
+static bool start_udp_server(uint16_t port)
+{
+    int res;
+
+    listen_sd = socket(PF_INET, SOCK_DGRAM, 0);
+
+    if (listen_sd < 0) {
+        printf("Socket create failed\r\n");
+        return false;
+    }
+    else {
+        printf("Socket create OK\r\n");
+    }
+
+    res = fcntl(listen_sd, F_SETFL, O_NONBLOCK);
+    if (res < 0) {
+        DBG printf("fcntl() failed");
+        closesocket(listen_sd);
+        return false;
+    }
+
+#if 0
+    /* Not used */
+    lwip_setsockopt(listen_sd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+    if (res < 0) {
+        printf("setsockopt() failed");
+        closesocket(listen_sd);
+        return false;
+    }
+
+    /* Not used (SO_REUSE==1 should be enabled) */
+    int on = 1;
+    res = setsockopt(listen_sd, SOL_SOCKET,  SO_REUSEADDR, (char *)&on, sizeof(on));
+    if (res < 0) {
+        printf("setsockopt() failed");
+        closesocket(listen_sd);
+        return false;
+    }
+#endif
+
+    memset(&sa, 0, sizeof(struct sockaddr_in));
+    sa.sin_family = AF_INET;
+    sa.sin_addr.s_addr = IPADDR_ANY;
+    sa.sin_port = htons(port);
+
+    if (bind(listen_sd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
+    {
+        DBG printf("Bind to port %d failed\n", port);
+        closesocket(listen_sd);
+        return false;
+    }
+
+    FD_ZERO(&master_set);
+    max_sd = listen_sd;
+    FD_SET(listen_sd, &master_set);
+
+    printf("Port %d opened\n", port);
+
+    return true;
+}
+
+/* Start server */
+static bool start_server(gwtrans_t transtype, uint16_t port)
+{
+    switch (transtype) {
+        case GW_TCP:
+            return start_tcp_server(port);
+        case GW_UDP:
+            return start_udp_server(port);
+        default:
+            return false;
+    }
+}
+
+/* TCP server main loop */
+static void tcp_server(void)
+{
+    int recvd, sent;
+    uint8_t c;
+    int new_sd;
+    static int active_sd = -1;
+    int desc_ready, rc;
+    struct timeval timeout;
+    bool close_conn;
+
+    timeout.tv_sec = 5;
+    timeout.tv_usec = 0;
+
+    memcpy(&read_set, &master_set, sizeof(master_set));
+    memcpy(&write_set, &master_set, sizeof(master_set));
+
+    DBG printf("Waiting on select()...\n");
+    rc = select(max_sd + 1, &read_set, &write_set, NULL, &timeout);
+
+    DBG printf("  select() returned %d\n", rc);
+
+    if (rc < 0) {
+        DBG printf("  select() failed\n");
+    }
+
+    if (rc == 0) {
+        DBG printf("  select() timed out.\n");
+    }
+
+    /* One or more descriptors are readable.  Need to         \
+        * determine which ones they are.                         */
+    desc_ready = rc;
+    for (int i=0; i <= max_sd  &&  desc_ready > 0; ++i) {
+        /*******************************************************/
+        /* Check to see if this descriptor is ready            */
+        /*******************************************************/
+        if (FD_ISSET(i, &read_set)) {
+            /* A descriptor was found that was readable - one  \
+            * less has to be looked for.  This is being done   \
+            * so that we can stop looking at the working set   \
+            * once we have found all of the descriptors that   \
+            * were ready.                                      */
+            desc_ready -= 1;
+
+            /* Check to see if this is the listening socket     */
+            if (i == listen_sd) {
+                DBG printf("  Listening socket is readable\n");
+
+                /* Accept all incoming connections that are      */
+                /* queued up on the listening socket before we   */
+                /* loop back and call select again.              */
+                do {
+
+                    /* Accept each incoming connection.  If       */
+                    /* accept fails with EWOULDBLOCK, then we     */
+                    /* have accepted all of them.  Any other      */
+                    /* failure on accept will cause us to end the */
+                    /* server.                                    */
+                    new_sd = accept(listen_sd, NULL, NULL);
+                    if (new_sd < 0 && errno != 0) {
+                        if (errno != EWOULDBLOCK) {
+                            DBG printf("  accept() failed: %d\n", errno);
+                        }
+                        break;
+                    }
+
+                    /* Add the new incoming connection to the     */
+                    /* master read set                            */
+                    DBG printf("  New incoming connection - %d\n", new_sd);
+                    FD_SET(new_sd, &master_set);
+                    if (new_sd > max_sd) {
+                        max_sd = new_sd;
+                    }
+
+#if TCP_DROP_PREV_CONNECTION
+                    /* Close previous active connection */
+                    if (active_sd != -1 && active_sd != new_sd) {
+                        DBG printf("  Close prev active connection %d\n", active_sd);
+                        close(active_sd);
+                        FD_CLR(active_sd, &master_set);
+                        if (active_sd == max_sd) {
+                            while (FD_ISSET(max_sd, &master_set) == false) {
+                                max_sd -= 1;
+                            }
+                        }
+                    }
+                    /* Mark new connection as active */
+                    active_sd = new_sd;
+                    DBG printf("  New active connection %d\n", active_sd);
+#endif
+
+                    /* Loop back up and accept another incoming   */
+                    /* connection                                 */
+                } while (new_sd != -1);
+            }
+
+            /* This is not the listening socket, therefore an   */
+            /* existing connection must be readable             */
+            else {
+                DBG printf("  Descriptor %d is readable\n", i);
+                close_conn = false;
+
+                /* Receive data on this connection until the  */
+                /* recv fails with EWOULDBLOCK.  If any other */
+                /* failure occurs, we will close the          */
+                /* connection.                                */
+                if ((recvd = recv(i, data_buffer, sizeof(data_buffer), 0)) > 0) {
+                    DBG {
+                        printf("received %d bytes:", recvd);
+                        for (uint32_t i = 0; i < 3; i++) {
+                            printf(" 0x%X", data_buffer[i]);
+                        }
+                        printf("...\r\n");
+                    }
+                    /* Put RX data to the queue */
+                    for (uint32_t i = 0; i < (uint32_t)recvd; i++) {
+                        if (xQueueSend(rs485TxQ, &data_buffer[i], 1000) != pdTRUE) {
+                            printf("[portgw] Rx data lost\r\n");
+                        }
+                    }
+                    /* Start RS485 transmission */
+                    rs485_enable_tx();
+                }
+
+                if (recvd < 0) {
+                    if (errno != EWOULDBLOCK){
+                        DBG printf("  recv() failed: %d\n", errno);
+                        close_conn = true;
+                    }
+                }
+
+                /* Check to see if the connection has been    */
+                /* closed by the client                       */
+                if (recvd == 0) {
+                    DBG printf("  Connection closed\n");
+                    close_conn = true;
+                }
+
+                /* If the close_conn flag was turned on, we need */
+                /* to clean up this active connection.  This     */
+                /* clean up process includes removing the        */
+                /* descriptor from the master set and            */
+                /* determining the new maximum descriptor value  */
+                /* based on the bits that are still turned on in */
+                /* the master set.                               */
+                if (close_conn) {
+                    closesocket(i);
+                    FD_CLR(i, &master_set);
+                    if (i == max_sd) {
+                        while (FD_ISSET(max_sd, &master_set) == false) {
+                            max_sd -= 1;
+                        }
+                    }
+                }
+            }
+        }
+
+        /* Socket is ready to write */
+        else if (FD_ISSET(i, &write_set)){
+            /* Put RX data to the queue */
+            uint32_t len = 0;
+            while (len < sizeof(data_buffer) && xQueueReceive(rs485RxQ, &c, 5) == pdTRUE) {
+                data_buffer[len++] = c;
+            }
+            if (len > 0) {
+                DBG printf("%d bytes to send\r\n", len);
+                sent = send(i, data_buffer, len, 0);
+                if (sent <= 0) {
+                    DBG printf("send failed (%d)\n", sent);
+                }
+            }
+        }
+    }
+}
+
+/* UDP server main loop */
+static void udp_server(void)
+{
+    struct timeval timeout;
+    int recvd, sent;
+    uint8_t c;
+    int rc;
+    bool close_conn;
+
+    timeout.tv_sec = 5;
+    timeout.tv_usec = 0;
+
+    memcpy(&read_set, &master_set, sizeof(master_set));
+    memcpy(&write_set, &master_set, sizeof(master_set));
+
+    /* TODO Remove select for UDP */
+    DBG printf("Waiting on select()...\n");
+    rc = select(max_sd + 1, &read_set, &write_set, NULL, &timeout);
+
+    DBG printf("  select() returned %d\n", rc);
+
+    if (rc < 0) {
+        DBG printf("  select() failed\n");
+    }
+
+    if (rc == 0) {
+        DBG printf("  select() timed out.\n");
+    }
+    else{
+        /*******************************************************/
+        /* Check to see if this descriptor is ready            */
+        /*******************************************************/
+        if (FD_ISSET(listen_sd, &read_set)) {
+            DBG printf("  Descriptor %d is readable\n", listen_sd);
+            close_conn = false;
+
+            /* Receive data on this connection until the  */
+            /* recv fails with EWOULDBLOCK.  If any other */
+            /* failure occurs, we will close the          */
+            /* connection.
+                */
+            socklen_t from_len;
+            /* Save addr & port where data (requests) come from */
+            if ((recvd = recvfrom(listen_sd, data_buffer, sizeof(data_buffer), 0, 
+                (struct sockaddr*)&sa, &from_len)) > 0) {
+                DBG {
+                    printf("From %s:%d received %d bytes:", 
+                        inet_ntoa(sa.sin_addr.s_addr), sa.sin_port, recvd);
+                    for (uint32_t i = 0; i < 3; i++) {
+                        printf(" 0x%X", data_buffer[i]);
+                    }
+                    printf("...\r\n");
+                }
+                /* Put RX data to the queue */
+                for (uint32_t i = 0; i < (uint32_t)recvd; i++) {
+                    if (xQueueSend(rs485TxQ, &data_buffer[i], 1000) != pdTRUE) {
+                        printf("[portgw] Rx data lost\r\n");
+                    }
+                }
+                /* Start RS485 transmission */
+                rs485_enable_tx();
+            }
+
+            if (recvd < 0) {
+                if (errno != EWOULDBLOCK){
+                    DBG printf("  recv() failed\n");
+                    close_conn = true;
+                }
+            }
+
+            /* Check to see if the connection has been    */
+            /* closed by the client                       */
+            if (recvd == 0) {
+                DBG printf("  Connection closed\n");
+                close_conn = true;
+            }
+
+            /* If the close_conn flag was turned on, we need */
+            /* to clean up this active connection.  This     */
+            /* clean up process includes removing the        */
+            /* descriptor from the master set and            */
+            /* determining the new maximum descriptor value  */
+            /* based on the bits that are still turned on in */
+            /* the master set.                               */
+            if (close_conn) {
+                closesocket(listen_sd);
+                FD_CLR(listen_sd, &master_set);
+            }
+        }
+
+        /* Socket is ready to write */
+        else if (FD_ISSET(listen_sd, &write_set)) {
+            uint32_t len = 0;
+            while (len < sizeof(data_buffer) && xQueueReceive(rs485RxQ, &c, 5) == pdTRUE) {
+                data_buffer[len++] = c;
+            }
+            if (len > 0) {
+                DBG printf("%d bytes to send\r\n", len);
+                /* Send data (responce) to the latest saved addr & port */
+                sent = sendto(listen_sd, data_buffer, len, 0, (struct sockaddr*)&sa, sizeof(sa));
+                if (sent <= 0) {
+                    DBG printf("send failed (%d)\n", sent);
+                }
+            }
+        } else {
+            /* Nothing to do */
+            taskYIELD();
+        }
+    }
+}
+
+/* Main task */
+void portgw_thread(void *arg)
+{
+    uint16_t port;
+    gwtrans_t transtype;
+    gwmode_t mode;
+    bool enabled;
+    gwparity_t parity;
+    uint8_t stopbits;
+    uint8_t databits;
+    uint32_t baud;
+    bool firstrun = true;
+    (void)arg;
+
+    FD_ZERO(&master_set);
+
+    enabled = sSettings.sPortGw.enabled;
+    port = sSettings.sPortGw.port;
+    transtype = sSettings.sPortGw.transtype;
+    mode = sSettings.sPortGw.mode;
+
+    parity = sSettings.sPortGw.parity;
+    stopbits = sSettings.sPortGw.stopbits;
+    databits = sSettings.sPortGw.databits;
+    baud = sSettings.sPortGw.baud;
+
+    (void)mode;
+
+    while (1) {
+        /* Check if network settings was changed */
+        if ((sSettings.sPortGw.port != port) ||
+            (sSettings.sPortGw.enabled != enabled) ||
+            (sSettings.sPortGw.transtype != transtype) ||
+            (firstrun))
+        {
+            port = sSettings.sPortGw.port;
+            enabled = sSettings.sPortGw.enabled;
+            transtype = sSettings.sPortGw.transtype;
+
+            if (!firstrun) {
+                /* Stop server */
+                stop_server();
+            }
+
+            if (enabled && xSemaphoreTake(rs485mutex, portMAX_DELAY) == pdTRUE) {
+                /* (Re)start server */
+                if (!start_server(transtype, port)) {
+                    DBG printf("Server start error\n");
+                    vTaskDelay(5000);
+                    continue;
+                }
+            }
+            else {
+                /* Clear buffers */
+                if (uxQueueMessagesWaiting(rs485TxQ) > 0) {
+                    xQueueReset(rs485TxQ);
+                }
+                if (uxQueueMessagesWaiting(rs485RxQ) > 0) {
+                    xQueueReset(rs485RxQ);
+                }
+                xSemaphoreGive(rs485mutex);
+                vTaskDelay(5000);
+                continue;
+            }
+        }
+
+        /* Check if serial settings was changed */
+        if ((sSettings.sPortGw.parity != parity) ||
+            (sSettings.sPortGw.stopbits != stopbits) ||
+            (sSettings.sPortGw.databits != databits) ||
+            (sSettings.sPortGw.baud != baud) ||
+            (firstrun))
+        {
+            parity = sSettings.sPortGw.parity;
+            stopbits = sSettings.sPortGw.stopbits;
+            databits = sSettings.sPortGw.databits;
+            baud = sSettings.sPortGw.baud;
+
+            serial_reinit();
+            DBG printf("Serial reinitialized\r\n");
+        }
+
+        if (!enabled) {
+            xSemaphoreGive(rs485mutex);
+            vTaskDelay(5000);
+            continue;
+        }
+
+        switch (transtype) {
+            case GW_UDP:
+                udp_server();
+                break;
+            case GW_TCP:
+                tcp_server();
+                break;
+            default:
+                vTaskDelay(5000);
+                break;
+        }
+        firstrun = false;
+    }
+}
+
+/* Main init */
+void portgw_init(void)
+{
+    xTaskCreate(portgw_thread, ( char * ) "portgw_thr", configMINIMAL_STACK_SIZE * 2,
+                NULL, tskIDLE_PRIORITY, NULL);
+}

+ 14 - 0
modules/portgw/portgw.h

@@ -0,0 +1,14 @@
+/*
+ * portgw.h
+ *
+ *  Created on: 19.09.2017
+ *      Author: pavel
+ */
+
+#ifndef PORTGW_H_
+#define PORTGW_H_
+
+
+void portgw_init(void);
+
+#endif /* PORTGW_H_ */

+ 0 - 1
modules/settings_api.c

@@ -15,7 +15,6 @@
 #include "common_config.h"
 #ifndef BT6702_SERVICE
 #include "snmp_api.h"
-#include "trap_api.h"
 #include "log.h"
 #endif
 #include "sys_api.h"

+ 54 - 1
modules/settings_api.h

@@ -17,7 +17,6 @@
 #include "stm32f4xx.h"
 #include <stdbool.h>
 #include "d_inouts.h"
-#include "trap_api.h"
 
 /* Предельные границы настроек */
 #define MAX_VOLT_CELL_RANGE				3.0
@@ -327,6 +326,55 @@ typedef struct
   uint32_t port;
 } SSH_t;
 
+/**
+  * @brief  Типы транспорта прозрачного порта
+  */
+typedef enum
+{
+    GW_UDP = 0,
+    GW_TCP,
+    MAX_TRANS_TYPES
+} gwtrans_t;
+
+/**
+  * @brief  Режим прозрачного порта
+  */
+typedef enum
+{
+    GW_SERVER = 0,
+    GW_CLIENT,
+    MAX_MODE_TYPES
+} gwmode_t;
+
+/**
+  * @brief  Четность прозрачного порта
+  */
+typedef enum
+{
+    GW_NO_PAR = 0,
+    GW_ODD_PAR,
+    GW_EVEN_PAR,
+    MAX_PARITY_TYPES
+} gwparity_t;
+
+/**
+  * @brief Настройки прозрачного порта
+  */
+typedef struct
+{
+    bool enabled;           /* Вкл/Откл */
+    gwtrans_t transtype;    /* Тип транспорта */
+    gwmode_t mode;          /* Режим: Клиент/Сервер */
+    char ip[16];            /* IP-адрес сервера (для клиента) */
+    uint16_t port;          /* Порт */
+    uint32_t baud;          /* Скорость порта */
+    gwparity_t parity;      /* Четность */
+    uint8_t databits;       /* Число бит данных */
+    uint8_t stopbits;       /* Число стоп-бит */
+    uint8_t timeout;        /* Таймаут ответа от устройства */
+    uint16_t quota;         /* Максимальное время занятия порта */
+} PORTGW_t;
+
 /**
   * @brief  Общая структура настроек
   */
@@ -408,6 +456,11 @@ void SETTINGS_SetSntpDef(void);
   */
 void SETTINGS_SetINOUTSDef(void);
 
+/**
+  * @brief  Установить значение настроек прозрачного порта по умолчанию
+  */
+void SETTINGS_SetPortGwDef(void);
+
 /**
   * @brief  Установить параметры RADIUS по умолчанию
   */

+ 235 - 0
modules/settings_api_bt6710.c

@@ -0,0 +1,235 @@
+/********************************* (C) ROTEK ***********************************
+ * @module  settings_api
+ * @file    settings_api.c
+ * @version 1.0.0
+ * @date    XX.XX.XXXX
+ * $brief   Settings
+ *******************************************************************************
+ * @history     Version  Author         Comment
+ * XX.XX.XXXX   1.0.0    Telenkov D.A.  First release.
+ *******************************************************************************
+ */
+#ifdef HARDWARE_BT6710
+#include "stm32f4xx.h"
+#include "settings_api.h"
+#include "common_config.h"
+#ifndef BT6702_SERVICE
+#include "snmp_api.h"
+#include "trap_api.h"
+#include "log.h"
+#endif
+#include "sys_api.h"
+
+#include "main.h"
+#include "parameters.h"
+
+#include "mbedtls/certs.h"
+
+#include <string.h>
+#include <stdlib.h>
+#ifdef PRINTF_STDLIB
+#include <stdio.h>
+#endif
+#ifdef PRINTF_CUSTOM
+#include "tinystdio.h"
+#endif
+
+//#define DBG if(0)
+
+const char *logsStrShortRu[] = {
+    "Перезагрузка контроллера",
+    "Сброс настроек",
+    "Обновление ПО",
+    "Включение",
+    "Смена пароля",
+    "Сохранение настроек",
+    "Авторизация",
+    "Тест ИБП",
+    "Откл. нагрузки ИБП",
+    "Авария дискр. входа 1",
+    "Авария дискр. входа 2",
+    "Низкое вых. напряжение",
+    "Высокое вых. напряжение",
+    "Высокая температура АКБ",
+    "Низкая температура АКБ",
+    "Высокая температура Шкафа",
+    "Низкая температура Шкафа",
+    "Авария вх. напряжения",
+    "Низкий заряд АКБ",
+    "Авария нагрузки",
+    "Авария связи с ИБП",
+    "Авария отключения АКБ",
+    "Замена АКБ",
+};
+
+/**
+  * @brief  Установить параметры SNMP по умолчанию
+  */
+void SETTINGS_SetSnmpDef(void)
+{
+    strcpy(sSettings.sSnmp.sysDesc.description, "");
+    sSettings.sSnmp.sysDesc.len = 0;
+    strcpy(sSettings.sSnmp.readCommunity, "public");
+    strcpy(sSettings.sSnmp.writeCommunity, "public");
+    strcpy(sSettings.sSnmp.sysContact.contact, "");
+    sSettings.sSnmp.sysContact.len = 0;
+    strcpy(sSettings.sSnmp.sysName.name, "");
+    sSettings.sSnmp.sysName.len = 0;
+    strcpy(sSettings.sSnmp.sysLocation.location, "");
+    sSettings.sSnmp.sysLocation.len = 0;
+    strcpy(sSettings.sSnmp.managerIP, "0.0.0.0");
+    strcpy(sSettings.sSnmp.managerIP2, "0.0.0.0");
+    strcpy(sSettings.sSnmp.managerIP3, "0.0.0.0");
+    strcpy(sSettings.sSnmp.managerIP4, "0.0.0.0");
+    strcpy(sSettings.sSnmp.managerIP5, "0.0.0.0");
+}
+
+/**
+  * @brief  Настройки ИБП по умолчанию
+  */
+void SETTINGS_SetUPSSettingsDef(void)
+{
+    sSettings.UPS_Setting.Ucellmin = 1.67;
+    sSettings.UPS_Setting.Ucellmax = 2.27;
+    sSettings.UPS_Setting.Uakb = 24;
+    sSettings.UPS_Setting.ups_power = 1000;
+    sSettings.UPS_Setting.set_data = 0;
+    sSettings.UPS_Setting.life_time = 5;
+    sSettings.UPS_Setting.common_capacity = 9;
+    sSettings.UPS_Setting.type_ups = ups_kestar;
+}
+
+/**
+  * @brief  Установить наcтройки менеджера Аварий по умолчанию
+  */
+void SETTINGS_SetAlarmManagerDef(void)
+{
+    sSettings.sAlarmManager.load_range.high = 70.0;
+    sSettings.sAlarmManager.load_range.low = 0;
+    sSettings.sAlarmManager.load_range.hyst = 1;
+
+    sSettings.sAlarmManager.ac_output_range.high = 250.0;
+    sSettings.sAlarmManager.ac_output_range.low = 150.0;
+    sSettings.sAlarmManager.ac_output_range.hyst = 20.0;
+
+    sSettings.sAlarmManager.Temprature_range.high = 70.0;
+    sSettings.sAlarmManager.Temprature_range.low = -40.0;
+    sSettings.sAlarmManager.Temprature_range.hyst = 1;
+}
+
+/**
+  * @brief  Установить значение сервисных настроек по умолчанию
+  */
+void SETTINGS_SetServiceDef(void)
+{
+    uint8_t user_id;
+
+    for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) {
+        switch (user_id) {
+            /* First users in the system is always ADMIN.
+             * Others are USER */
+            case 0:
+                sSettings.sAuth[user_id].level = ADMIN;
+                strcpy(sSettings.sAuth[user_id].login, "admin");
+                strcpy(sSettings.sAuth[user_id].password, "12345");
+                break;
+            case 1:
+            default:
+                sSettings.sAuth[user_id].level = USER;
+                strcpy(sSettings.sAuth[user_id].login, "user");
+                strcpy(sSettings.sAuth[user_id].password, "1234");
+                break;
+        }
+    }
+}
+
+/**
+  * @brief  Установить параметры SNTP по умолчанию
+  */
+void SETTINGS_SetSntpDef(void)
+{
+    sSettings.sSNTP.sntpEnable = true;
+    strcpy(sSettings.sSNTP.ip, "88.147.254.235");
+    sSettings.sSNTP.timeZone = 3.0;
+    strcpy(sSettings.sSNTP.data, "none");
+}
+
+/**
+  * @brief  Установить параметры настроек сухих контактов / реле по умолчанию
+  */
+void SETTINGS_SetINOUTSDef(void)
+{
+    sSettings.sInOuts.ro_type_source[0] = CRITICAL;
+    sSettings.sInOuts.ro_type_source[1] = SNMP_SET;
+
+    sSettings.sInOuts.din_type_act[0] = DI_CONN;
+}
+
+/**
+  * @brief  Установить значение настроек прозрачного порта по умолчанию
+  */
+void SETTINGS_SetPortGwDef(void)
+{
+    sSettings.sPortGw.enabled = true;
+    sSettings.sPortGw.transtype = GW_TCP;
+    sSettings.sPortGw.mode = GW_SERVER;
+    strcpy(sSettings.sPortGw.ip, "192.168.1.2");
+    sSettings.sPortGw.port = 1001;
+    sSettings.sPortGw.baud = 9600;
+    sSettings.sPortGw.parity = GW_EVEN_PAR;
+    sSettings.sPortGw.databits = 7;
+    sSettings.sPortGw.stopbits = 1;
+    sSettings.sPortGw.timeout = 3;
+    sSettings.sPortGw.quota = 60;
+}
+
+/**
+  * @brief  Установить параметры RADIUS по умолчанию
+  */
+void SETTINGS_SetRADIUSDef(void)
+{
+
+}
+
+/**
+  * @brief  Установить параметры сертификата сервера по умолчанию
+  */
+void SETTINGS_SetSSLcrtDef(void)
+{
+
+}
+
+/**
+  * @brief  Установить параметры Telnet
+  */
+void SETTINGS_SetTelnetDef(void)
+{
+
+}
+
+/**
+  * @brief  Установить параметры SSH
+  */
+void SETTINGS_SetSSHDef(void)
+{
+
+}
+
+/**
+  * @brief  Установить параметры списка доверительных хостов
+  */
+void SETTINGS_SetWhiteListDef(void)
+{
+
+}
+
+/**
+  * @brief  Установить параметры разрешения уведомлений по умолчанию
+  */
+void SETTINGS_SetFlagNotificationDef(void)
+{
+
+}
+
+#endif
+/********************************* (C) ROTEK **********************************/

+ 29 - 11
peripheral_modules/inc/usart.h

@@ -16,21 +16,39 @@
 
 #include <stdint.h>
 
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "semphr.h"
+
+#include "common_config.h"
+
 /**
   * @brief  
   */
-#define USER_USART			        USART1
-#define USER_USART_BAUD				115200
-#define	USER_USART_WORD_LEN			8
-#define	USER_USART_PARITY			USART_Parity_No
-#define USER_USART_STOP_BIT			USART_StopBits_1
-
-#define UPS_USART         			USART2
-#define UPS_USART_BAUD				2400
-#define	UPS_USART_WORD_LEN			8
-#define	UPS_USART_PARITY			USART_Parity_No
-#define UPS_USART_STOP_BIT			USART_StopBits_1
+#define USER_USART                USART1
+#define USER_USART_BAUD           115200
+#define	USER_USART_WORD_LEN       8
+#define	USER_USART_PARITY         USART_Parity_No
+#define USER_USART_STOP_BIT       USART_StopBits_1
+
+#define UPS_USART                 USART2
+#define UPS_USART_BAUD            2400
+#define	UPS_USART_WORD_LEN        8
+#define	UPS_USART_PARITY          USART_Parity_No
+#define UPS_USART_STOP_BIT        USART_StopBits_1
+
+#ifdef PORTGW_ENABLE
+#define RS485_USART               UART3
+#define RS485_USART_BAUD          115200
+#define RS485_USART_WORD_LEN      8
+#define RS485_USART_PARITY        USART_Parity_No
+#define RS485_USART_STOP_BIT      USART_StopBits_1
 
+/* Queue */
+QueueHandle_t rs485TxQ, rs485RxQ;
+/* RS485 mutex */
+SemaphoreHandle_t rs485mutex;
+#endif
 
 void init_ups_rbuf(void);
 /**

+ 64 - 1
peripheral_modules/src/usart.c

@@ -38,6 +38,8 @@ PUTCHAR_PROTOTYPE
 }   
 #endif
 
+#define RS485_RBUF_SIZE 512
+
 #ifdef BT6702_SERVICE
 #define UPS_RBUF_SIZE 1024
 #else
@@ -120,6 +122,15 @@ void InitUSART(void) {
 	rbuf32_init(&user_tx_rbuf, user_tx_fifo, USER_RBUF_SIZE);
 	rbuf32_init(&user_rx_rbuf, user_rx_fifo, USER_RBUF_SIZE);
 	uart_hw_init(USER_USART, USER_USART_BAUD, USER_USART_WORD_LEN, USER_USART_PARITY, USER_USART_STOP_BIT);
+
+#ifdef RS485_USART
+    rs485TxQ = xQueueCreate(RS485_RBUF_SIZE, 1);
+    rs485RxQ = xQueueCreate(RS485_RBUF_SIZE, 1);
+	rs485mutex = xSemaphoreCreateMutex();
+	/* Initial configuration. Port will be reconfigured later according to settings */
+	uart_hw_init(RS485_USART, RS485_USART_BAUD, RS485_USART_WORD_LEN, RS485_USART_PARITY, RS485_USART_STOP_BIT);
+#endif
+
 #ifdef PRINTF_CUSTOM    
 	init_printf(NULL, putc_);
 #endif
@@ -276,6 +287,56 @@ void rs232_irq_handler(void)
 	}
 }
 
+#ifdef RS485_USART
+inline void rs485_enable_tx(void) {
+	RS485_USART->CR1 |= USART_CR1_TXEIE;
+}
+
+inline void rs485_irq_handler(void) {
+	uint16_t c;
+	static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+	if (RS485_USART->SR & USART_SR_ORE) {
+		c = RS485_USART->DR;
+		DBG printf("[rs485] overrun\r\n");
+	}
+	if (RS485_USART->SR & USART_SR_PE) {
+		c = RS485_USART->DR;
+		DBG printf("[rs485] parity fail: 0x%X\r\n", c);
+	}
+	if (USART_GetITStatus(RS485_USART, USART_IT_TXE) != RESET) {
+		if (xQueueReceiveFromISR(rs485TxQ, &c, &xHigherPriorityTaskWoken) == pdTRUE) {
+			RS485_USART->DR = c;
+			// DBG printf("tx: 0x%x\r\n", c);
+			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+		} else {
+			RS485_USART->CR1 &= ~USART_CR1_TXEIE;
+			RS485_USART->CR1 |= USART_CR1_RXNEIE;
+		}
+		USART_ClearITPendingBit(RS485_USART, USART_IT_TXE);
+	}
+	if (USART_GetITStatus(RS485_USART, USART_IT_RXNE) != RESET) {
+		c = RS485_USART->DR;
+		/* Mask parity bits */
+		if (RS485_USART->CR1 & USART_CR1_PCE) {
+			if (RS485_USART->CR1 & USART_CR1_M) {
+				/* 8-bit data */
+				c &= 0xFF;
+			} else {
+				/* 7-bit data */
+				c &= 0x7F;
+			}
+		}
+		if (xQueueSendFromISR(rs485RxQ, &c, &xHigherPriorityTaskWoken) == pdTRUE) {
+			// DBG printf("rx: 0x%x\r\n", c);
+		} else {
+			DBG printf("[rs485] rx overflow\r\n");
+		}
+		USART_ClearITPendingBit(RS485_USART, USART_IT_RXNE);
+		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+	}
+}
+#endif /* RS485_USART */
+
 void USART1_IRQHandler(void) {
 	service_rs232_irq_handler();
 }
@@ -285,7 +346,9 @@ void USART2_IRQHandler(void) {
 }
 
 void USART3_IRQHandler(void) {
-
+#ifdef RS485_USART
+	rs485_irq_handler();
+#endif /* RS485_USART */
 }