9 Commits 88544ad69a ... 2610dd55a9

Author SHA1 Message Date
  Dmitry Telenkov 2610dd55a9 [BT-6721] change sw version 1.2 -> 1.3 1 week ago
  Dmitry Telenkov a0161cb3a1 Убрал некоторые printf. 1 week ago
  Dmitry Telenkov 033828a2e1 Добавил пины для тестирования КЗ. 2 weeks ago
  Dmitry Telenkov 7fc0d33544 Работа с тестированием на КЗ. 2 weeks ago
  Dmitry Telenkov e5f9cd7291 Temp commit 1 month ago
  ekat-ok dff06bce6f 1. Changelog; 2. sw 1.1 -> 1.2 3 months ago
  ekat-ok e90e47d367 make more universal 3 months ago
  ekat-ok f9e57ce65f add surppot new ups 3 months ago
  ekat-ok 1eab4dd226 add root oid for bt-6721 3 months ago

+ 1 - 1
.gdbinit_bt6710_service

@@ -1,5 +1,5 @@
 target remote localhost:3333
-file build/bt6702_service/stm32bt6710service/stm32bt6710service.elf
+file build/bt6702_service/stm32bt6721service/stm32bt6721service.elf
 load
 break Reset_Handler
 

+ 4 - 0
.gdbinit_service

@@ -0,0 +1,4 @@
+target remote localhost:3333
+file build/bt6702_service/stm32bt6721service/stm32bt6721service.elf
+load
+break Reset_Handler

+ 4 - 2
.vscode/settings.json

@@ -55,6 +55,8 @@
         "string_view": "c",
         "initializer_list": "c",
         "board_bt6711_v1.h": "c",
-        "freertos.h": "c"
-    }
+        "freertos.h": "c",
+        "syslog.h": "c"
+    },
+    "cmake.sourceDirectory": "/home/ebalbekova/my_project/bt-67xx_universal_hw/thirdparty/PolarSSL"
 }

+ 4 - 0
Makefile

@@ -96,6 +96,10 @@ fullflash_6721:
 	sleep 1
 	st-flash --reset write output/stm32bt6721.bin 0x8020000
 
+serviceflash:
+	st-flash --reset write output/iap.bin 0x8000000
+	sleep 1
+	st-flash --reset write output/stm32bt6721service.bin 0x8020000
 
 release_6703:
 	$(MAKE) -C modules HARDWARE=bt6703 VERBOSE=1 DEBUG=0 PRINTF=custom MAC=EC-4C-4D-00-80-0A release

+ 4 - 6
config/board_bt6721.h

@@ -52,7 +52,7 @@ WDG_PIN(X)
 /**
   * @brief  Версия прошивки
   */
-#define VERSION                         "1.1"
+#define VERSION                         "1.3"
 
 /**
   * brief  Текст сообщения при запуске CLI
@@ -91,7 +91,7 @@ XSETTING( Syslog_Settings_t,	sSyslog, SETTINGS_SetSyslogDef, ALL_DEFAULT ) \
 XSETTING( RADIUS_t, sRADIUS, SETTINGS_SetRADIUSDef, PART_DEFAULT_1 ) \
 
 
-#define SNMP_DEV_ROOT_OID       13
+#define SNMP_DEV_ROOT_OID       14
 
 #define MAX_IRQ_HANDLERS 4
 
@@ -279,8 +279,8 @@ typedef enum {
 #define BAT_CONNECT_MONITOR
 #define UPS_CONNECT_MONITOR
 #define TEST_ALARM_AKB_MONITOR
-#define PHASE_FAIL_MONITOR
-#define EPO_MONITOR
+//#define PHASE_FAIL_MONITOR
+//#define EPO_MONITOR
 #define OVERTEMPRATURE_MONITOR
 #define INVERTERHIGHVOLTAGE_MONITOR
 
@@ -294,8 +294,6 @@ typedef enum {
   XMONITOR(UPS_TemperatureHighRangeMonitor,     (UPS.Present == UPS_CONNECTED)) \
   XMONITOR(UPS_TemperatureLowRangeMonitor,      (UPS.Present == UPS_CONNECTED)) \
   XMONITOR(UPS_BatteryConnectMonitor,           (UPS.Present == UPS_CONNECTED)) \
-  XMONITOR(UPS_PhaseFailMonitor,                (UPS.Present == UPS_CONNECTED)) \
-  XMONITOR(UPS_EPOMonitor,                      (UPS.Present == UPS_CONNECTED)) \
   XMONITOR(UPS_OverTempratureMonitor,           (UPS.Present == UPS_CONNECTED)) \
   XMONITOR(UPS_InventerHighVoltageMonitor,      (UPS.Present == UPS_CONNECTED)) \
   XMONITOR(UPS_ConnectMonitor,                  1)

+ 1 - 1
docs/bt6721/BT6721.MIB

@@ -15,7 +15,7 @@ IMPORTS
         DESCRIPTION     ""
                                       ::= { enterprises 41752 }
     swt             OBJECT IDENTIFIER ::= { rotek 911 }
-    bt-6721         OBJECT IDENTIFIER ::= { swt 13}
+    bt-6721         OBJECT IDENTIFIER ::= { swt 14}
     signals         OBJECT IDENTIFIER ::= { bt-6721 1 }
     traps           OBJECT IDENTIFIER ::= { bt-6721 2 }
 

+ 26 - 0
docs/bt6721/Changelog.md

@@ -1,3 +1,29 @@
+# 1.3
+### Добавлено
+1. [UPS] Таймауты в функциях работы с SPI. 
+2. [UPS] Сброс ИБП командой "C".
+3. [SERVICE] Новый тест "PIN". Некоторые пины контроллера тестируются на наличие короткого замыкания.
+
+### Изменено
+4. [UPS] В логе отключены лишние аварии.
+5. [UPS] Полная мощность ИБП: 400.
+6. [UPS] Логика формирования записи "Авария входного напряжения 220В".
+7. [WEB] В режиме Offline отображается только частота выходного напряжения.
+
+### Исправлено
+8. [SYSLOG] Изменил текст аварии "Высокое выходное напряжение".
+
+
+# 1.2
+### Добавлено
+1. [UPS]Поддержка команды чтения SN
+### Изменено
+2. [UPS] Рассчет оставшейся емкости, выключение нагрузки
+### Исправлено
+3. [SNMP] корневой OID
+
+
+
 # 1.1
 ### Изменено
 1. [WEB] В разделе "Информация" изменено поле "Компания".

+ 1 - 1
iap/Makefile

@@ -46,7 +46,7 @@ CSRC += $(wildcard ../stm32/stm32f4x7_ethernet/*.c)
 CSRC += $(wildcard User/*.c)
 CSRC += $(wildcard stm32sprog/*.c)
 CSRC += $(wildcard ../thirdparty/TinyStdio/*.c)
-CSRC += ../peripheral_modules/src/spi_flash.c
+#CSRC += ../peripheral_modules/src/spi_flash.c
 #---
 
 CSRC += $(wildcard syscalls/syscalls.c)

+ 415 - 0
iap/Modules/spi_flash.c

@@ -0,0 +1,415 @@
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+#include <stddef.h>
+#include <unistd.h>
+
+#include "spi_flash.h"
+#include "gpio.h"
+
+/*
+struct {
+	uint8_t *tx;
+	uint8_t *rx;
+	uint16_t tx_len;
+	uint16_t rx_len;
+	uint8_t rx_skip;
+	TN_SEM ready;
+	TN_MUTEX busy;
+} xact;
+
+void SPI2_IRQHandler(void) {
+	uint32_t status = SPI2->SR;
+	uint8_t b;
+
+	if (!xact.tx_len && !xact.rx_len) {
+		SPI2->CR1 &= ~SPI_CR1_SPE;
+		SPI2->CR2 &= ~(SPI_CR2_TXEIE | SPI_CR2_RXNEIE);
+		tn_sem_isignal(&xact.ready);
+		return;
+	}
+
+	if (status & SPI_SR_RXNE) {
+		b = SPI2->DR;
+		if (!xact.tx_len) {
+			if (xact.rx_skip) {
+				xact.rx_skip--;
+			}
+			else if (xact.rx_len) {
+				*(xact.rx++) = b;
+				xact.rx_len--;
+			}
+		}
+	}
+
+	if (status & SPI_SR_TXE) {
+		if (xact.tx_len) {		// have smth for tx
+			SPI2->DR = *(xact.tx++);
+			xact.tx_len--;
+		}
+		else if (xact.rx_len) {
+			SPI2->DR = 0;
+		}
+	}
+}
+*/
+
+#define SPI_FLASH_CS_L() gpio_set(SPI2_NSS, 0)
+#define SPI_FLASH_CS_H() gpio_set(SPI2_NSS, 1)
+
+
+//static TN_MUTEX spi_mutex;
+
+#define RX_TX_DELLAY_MS		50
+
+static uint8_t spi_tx_rx(uint8_t byte) {
+	while (!(SPI2->SR & SPI_SR_TXE)) {}
+	SPI2->DR = byte;
+		
+	while (!(SPI2->SR & SPI_SR_RXNE)) {}
+	return SPI2->DR;
+}
+
+static void spi_cs_up(void) {
+	SPI2->CR1 &= ~SPI_CR1_SPE;
+//	GPIOB->BSRR = 1 << 12;
+}
+
+static void spi_cs_down(void) {
+//	GPIOB->BRR = 1 << 12;
+	SPI2->CR1 |= SPI_CR1_SPE;
+}
+
+static void spi_init_(void) {
+//	tn_mutex_create(&spi_mutex, TN_MUTEX_ATTR_INHERIT, 0);
+	//tn_sem_create(&xact.ready, 0, 1);
+
+	RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
+	RCC->APB1RSTR |= RCC_APB1RSTR_SPI2RST;
+	RCC->APB1RSTR &= ~RCC_APB1RSTR_SPI2RST;
+
+	SPI2->CR1 &= ~SPI_CR1_SPE;
+	//SPI2->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_1 | SPI_CR1_SSM | SPI_CR1_SSI;
+	SPI2->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI;
+	SPI2->CR2 = 0;//SPI_CR2_SSOE;
+	SPI2->CR1 |= SPI_CR1_SPE;
+}
+
+#define CMD_WREN	0x06
+#define CMD_WRDI	0x04
+#define CMD_WRSR	0x01
+#define CMD_RDSR	0x05
+#define CMD_READ	0x03
+#define CMD_SE		0x20
+#define CMD_BE		0x52
+#define CMD_CE		0x60
+#define CMD_PP		0x02
+#define CMD_RDSFDP	0x5A
+
+#define SR_WIP	(1 << 0)
+#define SR_WEL	(1 << 1)
+#define SR_SRWD	(1 << 7)
+
+spi_flash_desc_t spi_flash_desc;
+
+static inline void wait_write_enable(void) {
+	uint8_t status;
+//	spi_cs_down();
+	SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_RDSR);
+	do {
+		status = spi_tx_rx(0);
+	} while (!(status & SR_WEL));
+//	spi_cs_up();
+	SPI_FLASH_CS_H();
+}
+
+static inline void wait_write_end(void) {
+	uint8_t status;
+	SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_RDSR);
+	do {
+		status = spi_tx_rx(0);
+	} while (status & SR_WIP);
+	SPI_FLASH_CS_H();
+}
+
+static inline void send_addr(int addr) {
+	spi_tx_rx((addr >> 16) & 0xFF);
+	spi_tx_rx((addr >> 8) & 0xFF);
+	spi_tx_rx(addr & 0xFF);
+}
+
+static int spi_flash_read_sfdp(int addr, void *buf, size_t len) {
+    uint8_t* foo = (uint8_t *)buf;
+    SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_RDSFDP);
+	send_addr(addr);
+	spi_tx_rx(0);
+	while (len--)
+		//*((uint8_t *)buf++) = spi_tx_rx(0);
+      *(foo++) = spi_tx_rx(0);
+    SPI_FLASH_CS_H();
+	return 0;
+}
+
+ssize_t spi_flash_read(int addr, void *buf, size_t len, uint32_t timeout) {
+    uint8_t* foo = (uint8_t *)buf;
+	ssize_t ret = 0;
+//	ret = tn_mutex_lock(&spi_mutex, timeout);
+//	if (ret != TERR_NO_ERR)
+//		return ret;
+
+	SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_READ);
+	send_addr(addr);
+	while (len--)
+		//*((uint8_t *)buf++) = spi_tx_rx(0);
+        *(foo++) = spi_tx_rx(0);
+	SPI_FLASH_CS_H();
+//	tn_mutex_unlock(&spi_mutex);
+	return len;
+}
+
+#define TIMEOUT 10000
+
+uint16_t spi_flash_pp(int addr, const void *buf, size_t len, uint32_t timeout) {
+    uint8_t* foo = (uint8_t *)buf;
+//	ret = tn_mutex_lock(&spi_mutex, timeout);
+//	if (ret != TERR_NO_ERR)
+//		return ret;
+	// don't allow page wrapping
+	ssize_t ret = 0;
+	if ((addr & 0xFF) + len > 0xFF)
+	    len = 0x100 - (addr & 0xFF);
+	ret = len;
+
+	SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_WREN);
+	SPI_FLASH_CS_H();
+
+	wait_write_enable();
+
+	SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_PP);
+	send_addr(addr);
+	while (len--)
+	    //spi_tx_rx(*((uint8_t *)buf++));
+        spi_tx_rx(*(foo++));
+	SPI_FLASH_CS_H();
+
+	wait_write_end();
+
+//	tn_mutex_unlock(&spi_mutex);
+	return ret;
+}
+
+ssize_t spi_flash_write(int addr, const void *buf, size_t len, uint32_t timeout) {
+    uint8_t* foo = (uint8_t *)buf;
+	int ret = 0, offset = 0;
+	do {
+	    //ret = spi_flash_pp(addr + offset, buf + offset, len - offset, 0);
+        ret = spi_flash_pp(addr + offset, foo + offset, len - offset, 0);
+	    offset += ret;
+	} while (len - offset);
+	return 0;
+}
+
+int spi_flash_chip_erase(uint32_t timeout) {
+	SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_WREN);
+	SPI_FLASH_CS_H();
+	wait_write_enable();
+
+    	SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_CE);
+	SPI_FLASH_CS_H();
+
+	wait_write_end();
+	return 0;
+}
+
+int spi_flash_erase_sector(int addr, uint32_t timeout) {
+	int ret = 0;
+//	ret = tn_mutex_lock(&spi_mutex, timeout);
+//	if (ret != TERR_NO_ERR)
+//		return ret;
+
+	SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_WREN);
+	SPI_FLASH_CS_H();
+
+	wait_write_enable();
+
+	SPI_FLASH_CS_L();
+	spi_tx_rx(CMD_SE);
+	send_addr(addr);
+	SPI_FLASH_CS_H();
+
+	wait_write_end();
+
+//	tn_mutex_unlock(&spi_mutex);
+	return 0;
+}
+/*
+bool spi_flash_init(void) {
+	uint32_t i, ptable, bitsize = 0;
+	uint8_t tmp[4];
+
+	spi_flash_desc.present = false;
+
+	spi_init_();
+
+	// check SFDP magic
+	spi_flash_read_sfdp(0, tmp, 4);
+	if (!(tmp[0] == 0x53 && tmp[1] == 0x46 &&
+		tmp[2] == 0x44 && tmp[3] == 0x50))
+		return 0;
+
+	// get parameter headers count
+	spi_flash_read_sfdp(0x06, tmp, 1);
+
+	// find first jedec pheader (with ID == 0)
+	for (ptable = 0x08, i = 0; i <= tmp[0]; i++, ptable += 8) {
+		spi_flash_read_sfdp(ptable, tmp, 1);
+		if (tmp[0] == 0)
+			break;
+	}
+
+	// read ptable pointer from pheader
+	spi_flash_read_sfdp(ptable + 4, &ptable, 3);
+
+	// get flash density (size in bits)
+	if (spi_flash_read_sfdp(ptable + 4, &bitsize, 4) < 0 || !bitsize)
+		return 0;
+
+	// find smallest available sector
+	for (i = 0; i < 4; i++) {
+		tmp[0] = 0;
+		if (spi_flash_read_sfdp(ptable + 0x1C + i*2, &tmp, 2) >= 0 &&
+				tmp[0]) {
+			spi_flash_desc.sector_size = 1 << tmp[0];
+			spi_flash_desc.sector_erase_op = tmp[1];
+			spi_flash_desc.sector_count = (bitsize + 1) >> (3 + tmp[0]);
+			break;
+		}
+	}
+	if (!spi_flash_desc.sector_size)
+		return 0;
+
+	spi_flash_desc.present = true;
+    
+    return 1;
+
+}*/
+
+bool spi_flash_init(void){
+	spi_init_();
+	spi_flash_desc.sector_size = SPI_FLASH_SECTOR_SIZE;
+	spi_flash_desc.sector_erase_op = 32;
+	spi_flash_desc.sector_count = 512;
+	spi_flash_desc.present = true;
+
+	return 1;
+}
+
+uint8_t txbuf1[] = "This film came out on DVD yesterday and I rushed to buy it. \
+		    This version is the first to render all the detail and perfection \
+		    of Jack Cardiff's amazing compositions and brilliant, varied photography. \
+		    As a collection of memorable images, this film is better than any comparable \
+		    historical epic of the period and even gives GWTW a run for its money. \
+		    King Vidor's direction is a series of 'tableaux vivants' where the \
+		    characters are not posing but acting in a very natural, period-specific way. \
+		    I have never had a problem with this adaptation of Tolstoy's novel. \
+		    I think it is a wonderful introduction to the period and the novel and that \
+		    it is a very poetic, very original work in its own right. Henry Fonda's \
+		    characterization is especially moving, including great memorable interactions \
+		    with/reations to Mel Ferrer, Audrey Hepburn, Helmut Dantine and John Mills, but \
+		    all members of the cast are actually perfect. The harrowing last 45 minutes of \
+		    the film manage to convey a sense of history, a sense of grandeur as well as to \
+		    communicate very clearly Tolstoy's ideas about the meaning of life, by relying \
+		    mostly on the power of memorable images. The most conspicuous handicap of this movie, \
+		    in my opinion, is its soundtrack (in glorious mono). The barely hi-fi recording of \
+		    dialogues and music sounds pinched, hollow and tinny and it always has in very version \
+		    I have ever seen: in the theatres, on TV and on video. Even the soundtrack album is \
+		    an atrocity. In some scenes, before the necessary adjustments of bass and treble, \
+		    Audrey Hepburn's and Mel Ferrer's voices actually hurt your ear. Nino Rota's very \
+		    Russian-sounding score is serviceable and melodic, although rather sparse in its \
+		    orchestration and in the number of players. One can only wonder what 'War and Peace' \
+		    could have sounded like with a cohort of Hollywood arrangers, decent recording facilities \
+		    and lavish, varied orchestrations in true high fidelity and stereophonic sound. \
+		    According to Lukas Kendall of 'Film Score Monthly', the original recording elements \
+		    of the soundtrack have long ago disappeared, which is the common lot of international, \
+		    independent co-productions of the era. Someone somewhere is certainly guilty of \
+		    skimping on quality or embezzlement for this 1956 movie to sound so much worse \
+		    than a 1939, pre-hi-fi epic like GWTW. Like all VistaVision films, this one was \
+		    meant to be shown in Perspecta Stereophonic Sound where the mono dialog track was \
+		    meant to be channelled to three different directions, making it directional, while \
+		    the separate mono music + sound effects track was generally directed to all three \
+		    speakers at the same time. The results fooled the viewers into thinking everything \
+		    was in true stereo and the reproduction of the music was usually in very high fidelity. \
+		    Maybe the soundtrack used on the DVD is a mono reduction of those two separate tracks \
+		    that has squandered that fidelity and maybe the DVD can be issued again with better \
+		    results in some kind of 4.0 presentation. When they do, very little electronic \
+		    restoration work will be needed to make the image absolutely perfect. \
+		    But let's concentrate on the positive: This film is a summit of visual \
+		    splendour and its sets, costumes, colour photography, composition and lighting \
+            achieve, in every single scene, wonders of artistry, creativity and delicacy \
+		    But let's concentrate on the positive: This film is a summit of visual \
+		    splendour and its sets, costumes, colour photography, composition and lighting \
+		    achieve, in every single scene, wonders of artistry, creativity and delicacy \
+		    that will probably never be equalled. Suffice it to say that it has, \
+		    among many other treasures, a sunrise duel scene in the snow that still has viewers \
+		    wondering whether it was shot outdoors or in a studio and that will have them wondering foreverhsgkhgkshgu.\r\n";
+
+uint8_t txbuf2[] = "STM32F4xx SPI Firmware Library Example: communication with an M25P SPI FLASH\r\n";
+
+#define countof(a) (sizeof(a) / sizeof(*(a)))
+#define  bufsize1 (countof(txbuf1)-1)
+#define  bufsize2 (countof(txbuf2)-1)
+
+uint8_t  rxbuf1[bufsize1] = {0};
+uint8_t  rxbuf2[bufsize2] = {0};
+
+bool spi_flash_test(void) {
+
+	uint16_t i;
+    if (!spi_flash_init())
+	return false;
+    int ret = 0, addr = 0, offset = 0;
+    for(i = 0; i < 1; i ++){//spi_flash_desc.sector_count
+		//spi_flash_read(i*spi_flash_desc.sector_size, rxbuf1, bufsize1, 0);
+		spi_flash_erase_sector(i*spi_flash_desc.sector_size,0);
+		//spi_flash_read(0, rxbuf1, bufsize1, 0);
+
+		spi_flash_write(i*spi_flash_desc.sector_size, txbuf1, bufsize1, 0);
+
+		memset(rxbuf1, 0, bufsize1);
+		spi_flash_read(i*spi_flash_desc.sector_size, rxbuf1, bufsize1, 0);
+
+		if (memcmp(txbuf1, rxbuf1, bufsize1) != 0)
+		return false;
+
+    }
+    return true;
+    /*spi_flash_erase_sector(0,0);
+    spi_flash_read(0, rxbuf1, bufsize1, 0);
+
+    spi_flash_write(0, txbuf2, bufsize2, 0);
+
+    memset(rxbuf2, 0, bufsize2);
+    spi_flash_read(0, rxbuf2, bufsize2, 0);*/
+
+
+/*
+ * TODO restore spi_flash_init();
+	spi_flash_init();
+	if (!spi_flash_desc.present)
+		return -1;
+	printf("\tPresent: %d sectors, %d bytes per sector (%d bytes total)\n",
+		spi_flash_desc.sector_count,
+		spi_flash_desc.sector_size,
+		spi_flash_desc.sector_size * spi_flash_desc.sector_count);
+	return 0;
+*/
+    
+}

+ 54 - 0
iap/Modules/spi_flash.h

@@ -0,0 +1,54 @@
+#ifndef SPI_FLASH_H
+#define SPI_FLASH_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef PRINTF_STDLIB
+#include <stdio.h>
+#endif
+#ifdef PRINTF_CUSTOM
+#include "tinystdio.h"
+#endif
+
+#define SPI_FLASH_SECTOR_SIZE		        4096
+#define SPI_FLASH_SECTORS_IN_BLOCK_NUMBER   16
+#define SPI_FLASH_BLOCK_SIZE                16//4
+#define SPI_FLASH_BLOCK_NUMBER		        32
+
+// SPI flash partitioning layout
+#define LOG_FLASH_SECTOR_OFFSET	4
+#if HARDWARE_BT6711 || HARDWARE_BT6711_V1 || HARDWARE_BT6721
+// assuming 512 sectors
+#define ALARM_LOG_FLASH_SECTOR_OFFSET	174
+#define SECTOR_COUNT 170
+#define FIRMWARE_UPDATE_SECTOR_OFFSET	344
+#define FIRMWARE_UPDATE_SECTOR_COUNT	(512 - FIRMWARE_UPDATE_SECTOR_OFFSET)
+#else // HARDWARE_BT6711
+#define ALARM_LOG_FLASH_SECTOR_OFFSET	258
+#define SECTOR_COUNT (spi_flash_desc.sector_count/2 - LOG_FLASH_SECTOR_OFFSET)
+#endif // HARDWARE_BT6711
+
+#if defined ( __ICCARM__ )
+typedef int ssize_t;
+#endif
+
+typedef struct {
+	bool present;
+//	uint16_t sector_size;
+	uint32_t sector_size;
+	uint8_t sector_erase_op;
+	uint16_t sector_count;
+} spi_flash_desc_t;
+
+extern spi_flash_desc_t spi_flash_desc;
+
+extern bool spi_flash_init(void);
+extern ssize_t spi_flash_read(int addr, void *buf, size_t len, uint32_t timeout);
+extern ssize_t spi_flash_write(int addr, const void *buf, size_t len, uint32_t timeout);
+extern int spi_flash_erase_sector(int addr, uint32_t timeout);
+extern int spi_flash_chip_erase(uint32_t timeout);
+extern bool spi_flash_test(void);
+#endif /* SPI_FLASH_H */

+ 66 - 0
modules/MegaTec/crc_calc.c

@@ -0,0 +1,66 @@
+
+#include "crc_calc.h"
+
+static const uint8_t CRC_HI[] = {
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+	 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+	 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+	 0x00, 0xC1, 0x81, 0x40
+};
+
+static const uint8_t CRC_LO[] = {
+	 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
+	 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
+	 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
+	 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
+	 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
+	 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
+	 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
+	 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
+	 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
+	 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
+	 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
+	 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
+	 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
+	 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
+	 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
+	 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
+	 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
+	 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
+	 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
+	 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+	 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
+	 0x41, 0x81, 0x80, 0x40
+};
+
+uint16_t calc_crc16(uint8_t *data, uint16_t len) {
+	uint8_t crc_hi, crc_lo;
+	crc_hi = crc_lo = 0xff;
+	int idx;
+
+	while (len--)
+	{
+		idx = crc_lo ^ (uint8_t)*(data++);
+		crc_lo = (uint8_t)(crc_hi ^ CRC_HI[idx] );
+		crc_hi = CRC_LO[idx];
+	}
+	return ((uint16_t)crc_hi << 8) | (uint8_t)crc_lo;
+}

+ 12 - 0
modules/MegaTec/crc_calc.h

@@ -0,0 +1,12 @@
+#ifndef CRC_CALC_H_
+#define CRC_CALC_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+
+uint16_t calc_crc16(uint8_t *data, uint16_t len);
+
+
+#endif

+ 134 - 25
modules/MegaTec/megatec.c

@@ -17,6 +17,7 @@
 #include "parameters.h"
 #include "hal.h"
 #include "rtc.h"
+#include "crc_calc.h"
 #ifdef PRINTF_STDLIB
 #include <stdio.h>
 #endif
@@ -38,6 +39,7 @@ TimerHandle_t AutoTestTimer;
 extern SETTINGS_t sSettings;
 
 #define UPS_PDU_MAX_LEN 80
+#define UPS_PDU_MIN_LEN 5
 
 float TimeParamFloat = 0;
 uint16_t TimeParam = 0;
@@ -158,6 +160,46 @@ float power_load_average(void)
 {
     return (Pload_sum / Period_testing);
 }
+
+bool ups_additional_prtcl_rx_pdu(void)
+{
+    int c = 0;
+    uint8_t cnt_answer = 0;
+
+    ups_pdu.len = 0;
+
+    /* Check empty responce (UART has no data) */
+    if ((c = ups_getchar(1000)) < 0) {
+        DBG printf("no data\r\n");
+        return false;
+    } else {
+        ups_pdu.len = 0;
+        ups_pdu.data[ups_pdu.len++] = c;
+    }
+    while ((ups_pdu.len < UPS_PDU_MAX_LEN) && ((c = ups_getchar(10)) >= 0)) {
+        ups_pdu.data[ups_pdu.len++] = c;
+    }
+
+    DBG printf("rx %d bytes from 0x%X\r\n", ups_pdu.len, ups_pdu.data[0]);
+    if (ups_pdu.len < UPS_PDU_MIN_LEN ||
+        ups_pdu.data[0] != 0x01) {
+        return false;
+    }
+#if 1
+    uint16_t crc = (uint16_t)(ups_pdu.data[ups_pdu.len - 2] | ((uint16_t)(ups_pdu.data[ups_pdu.len - 1]) << 8));
+    if (crc != calc_crc16(ups_pdu.data, ups_pdu.len - 2)) {
+        DBG {
+            printf("bad crc:");
+            for (uint16_t i = 0; i < ups_pdu.len; i++) {
+                printf(" 0x%X", ups_pdu.data[i]);
+            }
+            printf("\r\n");
+        }
+        return false;
+    }
+#endif
+    return true;
+}
  
 
 void send_MegaTec_cmd(cmdMegaTecEnums_t command)
@@ -372,12 +414,20 @@ void ups_status_response(char *data)
     if(UPS.Status & 0x04) {
         UPS.SOC_prev = UPS.SOC;
     }
-    if (UPS.Vcell_curr < 7) {
-        UPS.SOC = round(100 * (UPS.Vcell_curr - sSettings.UPS_Setting.Ucellmin) / (sSettings.UPS_Setting.Ucellmax -
-                  sSettings.UPS_Setting.Ucellmin));
-    } else {
-        UPS.SOC = round(100 * (UPS.Vcell_curr / AKB_NUM_CELL - sSettings.UPS_Setting.Ucellmin) /
-                  (sSettings.UPS_Setting.Ucellmax - sSettings.UPS_Setting.Ucellmin));
+#ifdef HARDWARE_BT6721
+    if(UPS.Mode == 'B') {
+        UPS.SOC = round(100 * (UPS.Vcell_curr / AKB_NUM_CELL - 1.96) /
+                    (2.13 - 1.96));
+    } else
+#endif    
+    {
+        if (UPS.Vcell_curr < 7) {
+            UPS.SOC = round(100 * (UPS.Vcell_curr - sSettings.UPS_Setting.Ucellmin) / (sSettings.UPS_Setting.Ucellmax -
+                    sSettings.UPS_Setting.Ucellmin));
+        } else {
+            UPS.SOC = round(100 * (UPS.Vcell_curr / AKB_NUM_CELL - sSettings.UPS_Setting.Ucellmin) /
+                    (sSettings.UPS_Setting.Ucellmax - sSettings.UPS_Setting.Ucellmin));
+        }
     }
  //   }
 
@@ -497,6 +547,15 @@ void ups_general_status_response(char *data)
 */
 }
 
+void ups_specific_response_sn(uint8_t *data)
+{
+    uint8_t len = data[4] - 3;
+    if(len >= sizeof(UPS.serial)) {
+        len = sizeof(UPS.serial) - 1;
+    }
+    strncpy(UPS.serial, &data[8], len);
+}
+
 void ups_info_response(char *data)
 {
     uint8_t i = 0, j = 0;
@@ -540,10 +599,32 @@ void ups_info_response(char *data)
         }
     }
     data += (KSTAR_MODEL_LENGTH + 1);
-    strncpy(UPS.serial, data, 8);
-    data += 8;
+    if (UPS.serial[0] == 0 && data[0] != ' '){
+        strncpy(UPS.serial, data, 8);
+        data += 8;
+    } else {
+        while (*data == ' '){
+            data += 1;       
+        }
+    }
+    
+    memset(value, 0, sizeof(value));
+    j = 0;
+    while (*data != '\r'){
+        value[j] = *data;
+        j++;
+            data += 1;       
+    }
+
+    if( (sSettings.UPS_Setting.type_ups == ups_kestar || sSettings.UPS_Setting.type_ups == ups_offline) && strlen(UPS.serial) == 0){
+        uint8_t specific_req_sn[7] = {0x01, 0x06, 0x95, 0x00, 0x0f, 0x49, 0x60};
+        ups_send_block(specific_req_sn, 7);
+        if (ups_additional_prtcl_rx_pdu()) {
+            ups_specific_response_sn(ups_pdu.data);
+        }
+    }
 
-    strncpy(UPS.vertion, data, 2);
+    strncpy(UPS.vertion, value, (j+1));
     SNMP_SetObjDescr();
 }
 
@@ -1093,6 +1174,8 @@ void ups_temperature_response(char *data)
 }
 
 
+
+
 void ups_megatec_process_pdu(cmdMegaTecEnums_t command)
 {
     switch (command) {
@@ -1168,6 +1251,8 @@ int ups_metac_service_pdu(cmdMegaTecEnums_t command)
         megatec_send = false;
         if (command == ups_shutdown) {//sSettings.UPS_Setting.type_ups == ups_offline && 
             TimeParam2 = 1;
+            xTimerChangePeriod(UPSRestoreTimer, (TimeParamFloat + 0.1)*60*configTICK_RATE_HZ, 0);
+            xTimerStart(UPSRestoreTimer, 0);
             send_MegaTec_cmd(ups_shutdown_restore);
         } else {
             if((UPS.Status >> 2) & 0x01) {
@@ -1232,17 +1317,28 @@ int ups_metac_service_pdu(cmdMegaTecEnums_t command)
                 init_var_for_testing();
                 return 1;
             }
+
+            if  ((((UPS.Status >> 1) & 0x01) != ((UPS_Status_prev >> 1) & 0x01))
+             && ((UPS.Status >> 1) & 0x01)) {
+                return 1;
+            }
         }
 
         megatec_send = true;
     }
+#if HARDWARE_BT6721
+    if (command == ups_shutdown) {
+        return 1;
+    }
+#endif
     return -1;
 }
 
 void kstar_mode(void)
 {
     uint8_t mode = UPS.Mode;
-#if 0    
+    static uint32_t fault_mode_cnt = 0;
+
     if((UPS.Status >> 4) & 0x01) {
         UPS.Mode = 'F';
     } else if(!((UPS.Status >> 4) & 0x01) && UPS.VAC_out == 0) {
@@ -1256,20 +1352,20 @@ void kstar_mode(void)
     } else if((UPS.Status >> 2) & 0x01) {
         UPS.Mode = 'T';
     }
-#endif
 
-    if((UPS.Status >> 4) & 0x01) {
-        UPS.Mode = 'F';
-    } else if(!((UPS.Status >> 4) & 0x01) && UPS.VAC_out == 0) {
-        UPS.Mode = 'D';
-    } else if(((UPS.Status >> 5) & 0x01) && UPS.VAC_out > 120 && UPS.VAC_in != 0) {
-        UPS.Mode = 'Y';
-    } else if(((UPS.Status >> 7) & 0x01) && UPS.VAC_out > 190) {
-        UPS.Mode = 'B';
-    } else if((UPS.Status >> 2) & 0x01) {
-        UPS.Mode = 'T';
+    // Добавилл отправку команды "C", т.к. ИБП 
+    // самостоятельно не выходит из состояния Fault.
+    if (UPS.Mode == 'F') {
+        fault_mode_cnt++;
+    }
+    else {
+        fault_mode_cnt = 0;
     }
 
+    if (fault_mode_cnt == UPS_CANSEL_DELAY) {
+        send_MegaTec_cmd(ups_cancel_shut_down);
+        fault_mode_cnt = 0;
+    }
 
     if (UPS.Mode != mode) {
 #ifdef UPS_MODE_MONITOR
@@ -1288,8 +1384,7 @@ void kstar_mode(void)
 //void request_task(void)
 void request_task(void *params)
 {
-    //uint8_t kestar_req[4] = { ups_status_req, ups_remain_time_reg, ups_info, ups_kstar_status};
-    uint8_t kestar_req[1] = { ups_status_req};
+    uint8_t kestar_req[4] = { ups_status_req, ups_remain_time_reg, ups_info, ups_kstar_status};
     uint8_t voltronic_req[9] = {ups_temperature, ups_status_req, ups_akb_info, ups_model_req, ups_mode_req, ups_version_req, ups_version2_req, ups_serial_req, ups_warning_status};//
     uint8_t num_req = 0;
     uint8_t *req;
@@ -1405,6 +1500,13 @@ void request_task(void *params)
                         megatec_send = true;
                     }
                 }
+            } else if( sSettings.UPS_Setting.type_ups == ups_kestar || sSettings.UPS_Setting.type_ups == ups_offline){
+                uint8_t specific_req_sn[7] = {0x01, 0x06, 0x95, 0x00, 0x0f, 0x49, 0x60};
+                vTaskDelay(1000);
+                ups_send_block(specific_req_sn, 7);
+                if (ups_additional_prtcl_rx_pdu()) {
+                    ups_specific_response_sn(ups_pdu.data);
+                }
             }
 #ifdef CHECK_LOAD_ENABLE
             xTimerStart(AutoTestTimer, 0);
@@ -1430,12 +1532,13 @@ void request_task(void *params)
             }
         }
 
+        
+
         // printf("UPS.Flag_Present: %u\r\n", (uint8_t)UPS.Flag_Present);
         // printf("UPS_Setting.type_ups: %u\r\n", sSettings.UPS_Setting.type_ups);
-        kstar_mode();
 
 
-        if(UPS.Flag_Present && (sSettings.UPS_Setting.type_ups == ups_kestar 
+        if(UPS.Present == UPS_CONNECTED && (sSettings.UPS_Setting.type_ups == ups_kestar 
             || sSettings.UPS_Setting.type_ups == ups_offline)) {
                 kstar_mode();
         }
@@ -1483,9 +1586,15 @@ void UPSRestoreCallback(TimerHandle_t pxTimer)
         memset(ups_pdu.data, 0, UPS_PDU_MAX_LEN);
         megatec_send = false;
         //UPS.Flag_Present = false;
+#ifdef HARDWARE_BT6721
+        send_MegaTec_cmd(ups_cancel_shut_down);
+#else
         send_MegaTec_cmd(ups_remote_turn_on);
+#endif
         if (ups_megatec_rx_pdu()) {
+#ifndef HARDWARE_BT6721
             ups_megatec_process_pdu(ups_remote_turn_on);
+#endif
         }
         megatec_send = true;
     }

+ 1 - 0
modules/MegaTec/megatec.h

@@ -14,6 +14,7 @@
 
 
 #define PERIOD_AUTO_TEST	23.5*3600
+#define UPS_CANSEL_DELAY	5
 
 #define K_EFFICIENCY		0.9
 #define AKB_VOLTAGE			12

+ 1 - 1
modules/log/ringfs.c

@@ -382,7 +382,7 @@ int ringfs_append(struct ringfs *fs, const void *object)
         /* Free sector. Mark as used. */
         _sector_set_status(fs, fs->write.sector, SECTOR_IN_USE);
     } else if (status != SECTOR_IN_USE) {
-        printf("ringfs_append: corrupted filesystem\r\n");
+        DBG printf("ringfs_append: corrupted filesystem\r\n");
         return -1;
     }
 

+ 3 - 3
modules/monitor/ups_monitor.c

@@ -623,7 +623,7 @@ void UPS_LineFailMonitor(void)
   // Значение параметра изменилось
   if (lineFailCurrent != lineFailOldState)
   {
-    if (lineFailCurrent != 0){
+    if ((lineFailCurrent != 0) && (lineFailOldState == 0)) {
 #if	defined RELAY_AC_PRESENT
     	relay_setup_log(CurrROtype_Sourse, AC_PRESENT, 1);
 #endif
@@ -643,7 +643,7 @@ void UPS_LineFailMonitor(void)
 #endif
     	flUpdateLog = true;
     }
-    else{
+    else if (lineFailCurrent == 0) {
       if (UPS.VAC_in == 0) {
         return;
       }
@@ -784,7 +784,7 @@ void UPS_VACoutputHighRangeMonitor(void)
 #if HARDWARE_BT6711 || HARDWARE_BT6711_V1 || HARDWARE_BT6721
 	        // Отправка трапа о завышении
 	        SNMP_SendUserTrap(VAC_HIGH_OUTPUT_ALARM);
-		syslog(SYSLOG_ERROR, "Высокое входное напряжение (%0.1f В)", VACoutputCurrent);
+		syslog(SYSLOG_ERROR, "Высокое выходное напряжение (%0.1f В)", VACoutputCurrent);
 #endif
 	        flUpdateLog = true;
 	    } else {

+ 5 - 1
modules/parameters.c

@@ -98,7 +98,11 @@ bool GetRebootStatus(void)
   */
 void GetInputFreqStr(char *str, uint8_t *len)
 {
-    sprintf(str, "%0.1f", UPS.Freq_in);
+    if (UPS.Mode == 'Y')
+      sprintf(str, "%0.1f", UPS.Freq_in);
+    else
+      sprintf(str, "%0.1f", 0.0);
+
     *len = strlen(str);
 }
 

+ 1 - 1
modules/settings_api_bt6711.c

@@ -9,7 +9,7 @@
  * XX.XX.XXXX   1.0.0    Telenkov D.A.  First release.
  *******************************************************************************
  */
-#if HARDWARE_BT6711 || HARDWARE_BT6711_V1 || HARDWARE_BT6721
+#if HARDWARE_BT6711 || HARDWARE_BT6711_V1
 #include "stm32f4xx.h"  
 #include "settings_api.h"
 #include "common_config.h"

+ 316 - 0
modules/settings_api_bt6721.c

@@ -0,0 +1,316 @@
+/********************************* (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.
+ *******************************************************************************
+ */
+#if HARDWARE_BT6721
+#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 <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[] =
+{
+	  "Перезагрузка контроллера",
+    "Сброс настроек",
+    "Обновление ПО",
+    "Включение",
+    "Смена пароля",
+    "Сохранение настроек",
+    "Авторизация (Telnet)",
+    "Авторизация",
+    "Режим работы ИБП",
+    "Тест ИБП",
+    "Откл. нагрузки ИБП",
+    "Низкое вых. напряжение",
+    "Высокое вых. напряжение",
+    "Высокая температура",
+    "Низкая температура",
+    "Авария вх. напряжения",
+    "Низкий заряд АКБ",
+    "Авария нагрузки",
+    "Авария связи с ИБП",
+    "Авария отключения АКБ",
+    "Ёмкость АКБ",
+    "Ош. подкл. вх. напряжения",
+    "Срабатывание EPO",
+};
+
+const char* name_traps[] =
+{
+  "",
+	"Начало обновл. ПО",
+  "Успешное обновл. ПО",
+  "Сброс настроек",
+  "Перезагрузка",
+  "Режим работы ИБП",
+  "Норм. темп. АКБ по верх. границы",
+  "Авария темп. АКБ по верх. границы",
+  "Норм. темп. АКБ по ниж. границы",
+  "Авария темп. АКБ по ниж. границы",
+  "Авария на линии",
+  "Нормализация линии",
+  "Авария вых. напряжения по ниж. границы",
+  "Норм. вых. напряжения по ниж. границы",
+  "Авария вых. напряжения по верх. границы",
+  "Норм. вых. напряжения по верх. границы",
+  "Низкий заряд АКБ",
+  "Тест АКБ запущен",
+  "Тест АКБ завершен",
+  "Отказ АКБ",
+  "АКБ в норме",
+  "Нормализация заряда АКБ",
+  "Отключение АКБ",
+  "Подключение АКБ",
+  "Авария нагрузки",
+  "Нагрузка в норме",
+  "Авария соединения с ИБП",
+  "Норм. соединения с ИБП",
+  "Ош. подкл. вх. напряжения",
+  "Норм. подкл. вх. напряжения",
+  "Срабатывание EPO",
+  "EPO норма",
+};
+
+/**
+  * @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.89;
+  sSettings.UPS_Setting.Ucellmax = 2.36;
+  sSettings.UPS_Setting.Uakb = 12;
+  sSettings.UPS_Setting.common_capacity = 15;
+  sSettings.UPS_Setting.ups_power = 400;
+  sSettings.UPS_Setting.set_data = 0;
+  sSettings.UPS_Setting.life_time = 5;
+  sSettings.UPS_Setting.type_ups = ups_kestar;
+}
+
+/**
+  * @brief  Настройки серийного номера ИБП по умолчанию
+  */
+void SETTINGS_SetUPSSerialSettingsDef(void)
+{
+  sSettings.UPS_Setting.serial = 0;
+}
+
+/**
+  * @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_input_range.high = 250.0;
+	sSettings.sAlarmManager.ac_input_range.low = 150.0;
+	sSettings.sAlarmManager.ac_input_range.hyst = 20.0;
+
+	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_SetRelaysDef(void)
+{
+
+}
+
+/**
+  * @brief  Установить параметры настроек сухих контактов по умолчанию
+  */
+void SETTINGS_SetDINSDef(void)
+{
+
+}
+
+/**
+  * @brief  Установить параметры RADIUS по умолчанию
+  */
+void SETTINGS_SetRADIUSDef(void)
+{
+  sSettings.sRADIUS.Auth_enable = true;
+  //sSettings.sRADIUS.RDSEnable = false;
+  // todo вернуть на значение false
+  sSettings.sRADIUS.RDSEnable = false;
+  strcpy(sSettings.sRADIUS.ServerIP, "0.0.0.0");
+  //strcpy(sSettings.sRADIUS.ServerIP, "192.168.14.234");
+  sSettings.sRADIUS.port = 1812;
+  sSettings.sRADIUS.key_access = 123;
+  strcpy(sSettings.sRADIUS.rds_password, "R02ekR4MP2");
+}
+
+/**
+  * @brief  Установить параметры сертификата сервера по умолчанию
+  */
+void SETTINGS_SetSSLcrtDef(void){
+
+}
+
+/**
+  * @brief  Установить параметры Telnet
+  */
+void SETTINGS_SetTelnetDef(void){
+	sSettings.sTelnet.TelnetEnable = true;
+	sSettings.sTelnet.port = 23;
+}
+
+/**
+  * @brief  Установить параметры SSH
+  */
+void SETTINGS_SetSSHDef(void){
+
+}
+
+/**
+  * @brief  Установить параметры списка доверительных хостов
+  */
+void SETTINGS_SetWhiteListDef(void){
+	for(uint8_t i = 0; i < MAX_WHITE_LIST; i++){
+		strcpy(sSettings.sWhiteListTemp[i].ip_range, "");
+		SetWhiteListSTR(sSettings.sWhiteListTemp[i].ip_range, i);
+		strcpy(sSettings.sWhiteList[i].ip_range, sSettings.sWhiteListTemp[i].ip_range);
+		sSettings.sWhiteList[i].ip = sSettings.sWhiteListTemp[i].ip;
+		sSettings.sWhiteList[i].mask = sSettings.sWhiteListTemp[i].mask;
+	}
+}
+
+/**
+  * @brief  Установить параметры разрешения уведомлений по умолчанию
+  */
+void SETTINGS_SetFlagNotificationDef(void)
+{
+    uint8_t i;
+
+    for(i = 0; i < ALL_TRAPS; i++ ) {
+        sSettings.sFlagNotification[i] = 1;
+    }
+}
+
+void SETTINGS_SetFTPUpdateDef(void)
+{
+  IP4_ADDR(&sSettings.sFTPUpdate.server_ip, 192,168,0,253);
+  sSettings.sFTPUpdate.server_port = 21;
+  strcpy(&sSettings.sFTPUpdate.remote_path, "BT_6711xx.bin");
+  strcpy(&sSettings.sFTPUpdate.user, "anonymous");
+  strcpy(&sSettings.sFTPUpdate.pass, "guest");
+}
+
+void SETTINGS_SetSyslogDef(void)
+{
+  sSettings.sSyslog.enabled = false;
+  IP4_ADDR(&sSettings.sSyslog.server_ip, 192,168,0,253);
+  sSettings.sSyslog.server_port = 514;
+}
+
+/**
+  * @brief  Установить значение настроек прозрачного порта по умолчанию
+  */
+void SETTINGS_SetPortGwDef(void)
+{
+
+}
+
+/**
+  * @brief  Установить параметры датчиков температуры
+  */
+void SETTINGS_SetTempControlDef(void)
+{
+
+}
+
+#endif
+/********************************* (C) ROTEK **********************************/

+ 31 - 3
peripheral_modules/src/spi_flash.c

@@ -5,6 +5,9 @@
 
 #include "spi_flash.h"
 #include "gpio.h"
+#include "FreeRTOS.h"
+#include "task.h"
+
 
 /*
 struct {
@@ -59,11 +62,26 @@ void SPI2_IRQHandler(void) {
 
 //static TN_MUTEX spi_mutex;
 
+#define RX_TX_DELLAY_MS		50
+
 static uint8_t spi_tx_rx(uint8_t byte) {
-	while (!(SPI2->SR & SPI_SR_TXE)) {}
+	uint32_t tick_start = xTaskGetTickCount();
+
+	while (!(SPI2->SR & SPI_SR_TXE)) {
+		if ((xTaskGetTickCount() - tick_start) >= RX_TX_DELLAY_MS) {
+			break;
+		}	
+	}
+
 	SPI2->DR = byte;
-		
-	while (!(SPI2->SR & SPI_SR_RXNE)) {}
+
+	tick_start = xTaskGetTickCount();
+
+	while (!(SPI2->SR & SPI_SR_RXNE)) {
+		if ((xTaskGetTickCount() - tick_start) >= RX_TX_DELLAY_MS) {
+			break;
+		}
+	}
 	return SPI2->DR;
 }
 
@@ -111,11 +129,16 @@ spi_flash_desc_t spi_flash_desc;
 
 static inline void wait_write_enable(void) {
 	uint8_t status;
+	uint32_t tick_start;
 //	spi_cs_down();
 	SPI_FLASH_CS_L();
 	spi_tx_rx(CMD_RDSR);
+	tick_start = xTaskGetTickCount();
 	do {
 		status = spi_tx_rx(0);
+		if ((xTaskGetTickCount() - tick_start) >= RX_TX_DELLAY_MS) {
+			break;
+		} 
 	} while (!(status & SR_WEL));
 //	spi_cs_up();
 	SPI_FLASH_CS_H();
@@ -123,10 +146,15 @@ static inline void wait_write_enable(void) {
 
 static inline void wait_write_end(void) {
 	uint8_t status;
+	uint32_t tick_start;
 	SPI_FLASH_CS_L();
 	spi_tx_rx(CMD_RDSR);
+	tick_start = xTaskGetTickCount();
 	do {
 		status = spi_tx_rx(0);
+		if ((xTaskGetTickCount() - tick_start) >= RX_TX_DELLAY_MS) {
+			break;
+		}
 	} while (status & SR_WIP);
 	SPI_FLASH_CS_H();
 }

+ 125 - 1
service_hw/Commands/bt_6701_commands.c

@@ -56,6 +56,12 @@ extern BUTTON_NO_FIX_t setButton;
   */
 extern unsigned char eth_ready_flag;
 
+
+static bool test_pair_pins(pair_pin_t *pins);
+static void set_pin_as_output(GPIO_TypeDef *port, uint8_t pin);
+static void set_pin_as_input(GPIO_TypeDef *port, uint8_t pin);
+static void test_pin_print_result(pair_pin_t *pins, uint8_t *res);
+
 // -------------------------------------------------------------------------- //
 //                              __weak функции
 
@@ -460,7 +466,125 @@ void Test_Serno(void)
 }
 
 
-// -------------------------------------------------------------------------- //
 
 
+#define PAIR_PINS_SIZE      14
+
+pair_pin_t pins_with_pair[PAIR_PINS_SIZE] = {
+  {GPIOE, GPIO_Pin_6, 5, GPIOE, GPIO_Pin_5, 4},       // 1 : 5, 4
+  {GPIOE, GPIO_Pin_15, 46, GPIOB, GPIO_Pin_10, 47},   // 2 : 46, 47
+  {GPIOB, GPIO_Pin_3, 89, GPIOB, GPIO_Pin_4, 90},     // 3 : 89, 90
+  {GPIOB, GPIO_Pin_4, 90, GPIOB, GPIO_Pin_5, 91},     // 4 : 90, 91
+  {GPIOB, GPIO_Pin_5, 91, GPIOB, GPIO_Pin_6, 92},     // 5 : 91, 92
+  {GPIOC, GPIO_Pin_0, 15, GPIOC, GPIO_Pin_1, 16},     // 6 : 15, 16
+  {GPIOC, GPIO_Pin_1, 16, GPIOC, GPIO_Pin_2, 17},     // 7 : 16, 17
+  {GPIOA, GPIO_Pin_1, 24, GPIOA, GPIO_Pin_0, 23},     // 8 : 23, 24
+  {GPIOA, GPIO_Pin_1, 24, GPIOA, GPIO_Pin_2, 25},     // 9 : 24, 25
+  {GPIOA, GPIO_Pin_5, 30, GPIOA, GPIO_Pin_6, 31},     // 10 : 30, 31
+  {GPIOA, GPIO_Pin_6, 31, GPIOA, GPIO_Pin_7, 32},     // 11 : 31, 32
+  {GPIOC, GPIO_Pin_5, 34, GPIOB, GPIO_Pin_0, 35},     // 12 : 34, 35
+  {GPIOE, GPIO_Pin_12, 43, GPIOE, GPIO_Pin_13, 44},   // 13 : 43, 44
+  {GPIOB, GPIO_Pin_12, 51, GPIOB, GPIO_Pin_13, 52},   // 14 : 51, 52
+};
+
+uint8_t pair_pin_resut[PAIR_PINS_SIZE];
+
+// ------------------------------------------------------------------------ //
+
+//
+void Test_Pins(void)
+{
+  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
+  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
+  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
+  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
+  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
+ 
+  if (test_pair_pins(pins_with_pair))
+    printf("PIN OK\r\n");
+  else
+    printf("PIN FAIL\r\n");
+
+  TEST_SetTest(TEST_WAIT);
+}
+
+//
+static bool test_pair_pins(pair_pin_t *pins)
+{
+  uint8_t res_1 = Bit_RESET;
+  uint8_t res_2 = Bit_RESET;
+  bool ret = true;
+
+  // Low level PE_13 - ERST ethernet PHY
+  set_pin_as_output(GPIOE, GPIO_Pin_13);
+  GPIO_ResetBits(GPIOE, GPIO_Pin_13);
+
+  for (int i = 0; i < PAIR_PINS_SIZE; i++)
+  {
+    set_pin_as_output(pins[i].first_port, pins[i].first_pin);
+    set_pin_as_input(pins[i].second_port, pins[i].second_pin);
+
+    GPIO_SetBits(pins[i].first_port, pins[i].first_pin);
+    vTaskDelay(10);
+
+    res_1 = GPIO_ReadInputDataBit(pins[i].second_port, pins[i].second_pin);
+
+    GPIO_ResetBits(pins[i].first_port, pins[i].first_pin);
+    vTaskDelay(10);
+
+    res_2 = GPIO_ReadInputDataBit(pins[i].second_port, pins[i].second_pin);
+
+    if (res_1 != res_2) {
+      pair_pin_resut[i] = 1;
+      ret = false;
+    }
+    else 
+      pair_pin_resut[i] = 0;
+
+    set_pin_as_input(pins[i].first_port, pins[i].first_pin);
+  }
+
+  test_pin_print_result(pins, pair_pin_resut);
+
+  return ret;
+}
+
+//
+static void set_pin_as_output(GPIO_TypeDef *port, uint8_t pin)
+{
+  GPIO_InitTypeDef GPIO_InitStructure = {0};
+
+  GPIO_InitStructure.GPIO_Pin = pin;
+  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+  GPIO_Init(port, &GPIO_InitStructure);
+}
+
+//
+static void set_pin_as_input(GPIO_TypeDef *port, uint8_t pin)
+{
+  GPIO_InitTypeDef GPIO_InitStructure = {0};
+
+  GPIO_InitStructure.GPIO_Pin = pin;
+  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
+  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
+  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+  GPIO_Init(port, &GPIO_InitStructure);
+}
+
+//
+static void test_pin_print_result(pair_pin_t *pins, uint8_t *res)
+{
+  for (int i = 0; i < PAIR_PINS_SIZE; i++) {
+    if (res[i] != 0) {
+      printf("Short circuit between pins:\r\n");
+      printf("\t%u %u\r\n", pins[i].first_pin_num, pins[i].second_pin_num);
+    }
+  }
+  printf("\r\n"); 
+}
+
 /********************************* (C) РОТЕК **********************************/

+ 16 - 0
service_hw/Commands/bt_6701_commands.h

@@ -15,11 +15,27 @@
 #define __BT_6701_COMMANDS_H
 
 
+typedef struct
+{
+  GPIO_TypeDef  *first_port;
+  uint16_t      first_pin;
+  uint8_t       first_pin_num;
+
+  GPIO_TypeDef  *second_port;
+  uint16_t      second_pin;
+  uint8_t       second_pin_num;
+
+} pair_pin_t;
+
+
 /**
   * @brief
   */
 void Test_U232(void);
 
+//
+void Test_Pins(void);
+
 #endif /* #ifndef __BT_6701_COMMANDS_H */
 
 /****************************** (C) LiteMesh ***************** end of file ****/

+ 4 - 1
service_hw/Commands/commands_api.c

@@ -181,7 +181,10 @@ void vTestCommands(void *params)
                 Test_Serno();
             break;
             
-            
+            case TEST_PIN :
+              Test_Pins();
+            break;
+
             default :
             break;
         }

+ 1 - 0
service_hw/Commands/commands_api.h

@@ -31,6 +31,7 @@ typedef enum
     TEST_SPIFLASH,
     TEST_ETHERNET,
     TEST_SERNO,
+    TEST_PIN,
 
 } TEST_t;
 

+ 116 - 107
service_hw/Console/port_microrl.c

@@ -86,6 +86,8 @@
 #define _SCMD_PB  "port_b"
 #define _SCMD_PD  "port_d"
 
+#define _CMD_PIN          "PIN"
+
 #define _NUM_OF_CMD 
 #define _NUM_OF_SETCLEAR_SCMD 2
 
@@ -138,7 +140,9 @@ char * keyworld [] = {
   _CMD_RST,
 
   _CMD_SPIFLASH,
-  _CMD_U232
+  _CMD_U232,
+
+  _CMD_PIN,
 };
 
 // 'set/clear' command argements
@@ -198,7 +202,7 @@ void MICRORL_GetChar(uint8_t ch)
 // do what you want here, but don't write to argv!!! read only!!
 int execute (int argc, const char * const * argv)
 {
-	int i = 0;
+  int i = 0;
 	uint16_t len = 0;
 	
 	// just iterate through argv word and compare it with your commands
@@ -207,145 +211,150 @@ int execute (int argc, const char * const * argv)
 	  memset(param, 0, PARAM_LEN);  
 	  
 	  if (strcmp (argv[i], _CMD_HELP) == 0) 
-      {
- 		print ("microrl library v");
-		print (MICRORL_LIB_VER);
-		print ("\n\r");
-		print_help ();        // print help
+    {
+ 		  print ("microrl library v");
+		  print (MICRORL_LIB_VER);
+		  print ("\n\r");
+		  print_help ();        // print help
 	  } 
-      else if (strcmp (argv[i], _CMD_CLEAR) == 0) 
-      {
-		print ("\033[2J");    // ESC seq for clear entire screen
-		print ("\033[H");     // ESC seq for move cursor at left-top corner
+    else if (strcmp (argv[i], _CMD_CLEAR) == 0) 
+    {
+		  print ("\033[2J");    // ESC seq for clear entire screen
+		  print ("\033[H");     // ESC seq for move cursor at left-top corner
 	  }  
 	  /* Тестовая команда */
-      else if (strcmp (argv[i], _CMD_LED) == 0) 
-      {
-		//testLed = true;
-		// TODO Убрать затычку
-		printf("STATUS T1OK\r");
-		return 0;
-      } 
+    else if (strcmp (argv[i], _CMD_LED) == 0) 
+    {
+		  //testLed = true;
+		  // TODO Убрать затычку
+		  printf("STATUS T1OK\r");
+		  return 0;
+    } 
 	  /* Тест Ethernet */
 	  else if (strcmp (argv[i], _CMD_ETH) == 0) 
-      {
-        COM_SetMAC();
-		//testEthernet = true;
-        TEST_SetTest(TEST_ETHERNET);
-        print ("\n\r");
-        return 0;
-      }
+    {
+      COM_SetMAC();
+		  //testEthernet = true;
+      TEST_SetTest(TEST_ETHERNET);
+      print ("\n\r");
+      return 0;
+    }
 	  /* Тест кнопки SET */
 	  else if (strcmp (argv[i], _CMD_SET) == 0) 
-      {
-		//testSet = true;
-		TEST_SetTest(TEST_SET);
-		print ("\n\r");
-		return 0;
-      }
+    {
+		  //testSet = true;
+		  TEST_SetTest(TEST_SET);
+		  print ("\n\r");
+		  return 0;
+    }
 	  /* Тест кнопки DEF */
 	  else if (strcmp (argv[i], _CMD_DEF) == 0) 
-      {
-		//testDef = true;
-        TEST_SetTest(TEST_DEF);
-		print ("\n\r");
-		return 0;
-      }
+    {
+		  //testDef = true;
+      TEST_SetTest(TEST_DEF);
+		  print ("\n\r");
+		  return 0;
+    }
 	  /* Тест RTC */
 	  else if (strcmp (argv[i], _CMD_RTC) == 0) 
+    {
+		  if (++i < argc)
       {
-		if (++i < argc)
-        {
-          len = strlen(argv[i]);
-          strncpy(param, argv[i], len);
-		  SNTP_SetServerAddr(param);
-		  TEST_SetTest(TEST_RTC);
-		 // testRtc = true;
-          print ("\n\r");
-          return 0;
-        }
-		print ("\n\r");
+        len = strlen(argv[i]);
+        strncpy(param, argv[i], len);
+		    SNTP_SetServerAddr(param);
+		    TEST_SetTest(TEST_RTC);
+		    // testRtc = true;
+        print ("\n\r");
+        return 0;
       }
+		  print ("\n\r");
+    }
 	  /* Установка SERNO */
 	  else if (strcmp (argv[i], _CMD_SERNO) == 0) 
+    {
+		  if (++i < argc)
       {
-		if (++i < argc)
-        {
-          len = strlen(argv[i]);
-          strncpy(param, argv[i], len);
-		  SETTINGS_SetSerno(param);
-		  //testSerno = true;
-          TEST_SetTest(TEST_SERNO);
-          print ("\n\r");
-          return 0;
-        }
-		print ("\n\r");
+        len = strlen(argv[i]);
+        strncpy(param, argv[i], len);
+		    SETTINGS_SetSerno(param);
+		    //testSerno = true;
+        TEST_SetTest(TEST_SERNO);
+        print ("\n\r");
+        return 0;
       }
+		  print ("\n\r");
+    }
 	  
-      /* -------------------------------------------------------------------- */
-      /*                        Тесты для SmartUPS                            */
-      
-      /* Тест сухих контактов */
+    /* -------------------------------------------------------------------- */
+    /*                        Тесты для SmartUPS                            */
+    
+    /* Тест сухих контактов */
 	  else if (strcmp (argv[i], _CMD_DRY) == 0) 
-      {
-		//testSet = true;
-        TEST_SetTest(TEST_DRY);
-		print ("\n\r");
-		return 0;
-      }
+    {
+		  //testSet = true;
+      TEST_SetTest(TEST_DRY);
+		  print ("\n\r");
+		  return 0;
+    }
       
-      /* Тест дополнительных пинов RS232 */
+    /* Тест дополнительных пинов RS232 */
 	  else if (strcmp (argv[i], _CMD_U232) == 0)
-      {
-		//testSet = true;
-        TEST_SetTest(TEST_U232);
-		print ("\n\r");
-		return 0;
-      }
+    {
+		  //testSet = true;
+      TEST_SetTest(TEST_U232);
+		  print ("\n\r");
+		  return 0;
+    }
 
 	  /* Тест spi flash */
 	  else if (strcmp (argv[i], _CMD_SPIFLASH) == 0)
-	   {
-		//testSet = true;
-		 TEST_SetTest(TEST_SPIFLASH);
-		print ("\n\r");
-		return 0;
-	   }
+	  {
+		  //testSet = true;
+		  TEST_SetTest(TEST_SPIFLASH);
+		  print ("\n\r");
+		  return 0;
+	  }
 #ifdef DALLAS_SENSOR_ENABLE
-     	/* Тест линии OW */
-      else if (strcmp (argv[i], _CMD_ONEWIRE) == 0)
-      {
-        TEST_SetTest(TEST_OW);
-        print ("\n\r");
-        return 0;
-      }
+    /* Тест линии OW */
+    else if (strcmp (argv[i], _CMD_ONEWIRE) == 0)
+    {
+      TEST_SetTest(TEST_OW);
+      print ("\n\r");
+      return 0;
+    }
 #endif
 	  /* -------------------------------------------------------------------- */
 	  /*                          Тесты этапа Т2                              */
 	  /* Статус тестера */
 	  else if (strcmp (argv[i], _CMD_STATUS) == 0) 
-      {
-		//printf("STATUS %s\r", sSettings.sFlags.testState);
-        printf("STATUS %s\r", SETTINGS_GetTestState());
-		return 0;
-      }
+    {
+		  //printf("STATUS %s\r", sSettings.sFlags.testState);
+      printf("STATUS %s\r", SETTINGS_GetTestState());
+		  return 0;
+    }
 	  /* T2READY */
 	  else if (strcmp (argv[i], _CMD_T2READY) == 0) 
-      {
-		testT2Ready = true;		
-		return 0;
-      }
+    {
+		  testT2Ready = true;		
+		  return 0;
+    }
 	  
 	  /* Перезагрузить контроллер */
-      else if (strcmp (argv[i], _CMD_RST) == 0) 
-      {
-        NVIC_SystemReset();
-      }  
-      else 
-      {
-		print ("command: '");
-		print ((char*)argv[i]);
-		print ("' Not found.\n\r");
+    else if (strcmp (argv[i], _CMD_RST) == 0) 
+    {
+      NVIC_SystemReset();
+    }  
+
+    else if (strcmp(argv[i], _CMD_PIN) == 0)
+    {
+      TEST_SetTest(TEST_PIN);
+    }
+    else 
+    {
+  		print ("command: '");
+		  print ((char*)argv[i]);
+		  print ("' Not found.\n\r");
 	  }
 	  i++;
 	}