/****************************************************************************** * file Core/Src/dau.c * author YuLiang * version 1.0.0 * date 15-Aug-2024 * brief This file provides all the DAU related operation functions. ****************************************************************************** * Attention * *

© COPYRIGHT(c) 2024 LandPower

* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of WTOE nor the names of its contributors may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #include "stdio.h" #include "stdlib.h" #include "string.h" #include "time.h" #include "math.h" #include "spi.h" #include "usart.h" #include "common.h" #include "dev_config.h" #include "flash_if.h" #include "flash_log.h" #include "ADC_collect.h" #include "dau.h" #include "wireless.h" /* Private define ------------------------------------------------------------*/ #define DAU_WAVE_WAIT_MAX 3 // DAU 波形等待次数 /* 全局状态寄存器地址 -------------------------------- */ #define DAU_REG_ADDR_GSCR 0x0000 // 全局状态寄存器 - 软件特征寄存器 #define DAU_REG_ADDR_GSVR 0x0001 // 全局状态寄存器 - 软件版本寄存器 #define DAU_REG_ADDR_GSR 0x0002 // 全局状态寄存器 - 状态寄存器 #define DAU_REG_ADDR_GFTR 0x0003 // 全局状态寄存器 - 故障触发录波状态寄存器 #define DAU_REG_ADDR_GFTUR 0x0004 // 全局状态寄存器 - 故障触发 UTC 时间点寄存器 #define DAU_REG_ADDR_GFTNR 0x0006 // 全局状态寄存器 - 故障触发 ns 时间点寄存器 #define DAU_REG_ADDR_GRTR 0x0008 // 全局状态寄存器 - 寄存器触发录波状态寄存器 #define DAU_REG_ADDR_GUR 0x000a // 全局状态寄存器 - UTC 寄存器 #define DAU_REG_ADDR_GNR 0x000c // 全局状态寄存器 - ns 寄存器 /* 全局状态寄存器 - 状态寄存器 bit mask */ #define DAU_GSR_FLASH_Pos (2) // spi flash 空闲状态 #define DAU_GSR_FLASH_Msk (0x1 << DAU_GSR_FLASH_Pos) /*!< 0x0004 */ /* 全局状态寄存器 - 故障触发录波状态寄存器 bit mask */ #define DAU_GFTR_POWER_WAVE_Pos (3) // 故障触发工频电流波形状态 #define DAU_GFTR_POWER_WAVE_Msk (0x1 << DAU_GFTR_POWER_WAVE_Pos) /*!< 0x0008 */ #define DAU_GFTR_DEFECT_WAVE_Pos (2) // 故障触发缺陷电流波形状态 #define DAU_GFTR_DEFECT_WAVE_Msk (0x1 << DAU_GFTR_DEFECT_WAVE_Pos) /*!< 0x0004 */ #define DAU_GFTR_FAULT_WAVE_Pos (1) // 故障电流波形状态 #define DAU_GFTR_FAULT_WAVE_Msk (0x1 << DAU_GFTR_FAULT_WAVE_Pos) /*!< 0x0002 */ #define DAU_GFTR_FAULT_Pos (0) // 故障触发录波完成状态 #define DAU_GFTR_FAULT_Msk (0x1 << DAU_GFTR_FAULT_Pos) /*!< 0x0001 */ /* 全局状态寄存器 - 寄存器触发录波状态寄存器 bit mask */ #define DAU_GRTR_POWER_WAVE_Pos (3) // 寄存器触发工频电流波形状态 #define DAU_GRTR_POWER_WAVE_Msk (0x1 << DAU_GRTR_POWER_WAVE_Pos) /*!< 0x0008 */ #define DAU_GRTR_DEFECT_WAVE_Pos (2) // 寄存器触发缺陷电流波形状态 #define DAU_GRTR_DEFECT_WAVE_Msk (0x1 << DAU_GRTR_DEFECT_WAVE_Pos) /*!< 0x0004 */ #define DAU_GRTR_COMPLETE_Pos (0) // 寄存器触发录波完成状态 #define DAU_GRTR_COMPLETE_Msk (0x1 << DAU_GRTR_COMPLETE_Pos) /*!< 0x0001 */ /* 全局控制寄存器地址 -------------------------------- */ #define DAU_REG_ADDR_GFWSR 0x0200 // 全局控制寄存器 - Flash 写选择寄存器 #define DAU_REG_ADDR_GSUPR 0x0202 // 全局控制寄存器 - 固件升级页寄存器 #define DAU_REG_ADDR_GCFTR 0x0203 // 全局控制寄存器 - 故障触发录波控制寄存器 #define DAU_REG_ADDR_GCRTR 0x0204 // 全局控制寄存器 - 寄存器触发录波控制寄存器 #define DAU_REG_ADDR_GCUR 0x0205 // 全局控制寄存器 - UTC 配置寄存器 #define DAU_REG_ADDR_GSUDR 0x0e00 // 全局控制寄存器 - 固件升级数据寄存器 /* 全局控制寄存器 - 故障触发录波控制寄存器 bit mask */ #define DAU_GCFTR_PORT_Pos (4) // 故障触发波形端口 #define DAU_GCFTR_PORT_Msk (0x7 << DAU_GCFTR_PORT_Pos) /*!< 0x0070 */ #define DAU_GCFTR_POWER_WAVE_Pos (3) // 故障触发波形端口 #define DAU_GCFTR_POWER_WAVE_Msk (0x1 << DAU_GCFTR_POWER_WAVE_Pos) /*!< 0x0008 */ #define DAU_GCFTR_DEFECT_WAVE_Pos (2) // 故障触发缺陷电流波形读取 #define DAU_GCFTR_DEFECT_WAVE_Msk (0x1 << DAU_GCFTR_DEFECT_WAVE_Pos) /*!< 0x0004 */ #define DAU_GCFTR_FAULT_WAVE_Pos (1) // 故障电流波形读取 #define DAU_GCFTR_FAULT_WAVE_Msk (0x1 << DAU_GCFTR_FAULT_WAVE_Pos) /*!< 0x0002 */ /* 全局控制寄存器 - 寄存器触发录波控制寄存器 bit mask */ #define DAU_GCRTR_PORT_Pos (4) // 寄存器触发波形端口 #define DAU_GCRTR_PORT_Msk (0x7 << DAU_GCRTR_PORT_Pos) /*!< 0x0070 */ #define DAU_GCRTR_POWER_WAVE_Pos (3) // 寄存器触发工频电流波形读取 #define DAU_GCRTR_POWER_WAVE_Msk (0x1 << DAU_GCRTR_POWER_WAVE_Pos) /*!< 0x0008 */ #define DAU_GCRTR_DEFECT_WAVE_Pos (2) // 寄存器触发缺陷电流波形读取 #define DAU_GCRTR_DEFECT_WAVE_Msk (0x1 << DAU_GCRTR_DEFECT_WAVE_Pos) /*!< 0x0004 */ #define DAU_GCRTR_START_WAVE_Pos (0) // 录波控制 #define DAU_GCRTR_START_WAVE_Msk (0x1 << DAU_GCRTR_START_WAVE_Pos) /*!< 0x0001 */ /* 通道状态寄存器地址 -------------------------------- */ #define DAU_REG_ADDR_PMSR 0x0300 // 通道状态寄存器 - 缺陷电流通道周波原始采样值的平均值寄存器 #define DAU_REG_ADDR_PPWR 0x03b0 // 通道状态寄存器 - 通道录波数据寄存器 #define DAU_ID 0x0702 // DAU 软件识别码 /* Private typedef -----------------------------------------------------------*/ /* 波形触发源 */ typedef enum { DAU_SOURCE_FAULT = 0, DAU_SOURCE_REG, DAU_SOURCE_CNT, } DAU_SOURCE_E; /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* DAU 任务参数 */ const osThreadAttr_t dau_attributes = { .name = "DAU", .stack_size = 160 * 4, .priority = (osPriority_t) osPriorityRealtime, }; const osThreadAttr_t dau_gps_attributes = { .name = "GPS", .stack_size = 160 * 4, .priority = (osPriority_t) osPriorityNormal, }; /* DAU 全局结构体 */ dau_ctrl_t dau_ctrl; static struct tm _dau_tm; int8_t _dau_spi_rw; uint16_t _dau_spi_addr; uint16_t _dau_spi_len; /* Private function prototypes -----------------------------------------------*/ /* Internal functions --------------------------------------------------------*/ /* description: DAU 写寄存器报文发送 param: addr -- 寄存器地址 len -- 写长度 return: HAL_xxx */ int32_t _dau_reg_write(uint16_t addr, uint16_t len) { uint8_t *pkt_tx = dau_ctrl.buf_dau_tx; uint8_t *pkt_rx = dau_ctrl.buf_dau_rx; uint32_t notify_value = 0xff; int32_t rv = 0; /* 发送数据. */ /* 组装报文, 报文头是大端模式 */ pkt_tx[0] = (addr >> 8) & 0x7f; // 最高位为 0 表示读 pkt_tx[1] = addr & 0x00ff; len +=2; /* 调试打印报文 */ DBG(DBG_M_DAU_TXRX, "DAU write send(%d):\r\n", len); if (dbg_stat_get(DBG_M_DAU_TXRX)) { buf_print(pkt_tx, len > 32 ? 32 : len); } /* 发送数据. */ DAU_CS_ENABLE(); rv = HAL_SPI_TransmitReceive_DMA(dau_ctrl.spi, pkt_tx, pkt_rx, len); if (rv != HAL_OK) { DBG(DBG_M_DAU, "DAU spi read err %d\r\n", rv); return rv; } /* 等待收包完成. */ notify_value = ulTaskNotifyTake(pdTRUE, 1000); if (0 == notify_value) { /* 收包超时 */ DAU_CS_DISABLE(); DBG(DBG_M_DAU, "DAU spi read timeout\r\n"); return HAL_TIMEOUT; } return HAL_OK; } /* description: DAU 读取寄存器报文发送 param: addr -- 寄存器地址 len -- 读取长度 return: HAL_xxx */ int32_t _dau_reg_read(uint16_t addr, uint16_t len) { uint8_t *pkt_tx = dau_ctrl.buf_dau_tx; uint8_t *pkt_rx = dau_ctrl.buf_dau_rx; uint32_t notify_value = 0xff; int32_t rv = 0; /* 发送数据. */ /* 组装报文, 报文头是大端模式 */ pkt_tx[0] = (addr >> 8) | 0x80; // 最高位为 1 表示读 pkt_tx[1] = addr & 0x00ff; /* 调试打印报文 */ DBG(DBG_M_DAU_TXRX, "DAU read send:\r\n"); if (dbg_stat_get(DBG_M_DAU_TXRX)) { buf_print(pkt_tx, 2); } /* 发送数据. */ DAU_CS_ENABLE(); rv = HAL_SPI_TransmitReceive_DMA(dau_ctrl.spi, pkt_tx, pkt_rx, len + 2); if (rv != HAL_OK) { DAU_CS_DISABLE(); DBG(DBG_M_DAU, "DAU spi read err %d\r\n", rv); return rv; } /* 等待收包完成. */ notify_value = ulTaskNotifyTake(pdTRUE, 1000); if (0 == notify_value) { /* 收包超时 */ DBG(DBG_M_DAU, "DAU spi read timeout\r\n"); return HAL_TIMEOUT; } /* 调试打印报文. */ DBG(DBG_M_DAU_TXRX, "DAU read recv(%d):\r\n", len); if (dbg_stat_get(DBG_M_DAU_TXRX)) { buf_print(pkt_rx + 2, len > 32 ? 32 : len); vty_print("\r\n"); } return HAL_OK; } /* description: DAU 读取全局状态寄存器报文发送 param: return: HAL_xxx */ int32_t _dau_reg_read_global_state(void) { dau_reg_global_t *p = (dau_reg_global_t*)(dau_ctrl.buf_dau_rx + 2); int32_t rv = HAL_ERROR; /* 读取全局寄存器 */ rv = _dau_reg_read(DAU_REG_ADDR_GSCR, sizeof(dau_reg_global_t)); if (rv != HAL_OK) { return rv; } if (p->GSCR != DAU_ID) { DBG(DBG_M_DAU, "DAU read 0x0 data %x err\r\n", p->GSCR); return HAL_ERROR; } memcpy(&dau_ctrl.reg_global, p, sizeof(dau_reg_global_t)); return rv; } /* description: DAU 读取端口状态寄存器报文发送 param: return: HAL_xxx */ int32_t _dau_reg_read_port_state(void) { int32_t rv = HAL_ERROR; /* 读取全局寄存器 */ rv = _dau_reg_read(DAU_REG_ADDR_PMSR, sizeof(dau_port_state_reg_t)); if (rv != HAL_OK) { return rv; } memcpy(&dau_ctrl.reg_port_state, dau_ctrl.buf_dau_rx + 2, sizeof(dau_port_state_reg_t)); return rv; } /* description: DAU 历史数据保存 param: return: */ static void _dau_data_save(void) { uint8_t i = 0; /* 装填数据. */ fd_data.temperature = ADC_ctrl.ADCi_temp; fd_data.vbat = ADC_ctrl.ADCi_vbat; fd_data.vin = ADC_ctrl.ADCi_vin; fd_data.vsc = ADC_ctrl.ADCi_vsc; for(i = 0; i < DAU_PORT_DEFECT_CNT; i++) { fd_data.defect[i] = dau_ctrl.reg_port_state.MAX[i]; } for(i = 0; i < DAU_PORT_DEFECT_CNT; i++) { fd_data.elec[i] = dau_ctrl.reg_elec[i]; } fd_data.col_flag = dau_ctrl.col_flag; fd_write(&fd_data); } /* description: DAU UTC 对时处理 param: return: */ int32_t _dau_update(void) { uint8_t *data = (uint8_t*)&dau_ctrl.buf_dau_tx[2]; uint16_t *reg = (uint16_t*)&dau_ctrl.buf_dau_tx[2]; uint16_t cnt = 0; uint16_t page_cnt = 0; //uint32_t app_len = wl_ctrl.app_len; uint32_t app_len = 2097378; uint32_t len = 0; uint32_t addr = TFTP_APP_ADDRESS; int32_t rv = HAL_ERROR; /* 初始化状态. */ dau_ctrl.update_rt = DAU_UPD_NONE; /* 发送升级数据 */ while(1) { /* 组装数据报文, 报文头是大端模式 DAU_REG_ADDR_GSUDR */ len = app_len < 1024 ? app_len : 1024; if (0 == len) { /* 无数据, 直接结束 */ break; } /* 读取固件数据 */ E_RETURN(spi_flash_read(addr, data, 1024)); /* 先发送数据报文, 0x0e00 */ E_RETURN(_dau_reg_write(DAU_REG_ADDR_GSUDR, 1024)); /* 再发送页报文, 0x0202 */ *reg = page_cnt; E_RETURN(_dau_reg_write(DAU_REG_ADDR_GSUPR, 2)); /* 向 0x0200 写 1, 表示固件升级 */ *reg = 1; E_RETURN(_dau_reg_write(DAU_REG_ADDR_GFWSR, sizeof(uint16_t))); /* 等待 spi flash 完成, 0x0002 bit2 为高 */ cnt = 0; while(1) { osDelay(500); cnt++; if (cnt > 3) { DBG(DBG_M_DAU, "DAU update timeout\r\n"); return HAL_TIMEOUT; } /* 读取 spi flash 状态 DAU_REG_ADDR_GSR */ E_RETURN(_dau_reg_read_global_state()); /* 0 - 空闲, 1 - 忙 */ if (!((dau_ctrl.reg_global.GSR & DAU_GSR_FLASH_Msk) >> DAU_GSR_FLASH_Pos)) { break; } } /* 结束直接返回 */ if (len < 1024) { break; } /* 更新参数 */ app_len -= len; page_cnt++; addr += 1024; } /* 向 DAU_REG_ADDR_GFWSR 写 0, 回复标志 */ *reg = 0; E_RETURN(_dau_reg_write(DAU_REG_ADDR_GFWSR, sizeof(uint16_t))); return HAL_OK; } /* description: DAU UTC 对时处理 param: return: */ void _dau_utc(void) { uint32_t *utc = (uint32_t*)&dau_ctrl.buf_dau_tx[2]; /* dau 主循环大概 250ms 运行一次, 在第 3 次循环 (500 ~ 750ms) 对时, 此时 GPS 对时一定是可用的 */ if (50000000 < dau_ctrl.reg_global.GNR && dau_ctrl.reg_global.GNR <= 75000000 && dau_ctrl.is_utc_valid && dau_ctrl.reg_global.GUR != dau_ctrl.utc) { *utc = dau_ctrl.utc; _dau_reg_write(DAU_REG_ADDR_GCUR, sizeof(uint32_t)); vty_print("Change\r\n"); vty_print("%d %d %d %d\r\n", dau_ctrl.reg_global.GUR, dau_ctrl.reg_global.GNR, dau_ctrl.is_utc_valid, dau_ctrl.utc); } } /* description: 寄存器触发波形采集开始 param: return: HAL_xxx */ int32_t _dau_wave_col_start(void) { uint16_t *reg = (uint16_t*)&dau_ctrl.buf_dau_tx[2]; uint8_t i = 0; int32_t rv = HAL_ERROR; /* 请求录波 */ *reg = DAU_GCRTR_START_WAVE_Msk; E_RETURN(_dau_reg_write(DAU_REG_ADDR_GCRTR, sizeof(uint16_t))); /* 等待录波完成 */ while(1) { if (i >= DAU_WAVE_WAIT_MAX) { DBG(DBG_M_DAU, "DAU wave err\r\n", rv); return HAL_TIMEOUT; } osDelay(3000); E_RETURN(_dau_reg_read_global_state()); if ((dau_ctrl.reg_global.GRTR & DAU_GRTR_COMPLETE_Msk) >> DAU_GRTR_COMPLETE_Pos) { break; } i++; vty_print("#D5 %d\r\n", i); } return rv; } /* description: 故障波形采集 param: return: HAL_xxx */ int32_t _dau_wave_col_fault(void) { #if 0 uint16_t *reg = (uint16_t*)&dau_ctrl.buf_dau_tx[2]; uint8_t i = 0; uint8_t j = 0; uint32_t addr = 0; /* 读取触发电流值 */ E_RETURN(_dau_reg_read_port_state()); /* 数据地址应该是被擦除过的地址 (当前地址向前偏移 128k). */ addr = dau_ctrl.addr_fault; /* 读取故障数据 */ for(i = 0; i < DAU_PORT_FAULT_CNT; i++) { dau_ctrl.fault_trig[i] = dau_ctrl.reg_port_state.FAULT[i]; /* 请求读取故障波形 */ *reg = DAU_GCFTR_FAULT_WAVE_Msk | (i << DAU_GCFTR_PORT_Pos); E_RETURN(_dau_reg_write(DAU_REG_ADDR_GCFTR, sizeof(uint16_t))); /* 等待 DAU 准备故障数据 */ j = 0; while(1) { if (j >= DAU_WAVE_WAIT_MAX) { DBG(DBG_M_DAU, "DAU fault wave err\r\n"); return HAL_TIMEOUT; } osDelay(10); E_RETURN(_dau_reg_read_global_state()); if ((dau_ctrl.reg_global.GFTR & DAU_GFTR_FAULT_WAVE_Msk) >> DAU_GFTR_FAULT_WAVE_Pos) { break; } j++; } for(j = 0; j < DAU_PKT_FAULT_CNT; j++) { E_RETURN(_dau_reg_read(DAU_REG_ADDR_PFWR + i, DAU_PKT_FAULT_BYTE_CNT)); E_RETURN(spi_flash_write(addr, &dau_ctrl.buf_dau_rx[2], DAU_PKT_FAULT_BYTE_CNT)); addr += DAU_PKT_FAULT_BYTE_CNT; } } return HAL_OK; #endif uint8_t i = 0; uint8_t j = 0; uint32_t addr = 0; int32_t rv = HAL_ERROR; /* 读取故障数据 */ addr = dau_ctrl.addr_fault; for(i = 0; i < DAU_PORT_FAULT_CNT; i++) { dau_ctrl.fault_trig[i] = 100 + i; memset(&dau_ctrl.buf_dau_rx[2], i, DAU_PKT_FAULT_BYTE_CNT); for(j = 0; j < DAU_PKT_FAULT_CNT; j++) { E_RETURN(spi_flash_write(addr, &dau_ctrl.buf_dau_rx[2], DAU_PKT_FAULT_BYTE_CNT)); addr += DAU_PKT_FAULT_BYTE_CNT; } } vty_print("#D2 %x\r\n", addr); return rv; } /* description: 缺陷波形采集 param: return: HAL_xxx */ int32_t _dau_wave_col_defect(void) { uint16_t *reg = (uint16_t*)&dau_ctrl.buf_dau_tx[2]; uint8_t i = 0; uint8_t j = 0; uint8_t is_exceed = FALSE; uint32_t addr = 0; int32_t rv = HAL_ERROR; /* 比较缺陷波形是否超过阈值 */ E_RETURN(_dau_reg_read_port_state()); for(i = 0; i < DAU_PORT_DEFECT_CNT; i++) { dau_ctrl.reg_defect_max[i] = dau_ctrl.reg_port_state.MAX[i]; if (dau_ctrl.reg_port_state.MAX[i] > dev_config.wave_threshold) { is_exceed = TRUE; } } /* 没有超过阈值并没有强制录波直接返回 */ //if (!is_exceed && !IS_MONITOR_BIT_SET(dau_ctrl.col_flag, DAU_COL_FLAG_WAVE_FORCE)) //{ // MONITOR_BITMAP_RESET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_DEFECT); // return HAL_OK; //} /* 擦除 flash */ addr = dau_ctrl.addr_reg; vty_print("#D3 %x\r\n", addr); for(i = 0; i < 2; i++) { E_RETURN(spi_flash_erase(addr, SPI_CMD_BLOCK64_ERASE)); addr += SPI_FLASH_BLOCK64_SIZE; } /* 数据地址应该是被擦除过的地址 (当前地址向前偏移 128k). */ addr = dau_ctrl.addr_reg; /* 读取缺陷数据 */ for(i = 0; i < DAU_PORT_DEFECT_CNT; i++) { /* 请求读取缺陷波形 */ *reg = DAU_GCRTR_DEFECT_WAVE_Msk | (i << DAU_GCRTR_PORT_Pos); E_RETURN(_dau_reg_write(DAU_REG_ADDR_GCRTR, sizeof(uint16_t))); /* 等待 DAU 准备缺陷数据 */ j = 0; while(1) { if (j >= DAU_WAVE_WAIT_MAX) { DBG(DBG_M_DAU, "DAU defect wave err\r\n", rv); return HAL_TIMEOUT; } osDelay(5); E_RETURN(_dau_reg_read_global_state()); if ((dau_ctrl.reg_global.GRTR & DAU_GRTR_DEFECT_WAVE_Msk) >> DAU_GRTR_DEFECT_WAVE_Pos) { break; } j++; vty_print("#D6 %d\r\n", j); } for(j = 0; j < DAU_PKT_DEFECT_CNT; j++) { vty_print("%d %d\r\n", i, j); E_RETURN(_dau_reg_read(DAU_REG_ADDR_PPWR, DAU_PKT_DEFECT_BYTE_CNT)); osDelay(200); E_RETURN(spi_flash_write(addr, &dau_ctrl.buf_dau_rx[2], DAU_PKT_DEFECT_BYTE_CNT)); addr += DAU_PKT_DEFECT_BYTE_CNT; } vty_print("DE%d\r\n", i); } vty_print("#D4 %x\r\n", addr); MONITOR_BITMAP_SET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_DEFECT); return rv; #if 0 uint8_t i = 0; uint8_t j = 0; uint8_t is_exceed = FALSE; uint32_t addr = 0; int32_t rv = HAL_ERROR; /* 比较缺陷波形是否超过阈值 */ //E_RETURN(_dau_reg_read_port_state()); for(i = 0; i < DAU_PORT_DEFECT_CNT; i++) { dau_ctrl.reg_defect_max[i] = 100 +i; if (dau_ctrl.reg_defect_max[i] > dev_config.wave_threshold) { is_exceed = TRUE; } } /* 没有超过阈值并没有强制录波直接返回 */ if (!is_exceed && !IS_MONITOR_BIT_SET(dau_ctrl.col_flag, DAU_COL_FLAG_WAVE_FORCE)) { MONITOR_BITMAP_RESET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_DEFECT); return HAL_OK; } /* 擦除 flash */ addr = dau_ctrl.addr_reg; vty_print("#D3 %x\r\n", addr); for(i = 0; i < 2; i++) { E_RETURN(spi_flash_erase(addr, SPI_CMD_BLOCK64_ERASE)); addr += SPI_FLASH_BLOCK64_SIZE; } /* 数据地址应该是被擦除过的地址 (当前地址向前偏移 128k). */ addr = dau_ctrl.addr_reg; /* 读取缺陷数据 */ for(i = 0; i < DAU_PORT_DEFECT_CNT; i++) { memset(&dau_ctrl.buf_dau_rx[2], i, DAU_PKT_FAULT_BYTE_CNT); for(j = 0; j < DAU_PKT_DEFECT_CNT; j++) { E_RETURN(spi_flash_write(addr, &dau_ctrl.buf_dau_rx[2], DAU_PKT_DEFECT_BYTE_CNT)); addr += DAU_PKT_DEFECT_BYTE_CNT; } } vty_print("#D4 %x\r\n", addr); MONITOR_BITMAP_SET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_DEFECT); return rv; #endif } /* description: 工频波形采集 param: flag - 采集来源见 DAU_COL_FLAG_E return: HAL_xxx */ int32_t _dau_wave_col_power(DAU_SOURCE_E source) { uint16_t *reg = (uint16_t*)&dau_ctrl.buf_dau_tx[2]; int16_t *power = NULL; uint8_t i = 0; uint8_t j = 0; int32_t rv = HAL_ERROR; /* 读取工频数据 */ for(i = 0; i < DAU_PORT_POWER_CNT; i++) { /* 请求读取工频波形 */ if (DAU_SOURCE_FAULT == source) { *reg = DAU_GCFTR_POWER_WAVE_Msk | (i << DAU_GCFTR_PORT_Pos); E_RETURN(_dau_reg_write(DAU_REG_ADDR_GCFTR, sizeof(uint16_t))); } else { *reg = DAU_GCRTR_POWER_WAVE_Msk | (i << DAU_GCRTR_PORT_Pos); E_RETURN(_dau_reg_write(DAU_REG_ADDR_GCRTR, sizeof(uint16_t))); } /* 等待 DAU 准备工频数据 */ j = 0; while(1) { if (j >= DAU_WAVE_WAIT_MAX) { DBG(DBG_M_DAU, "DAU power wave err\r\n"); return HAL_TIMEOUT; } osDelay(5); E_RETURN(_dau_reg_read_global_state()); if (DAU_SOURCE_FAULT == source) { if ((dau_ctrl.reg_global.GFTR & DAU_GFTR_POWER_WAVE_Msk) >> DAU_GFTR_POWER_WAVE_Pos) { break; } } else { if ((dau_ctrl.reg_global.GRTR & DAU_GRTR_POWER_WAVE_Msk) >> DAU_GRTR_POWER_WAVE_Pos) { break; } } j++; vty_print("#D7 %d\r\n", j); } /* 选择存储位置, 读取数据 */ power = (DAU_SOURCE_FAULT == source) ? dau_ctrl.fault_power[i] : dau_ctrl.reg_power[i]; for(j = 0; j < DAU_PKT_POWER_CNT; j++) { E_RETURN(_dau_reg_read(DAU_REG_ADDR_PPWR, DAU_PKT_POWER_BYTE_CNT)); osDelay(200); memcpy(power, &dau_ctrl.buf_dau_rx[2], DAU_PKT_POWER_BYTE_CNT); power += DAU_PKT_POWER_BYTE_CNT >> 1; } vty_print("PO%d\r\n", i); } return HAL_OK; #if 0 int16_t *power = NULL; uint8_t i = 0; uint8_t j = 0; /* 读取工频数据 */ for(i = 0; i < DAU_PORT_POWER_CNT; i++) { /* 选择存储位置, 读取数据 */ power = (DAU_SOURCE_FAULT == source) ? dau_ctrl.fault_power[i] : dau_ctrl.reg_power[i]; memset(&dau_ctrl.buf_dau_rx[2], i, DAU_PKT_POWER_BYTE_CNT); for(j = 0; j < DAU_PKT_POWER_CNT; j++) { memcpy(power, &dau_ctrl.buf_dau_rx[2], DAU_PKT_POWER_BYTE_CNT); power += DAU_PKT_POWER_BYTE_CNT >> 1; } } return HAL_OK; #endif } /* description: DAU 工频电流计算 param: return: */ void _dau_power_calculate(DAU_SOURCE_E source) { int16_t (*val)[DAU_POWER_DATE_LEN] = (DAU_SOURCE_FAULT == source) ? dau_ctrl.fault_power : dau_ctrl.reg_power; uint32_t *power = (DAU_SOURCE_FAULT == source) ? dau_ctrl.fault_elec : dau_ctrl.reg_elec; uint8_t ch = 0; uint8_t adj = 0; uint16_t i = 0; uint64_t square_sum = 0; int32_t mean_sum = 0; float temp = 0; /* 遍历通道, 计算有效值 */ for(ch = 0; ch < DAU_PORT_POWER_CNT; ch++) { square_sum = 0; mean_sum = 0; /* 遍历通道所有值, 求和, 并计算出最大值和最小值. */ for(i = 0; i < DAU_POWER_DATE_LEN; i++) { square_sum += val[ch][i] * val[ch][i]; mean_sum += val[ch][i]; } /* 根据数据查找数据落在哪个分段点上. */ temp = (double)sqrt(square_sum / DAU_POWER_DATE_LEN) - abs(mean_sum / DAU_POWER_DATE_LEN); for(adj = 0; adj < DAU_POWER_ADJ_CNT - 1; adj++) { if (temp <= dev_config.ADC_base[ch][adj]) { break; } } /* 根据分段点计算有效值. */ if (0 == adj) { power[ch] = (uint32_t)(temp * dev_config.ADC_adj[ch][adj] * dev_config.ADC_ratio[ch] * 1.414/ 32768); } else { power[ch] = (uint32_t)((temp - dev_config.ADC_base[ch][adj - 1]) * dev_config.ADC_adj[ch][adj] * dev_config.ADC_ratio[ch] * 1.414 / 32768 + dev_config.ADC_base_elec[ch][adj - 1]); } } if (DAU_SOURCE_REG == source) { /* 固定前 4 个通道是接地电流, 判断接地电流有没有突变 */ for(ch = 0; ch < DAU_PORT_GROUND_CNT; ch++) { /* 判断工频录波上传阈值 */ if (abs_cal_u(power[ch], fd_data.elec[ch]) >= (uint32_t)dev_config.threshold * 1000) { MONITOR_BITMAP_SET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_POWER); break; } } if (DAU_PORT_GROUND_CNT == ch) { /* 没有超过阈值, 不传输波形 */ MONITOR_BITMAP_RESET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_POWER); } if (IS_MONITOR_BIT_SET(dau_ctrl.col_flag, DAU_COL_FLAG_WAVE_FORCE)) { /* 强制录波, 传输波形 */ MONITOR_BITMAP_SET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_POWER); MONITOR_BITMAP_RESET(dau_ctrl.col_flag, DAU_COL_FLAG_WAVE_FORCE); } } /* 计算工频录波每个点的电流值 */ //if (DAU_SOURCE_FAULT == source // || IS_MONITOR_BIT_SET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_POWER)) //{ // for(ch = 0; ch < DAU_PORT_POWER_CNT; ch++) // { // for(i = 0; i < DAU_POWER_DATE_LEN; i++) // { // val[ch][i] = (int64_t)val[ch][i] * 7257 * dev_config.ADC_ratio[ch] / 3276800; // } // } //} } /* description: 故障触发波形采集 param: return: HAL_xxx */ int32_t _dau_wave_col_trigger_by_fault(void) { #if 0 uint8_t i = 0; uint32_t addr = 0; /* 上次触发没有完成直接退出 */ if (!IS_MONITOR_BIT_SET(dau_ctrl.col_flag, DAU_COL_FLAG_FAULT_CMP)) { return HAL_OK; } /* 没有触发直接退出 */ if (!((dau_ctrl.reg_global.GFTR & DAU_GFTR_FAULT_Msk) >> DAU_GFTR_FAULT_Pos)) { return HAL_OK; } dau_ctrl.fault_utc = dau_ctrl.reg_global.GFTUR; dau_ctrl.fault_ns = dau_ctrl.reg_global.GFTNR; /* 擦除 flash */ addr = dau_ctrl.addr_fault; for(i = 0; i < 2; i++) { E_RETURN(spi_flash_erase(addr, SPI_CMD_BLOCK64_ERASE)); addr += SPI_FLASH_BLOCK64_SIZE; } /* 采集波形 */ E_RETURN(_dau_wave_col_fault()); E_RETURN(_dau_wave_col_power(DAU_SOURCE_FAULT)); _dau_power_calculate(DAU_SOURCE_FAULT); /* 置标志位 */ MONITOR_BITMAP_RESET(dau_ctrl.col_flag, DAU_COL_FLAG_FAULT_CMP); return HAL_OK; #endif static uint8_t temp = FALSE; if (temp) { return HAL_OK; } osDelay(30000); temp = TRUE; uint8_t i = 0; uint32_t addr = 0; int32_t rv = HAL_ERROR; /* 没有触发直接退出 */ dau_ctrl.fault_utc = dau_ctrl.utc; dau_ctrl.fault_ns = 123456789; /* 擦除 flash */ addr = dau_ctrl.addr_fault; vty_print("#D1 %x\r\n", addr); for(i = 0; i < 2; i++) { E_RETURN(spi_flash_erase(addr, SPI_CMD_BLOCK64_ERASE)); addr += SPI_FLASH_BLOCK64_SIZE; } /* 采集波形 */ E_RETURN(_dau_wave_col_fault()); E_RETURN(_dau_wave_col_power(DAU_SOURCE_FAULT)); _dau_power_calculate(DAU_SOURCE_FAULT); /* 置标志位 */ MONITOR_BITMAP_RESET(dau_ctrl.col_flag, DAU_COL_FLAG_FAULT_CMP); return rv; } /* description: 寄存器触发波形采集 param: return: HAL_xxx */ int32_t _dau_wave_col_trigger_by_reg(void) { uint32_t tick = 0; int32_t rv = HAL_ERROR; /* 上次触发没有完成直接退出 */ if (!IS_MONITOR_BIT_SET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_CMP)) { return HAL_OK; } /* 定时开始采集 */ tick = HAL_GetTick(); if ((tick - dau_ctrl.col_time) < (dev_config.collect_interval * 60000) && !IS_MONITOR_BIT_SET(dau_ctrl.col_flag, DAU_COL_FLAG_WAVE_FORCE)) { return HAL_OK; } E_RETURN(_dau_wave_col_start()); //E_RETURN(_dau_wave_col_defect()); E_RETURN(_dau_wave_col_power(DAU_SOURCE_REG)); _dau_power_calculate(DAU_SOURCE_REG); /* 置标志位, 保存数据 */ _dau_data_save(); MONITOR_BITMAP_RESET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_CMP); dau_ctrl.col_time = tick; return rv; } /* description: DAU 初始化 param: return: */ static void _dau_init(void) { char version[DEV_COMPILE_TIME_LEN] = {0}; dau_ctrl.spi = &hspi1; if (st_data.addr_fault >= WARE_FAULT_ADDRESS && st_data.addr_fault < WARE_FAULT_ADDRESS_END && 0 == (st_data.addr_fault & 0x1ffff)) { dau_ctrl.addr_fault = st_data.addr_fault; } else { dau_ctrl.addr_fault = WARE_FAULT_ADDRESS; } vty_print("#D7 %x %x\r\n", st_data.addr_fault, dau_ctrl.addr_fault); if (st_data.addr_reg >= WARE_REG_ADDRESS && st_data.addr_reg < WARE_REG_ADDRESS_END && 0 == (st_data.addr_reg & 0x1ffff)) { dau_ctrl.addr_reg = st_data.addr_reg; } else { dau_ctrl.addr_reg = WARE_REG_ADDRESS; } vty_print("#D8 %x %x\r\n", st_data.addr_reg, dau_ctrl.addr_reg); /* 开启第一次采集前, 默认上传完成 */ dau_ctrl.col_time = 600000; MONITOR_BITMAP_SET(dau_ctrl.col_flag, DAU_COL_FLAG_FAULT_CMP); MONITOR_BITMAP_SET(dau_ctrl.col_flag, DAU_COL_FLAG_REG_CMP); HAL_GPIO_WritePin(DAU_RST_GPIO_Port, DAU_RST_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(POWER_DAU_GPIO_Port, POWER_DAU_Pin, GPIO_PIN_SET); osDelay(1000); /* 读取 FPGA 版本信息 */ if (HAL_OK == _dau_reg_read_global_state()) { snprintf(version, DEV_COMPILE_TIME_LEN, "%d.%d", dau_ctrl.reg_global.GSVR >> 8, dau_ctrl.reg_global.GSVR & 0xff); if (strncmp((char*)dev_info.FPGA_version, version, DEV_COMPILE_TIME_LEN - 1) != 0) { strncpy((char*)dev_info.FPGA_version, version, DEV_COMPILE_TIME_LEN - 1); common_sys_set(COM_SYS_SAVE_INFO, 0); } } } /* description: DAU 主任务循环 param: return: */ static void _dau_start(void *argument) { //uint16_t *buf = (uint16_t*)(&dau_ctrl.buf_dau_rx[2]); uint16_t *buf = NULL; uint32_t addr = 0; uint8_t i = 0; uint8_t j = 0; uint16_t k = 0; int32_t rv = HAL_ERROR; /* 状态初始化 */ _dau_init(); for (;;) { osDelay(5000); common_watchdog_set(COM_WDG_DAU); /* 读取全局状态寄存器 */ rv = _dau_reg_read_global_state(); if (rv != HAL_OK) { continue; } /* 处理升级 */ //if (dau_ctrl.update_flag) //{ // if (HAL_OK == _dau_update()) // { // dau_ctrl.update_rt = DAU_UPD_OK; // } // else // { // dau_ctrl.update_rt = DAU_UPD_ERROR; // } //} /* utc 对时处理 */ //_dau_utc(); /* 故障电流采集 */ //_dau_wave_col_trigger_by_fault(); /* 循环工频缺陷电流采集 */ _dau_wave_col_trigger_by_reg(); if (1 == _dau_spi_rw) { _dau_spi_rw = 0; _dau_reg_read(_dau_spi_addr, _dau_spi_len << 1); } else if(2 == _dau_spi_rw) { uint16_t *data = (uint16_t*)&dau_ctrl.buf_dau_tx[2]; *data = _dau_spi_len; _dau_spi_rw = 0; _dau_reg_write(_dau_spi_addr, 2); } common_watchdog_set(COM_WDG_DAU); #if 0 addr = dau_ctrl.addr_reg; for(i = 0; i < 3; i++) { vty_print("DEFECT %x %d\r\n", addr, i); for(j = 0; j < DAU_PKT_DEFECT_CNT; j++) { common_watchdog_set(COM_WDG_DAU); spi_flash_read(addr, &dau_ctrl.buf_dau_rx[2], 1024); addr += DAU_PKT_DEFECT_BYTE_CNT; for(k = 0; k < 512;) { vty_print("%04x ", buf[k++]); if(0 == k % 32) { osDelay(100); vty_print("\r\n"); } } if(k % 32 != 0) { osDelay(100); vty_print("\r\n"); } } vty_print("\r\n"); } #endif #if 1 for(i = 0; i < DAU_PORT_POWER_CNT; i++) { vty_print("POWER %d\r\n", i); buf = (uint16_t*)dau_ctrl.reg_power[i]; for(j = 0; j < DAU_PKT_POWER_CNT; j++) { common_watchdog_set(COM_WDG_DAU); for(k = 0; k < 512;) { vty_print("%-04x ", buf[k++]); if(0 == k % 32) { osDelay(100); vty_print("\r\n"); } } if(k % 32 != 0) { osDelay(100); vty_print("\r\n"); } buf += 512; } vty_print("\r\n"); } #endif while(1) { osDelay(5000); common_watchdog_set(COM_WDG_DAU); //vty_print("sleep\r\n"); } } } /* description: GPS 报文处理 ($GNZDA,235949.012,05,01,1980,,*4F) param: return: */ static int32_t _dau_gps_process(void) { char *pkt = (char*)dau_ctrl.buf_gps; uint8_t n = 0; uint16_t i = 0; uint32_t hour = 0; uint32_t min = 0; uint32_t sec = 0; uint32_t day = 0; uint32_t mon = 0; uint32_t year = 0; uint32_t ms = 0; /* 遍历字符串 */ while(pkt[i]) { if (pkt[i] != '$') { i++; continue; } /* 查找对时字符串 "$GNZDA" */ if (strncmp(&pkt[i], "$GNZDA", 6) != 0) { i++; continue; } /* 查找时分秒日月年 */ n = sscanf(&pkt[i], "$GNZDA,%02d%02d%02d.%d,%02d,%02d,%04d", &hour, &min, &sec, &ms, &day, &mon, &year); if (n != 7) { return HAL_ERROR; } DBG(DBG_M_GPS, "%d/%d/%d %d:%d:%d\r\n", year, mon, day, hour, min, sec); /* 小于 2024 说明对时不成功. */ if (year < 2024) { return HAL_ERROR; } _dau_tm.tm_year = year - 1900; _dau_tm.tm_mon = mon - 1; _dau_tm.tm_mday = day; _dau_tm.tm_hour = hour; _dau_tm.tm_min = min; _dau_tm.tm_sec = sec; dau_ctrl.utc = mktime(&_dau_tm); rtc_time_set(dau_ctrl.utc); return HAL_OK; } return HAL_ERROR; } /* description: GPS 初始化 param: return: */ static void _dau_gps_init(void) { dau_ctrl.uart = &huart2; HAL_GPIO_WritePin(POWER_GPS_GPIO_Port, POWER_GPS_Pin, GPIO_PIN_SET); osDelay(1000); HAL_GPIO_WritePin(GPS_RST_GPIO_Port, GPS_RST_Pin, GPIO_PIN_RESET); osDelay(100); HAL_GPIO_WritePin(GPS_RST_GPIO_Port, GPS_RST_Pin, GPIO_PIN_SET); } /* description: GPS 主任务循环 param: return: */ static void _dau_gps_start(void *argument) { uint32_t notify_value = 0xff; uint32_t err_cnt = 5; /* 状态初始化 */ _dau_gps_init(); for (;;) { /* 连续 5 次失败才认为对时失败 */ dau_ctrl.is_utc_ok = (err_cnt < 5); common_watchdog_set(COM_WDG_GPS); /* 开启串口空闲中断收包 */ if (HAL_OK == HAL_UARTEx_ReceiveToIdle_DMA(dau_ctrl.uart, dau_ctrl.buf_gps, DAU_GPS_BUF_LEN)) { dau_ctrl.len_buf_gps = 0; dau_ctrl.is_half_buf_gps = FALSE; } /* 等待收包完成. */ notify_value = ulTaskNotifyTake(pdTRUE, 10000); if (0 == notify_value) { /* 收包超时 */ dau_ctrl.is_utc_valid = FALSE; err_cnt++; continue; } DBG(DBG_M_GPS, "Len %d\r\n", dau_ctrl.len_buf_gps); /* 命令过长. */ if (dau_ctrl.len_buf_gps >= DAU_GPS_BUF_LEN) { dau_ctrl.is_utc_valid = FALSE; err_cnt++; continue; } /* 字符串结束标志 */ dau_ctrl.buf_gps[dau_ctrl.len_buf_gps] = 0; if (HAL_OK == _dau_gps_process()) { dau_ctrl.is_utc_valid = TRUE; err_cnt = 0; } else { dau_ctrl.is_utc_valid = FALSE; err_cnt++; } } } /* Interface functions -------------------------------------------------------*/ /* description: DAU 采集任务初始化 param: return: */ void dau_init(void) { dau_ctrl.dau_handle = osThreadNew(_dau_start, NULL, &dau_attributes); dau_ctrl.gps_handle = osThreadNew(_dau_gps_start, NULL, &dau_gps_attributes); } /* description: spi 接口测试函数 param: return: */ void dau_spi_rw(int8_t rw, uint16_t addr, uint16_t len) { _dau_spi_rw = rw; _dau_spi_addr = addr; _dau_spi_len = len; } /* description: dau 显示接口 param: return: */ void dau_show(void) { struct tm *day = NULL; uint32_t utc = dau_ctrl.utc; vty_print("state: %d\r\n", dau_ctrl.is_utc_ok); if (dau_ctrl.is_utc_valid) { utc += 28800; day = localtime(&utc); vty_print("date: %d/%d/%d %d:%d:%d\r\n", day->tm_year - 100, day->tm_mon + 1, day->tm_mday, day->tm_hour, day->tm_min, day->tm_sec); } vty_print("\n"); } /******************* (C) COPYRIGHT LandPower ***** END OF FILE ****************/