/*
*********************************************************************************************************
*                                       IAR Development Kits
*                                              on the
*
*                                    M451
*
* Filename      : dwin_form.c
* Version       : V1.00
* Programmer(s) : Qian Xianghong
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                             INCLUDE FILES
*********************************************************************************************************
*/
#include "includes.h"

// 提示信息显示时间
uint32_t Form_messageSeconds = 0;

// 显示屏读写操作
#define DWIN_OPER_WRITE	(0x82)
#define DWIN_OPER_READ	(0x83)

// 显示颜色
#define DWIN_COLOR_BLACK	(0x00)
#define DWIN_COLOR_WHITE	(0xFFFF)
#define DWIN_COLOR_RED		(0xF800)
#define DWIN_COLOR_GREEN	(0x07E0)
#define DWIN_COLOR_BLUE		(0x001F)
#define DWIN_COLOR_YELLOW	(0xFFE0)

// 向屏幕写命令队列
#define FORM_DATA_COUNT 100
loopbuff_t Form_DataM;
uint8_t Form_DataM_Data[sizeof(form_data_t) * (FORM_DATA_COUNT + 1)] = {0};
SemaphoreHandle_t Form_DataQ = NULL;
SemaphoreHandle_t Form_DataLock = NULL;
static int16_t topPtr=0;
// 屏幕读取结果队列
#define FORM_READ_COUNT 3
loopbuff_t Form_ReadM;
uint8_t Form_ReadM_Data[sizeof(form_data_t) * (FORM_READ_COUNT + 1)] = {0};
SemaphoreHandle_t Form_ReadQ = NULL;

// 屏幕按键返回队列
#define FORM_KEY_COUNT 3
loopbuff_t Form_KeyM;
uint8_t Form_KeyM_Data[sizeof(form_data_t) * (FORM_KEY_COUNT + 1)] = {0};
SemaphoreHandle_t Form_KeyQ = NULL;

// 首页表格，报警页表格，查询表格, 关于表格
form_grid_t gridAll, gridWarn, gridQuery, gridAbout,gridAboutEn;
form_grid2_t gridBox;
// 用于生成显示屏命令
form_data_t formData;

// 记录查询功能(储罐、数据或曲线)和查询条件
form_query_t formQuery;

// 重新寻找SOF
void DWIN_SearchSOF(uint8_t *buf, uint16_t fromPos, uint16_t *len)
{
    uint16_t i;

    for(i = fromPos; i < *len && buf[i] != 0x5A; i++)
    {
    }

    *len -= i;
    memmove(buf, buf + i, *len);
}

// 分析串口数据，组帧
void DWIN_ParseFrame(uint8_t c)
{
    BaseType_t xHigherPriorityTaskWoken;
    static uint16_t RdIdx = 0;
    static uint8_t DWIN_Data[512];
    static form_data_t readData;
    uint8_t frameOk, frameErr;
    uint16_t i;

    while(1)
    {
        if(RdIdx == 0 && c != 0x5A)
            return;
        if(RdIdx == 1 && c != 0xA5)
        {
            RdIdx = 0;
            continue;
        }
        if(RdIdx == 3 && c != DWIN_OPER_READ && c != DWIN_OPER_WRITE)
        {
            RdIdx = 0;
            continue;
        }
        break;
    }

    DWIN_Data[RdIdx++] = c;

    do
    {
        frameErr = ((RdIdx >= 1 && DWIN_Data[0] != 0x5A)
                    || (RdIdx >= 2 && DWIN_Data[1] != 0xA5)
                    || (RdIdx >= 4 && DWIN_Data[3] != DWIN_OPER_READ && DWIN_Data[3] != DWIN_OPER_WRITE));
        if(frameErr)
        {
            // 从1开始寻找SOF
            DWIN_SearchSOF(DWIN_Data, 1, &RdIdx);
        }
        frameOk = (RdIdx >= 4 && DWIN_Data[0] == 0x5A && DWIN_Data[1] == 0xA5 &&
                   (DWIN_Data[3] == DWIN_OPER_READ || DWIN_Data[3] == DWIN_OPER_WRITE) && RdIdx >= DWIN_Data[2] + 3);
        if(frameOk)
        {
            if(DWIN_Data[3] == DWIN_OPER_READ)
            {
                readData.oper = DWIN_OPER_READ;
                readData.Addr = (DWIN_Data[4] << 8) | DWIN_Data[5];
                readData.count = DWIN_Data[6] * 2;
                memmove(readData.byte, DWIN_Data + 7, readData.count);

                printf("\nRead from screen, 0x%04X (%d bytes):\n", readData.Addr, readData.count);
                for(i = 0; i < readData.count; i++)
                    printf(" %02X", readData.byte[i]);
                printf("\n");

                // 触摸按键返回
                if(readData.Addr == 0x5000 || readData.Addr == 0x5012 || readData.Addr == 0x5030
                        || readData.Addr == 0x5022 || readData.Addr == 0x502C || readData.Addr == 0x502E
                        || readData.Addr == 0x5032|| readData.Addr == 0x5034|| readData.Addr == 0x5036|| readData.Addr == 0x6F00)
                {
                    LoopBuff_PutItem(&Form_KeyM, (uint8_t *) &readData);
                    // 发消息给任务
                    xSemaphoreGiveFromISR(Form_KeyQ, &xHigherPriorityTaskWoken);
                }
                else
                {
                    LoopBuff_PutItem(&Form_ReadM, (uint8_t *) &readData);
                    // 发消息给任务
                    xSemaphoreGiveFromISR(Form_ReadQ, &xHigherPriorityTaskWoken);
                }
            }

            // 继续寻找下一帧
            RdIdx -= (DWIN_Data[2] + 3);
            memmove(DWIN_Data, DWIN_Data + (DWIN_Data[2] + 3), RdIdx);

            // 从0开始寻找SOF
            DWIN_SearchSOF(DWIN_Data, 0, &RdIdx);
        }
    } while(frameOk || frameErr);
}

// DWIN screen uart
void DWIN_IRQHandler(USART_Handle *huart)
{
    uint8_t u8DTU = (uint8_t) huart->Instance->DR;

    //printf("%02X ", u8DTU);
    DWIN_ParseFrame(u8DTU);
}

void DWIN_Refresh(form_data_t *pData)
{
    uint16_t i = 0;
    static uint8_t buf[128];

    buf[i++] = 0x5A;
    buf[i++] = 0xA5;
    if(pData->oper == DWIN_OPER_WRITE)
        buf[i++] = 3 + pData->count;
    else
        buf[i++] = 3 + 1;
    buf[i++] = pData->oper;
    buf[i++] = (pData->Addr >> 8);
    buf[i++] = (pData->Addr & 0xFF);
    if(pData->oper == DWIN_OPER_WRITE)
    {
        memmove(buf + i, pData->byte, pData->count);
        i += pData->count;
    }
    else
        buf[i++] = pData->count / 2;

    UART_Transmit(&huart10, buf, i);
}

// 模拟一次触控点击
void DWIN_Touch(uint16_t x, uint16_t y)
{
    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    formData.oper = DWIN_OPER_WRITE;
    formData.Addr = 0x00D4;
    formData.count = 8;
    formData.word[0] = htons(0x5AA5);
    formData.word[1] = htons(0x0004);
    formData.word[2] = htons(x);
    formData.word[3] = htons(y);
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);
}

// 清除提示信息
void Form_ClearMessage()
{
    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    formData.oper = DWIN_OPER_WRITE;
    formData.Addr = 0x5D80;
    formData.count = 26;
    memset(formData.str, ' ', formData.count);
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);
}

// 提示信息: 最多显示26个字符
void Form_DispMessage(char *str, uint16_t color)
{
    static uint16_t last_color = DWIN_COLOR_WHITE;

    // 先清除提示信息
    Form_ClearMessage();

    // 提示信息显示5秒
    Form_messageSeconds = rf_get_seconds() + 5;

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    formData.oper = DWIN_OPER_WRITE;
    formData.Addr = 0x5D80;
    formData.count = strlen(str);
    memmove(formData.str, str, formData.count);
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    if(color != last_color)
    {
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = 0xA273;
        formData.count = 2;
        formData.word[0] = htons(color);
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
        // 保存当前提示信息的颜色
        last_color = color;
    }
    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);
}

// 切换显示页面
void Form_SwitchPage(uint16_t pageNo)
{
    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    formData.oper = DWIN_OPER_WRITE;
    // 加入队列
    formData.Addr = 0x0084;
    formData.count = 4;
    formData.word[0] = htons(0x5A01);
    formData.word[1] = htons(pageNo);
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);
}

// 清除表格内容
void Form_ClearGrid(form_grid_t *grid)
{
    memset(grid->rowStr, 0, sizeof(grid->rowStr));
    Form_RefreshGrid(grid);
}

// 刷新表格
void Form_RefreshGrid(form_grid_t *grid)
{
    int16_t i, len;

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    // 先将数据写入备份缓冲
    for(i = 0; i < grid->rowCount; i++)
    {
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = grid->rowPtr[i] + (grid->bufIdx == 0 ? 0x40 : 0);
        strcpy(formData.str, grid->rowStr[i]);
        len = strlen(formData.str);
        memset(formData.str + len, ' ', sizeof(formData.str) - len);
        formData.count = sizeof(formData.str);
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }

    // 再将备份缓冲作为显示缓冲
    for(i = 0; i < 10; i++)
    {
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = grid->rowDesc[i];
        formData.count = 2;
        formData.word[0] = htons(grid->rowPtr[i] + (grid->bufIdx == 0 ? 0x40 : 0));
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }

    // 将原显示缓冲作为备份缓冲
    grid->bufIdx = 1 - grid->bufIdx;

    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);
}
// 刷新表格
void Form_RefreshGrid2(form_grid2_t *grid)
{
    int16_t i, len;

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    // 先将数据写入备份缓冲
    for(i = 0; i < grid->rowCount; i++)
    {
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = grid->rowPtr[i] + (grid->bufIdx == 0 ? 0x40 : 0);
        strcpy(formData.str, grid->rowStr[i]);
        len = strlen(formData.str);
        memset(formData.str + len, ' ', sizeof(formData.str) - len);
        formData.count = sizeof(formData.str);
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }
				            //boxCnt.count=12;
                    formData.oper = DWIN_OPER_WRITE;
                    formData.Addr = 0x9002;
                    formData.count = 2;
                    formData.word[0] = htons((boxCnt.count/30)+1);
                    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    formData.oper = DWIN_OPER_WRITE;
                    formData.Addr = 0x9000;
                    formData.count = 2;
                    formData.word[0] = htons((topPtr/30)+1);
                    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
		
		
    // 再将备份缓冲作为显示缓冲
    for(i = 0; i < 30; i++)
    {
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = grid->rowDesc[i];
        formData.count = 2;
        formData.word[0] = htons(grid->rowPtr[i] + (grid->bufIdx == 0 ? 0x40 : 0));
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }

    // 将原显示缓冲作为备份缓冲
    grid->bufIdx = 1 - grid->bufIdx;

    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);
}
// 滚动表格
void Form_ScrollGrid(form_grid_t *grid)
{
    int16_t i, len;
    uint16_t tempPtr;

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    tempPtr = grid->rowPtr[grid->rowCount - 1];

    // 先将第2~10行往下移
    for(i = grid->rowCount - 1; i > 0; i--)
    {
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = grid->rowDesc[i];
        formData.count = 2;
        formData.word[0] = htons(grid->rowPtr[i - 1] + (grid->bufIdx == 1 ? 0x40 : 0));
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

        // 记录新的文本指针
        grid->rowPtr[i] = grid->rowPtr[i - 1];
    }

    // 写入第1行的内容
    formData.oper = DWIN_OPER_WRITE;
    formData.Addr = tempPtr + (grid->bufIdx == 1 ? 0x40 : 0);
    strcpy(formData.str, grid->rowStr[0]);
    len = strlen(formData.str);
    memset(formData.str + len, ' ', sizeof(formData.str) - len);
    formData.count = sizeof(formData.str);
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    // 显示第1行内容
    formData.oper = DWIN_OPER_WRITE;
    formData.Addr = grid->rowDesc[0];
    formData.count = 2;
    formData.word[0] = htons(tempPtr + (grid->bufIdx == 1 ? 0x40 : 0));
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    // 记录新的文本指针
    grid->rowPtr[0] = tempPtr;

    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);
}

// 初始化
void Form_Open()
{
    int16_t i;

    // 创建信号量
    Form_DataQ = xSemaphoreCreateBinary();
    Form_ReadQ = xSemaphoreCreateBinary();
    Form_KeyQ = xSemaphoreCreateBinary();

    // 创建互斥锁
    Form_DataLock = xSemaphoreCreateMutex();

    // 创建消息队列
    LoopBuff_Create(&Form_DataM, sizeof(form_data_t), FORM_DATA_COUNT, 0, (uint32_t) Form_DataM_Data);
    LoopBuff_Create(&Form_ReadM, sizeof(form_data_t), FORM_READ_COUNT, 0, (uint32_t) Form_ReadM_Data);
    LoopBuff_Create(&Form_KeyM, sizeof(form_data_t), FORM_KEY_COUNT, 0, (uint32_t) Form_KeyM_Data);

    // 初始化表格
    memset(&gridAll, 0, sizeof(gridAll));
    memset(&gridWarn, 0, sizeof(gridWarn));
    memset(&gridQuery, 0, sizeof(gridQuery));
    memset(&gridAbout, 0, sizeof(gridAbout));
    memset(&gridAboutEn, 0, sizeof(gridAboutEn));
    gridAll.rowCount = 10;
    gridWarn.rowCount = 10;
    gridQuery.rowCount = 10;
    gridAbout.rowCount = 10;
    gridAboutEn.rowCount = 10;
    gridBox.rowCount=30;

    gridAll.hdrAddr = 0x5200;
    for(i = 0; i < gridAll.rowCount; i++)
    {
        gridAll.rowDesc[i] = 0xA0A0 + 0x10 * i;
        gridAll.rowPtr[i] = 0x5280 + 0x80 * i;
    }
    gridWarn.hdrAddr = 0x5780;
    for(i = 0; i < gridWarn.rowCount; i++)
    {
        gridWarn.rowDesc[i] = 0xA150 + 0x10 * i;
        gridWarn.rowPtr[i] = 0x5800 + 0x80 * i;
    }
    gridQuery.hdrAddr = 0x6000;
    for(i = 0; i < gridQuery.rowCount; i++)
    {
        gridQuery.rowDesc[i] = 0xA350 + 0x10 * i;
        gridQuery.rowPtr[i] = 0x6080 + 0x80 * i;
    }
    gridAbout.hdrAddr = 0x6980;
    for(i = 0; i < gridAbout.rowCount; i++)
    {
        gridAbout.rowDesc[i] = 0xA7F0 + 0x10 * i;
        gridAbout.rowPtr[i] = 0x6A00 + 0x80 * i;
    }
    gridAboutEn.hdrAddr = 0x7980;
    for(i = 0; i < gridAboutEn.rowCount; i++)
    {
        gridAboutEn.rowDesc[i] = 0xB7F0 + 0x10 * i;
        gridAboutEn.rowPtr[i] = 0x7A00 + 0x80 * i;
    }
    gridBox.hdrAddr=0x8000;
    for(i = 0; i < gridBox.rowCount; i++)
    {
        gridBox.rowDesc[i] = 0xC010 + 0x10 * i;
        gridBox.rowPtr[i] = 0x8080 + 0x80 * i;
    }
    // 启动串口
    huart10.RxISR = DWIN_IRQHandler;
    SET_BIT(UART10->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
    LL_USART_Enable(UART10);
}

// 导入首页和报警页最近数据
void Form_LoadRecent()
{
    int32_t lastRec = -1;
    int16_t idx;
    uint8_t rowAll = 0, rowWarn = 0;
    S_RTC_TIME_DATA_T sRTC;
    char tggu[16], pct[8], mmWC[8], kg[8], press[8], tempr[8];

    static ext_data_t Gprs;
    rf_app_data_t *pData = (rf_app_data_t *) Gprs.payload;

    // 查询所有储罐
    if(LoopBuff_GetCount(&RF_DataM) > 0)
    {
        if(RF_DataM.info.wtPtr == 0)
            lastRec = RF_DataM.maxItemCount;
        else
            lastRec = RF_DataM.info.wtPtr - 1;
    }

    while(lastRec != -1 && (rowAll < gridAll.rowCount || rowWarn < gridWarn.rowCount))
    {
        // 读取最后一条记录
        SFlash_LoadInfo(LoopBuff_GetDataPos(&RF_DataM, lastRec), (uint8_t *) &Gprs, sizeof(ext_data_t));
        // 前一条记录
        if(lastRec == RF_DataM.info.rdPtr)
            lastRec = -1;
        else if(lastRec == 0)
            lastRec = RF_DataM.maxItemCount;
        else
            lastRec--;

        // 转换绝对时间
        Wakeup_CalcUTCTime(Gprs.recvTime - pData->relative_time, &sRTC);

        // 查找储罐档案
        idx = Ext_Lookup_Box_PSN(Gprs.oriPSN, boxCnt.count);
        if(idx >= 0)
            strcpy(tggu, boxPSN[idx].TGGU);
        else
            strcpy(tggu, "");

        if(pData->Sensor.staDiff == RF_SENSOR_STATUS_NOCONNECT)
        {
            strcpy(mmWC, "---");
            strcpy(kg, "---");
            strcpy(pct, "---");
        }
        else if(pData->Sensor.staDiff == RF_SENSOR_STATUS_UNDERFLOW)
        {
            strcpy(mmWC, "-EE");
            strcpy(kg, "-EE");
            strcpy(pct, "-EE");
        }
        else if(pData->Sensor.staDiff == RF_SENSOR_STATUS_OVERFLOW)
        {
            strcpy(mmWC, "+EE");
            strcpy(kg, "+EE");
            strcpy(pct, "+EE");
        }
        else
        {
            sprintf(mmWC, "%d", (uint32_t) KPa2mmH2O(pData->diff * 0.01));
            sprintf(kg, "%d", (uint32_t) Vol2Quantity(Gprs.volume, pData->density * 0.001));
            sprintf(pct, "%.1f", Gprs.volumePct * 0.01);
        }

        if(pData->Sensor.staPress == RF_SENSOR_STATUS_NOCONNECT)
            strcpy(press, "---");
        else if(pData->Sensor.staPress == RF_SENSOR_STATUS_UNDERFLOW)
            strcpy(press, "-EE");
        else if(pData->Sensor.staPress == RF_SENSOR_STATUS_OVERFLOW)
            strcpy(press, "+EE");
        else
            sprintf(press, "%.2f", pData->press * 0.001);
        if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_NOCONNECT)
            strcpy(tempr, "---");
        else if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_UNDERFLOW)
            strcpy(tempr, "-EE");
        else if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_OVERFLOW)
            strcpy(tempr, "+EE");
        else
            sprintf(tempr, "%d", pData->tempr);

        if(rowAll < gridAll.rowCount)
        {
            sprintf(gridAll.rowStr[rowAll++], " %02d-%02d %02d:%02d  %11s  %7s    %7s  %5s  %7s   %6s   %2s   %2s    20%02d%02d%02d%02d%03d",
                    sRTC.u32Month, sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute,
                    tggu, mmWC, kg, pct, press, tempr, (Gprs.warn ? "W" : ""), (Gprs.fault ? "F" : ""),
                    Gprs.oriPSN[0], Gprs.oriPSN[1], Gprs.oriPSN[2], Gprs.oriPSN[3], (Gprs.oriPSN[4] << 8) | Gprs.oriPSN[5]);
        }
        if((Gprs.warn || Gprs.fault) && rowWarn < gridWarn.rowCount)
        {
            sprintf(gridWarn.rowStr[rowWarn++], " %02d-%02d %02d:%02d  %11s  %7s    %7s  %5s  %7s   %6s   %2s   %2s    20%02d%02d%02d%02d%03d",
                    sRTC.u32Month, sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute,
                    tggu, mmWC, kg, pct, press, tempr, (Gprs.warn ? "W" : ""), (Gprs.fault ? "F" : ""),
                    Gprs.oriPSN[0], Gprs.oriPSN[1], Gprs.oriPSN[2], Gprs.oriPSN[3], (Gprs.oriPSN[4] << 8) | Gprs.oriPSN[5]);
        }
    }

    // 刷新表格
    while(rowAll < gridAll.rowCount)
        strcpy(gridAll.rowStr[rowAll++], "");
    Form_RefreshGrid(&gridAll);

    while(rowWarn < gridWarn.rowCount)
        strcpy(gridWarn.rowStr[rowWarn++], "");
    Form_RefreshGrid(&gridWarn);
}

// 显示任务主体
void Form_Task(void *p_arg)
{
    static form_data_t data;
    ext_bottle_t	bottle;
    uint32_t seconds, seconds1, rtcSeconds = 0, statisSeconds = 0;
    uint8_t last_lora = 0, last_gps = 0, last_net = 0, last_rssi = 0;
    int16_t last_totalCount = 0, last_offlineCount = 0, last_faultCount = 0, last_warnCount = 0;
    int16_t i, idx, val, val1, val2, val3;
    uint32_t tick = 0;
    S_RTC_TIME_DATA_T sRTC;

    int32_t axisMax, axisMin, axisSeg = 10;

    // 屏幕复位
    data.oper = DWIN_OPER_WRITE;
    data.Addr = 0x0004;
    data.count = 4;
    data.dword[0] = htonl(0x55AA5AA5);
    DWIN_Refresh(&data);
    // 延时200毫秒
    osDelay(200);

    // 设置表头
    data.oper = DWIN_OPER_WRITE;
    data.Addr = gridAll.hdrAddr;
    sprintf(data.str, " %5s %5s  %11s  %10s %8s %6s %9s %8s %4s %4s  %13s",
            " 日期", " 时间", "  罐箱号   ", "液位(mmWC)", "质量(kg)", "百分比", "压力(MPa)", "温度(℃)", "报警", "故障", "     PSN     ");
    data.count = strlen(data.str);
    DWIN_Refresh(&data);
    // 设置表头
    data.oper = DWIN_OPER_WRITE;
    data.Addr = gridAll.hdrAddr+0x2000;
    sprintf(data.str, " %5s %5s  %11s  %10s %8s %6s %9s %6s %4s %4s  %13s",
            " data", " time", "Number_Box", "Level(mmWC)", "Qual(kg)", "Per(%)", "Pres(MPa)", "T(deg)", "Warn", "Err", "     PSN     ");
    data.count = strlen(data.str);
    DWIN_Refresh(&data);

    data.oper = DWIN_OPER_WRITE;
    data.Addr = gridWarn.hdrAddr;
    sprintf(data.str, " %5s %5s  %11s  %10s %8s %6s %9s %8s %4s %4s  %13s",
            " 日期", " 时间", "  罐箱号   ", "液位(mmWC)", "质量(kg)", "百分比", "压力(MPa)", "温度(℃)", "报警", "故障", "     PSN     ");
    data.count = strlen(data.str);
    DWIN_Refresh(&data);

    data.oper = DWIN_OPER_WRITE;
    data.Addr = gridWarn.hdrAddr+0x2000;
    sprintf(data.str, " %5s %5s  %11s  %10s %8s %6s %9s %6s %4s %4s  %13s",
            " data", " time", "Number_Box", "Level(mmWC)", "Qual(kg)", "Per(%)", "Pres(MPa)", "T(deg)", "Warn", "Err", "     PSN     ");
    data.count = strlen(data.str);
    DWIN_Refresh(&data);

    data.oper = DWIN_OPER_WRITE;
    data.Addr = gridBox.hdrAddr;
    sprintf(data.str, " %11s   %13s  %11s   %13s  %11s   %13s ",
            "BOX   ",  "PSN     "," BOX   ",  "PSN     "," BOX    ",  "PSN     ");
    data.count = strlen(data.str);
    DWIN_Refresh(&data);
		
//		 data.oper = DWIN_OPER_WRITE;
//    data.Addr = gridBox.hdrAddr+0x1000;
//    sprintf(data.str, "%6s",
//            "00");
//    data.count = strlen(data.str);
//    DWIN_Refresh(&data);

    // 设置曲线的纵坐标
    // 绿轴：液位（百分比）
    data.oper = DWIN_OPER_WRITE;
    data.Addr = 0x6580;
    if(dcBuff.configDisplay.ch_en)
        strcpy(data.str, "  Level-%");
    else
        strcpy(data.str, "  液位-%");
    data.count = strlen(data.str);
    DWIN_Refresh(&data);
    axisMax = 100;
    axisMin = 0;
    for(i = 0; i <= axisSeg; i++)
    {
        data.oper = DWIN_OPER_WRITE;
        data.Addr = 0x65B0 + i * 0x10;
        sprintf(data.str, "%7d", axisMin + (axisMax - axisMin) / axisSeg * i);
        data.count = strlen(data.str);
        DWIN_Refresh(&data);
    }
    // 黄轴：压力（MPa）
    data.oper = DWIN_OPER_WRITE;
    data.Addr = 0x6590;
    if(dcBuff.configDisplay.ch_en)
        strcpy(data.str, "pressure-%");
    else
        strcpy(data.str, "压力-MPa");
    data.count = strlen(data.str);
    DWIN_Refresh(&data);
    axisMax = 5;
    axisMin = 0;
    for(i = 0; i <= axisSeg; i++)
    {
        data.oper = DWIN_OPER_WRITE;
        data.Addr = 0x6660 + i * 0x10;
        sprintf(data.str, "%7.2f", ((float) axisMin + (axisMax - axisMin)) / axisSeg * i);
        data.count = strlen(data.str);
        DWIN_Refresh(&data);
    }
    // 红轴：温度（℃）
    data.oper = DWIN_OPER_WRITE;
    data.Addr = 0x65A0;
    if(dcBuff.configDisplay.ch_en)
        strcpy(data.str, "Temperature-%");
    else
        strcpy(data.str, "温度-℃");
    data.count = strlen(data.str);
    DWIN_Refresh(&data);
    axisMax = 90;
    axisMin = -210;
    for(i = 0; i <= axisSeg; i++)
    {
        data.oper = DWIN_OPER_WRITE;
        data.Addr = 0x6710 + i * 0x10;
        sprintf(data.str, "%7d", axisMin + (axisMax - axisMin) / axisSeg * i);
        data.count = strlen(data.str);
        DWIN_Refresh(&data);
    }

    // 导入首页和报警页最近数据
    Form_LoadRecent();

    // 开机画面等待4秒
    osDelay(3000);
    // 跳转到首页
    if(dcBuff.configDisplay.ch_en)
        Form_SwitchPage(50);
    else
        Form_SwitchPage(0);

    while(1)
    {
        if(IsTickOut(tick))
        {
            // 每半秒刷新一次状态
            tick = GetDelayTick(500);

            // 清除提示信息

            // 网络连接状态
            val = Ethernet_connected;
            if(last_net != val)
            {
                data.oper = DWIN_OPER_WRITE;
                data.Addr = 0x5006;
                data.count = 2;
                data.word[0] = htons(val);
                DWIN_Refresh(&data);

                last_net = val;
            }

            // 4G信号强度
            val = (dcBuff.dtuData.rssi + 12) / 25;
            if(last_rssi != val)
            {
                data.oper = DWIN_OPER_WRITE;
                data.Addr = 0x5008;
                data.count = 2;
                data.word[0] = htons(val);
                DWIN_Refresh(&data);

                last_rssi = val;
            }

            seconds = rf_get_seconds();
//apex
//            // LORA: 最新接收时间在3秒以内
            val = (RF_initStatus && RF_seconds > 0 && RF_seconds + 3 > seconds);
            if(last_lora != val)
            {
                data.oper = DWIN_OPER_WRITE;
                data.Addr = 0x5002;
                data.count = 2;
                data.word[0] = htons(val);
                DWIN_Refresh(&data);

                last_lora = val;
            }

            // GPS标志: 最新定位时间在180秒以内
            if(dcBuff.dtuData.posState)
            {
                seconds1 = Calc_SecondsFromYear(INITIAL_YEAR, dcBuff.dtuData.sysTime.year + 2000, dcBuff.dtuData.sysTime.month,
                                                dcBuff.dtuData.sysTime.day, dcBuff.dtuData.sysTime.hour, dcBuff.dtuData.sysTime.minute, dcBuff.dtuData.sysTime.second);
            }
            val = (RTC_offsetSeconds > 0 && dcBuff.dtuData.posState && seconds1 + 180 > RTC_offsetSeconds + seconds);
            if(last_gps != val)
            {
                data.oper = DWIN_OPER_WRITE;
                data.Addr = 0x5004;
                data.count = 2;
                data.word[0] = htons(val);
                DWIN_Refresh(&data);

                last_gps = val;
            }

            if(Form_messageSeconds > 0 && seconds >= Form_messageSeconds)
            {
                Form_messageSeconds = 0;
                Form_ClearMessage();
            }
            // 每30秒统计一次设备数量
            if(/*RTC_offsetSeconds > 0 &&*/ seconds >= statisSeconds)
            {
                statisSeconds = seconds + 30;

                // 离线总数
                val1 = boxCnt.count;
                val2 = 0;
                val3 = 0;
                for(i = 0; i < boxCnt.count; i++)
                {
                    idx = Ext_Lookup_Bottle_PSN(boxPSN[i].PSN, bottleCnt.count);
                    if(idx >= 0)
                    {
                        FRAM_BufferRead(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * bottlePSN[idx].recNo, (uint8_t *) &bottle, sizeof(ext_bottle_t));
                        if(bottle.recvTime + dcBuff.configBottle.offlineSeconds > RTC_offsetSeconds + seconds)
                        {
                            // 设备在线，离线数量-1
                            val1--;
                        }
                        // 故障和报警只统计在线设备
                        if(bottle.fault)
                            val2++;
                        if(bottle.warn)
                            val3++;
                    }
                }

                // 设备总数
                val = boxCnt.count;
                if(last_totalCount != val)
                {
                    data.oper = DWIN_OPER_WRITE;
                    data.Addr = 0x500A;
                    data.count = 2;
                    data.word[0] = htons(val);
                    DWIN_Refresh(&data);

                    last_totalCount = val;
                }

                // 离线总数
                val = val1;
                if(last_offlineCount != val)
                {
                    data.oper = DWIN_OPER_WRITE;
                    data.Addr = 0x500C;
                    data.count = 2;
                    data.word[0] = htons(val);
                    DWIN_Refresh(&data);
                    // 修改白色/红色
                    if((last_offlineCount > 0 && val == 0) || (last_offlineCount == 0 && val > 0))
                    {
                        data.oper = DWIN_OPER_WRITE;
                        data.Addr = 0xA053;
                        data.count = 2;
                        data.word[0] = htons(val == 0 ? DWIN_COLOR_WHITE : DWIN_COLOR_RED);
                        DWIN_Refresh(&data);
                    }

                    last_offlineCount = val;
                }

                // 故障总数
                val = val2;
                if(last_faultCount != val)
                {
                    data.oper = DWIN_OPER_WRITE;
                    data.Addr = 0x500E;
                    data.count = 2;
                    data.word[0] = htons(val);
                    DWIN_Refresh(&data);
                    // 修改白色/红色
                    if((last_faultCount > 0 && val == 0) || (last_faultCount == 0 && val > 0))
                    {
                        data.oper = DWIN_OPER_WRITE;
                        data.Addr = 0xA063;
                        data.count = 2;
                        data.word[0] = htons(val == 0 ? DWIN_COLOR_WHITE : DWIN_COLOR_RED);
                        DWIN_Refresh(&data);
                    }

                    last_faultCount = val;
                }

                // 报警总数
                val = val3;
                if(last_warnCount != val)
                {
                    data.oper = DWIN_OPER_WRITE;
                    data.Addr = 0x5010;
                    data.count = 2;
                    data.word[0] = htons(val);
                    DWIN_Refresh(&data);
                    // 修改白色/黄色
                    if((last_warnCount > 0 && val == 0) || (last_warnCount == 0 && val > 0))
                    {
                        data.oper = DWIN_OPER_WRITE;
                        data.Addr = 0xA073;
                        data.count = 2;
                        data.word[0] = htons(val == 0 ? DWIN_COLOR_WHITE : DWIN_COLOR_YELLOW);
                        DWIN_Refresh(&data);
                    }

                    last_warnCount = val;
                }
            }

            // 每小时重设一次显示屏的RTC时钟
            if(RTC_offsetSeconds > 0 && seconds >= rtcSeconds)
            {
                rtcSeconds = seconds + 3600;

                // 设置RTC时钟
                Wakeup_CalcUTCTime(RTC_offsetSeconds + seconds, &sRTC);
                data.oper = DWIN_OPER_WRITE;
                data.Addr = 0x009C;
                data.count = 8;
                data.byte[0] = 0x5A;
                data.byte[1] = 0xA5;
                data.byte[2] = sRTC.u32Year - 2000;
                data.byte[3] = sRTC.u32Month;
                data.byte[4] = sRTC.u32Day;
                data.byte[5] = sRTC.u32Hour;
                data.byte[6] = sRTC.u32Minute;
                data.byte[7] = sRTC.u32Second;
                DWIN_Refresh(&data);
            }
        }

        // 处理其它显示任务
        if(xSemaphoreTake(Form_DataQ, 500) != pdTRUE)
            continue;
        while(LoopBuff_GetCount(&Form_DataM) > 0)
        {
            memmove(&data, LoopBuff_GetDataPtr(&Form_DataM, Form_DataM.info.rdPtr), sizeof(form_data_t));
            LoopBuff_RemoveItems(&Form_DataM, 1);
            DWIN_Refresh(&data);
        }
    }
}

// 从屏幕读取数据
uint8_t Form_ReadInt16(uint16_t addr, int16_t *val)
{
    form_data_t resp;
    uint8_t count;
    uint16_t uval;
    uint32_t tick;

    // 先发送读取命令

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);
    formData.oper = DWIN_OPER_READ;
    formData.Addr = addr;
    formData.count = 2;
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    // 解锁
    xSemaphoreGive(Form_DataLock);
    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);

    // 等待服务器返回：4秒
    tick = GetDelayTick(4000);
    while(!IsTickOut(tick))
    {
        if(xSemaphoreTake(Form_ReadQ, 500) != pdTRUE)
            continue;

        count = LoopBuff_GetCount(&Form_ReadM);
        while(count--)
        {
            memmove(&resp, LoopBuff_GetDataPtr(&Form_ReadM, Form_ReadM.info.rdPtr), sizeof(resp));
            LoopBuff_RemoveItems(&Form_ReadM, 1);
            if(resp.Addr == addr && resp.count == 2)
            {
                uval = ntohs(resp.word[0]);
                memmove(val, &uval, 2);
                return 1;
            }
        }
    }

    return 0;
}

// 从屏幕读取数据
uint8_t Form_ReadUInt16(uint16_t addr, uint16_t *val)
{
    form_data_t resp;
    uint8_t count;
    uint16_t uval;
    uint32_t tick;

    // 先发送读取命令

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);
    formData.oper = DWIN_OPER_READ;
    formData.Addr = addr;
    formData.count = 2;
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    // 解锁
    xSemaphoreGive(Form_DataLock);
    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);

    // 等待服务器返回：4秒
    tick = GetDelayTick(4000);
    while(!IsTickOut(tick))
    {
        if(xSemaphoreTake(Form_ReadQ, 500) != pdTRUE)
            continue;

        count = LoopBuff_GetCount(&Form_ReadM);
        while(count--)
        {
            memmove(&resp, LoopBuff_GetDataPtr(&Form_ReadM, Form_ReadM.info.rdPtr), sizeof(resp));
            LoopBuff_RemoveItems(&Form_ReadM, 1);
            if(resp.Addr == addr && resp.count == 2)
            {
                uval = ntohs(resp.word[0]);
                memmove(val, &uval, 2);
                return 1;
            }
        }
    }

    return 0;
}

// 从屏幕读取数据
uint8_t Form_ReadInt32(uint16_t addr, int32_t *val)
{
    form_data_t resp;
    uint8_t count;
    uint32_t uval;
    uint32_t tick;

    // 先发送读取命令

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);
    formData.oper = DWIN_OPER_READ;
    formData.Addr = addr;
    formData.count = 4;
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    // 解锁
    xSemaphoreGive(Form_DataLock);
    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);

    // 等待服务器返回：4秒
    tick = GetDelayTick(4000);
    while(!IsTickOut(tick))
    {
        if(xSemaphoreTake(Form_ReadQ, 500) != pdTRUE)
            continue;

        count = LoopBuff_GetCount(&Form_ReadM);
        while(count--)
        {
            memmove(&resp, LoopBuff_GetDataPtr(&Form_ReadM, Form_ReadM.info.rdPtr), sizeof(resp));
            LoopBuff_RemoveItems(&Form_ReadM, 1);
            if(resp.Addr == addr && resp.count == 4)
            {
                uval = ntohl(resp.dword[0]);
                memmove(val, &uval, 4);
                return 1;
            }
        }
    }

    return 0;
}

// 从屏幕读取数据
uint8_t Form_ReadUInt32(uint16_t addr, uint32_t *val)
{
    form_data_t resp;
    uint8_t count;
    uint32_t uval;
    uint32_t tick;

    // 先发送读取命令

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);
    formData.oper = DWIN_OPER_READ;
    formData.Addr = addr;
    formData.count = 4;
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    // 解锁
    xSemaphoreGive(Form_DataLock);
    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);

    // 等待服务器返回：4秒
    tick = GetDelayTick(4000);
    while(!IsTickOut(tick))
    {
        if(xSemaphoreTake(Form_ReadQ, 500) != pdTRUE)
            continue;

        count = LoopBuff_GetCount(&Form_ReadM);
        while(count--)
        {
            memmove(&resp, LoopBuff_GetDataPtr(&Form_ReadM, Form_ReadM.info.rdPtr), sizeof(resp));
            LoopBuff_RemoveItems(&Form_ReadM, 1);
            if(resp.Addr == addr && resp.count == 4)
            {
                uval = ntohl(resp.dword[0]);
                memmove(val, &uval, 4);
                return 1;
            }
        }
    }

    return 0;
}

// 从屏幕读取数据
uint8_t Form_ReadStr(uint16_t addr, char *val, uint8_t size)
{
    form_data_t resp;
    uint8_t count, i = 0;
    uint32_t tick;

    // 先发送读取命令

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);
    formData.oper = DWIN_OPER_READ;
    formData.Addr = addr;
    formData.count = size;
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    // 解锁
    xSemaphoreGive(Form_DataLock);
    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);

    // 等待服务器返回：4秒
    tick = GetDelayTick(4000);
    while(!IsTickOut(tick))
    {
        if(xSemaphoreTake(Form_ReadQ, 500) != pdTRUE)
            continue;

        count = LoopBuff_GetCount(&Form_ReadM);
        while(count--)
        {
            memmove(&resp, LoopBuff_GetDataPtr(&Form_ReadM, Form_ReadM.info.rdPtr), sizeof(resp));
            LoopBuff_RemoveItems(&Form_ReadM, 1);
            if(resp.Addr == addr)
            {
                while(i < resp.count && resp.byte[i] != 0xFF && resp.byte[i] != 0)
                    i++;

                memset(val, 0, size);
                if(i >= size)
                    memmove(val, resp.byte, size - 1);
                else
                    memmove(val, resp.byte, i);
                return 1;
            }
        }
    }

    return 0;
}

// 恢复参数
void Form_RestoreParam()
{
    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    formData.oper = DWIN_OPER_WRITE;
    // 加入队列
    formData.Addr = 0x5014;
    formData.count = 2;
    formData.word[0] = htons(dcBuff.configBottle.emptyPct / 100);
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    formData.Addr = 0x5016;
    formData.count = 2;
    formData.word[0] = htons(dcBuff.configBottle.fullPct / 100);
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    formData.Addr = 0x5018;
    formData.count = 4;
    formData.dword[0] = htonl(dcBuff.configBottle.warnPress / 10);
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    formData.Addr = 0x501A;
    formData.count = 4;
    formData.dword[0] = htonl(dcBuff.configBottle.warnPressH / 10);
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    formData.Addr = 0x501C;
    formData.count = 4;
    formData.dword[0] = htonl(dcBuff.configBottle.warnTempr);
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    formData.Addr = 0x501E;
    formData.count = 4;
    formData.dword[0] = htonl(dcBuff.configBottle.warnTemprH);
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    formData.Addr = 0x5020;
    formData.count = 4;
    formData.dword[0] = htonl(dcBuff.configBottle.offlineSeconds);
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
		
		formData.Addr = 0x5038;
    formData.count = 2;
    formData.dword[0] = htons(dcBuff.configBottle.lora_freq);
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);
}

// 保存参数
uint8_t Form_SaveParam()
{
    uint16_t emptyPct, fullPct, lora_freq;
    uint32_t warnPress, warnPressH, offlineSeconds;
    int32_t warnTempr, warnTemprH;
    uint8_t save = 0;

    if(!Form_ReadUInt16(0x5014, &emptyPct))
        return 0;
    if(!Form_ReadUInt16(0x5016, &fullPct))
        return 0;
    if(!Form_ReadUInt32(0x5018, &warnPress))
        return 0;
    if(!Form_ReadUInt32(0x501A, &warnPressH))
        return 0;
    if(!Form_ReadInt32(0x501C, &warnTempr))
        return 0;
    if(!Form_ReadInt32(0x501E, &warnTemprH))
        return 0;
    if(!Form_ReadUInt32(0x5020, &offlineSeconds))
        return 0;
  if(!Form_ReadUInt16(0x5038, &lora_freq))
        return 0;
	
    if(emptyPct * 100 != dcBuff.configBottle.emptyPct)
    {
        dcBuff.configBottle.emptyPct = emptyPct * 100;
        save = 1;
    }
    if(fullPct * 100 != dcBuff.configBottle.fullPct)
    {
        dcBuff.configBottle.fullPct = fullPct * 100;
        save = 1;
    }
    if(warnPress * 10 != dcBuff.configBottle.warnPress)
    {
        dcBuff.configBottle.warnPress = warnPress * 10;
        save = 1;
    }
    if(warnPressH * 10 != dcBuff.configBottle.warnPressH)
    {
        dcBuff.configBottle.warnPressH = warnPressH * 10;
        save = 1;
    }
    if(warnTempr != dcBuff.configBottle.warnTempr)
    {
        dcBuff.configBottle.warnTempr = warnTempr;
        save = 1;
    }
    if(warnTemprH != dcBuff.configBottle.warnTemprH)
    {
        dcBuff.configBottle.warnTemprH = warnTemprH;
        save = 1;
    }
    if(offlineSeconds != dcBuff.configBottle.offlineSeconds)
    {
        dcBuff.configBottle.offlineSeconds = offlineSeconds;
        save = 1;
    }
    if(lora_freq != dcBuff.configBottle.lora_freq)
    {
        dcBuff.configBottle.lora_freq = lora_freq;
        save = 1;
    }
    if(save)
        Config_SaveConfig();

    return 1;
}

// 修改PSN
uint8_t Form_ModifyPSN(form_data_t *key, char *msg)
{
    uint8_t PSN[6];
    char str[26];
    uint8_t len, i = 0;
    u16 serial = 0;
    char errMsg[20] =  "PSN输入有误!";
    char errMsgEn[20] =  "PSN incorrect";
    if(dcBuff.configDisplay.ch_en)
    {

        strcpy(errMsg, errMsgEn);

    }

    // 读取PSN
    while(i < key->count && key->byte[i] != 0xFF && key->byte[i] != 0)
        i++;
    memset(str, 0, sizeof(str));
    if(i >= sizeof(str))
        memmove(str, key->byte, sizeof(str) - 1);
    else
        memmove(str, key->byte, i);

    len = strlen(str);
    if(len != 13)
    {
        strcpy(msg, errMsg);
        return 0;
    }
    if(str[0] != '2' || str[1] != '0')
    {
        strcpy(msg, errMsg);
        return 0;
    }
    for(i = 0; i < len; i++)
    {
        if(!isdigit(str[i]))
        {
            strcpy(msg, errMsg);
            return 0;
        }
    }
    \
    serial = atoi(str + 10);
    PSN[5] = serial & 0xFF;
    PSN[4] = serial >> 8;

    str[10] = 0;
    PSN[3] = atoi(str + 8);
    str[8] = 0;
    PSN[2] = atoi(str + 6);
    str[6] = 0;
    PSN[1] = atoi(str + 4);
    str[4] = 0;
    PSN[0] = atoi(str + 2);

    if(memcmp(dcBuff.configBottle.PSN, PSN, 6) != 0)
    {
        memmove(dcBuff.configBottle.PSN, PSN, 6);
        Config_SaveConfig();
    }

    return 1;
}

// 读取查询条件
uint8_t Form_GetQuery(uint16_t func, char *msg)
{
    char str[26];
    uint8_t len, i;
    u16 serial = 0, y = 2000, m = 1, d = 1;

    char errMsg[5][20] =
    {
        "通信故障!",
        "罐箱号输入有误!",
        "PSN输入有误!",
        "起始日期输入有误!",
        "查询天数输入有误!"
    };
    char errMsgEn[5][20] =
    {
        "Commu failure!",
        "Box number err",
        "The PSN err",
        "startdate err.",
        " days err"
    };
    if(dcBuff.configDisplay.ch_en)
    {
        for (i = 0; i < 5; ++i) {
            strcpy(errMsg[i], errMsgEn[i]);
        }
    }

    // 读取罐箱号
    if(!Form_ReadStr(0x5E00, str, sizeof(str)))
    {
        strcpy(msg, errMsg[0]);
        return 0;
    }
    len = strlen(str);
    if(len != 0 && len != 11)
    {
        strcpy(msg, errMsg[1]);
        return 0;
    }
    // 转换成大写
    for(i = 0; i < len; i++)
    {
        if(str[i] >= 'a' && str[i] <= 'z')
            str[i] -= 32;
    }
    strcpy(formQuery.TGGU, str);
    formQuery.tgguFlag = (len > 0);

    // 读取PSN
    if(!Form_ReadStr(0x5E80, str, sizeof(str)))
    {
        strcpy(msg, errMsg[0]);
        return 0;
    }
    len = strlen(str);
    if(len != 0 && len != 13)
    {
        strcpy(msg, errMsg[2]);
        return 0;
    }
    if(len > 0 && (str[0] != '2' || str[1] != '0'))
    {
        strcpy(msg, errMsg[2]);
        return 0;
    }
    for(i = 0; i < len; i++)
    {
        if(!isdigit(str[i]))
        {
            strcpy(msg, errMsg[2]);
            return 0;
        }
    }
    if(len > 0)
    {
        serial = atoi(str + 10);
        formQuery.PSN[5] = serial & 0xFF;
        formQuery.PSN[4] = serial >> 8;

        str[10] = 0;
        formQuery.PSN[3] = atoi(str + 8);
        str[8] = 0;
        formQuery.PSN[2] = atoi(str + 6);
        str[6] = 0;
        formQuery.PSN[1] = atoi(str + 4);
        str[4] = 0;
        formQuery.PSN[0] = atoi(str + 2);
    }
    formQuery.psnFlag = (len > 0);

    // 读取起始日期
    if(func == 2 || func == 3)
    {
        if(!Form_ReadStr(0x5F00, str, sizeof(str)))
        {
            strcpy(msg, errMsg[0]);
            return 0;
        }
        len = strlen(str);
        if(len != 0 && len != 8)
        {
            strcpy(msg, errMsg[3]);
            return 0;
        }
        if(len > 0)
        {
            for(i = 0; i < len; i++)
            {
                if(!isdigit(str[i]))
                {
                    strcpy(msg, errMsg[3]);
                    return 0;
                }
            }

            d = atoi(str + 6);
            str[6] = 0;
            m = atoi(str + 4);
            str[4] = 0;
            y = atoi(str);
            if( y < 2000 || y > 2099 || m < 1 || m > 12 || d < 1 || d > get_month_days(y, m))
            {
                strcpy(msg, errMsg[3]);
                return 0;
            }
            formQuery.date = y * 10000 + m * 100 + d;
        }
        formQuery.dateFlag = (len > 0);
    }

    // 读取查询天数
    if(func == 3)
    {
        if(!Form_ReadStr(0x5F80, str, sizeof(str)))
        {
            strcpy(msg, errMsg[0]);
            return 0;
        }
        len = strlen(str);
        if(len == 0)
            formQuery.days = 1;
        else
        {
            for(i = 0; i < len; i++)
            {
                if(!isdigit(str[i]))
                {
                    strcpy(msg, errMsg[4]);
                    return 0;
                }
            }
            formQuery.days = atoi(str);
            if(formQuery.days < 1 || formQuery.days > 12)
            {
                strcpy(msg, errMsg[4]);
                return 0;
            }
        }
    }

    if(func == 1 || func == 2)
    {
        // 读取正常选项
        if(!Form_ReadInt16(0x5024, &formQuery.normal))
        {
            strcpy(msg, errMsg[0]);
            return 0;
        }
        // 读取故障选项
        if(!Form_ReadInt16(0x5026, &formQuery.fault))
        {
            strcpy(msg, errMsg[0]);
            return 0;
        }
        // 读取报警选项
        if(!Form_ReadInt16(0x5028, &formQuery.warn))
        {
            strcpy(msg, errMsg[0]);
            return 0;
        }
    }

    if(func == 1)
    {
        // 读取离线选项
        if(!Form_ReadInt16(0x502A, &formQuery.offline))
        {
            strcpy(msg, errMsg[0]);
            return 0;
        }
    }

    return 1;
}

// 设置查询表头
uint8_t Form_PreQuery()
{
    int16_t idx, len;

    // 储罐要判断是否离线
    if(formQuery.func == 1 && RTC_offsetSeconds == 0)
    {
        if(dcBuff.configDisplay.ch_en)
            Form_DispMessage("The time  not obtained!", DWIN_COLOR_RED);
        else
            Form_DispMessage("尚未获取基站时间!", DWIN_COLOR_RED);
        return 0;
    }

    // 曲线只能查询唯一PSN的数据
    if(formQuery.func == 3 && !formQuery.tgguFlag && !formQuery.psnFlag)
    {
        if(dcBuff.configDisplay.ch_en)
            Form_DispMessage("Enter the Box number or PSN", DWIN_COLOR_RED);
        else
            Form_DispMessage("请输入罐箱号或PSN!", DWIN_COLOR_RED);
        return 0;
    }

    // 如果输入了罐箱号或PSN，只能查询一个罐子的数据，罐箱号或PSN不能冲突
    if(formQuery.tgguFlag)
    {
        // 查找储罐扩展档案
        idx = Ext_Lookup_Box_TGGU(formQuery.TGGU, boxCnt.count);
        if(idx == -1)
        {
            if(dcBuff.configDisplay.ch_en)
                Form_DispMessage("There is no box number", DWIN_COLOR_RED);
            else
                Form_DispMessage("无此罐箱号!", DWIN_COLOR_RED);
            return 0;
        }
        if(formQuery.psnFlag && memcmp(formQuery.PSN, boxTGGU[idx].PSN, 6) != 0)
        {
            if(dcBuff.configDisplay.ch_en)
                Form_DispMessage("Box number conflicts with  PSN", DWIN_COLOR_RED);
            else
                Form_DispMessage("罐箱号和PSN冲突!", DWIN_COLOR_RED);
            return 0;
        }
        // 记录PSN，用于查询显示
        memmove(formQuery.PSN, boxTGGU[idx].PSN, 6);
    }
    else if(formQuery.psnFlag)
    {
        // 查找储罐扩展档案
        idx = Ext_Lookup_Box_PSN(formQuery.PSN, boxCnt.count);
        if(idx >= 0)
        {
            // 记录TGGU，用于显示
            strcpy(formQuery.TGGU, boxPSN[idx].TGGU);
        }
    }

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    if(formQuery.func == 1 || formQuery.func == 2)
    {
        // 加入队列
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = gridQuery.hdrAddr;
        if(formQuery.func == 1)
        {
            if(dcBuff.configDisplay.ch_en)
                sprintf(formData.str, " %4s %11s  %6s %9s %8s %4s %4s %4s  %13s  %5s %5s %7s",
                        "Num", "  Box_number  ", "Percentage", "Press(MPa)", "Temp(℃)", "Alarm", "Err", "Offline", "     PSN     ", "Date", "Time", "Vol(v)");

            else
                sprintf(formData.str, " %4s %11s  %6s %9s %8s %4s %4s %4s  %13s  %5s %5s %7s",
                        "序号", "  罐箱号   ", "百分比", "压力(MPa)", "温度(℃)", "报警", "故障", "离线", "     PSN     ", "日期", "时间", "电压(v)");
        }
        else if(formQuery.func == 2)
        {
            if(dcBuff.configDisplay.ch_en)
                sprintf(formData.str, " %5s %5s  %11s  %10s %8s %6s %9s %8s %4s %4s  %13s",
                        "Data", "Time", " Box_number ", "Level(mmWC)", "m(kg)", "Percent", "Press(MPa)", "Temp(℃)", "Alarm", "Err", "     PSN     ");

            else
                sprintf(formData.str, " %5s %5s  %11s  %10s %8s %6s %9s %8s %4s %4s  %13s",
                        " 日期", " 时间", "  罐箱号   ", "液位(mmWC)", "质量(kg)", "百分比", "压力(MPa)", "温度(℃)", "报警", "故障", "     PSN     ");
        }
        len = strlen(formData.str);
        memset(formData.str + len, ' ', sizeof(formData.str) - len);
        formData.count = sizeof(formData.str);
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }
    else if(formQuery.func == 3)
    {
        // 显示标题
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = 0x6960;
        sprintf(formData.str, "%s / 20%02d%02d%02d%02d%03d",
                formQuery.TGGU, formQuery.PSN[0], formQuery.PSN[1], formQuery.PSN[2], formQuery.PSN[3],
                (formQuery.PSN[4] << 8) | formQuery.PSN[5]);
        formData.count = strlen(formData.str);
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }

    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);

    // 切换页面
    Form_ClearGrid(&gridQuery);
    Form_SwitchPage(17 + (formQuery.func - 1));
    // 用于翻页的序号
    gridQuery.topPtr = -1;

    return 1;
}

// 查询储罐
void Form_QueryBox(int32_t lastRec)
{
    int16_t idx;
    int32_t i, topPtr;
    ext_box_t boxRec;
    ext_bottle_t bottleRec;
    uint32_t seconds;
    uint8_t offline, included, row = 0;
    S_RTC_TIME_DATA_T sRTC;
    char pct[8], press[8], tempr[8], date[6], time[6], voltage[8];

    static int16_t dispNo = 1;
    static ext_data_t Gprs;
    rf_app_data_t *pData = (rf_app_data_t *) Gprs.payload;

    // 初始化记录序号
    if(lastRec == -1)
        dispNo = 1;

    // 获取实时时钟
    seconds = rf_get_seconds();

    // 查询记录：按罐箱号排序
    for(i = lastRec + 1; i < boxCnt.count && row < gridQuery.rowCount; i++)
    {
        FRAM_BufferRead(FRAM_BOX_DATA_BASE + sizeof(ext_box_t) * boxTGGU[i].recNo, (uint8_t *) &boxRec, sizeof(ext_box_t));
        // 记录用于翻页
        topPtr = i;

        idx = Ext_Lookup_Bottle_PSN(boxRec.PSN, bottleCnt.count);
        if(idx >= 0)
        {
            // 判断是否离线
            FRAM_BufferRead(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * bottlePSN[idx].recNo, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
            offline = (bottleRec.recvTime + dcBuff.configBottle.offlineSeconds <= RTC_offsetSeconds + seconds);
        }

        // 判断筛选条件
        included = 0;

        // 如果输入了罐箱号或PSN, 则忽略储罐状态
        if(formQuery.psnFlag || formQuery.tgguFlag)
            included = 1;
        // 复选框为或的逻辑关系
        if(formQuery.offline && (idx < 0 || offline))
            included = 1;
        else if(formQuery.normal && (idx >= 0 && !bottleRec.warn && !bottleRec.fault && !offline))
            included = 1;
        else if(formQuery.fault && (idx >= 0 && bottleRec.fault))
            included = 1;
        else if(formQuery.warn && (idx >= 0 && bottleRec.warn))
            included = 1;

        // 如果输入了罐箱号或PSN
        if(formQuery.psnFlag && memcmp(boxRec.PSN, formQuery.PSN, 6) != 0)
            included = 0;
        else if(formQuery.tgguFlag && strcmp(boxRec.TGGU, formQuery.TGGU) != 0)
            included = 0;

        if(!included)
            continue;

        strcpy(pct, "");
        strcpy(press, "");
        strcpy(tempr, "");
        strcpy(date, "");
        strcpy(time, "");
        strcpy(voltage, "");
        if(idx >= 0 && bottleRec.lastData >= 0)
        {
            // 读取最后一条记录
            SFlash_LoadInfo(LoopBuff_GetDataPos(&RF_DataM, bottleRec.lastData), (uint8_t *) &Gprs, sizeof(ext_data_t));

            if(pData->Sensor.staDiff == RF_SENSOR_STATUS_NOCONNECT)
                strcpy(pct, "---");
            else if(pData->Sensor.staDiff == RF_SENSOR_STATUS_UNDERFLOW)
                strcpy(pct, "-EE");
            else if(pData->Sensor.staDiff == RF_SENSOR_STATUS_OVERFLOW)
                strcpy(pct, "+EE");
            else
                sprintf(pct, "%.1f", Gprs.volumePct * 0.01);

            if(pData->Sensor.staPress == RF_SENSOR_STATUS_NOCONNECT)
                strcpy(press, "---");
            else if(pData->Sensor.staPress == RF_SENSOR_STATUS_UNDERFLOW)
                strcpy(press, "-EE");
            else if(pData->Sensor.staPress == RF_SENSOR_STATUS_OVERFLOW)
                strcpy(press, "+EE");
            else
                sprintf(press, "%.2f", pData->press * 0.001);
            if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_NOCONNECT)
                strcpy(tempr, "---");
            else if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_UNDERFLOW)
                strcpy(tempr, "-EE");
            else if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_OVERFLOW)
                strcpy(tempr, "+EE");
            else
                sprintf(tempr, "%d", pData->tempr);

            Wakeup_CalcUTCTime(Gprs.recvTime - pData->relative_time, &sRTC);
            sprintf(date, "%02d-%02d", sRTC.u32Month, sRTC.u32Day);
            sprintf(time, "%02d:%02d", sRTC.u32Hour, sRTC.u32Minute);

            sprintf(voltage, "%.2f", pData->voltage * 0.01);
        }
        sprintf(gridQuery.rowStr[row++], " %3d  %11s  %5s  %7s   %6s   %2s   %2s   %2s    20%02d%02d%02d%02d%03d  %5s %5s %5s ",
                dispNo++, boxRec.TGGU, pct, press, tempr,
                ((idx >= 0 && bottleRec.warn) ? "W" : ""),
                ((idx >= 0 && bottleRec.fault) ? "F" : ""),
                ((idx < 0 || offline) ? "L" : ""),
                boxRec.PSN[0], boxRec.PSN[1], boxRec.PSN[2], boxRec.PSN[3], (boxRec.PSN[4] << 8) | boxRec.PSN[5],
                date, time, voltage);
    }

    if(row < gridQuery.rowCount)
    {
        if(dcBuff.configDisplay.ch_en)
            Form_DispMessage("There are no more records.", DWIN_COLOR_RED);
        else
            Form_DispMessage("没有更多记录!", DWIN_COLOR_GREEN);
    }
    else
    {
        Form_ClearMessage();
        // 满页才更新起始序号
        gridQuery.topPtr = topPtr;
    }

    if(row > 0)
    {
        // 清除未满的记录
        while(row < gridQuery.rowCount)
            strcpy(gridQuery.rowStr[row++], "");
        // 刷新表格
        Form_RefreshGrid(&gridQuery);
    }
}

// 查询数据
void Form_QueryData(int32_t lastRec)
{
    int16_t idx;
    int32_t topPtr;
    ext_bottle_t bottleRec;
    uint8_t included, row = 0;
    S_RTC_TIME_DATA_T sRTC;
    char tggu[16], pct[8], mmWC[8], kg[8], press[8], tempr[8];
    uint32_t minTime = 0xFFFFFFFF;

    static ext_data_t Gprs;
    rf_app_data_t *pData = (rf_app_data_t *) Gprs.payload;

    if(lastRec == -1) // 首页
    {
        // 查询单个储罐
        if(formQuery.tgguFlag || formQuery.psnFlag)
        {
            // 查找储罐档案
            idx = Ext_Lookup_Bottle_PSN(formQuery.PSN, bottleCnt.count);
            if(idx >= 0)
                FRAM_BufferRead(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * bottlePSN[idx].recNo, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
            if(idx < 0 || bottleRec.lastData < 0)
            {
                if(dcBuff.configDisplay.ch_en)
                    Form_DispMessage("There is no data for PSN", DWIN_COLOR_RED);
                else
                    Form_DispMessage("无此PSN的数据!", DWIN_COLOR_RED);
                return;
            }

            lastRec = bottleRec.lastData;
        }
        else // 查询所有储罐
        {
            if(LoopBuff_GetCount(&RF_DataM) > 0)
            {
                if(RF_DataM.info.wtPtr == 0)
                    lastRec = RF_DataM.maxItemCount;
                else
                    lastRec = RF_DataM.info.wtPtr - 1;
            }
        }
    }
    else // 翻页
    {
        // 查询单个储罐
        if(formQuery.tgguFlag || formQuery.psnFlag)
        {
            // 读取上一条记录
            SFlash_LoadInfo(LoopBuff_GetDataPos(&RF_DataM, lastRec), (uint8_t *) &Gprs, sizeof(ext_data_t));
            minTime = Gprs.recvTime - pData->relative_time;
            if(lastRec == RF_DataM.info.rdPtr)
                lastRec = -1;
            else
                lastRec = Gprs.prevData;
        }
        else	// 查询所有储罐
        {
            if(lastRec == RF_DataM.info.rdPtr)
                lastRec = -1;
            else if(lastRec == 0)
                lastRec = RF_DataM.maxItemCount;
            else
                lastRec--;
        }
    }

    while(lastRec != -1 && row < gridQuery.rowCount)
    {
        // 读取最后一条记录
        SFlash_LoadInfo(LoopBuff_GetDataPos(&RF_DataM, lastRec), (uint8_t *) &Gprs, sizeof(ext_data_t));
        // 记录用于翻页
        topPtr = lastRec;
        // 前一条记录
        if(formQuery.tgguFlag || formQuery.psnFlag) // 查询单个储罐
        {
            // 记录已被覆盖
            if(memcmp(Gprs.oriPSN, formQuery.PSN, 6) != 0 || Gprs.recvTime - pData->relative_time > minTime)
                break;
            minTime = Gprs.recvTime - pData->relative_time;
            if(lastRec == RF_DataM.info.rdPtr)
                lastRec = -1;
            else
                lastRec = Gprs.prevData;
        }
        else	// 查询所有储罐
        {
            if(lastRec == RF_DataM.info.rdPtr)
                lastRec = -1;
            else if(lastRec == 0)
                lastRec = RF_DataM.maxItemCount;
            else
                lastRec--;
        }

        // 判断日期
        Wakeup_CalcUTCTime(Gprs.recvTime - pData->relative_time, &sRTC);
        if(formQuery.dateFlag && sRTC.u32Year * 10000 + sRTC.u32Month * 100 + sRTC.u32Day > formQuery.date)
            continue;

        // 判断筛选条件
        included = 0;

        if(formQuery.normal && (!Gprs.warn && !Gprs.fault))
            included = 1;
        else if(formQuery.fault && Gprs.fault)
            included = 1;
        else if(formQuery.warn && Gprs.warn)
            included = 1;

        if(!included)
            continue;

        if(formQuery.tgguFlag || formQuery.psnFlag)
            strcpy(tggu, formQuery.TGGU);
        else
        {
            // 查找储罐档案
            idx = Ext_Lookup_Box_PSN(Gprs.oriPSN, boxCnt.count);
            if(idx >= 0)
                strcpy(tggu, boxPSN[idx].TGGU);
            else
                strcpy(tggu, "");
        }
        if(pData->Sensor.staDiff == RF_SENSOR_STATUS_NOCONNECT)
        {
            strcpy(mmWC, "---");
            strcpy(kg, "---");
            strcpy(pct, "---");
        }
        else if(pData->Sensor.staDiff == RF_SENSOR_STATUS_UNDERFLOW)
        {
            strcpy(mmWC, "-EE");
            strcpy(kg, "-EE");
            strcpy(pct, "-EE");
        }
        else if(pData->Sensor.staDiff == RF_SENSOR_STATUS_OVERFLOW)
        {
            strcpy(mmWC, "+EE");
            strcpy(kg, "+EE");
            strcpy(pct, "+EE");
        }
        else
        {
            sprintf(mmWC, "%d", (uint32_t) KPa2mmH2O(pData->diff * 0.01));
            sprintf(kg, "%d", (uint32_t) Vol2Quantity(Gprs.volume, pData->density * 0.001));
            sprintf(pct, "%.1f", Gprs.volumePct * 0.01);
        }

        if(pData->Sensor.staPress == RF_SENSOR_STATUS_NOCONNECT)
            strcpy(press, "---");
        else if(pData->Sensor.staPress == RF_SENSOR_STATUS_UNDERFLOW)
            strcpy(press, "-EE");
        else if(pData->Sensor.staPress == RF_SENSOR_STATUS_OVERFLOW)
            strcpy(press, "+EE");
        else
            sprintf(press, "%.2f", pData->press * 0.001);
        if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_NOCONNECT)
            strcpy(tempr, "---");
        else if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_UNDERFLOW)
            strcpy(tempr, "-EE");
        else if(pData->Sensor.staETempr1 == RF_SENSOR_STATUS_OVERFLOW)
            strcpy(tempr, "+EE");
        else
            sprintf(tempr, "%d", pData->tempr);

        sprintf(gridQuery.rowStr[row++], " %02d-%02d %02d:%02d  %11s  %7s    %7s  %5s  %7s   %6s   %2s   %2s    20%02d%02d%02d%02d%03d",
                sRTC.u32Month, sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute,
                tggu, mmWC, kg, pct, press, tempr, (Gprs.warn ? "W" : ""), (Gprs.fault ? "F" : ""),
                Gprs.oriPSN[0], Gprs.oriPSN[1], Gprs.oriPSN[2], Gprs.oriPSN[3], (Gprs.oriPSN[4] << 8) | Gprs.oriPSN[5]);
    }

    if(row < gridQuery.rowCount)
    {
        if(dcBuff.configDisplay.ch_en)
            Form_DispMessage("There are no more records.", DWIN_COLOR_GREEN);
        else
            Form_DispMessage("没有更多记录!", DWIN_COLOR_GREEN);
    }
    else
    {
        Form_ClearMessage();
        // 满页才更新起始序号
        gridQuery.topPtr = topPtr;
    }

    if(row > 0)
    {
        // 清除未满的记录
        while(row < gridQuery.rowCount)
            strcpy(gridQuery.rowStr[row++], "");
        // 刷新表格
        Form_RefreshGrid(&gridQuery);
    }
}

// 清除一条曲线的作图区域
void Form_ClearCurve(uint16_t curveAddr)
{
    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    // 清除曲线: 在区域以外打一个点
    formData.oper = DWIN_OPER_WRITE;
    formData.Addr = curveAddr;
    formData.count = 10;
    formData.word[0] = htons(0x0001);
    formData.word[1] = htons(1);
    formData.word[2] = htons(0xFFFF);
    formData.word[3] = htons(0xFFFF);
    formData.word[4] = htons(0);
    // 加入队列
    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);
}

// 清除全部作图区域
void Form_ClearCurves()
{
    uint16_t levelAddr = 0x2800, pressAddr = 0x3555, temprAddr = 0x42AA;

    Form_ClearCurve(levelAddr);
    Form_ClearCurve(pressAddr);
    Form_ClearCurve(temprAddr);
}

// 查询曲线
void Form_QueryCurve(int32_t lastRec)
{
#if 1
    int16_t idx, i;
    ext_bottle_t bottleRec;
    uint16_t levelRow, pressRow, temprRow;
    uint16_t levelCnt = 0, pressCnt = 0, temprCnt = 0, done = 0;
    int32_t topPtr;
    S_RTC_TIME_DATA_T sRTC;
    static uint16_t levelBuff[40], pressBuff[40], temprBuff[40];
    static ext_data_t Gprs;
    rf_app_data_t *pData = (rf_app_data_t *) Gprs.payload;
    uint32_t axisMin, axisMax, axisRange, axisTime, axisSeg = 12;
    const float x0 = 282, w = 930,
                          y0 = 579, h = -421;
    const float levelMin = 0, levelRange = 10000,
                              pressMin = 0, pressRange = 5000,
                                            temprMin = -210, temprRange = 300;
    uint16_t levelAddr = 0x2800, pressAddr = 0x3555, temprAddr = 0x42AA;
    uint16_t levelColor = DWIN_COLOR_GREEN, pressColor = DWIN_COLOR_YELLOW, temprColor = DWIN_COLOR_RED;
    uint16_t x, y;
    uint32_t minTime = 0xFFFFFFFF;

    // 计算日期范围
    axisRange = formQuery.days * 86400;

    if(lastRec == -1) // 首页
    {
        // 查找储罐档案
        idx = Ext_Lookup_Bottle_PSN(formQuery.PSN, bottleCnt.count);
        if(idx >= 0)
            FRAM_BufferRead(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * bottlePSN[idx].recNo, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));
        if(idx < 0 || bottleRec.lastData < 0)
        {
            Form_ClearCurves();
            if(dcBuff.configDisplay.ch_en)
                Form_DispMessage("There is no data for PSN", DWIN_COLOR_RED);
            else
                Form_DispMessage("无此PSN的数据!", DWIN_COLOR_RED);
            return;
        }

        if(!formQuery.dateFlag)
        {
            bottleRec.recvTime -= bottleRec.recvTime % 86400;
            bottleRec.recvTime += 86400;
            bottleRec.recvTime -= 86400 * formQuery.days;
            Wakeup_CalcUTCTime(bottleRec.recvTime, &sRTC);
            formQuery.date = sRTC.u32Year * 10000 + sRTC.u32Month * 100 + sRTC.u32Day;
        }

        lastRec = bottleRec.lastData;

        // 设置时间轴范围
        sRTC.u32Year = formQuery.date / 10000;
        sRTC.u32Month = (formQuery.date % 10000) / 100;
        sRTC.u32Day = formQuery.date % 100;
        sRTC.u32Hour = 0;
        sRTC.u32Minute = 0;
        sRTC.u32Second = 0;
        axisMin = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month,
                                       sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
        axisMax = axisMin + axisRange;
    }
    else // 翻页
    {
        // 读取上一条记录
        SFlash_LoadInfo(LoopBuff_GetDataPos(&RF_DataM, lastRec), (uint8_t *) &Gprs, sizeof(ext_data_t));
        minTime = Gprs.recvTime - pData->relative_time;
        if(lastRec == RF_DataM.info.rdPtr)
            lastRec = -1;
        else
            lastRec = Gprs.prevData;

        // 设置时间轴范围
        sRTC.u32Year = formQuery.date / 10000;
        sRTC.u32Month = (formQuery.date % 10000) / 100;
        sRTC.u32Day = formQuery.date % 100;
        sRTC.u32Hour = 0;
        sRTC.u32Minute = 0;
        sRTC.u32Second = 0;
        axisMax = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month,
                                       sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
        axisMin = axisMax - axisRange;
        // 重置日期
        Wakeup_CalcUTCTime(axisMin, &sRTC);
        formQuery.date = sRTC.u32Year * 10000 + sRTC.u32Month * 100 + sRTC.u32Day;
    }

    // 设置时间轴
    for(i = 0; i <= axisSeg; i++)
    {
        axisTime = axisMin + (axisMax - axisMin) / axisSeg * i;
        Wakeup_CalcUTCTime(axisTime, &sRTC);
        // 时间标签
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = 0x67C0 + i * 0x10;
        sprintf(formData.str, "%02d:%02d", sRTC.u32Hour, sRTC.u32Minute);
        formData.count = strlen(formData.str);
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
        // 日期标签
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = 0x6890 + i * 0x10;
        sprintf(formData.str, "%02d-%02d", sRTC.u32Month, sRTC.u32Day);
        formData.count = strlen(formData.str);
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }

    while(lastRec != -1 && !done)
    {
        for(levelRow = 0, pressRow = 0, temprRow = 0; lastRec != -1 && !done; )
        {
            // 读取最后一条记录
            SFlash_LoadInfo(LoopBuff_GetDataPos(&RF_DataM, lastRec), (uint8_t *) &Gprs, sizeof(ext_data_t));
            // 记录用于翻页
            topPtr = lastRec;
            // 记录已被覆盖
            if(memcmp(Gprs.oriPSN, formQuery.PSN, 6) != 0 || Gprs.recvTime - pData->relative_time > minTime)
                break;
            minTime = Gprs.recvTime - pData->relative_time;
            if(lastRec == RF_DataM.info.rdPtr)
                lastRec = -1;
            else
                lastRec = Gprs.prevData;

            // 判断日期
            axisTime = Gprs.recvTime - pData->relative_time;
            if(axisTime >= axisMax)
                continue;
            if(axisTime < axisMin)
            {
                done = 1;
                break;
            }

            // 计算坐标点
            x = (uint16_t) (x0 + (axisTime - axisMin) * w / axisRange);
            if(pData->Sensor.staDiff == 0)
            {
                y = (uint16_t) (y0 + (Gprs.volumePct - levelMin) * h / levelRange);
                //y += rand() % 100;
                levelBuff[levelRow * 2] = htons(x);
                levelBuff[levelRow * 2 + 1] = htons(y);
                levelRow++;
                levelCnt++;
            }
            if(pData->Sensor.staPress == 0)
            {
                y = (uint16_t) (y0 + (pData->press - pressMin) * h / pressRange);
                //y += rand() % 100;
                pressBuff[pressRow * 2] = htons(x);
                pressBuff[pressRow * 2 + 1] = htons(y);
                pressRow++;
                pressCnt++;
            }
            if(pData->Sensor.staETempr1 == 0)
            {
                y = (uint16_t) (y0 + (pData->tempr - temprMin) * h / temprRange);
                //y += rand() % 100;
                temprBuff[temprRow * 2] = htons(x);
                temprBuff[temprRow * 2 + 1] = htons(y);
                temprRow++;
                temprCnt++;
            }

            // 一次最多发送20个点
            if(levelRow >= 20 || pressRow >= 20 || temprRow >= 20)
                break;

            // 总共最多查询1700个点
            if(levelCnt >= 1700 || pressCnt >= 1700 || temprCnt >= 1700)
            {
                done = 1;
                break;
            }
        }

        // 加锁
        xSemaphoreTake(Form_DataLock, portMAX_DELAY);

        if(levelRow > 0)
        {
            formData.oper = DWIN_OPER_WRITE;
            formData.Addr = levelAddr + 3 + (levelCnt - levelRow) * 2;
            formData.count = levelRow * 4;
            memmove(formData.byte, levelBuff, formData.count);

            // 加入队列
            LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
        }
        if(pressRow > 0)
        {
            formData.oper = DWIN_OPER_WRITE;
            formData.Addr = pressAddr + 3 + (pressCnt - pressRow) * 2;
            formData.count = pressRow * 4;
            memmove(formData.byte, pressBuff, formData.count);
            // 加入队列
            LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
        }
        if(temprRow > 0)
        {
            formData.oper = DWIN_OPER_WRITE;
            formData.Addr = temprAddr + 3 + (temprCnt - temprRow) * 2;
            formData.count = temprRow * 4;
            memmove(formData.byte, temprBuff, formData.count);
            // 加入队列
            LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
        }
        // 解锁
        xSemaphoreGive(Form_DataLock);

        // 发送消息给任务
        xSemaphoreGive(Form_DataQ);
    }

    // 加锁
    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

    if(levelCnt > 1)
    {
        // 画曲线
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = levelAddr;
        formData.count = 6;
        formData.word[0] = htons(0x0002);
        formData.word[1] = htons(levelCnt - 1);
        formData.word[2] = htons(levelColor);
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }
    else if(levelCnt == 1)
    {
        // 打一个点
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = levelAddr;
        formData.count = 10;
        formData.word[0] = htons(0x0001);
        formData.word[1] = htons(1);
        formData.word[2] = levelBuff[0];
        formData.word[3] = levelBuff[1];
        formData.word[4] = htons(levelColor);
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }

    if(pressCnt > 1)
    {
        // 画曲线
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = pressAddr;
        formData.count = 6;
        formData.word[0] = htons(0x0002);
        formData.word[1] = htons(pressCnt - 1);
        formData.word[2] = htons(pressColor);
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }
    else if(pressCnt == 1)
    {
        // 打一个点
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = pressAddr;
        formData.count = 10;
        formData.word[0] = htons(0x0001);
        formData.word[1] = htons(1);
        formData.word[2] = pressBuff[0];
        formData.word[3] = pressBuff[1];
        formData.word[4] = htons(pressColor);
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }

    if(temprCnt > 1)
    {
        // 画曲线
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = temprAddr;
        formData.count = 6;
        formData.word[0] = htons(0x0002);
        formData.word[1] = htons(temprCnt - 1);
        formData.word[2] = htons(temprColor);
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }
    else if(temprCnt == 1)
    {
        // 打一个点
        formData.oper = DWIN_OPER_WRITE;
        formData.Addr = temprAddr;
        formData.count = 10;
        formData.word[0] = htons(0x0001);
        formData.word[1] = htons(1);
        formData.word[2] = temprBuff[0];
        formData.word[3] = temprBuff[1];
        formData.word[4] = htons(temprColor);
        // 加入队列
        LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);
    }

    // 解锁
    xSemaphoreGive(Form_DataLock);

    // 发送消息给任务
    xSemaphoreGive(Form_DataQ);

    // 翻页设置
    if(lastRec >= 0)
        gridQuery.topPtr = topPtr;

    // 清除空曲线
    if(levelCnt == 0)
        Form_ClearCurve(levelAddr);
    if(pressCnt == 0)
        Form_ClearCurve(pressAddr);
    if(temprCnt == 0)
        Form_ClearCurve(temprAddr);
    if(levelCnt == 0 && pressCnt == 0 && temprCnt == 0)
    {
        if(dcBuff.configDisplay.ch_en)
            Form_DispMessage("No data for this time period", DWIN_COLOR_GREEN);
        else
            Form_DispMessage("无此时间段内的数据!", DWIN_COLOR_GREEN);
    }
    else if(lastRec < 0)
    {
        if(dcBuff.configDisplay.ch_en)
            Form_DispMessage("No data from an earlier time", DWIN_COLOR_GREEN);
        else
            Form_DispMessage("无更早时间的数据!", DWIN_COLOR_GREEN);
    }
    else
        Form_ClearMessage();

#else	// 测试代码，沿着边框画一个蓝色矩形	
    osDelay(1000);
    uint8_t cmd1[50] = {
        0x5A, 0xA5, 0x0F, 0x82, 0x28, 0x03,
        282 >> 8, 282 & 0xFF, 579 >> 8, 579 & 0xFF,
            282 >> 8, 282 & 0xFF, 158 >> 8, 158 & 0xFF,
            1212 >> 8, 1212 & 0xFF, 158 >> 8, 158 & 0xFF
    };
    uint8_t cmd2[50] = {
        0x5A, 0xA5, 0x0B, 0x82, 0x28, 0x09,
        1212 >> 8, 1212 & 0xFF, 579 >> 8, 579 & 0xFF,
             282 >> 8, 282 & 0xFF, 579 >> 8, 579 & 0xFF
    };
    uint8_t cmd3[50] = {
        0x5A, 0xA5, 0x09, 0x82, 0x28, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x1F
    };
    UART_Transmit(&huart10, cmd1, cmd1[2] + 3);
    UART_Transmit(&huart10, cmd2, cmd2[2] + 3);
    UART_Transmit(&huart10, cmd3, cmd3[2] + 3);
#endif
}

// 查询数据
void Form_Query(int32_t lastRec)
{
    if(formQuery.func == 1)
        Form_QueryBox(lastRec);
    else if(formQuery.func == 2)
        Form_QueryData(lastRec);
    else if(formQuery.func == 3)
        Form_QueryCurve(lastRec);
}

// 关于信息
void Form_About()
{
    uint8_t row = 0;

    sprintf(gridAbout.rowStr[row++], "  本机PSN: 20%02d%02d%02d%02d%03d",
            dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], dcBuff.configBottle.PSN[2],
            dcBuff.configBottle.PSN[3], (dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]);
    sprintf(gridAbout.rowStr[row++], " 硬件版本: %d.%d, 软件版本: %d.%d, 软件日期：20%02d-%02d-%02d",
            dcBuff.powerInfo.hardVer.major, dcBuff.powerInfo.hardVer.minor,
            dcBuff.powerInfo.softVer.major, dcBuff.powerInfo.softVer.minor,
            dcBuff.powerInfo.softDate.year, dcBuff.powerInfo.softDate.month, dcBuff.powerInfo.softDate.day);
    sprintf(gridAbout.rowStr[row++], " 通信模块: %s", dcBuff.powerInfo.dtuRevison);
    sprintf(gridAbout.rowStr[row++], "   IMEI号: %s", dcBuff.powerInfo.imeiNumber);
    sprintf(gridAbout.rowStr[row++], "  SIM卡号: %s", dcBuff.powerInfo.simNumber);
    sprintf(gridAbout.rowStr[row++], "   4G信号: %d%%, 错误代码: %s", dcBuff.dtuData.rssi, dcBuff.powerInfo.gprsFailCode);
    sprintf(gridAbout.rowStr[row++], " 定位位置: %.6f, %.6f", dcBuff.dtuData.longitude * 0.000001, dcBuff.dtuData.latitude * 0.000001);
    sprintf(gridAbout.rowStr[row++], " 定位时间: 20%02d-%02d-%02d %02d:%02d:%02d",
            dcBuff.dtuData.sysTime.year, dcBuff.dtuData.sysTime.month, dcBuff.dtuData.sysTime.day,
            dcBuff.dtuData.sysTime.hour, dcBuff.dtuData.sysTime.minute, dcBuff.dtuData.sysTime.second);
    sprintf(gridAbout.rowStr[row++], " Copyright 安捷汇物联信息技术（苏州）有限公司");

    Form_RefreshGrid(&gridAbout);
}

// 关于信息
void Form_En_About()
{
    uint8_t row = 0;
    sprintf(gridAboutEn.rowStr[row++], "  PSN: 20%02d%02d%02d%02d%03d",
            dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], dcBuff.configBottle.PSN[2],
            dcBuff.configBottle.PSN[3], (dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]);
    sprintf(gridAboutEn.rowStr[row++], " Hard ver: %d.%d, Soft ver: %d.%d, data：20%02d-%02d-%02d",
            dcBuff.powerInfo.hardVer.major, dcBuff.powerInfo.hardVer.minor,
            dcBuff.powerInfo.softVer.major, dcBuff.powerInfo.softVer.minor,
            dcBuff.powerInfo.softDate.year, dcBuff.powerInfo.softDate.month, dcBuff.powerInfo.softDate.day);
    sprintf(gridAboutEn.rowStr[row++], " Communication module version: %s", dcBuff.powerInfo.dtuRevison);
    sprintf(gridAboutEn.rowStr[row++], "   IMEI:%s", dcBuff.powerInfo.imeiNumber);
    sprintf(gridAboutEn.rowStr[row++], "   SIM: %s", dcBuff.powerInfo.simNumber);
    sprintf(gridAboutEn.rowStr[row++], "   The signal of 4G: %d%%, Err Code: %s", dcBuff.dtuData.rssi, dcBuff.powerInfo.gprsFailCode);
    sprintf(gridAboutEn.rowStr[row++], " Location : %.6f, %.6f", dcBuff.dtuData.longitude * 0.000001, dcBuff.dtuData.latitude * 0.000001);
    sprintf(gridAboutEn.rowStr[row++], " Positioning Time: 20%02d-%02d-%02d %02d:%02d:%02d",
            dcBuff.dtuData.sysTime.year, dcBuff.dtuData.sysTime.month, dcBuff.dtuData.sysTime.day,
            dcBuff.dtuData.sysTime.hour, dcBuff.dtuData.sysTime.minute, dcBuff.dtuData.sysTime.second);
    sprintf(gridAboutEn.rowStr[row++], " Copyright Anjiehui Internet of Things Information Technology (Suzhou) Co., LTD");

    Form_RefreshGrid(&gridAboutEn);
}

void Form_BOX_PSN()
{
//	static form_data_t data2;
    int i=0;
    uint8_t row = 0;
    int16_t rowCount=0;
    topPtr=0;
    gridBox.rowCount=boxCnt.count;//
    rowCount=gridBox.rowCount;
    if(rowCount>30)
		{
			rowCount=30;
			gridBox.rowCount=30;
		}
    for(i=0; i<rowCount; i++)
    {
        sprintf(gridBox.rowStr[row++], "%s 20%02d%02d%02d%02d%03d",
                boxTGGU[i].TGGU, boxTGGU[i].PSN[0], boxTGGU[i].PSN[1], boxTGGU[i].PSN[2],
                boxTGGU[i].PSN[3], (boxTGGU[i].PSN[4] << 8) | boxTGGU[i].PSN[5]);


    }
    Form_RefreshGrid2(&gridBox);
//		boxCnt.count=12;
//                    data2.oper = DWIN_OPER_WRITE;
//                    data2.Addr = 0x9000;
//                    data2.count = 2;
//                    data2.word[0] = htons(boxCnt.count);
//                    DWIN_Refresh(&data2);

}
void Form_BOX_PSN_D0WN()
{
    int i=0;
    int16_t rowCount=0;
    uint8_t row = 0;

//boxCnt.count
    rowCount=boxCnt.count-topPtr;
    if(rowCount<31) return;
    topPtr+=30;
    rowCount-=30;
    row=0;
    if(rowCount>30)rowCount=30;
    memset(gridBox.rowStr, 0, sizeof(gridBox.rowStr));
    for(i=0; i<rowCount; i++)
    {
        sprintf(gridBox.rowStr[row++], "%s 20%02d%02d%02d%02d%03d",
                boxTGGU[topPtr+i].TGGU, boxTGGU[topPtr+i].PSN[0], boxTGGU[topPtr+i].PSN[1], boxTGGU[topPtr+i].PSN[2],
                boxTGGU[topPtr+i].PSN[3], (boxTGGU[topPtr+i].PSN[4] << 8) | boxTGGU[topPtr+i].PSN[5]);

    }
    Form_RefreshGrid2(&gridBox);

}
void Form_BOX_PSN_UP()
{
	
    int i=0;
    int16_t rowCount=0;
    uint8_t row = 0;
    if(topPtr<30)return;
    topPtr-=30;

    for(i=0; i<30; i++)
    {
        sprintf(gridBox.rowStr[row++], "%s 20%02d%02d%02d%02d%03d",
                boxTGGU[topPtr+i].TGGU, boxTGGU[topPtr+i].PSN[0], boxTGGU[topPtr+i].PSN[1], boxTGGU[topPtr+i].PSN[2],
                boxTGGU[topPtr+i].PSN[3], (boxTGGU[topPtr+i].PSN[4] << 8) | boxTGGU[topPtr+i].PSN[5]);

    }
    Form_RefreshGrid2(&gridBox);
		
 


}

// 按键任务主体
void Key_Task(void *p_arg)
{
    static form_data_t key;
    uint8_t page = 0;
    uint16_t val;
    char msg[40];

    while(1)
    {
        // 处理其它显示任务
        if(xSemaphoreTake(Form_KeyQ, 500) != pdTRUE)
            continue;
        while(LoopBuff_GetCount(&Form_KeyM) > 0)
        {
            memmove(&key, LoopBuff_GetDataPtr(&Form_KeyM, Form_KeyM.info.rdPtr), sizeof(form_data_t));
            LoopBuff_RemoveItems(&Form_KeyM, 1);

            val = ntohs(key.word[0]);
            if(key.Addr == 0x5000)			// 菜单
            {
                // 点击当前页面，不处理
                if(page == val)
                    continue;


                if((val == 3)||(val == 0x13))	// 进入设置页
                    Form_RestoreParam();
                else if(val == 4) // 显示关于信息
                {
//					Form_SwitchPage(23);	// 切换到开机画面
//					osDelay(2000);			// 延时2秒

                    Form_About();			// 显示关于信息
                }
                else if(val == 0x14) // 显示关于信息
                {
//					Form_SwitchPage(23);	// 切换到开机画面

                    Form_En_About();			// 显示关于信息

                }
                else if(val == 0x15) // 显示关于信息
                {
                    if(3==page)
                        Form_En_About();			// 显示关于信息
                    dcBuff.configDisplay.ch_en=0;
                    Config_SaveConfig();
                }
                else if(val == 0x05) // 显示关于信息
                {
                    dcBuff.configDisplay.ch_en=1;
                    if(4==page)
                        Form_En_About();			// 显示关于信息
                    Config_SaveConfig();
                }
                else if(val == 0x06) // chu罐
                {
                    Form_BOX_PSN();
                }

                page = val;
            }
            else if(key.Addr == 0x5034) // chu罐
            {
                Form_BOX_PSN_UP();
            }
            else if(key.Addr == 0x5036) // chu罐
            {
                Form_BOX_PSN_D0WN();
            }
            else if(key.Addr == 0x5012)		// 设置
            {
                if(val == 1) // 保存参数
                {
                    if(dcBuff.configDisplay.ch_en)
                        Form_DispMessage("Please enter the password.", DWIN_COLOR_GREEN);
                    else
                        Form_DispMessage("请输入密码!", DWIN_COLOR_GREEN);
                    // 弹出密码输入对话（触控区域在可视区域之外，只能由程序弹出）
                    DWIN_Touch(2040, 257);

                }
                else	// 取消
                    Form_RestoreParam();
            }
            else if(key.Addr == 0x5030)	// 保存参数的密码输入
            {
                if(ntohl(key.dword[0]) == atoi(dcBuff.configDisplay.pwd1))
                {
                    if(Form_SaveParam())
                    {
                        if(dcBuff.configDisplay.ch_en)
                            Form_DispMessage("Save successfully", DWIN_COLOR_GREEN);
                        else
                            Form_DispMessage("保存成功!", DWIN_COLOR_GREEN);
                    }
                    else
                    {
                        if(dcBuff.configDisplay.ch_en)
                            Form_DispMessage("Communication and save failure", DWIN_COLOR_RED);
                        else
                            Form_DispMessage("通信故障，保存失败!", DWIN_COLOR_RED);
                    }
                }
                else
                {
                    if(dcBuff.configDisplay.ch_en)
                        Form_DispMessage("Password error", DWIN_COLOR_RED);
                    else
                        Form_DispMessage("密码错误!", DWIN_COLOR_RED);
                }
            }
            else if(key.Addr == 0x5022)		// 查询储罐、数据和曲线
            {
                // 读取查询条件
                if(!Form_GetQuery(val, msg))
                {
                    Form_DispMessage(msg, DWIN_COLOR_RED);
                    continue;
                }
                // 设置查询功能
                formQuery.func = val;
                // 设置表头
                if(!Form_PreQuery())
                    continue;
                // 首页查询
                Form_Query(-1);
            }
            else if(key.Addr == 0x502C)	// 翻页
            {
                // 翻页查询
                Form_Query(gridQuery.topPtr);
            }
            else if(key.Addr == 0x5032)		// 修改PSN
            {
                if(dcBuff.configDisplay.ch_en)
                    Form_DispMessage("Please enter the password.", DWIN_COLOR_GREEN);
                else
                    Form_DispMessage("请输入密码!", DWIN_COLOR_GREEN);
                // 弹出密码输入对话（触控区域在可视区域之外，只能由程序弹出）
                DWIN_Touch(1541, 166);
            }
            else if(key.Addr == 0x502E)	// 修改PSN的密码输入
            {
                if(ntohl(key.dword[0]) == atoi(dcBuff.configDisplay.pwd2))
                {
                    // 设置PSN输入的默认值

                    // 加锁
                    xSemaphoreTake(Form_DataLock, portMAX_DELAY);

                    formData.oper = DWIN_OPER_WRITE;
                    // 加入队列
                    formData.Addr = 0x6F00;
                    sprintf(formData.str, "20%02d%02d%02d%02d%03d",
                            dcBuff.configBottle.PSN[0], dcBuff.configBottle.PSN[1], dcBuff.configBottle.PSN[2],
                            dcBuff.configBottle.PSN[3], (dcBuff.configBottle.PSN[4] << 8) | dcBuff.configBottle.PSN[5]);
                    formData.count = strlen(formData.str);
                    LoopBuff_PutItem(&Form_DataM, (uint8_t *) &formData);

                    // 解锁
                    xSemaphoreGive(Form_DataLock);

                    // 发送消息给任务
                    xSemaphoreGive(Form_DataQ);
                    if(dcBuff.configDisplay.ch_en)
                        Form_DispMessage("Please enter a new PSN", DWIN_COLOR_GREEN);
                    else
                        Form_DispMessage("请输入新的PSN!", DWIN_COLOR_GREEN);
                    // 弹出PSN输入对话（触控区域在可视区域之外，只能由程序弹出）
                    DWIN_Touch(2179, 166);
                }
                else
                {
                    if(dcBuff.configDisplay.ch_en)
                        Form_DispMessage("Password error", DWIN_COLOR_GREEN);
                    else
                        Form_DispMessage("密码错误!", DWIN_COLOR_RED);
                }
            }
            else if(key.Addr == 0x6F00)	// PSN输入
            {
                if(!Form_ModifyPSN(&key, msg))
                    Form_DispMessage(msg, DWIN_COLOR_RED);
                else
                {
                    if(dcBuff.configDisplay.ch_en)
                    {
                        Form_En_About(); // 刷新关于页的内容

                        Form_DispMessage("The modification was successful.", DWIN_COLOR_GREEN);
                    }
                    else
                    {
                        Form_About(); // 刷新关于页的内容

                        Form_DispMessage("修改成功!", DWIN_COLOR_GREEN);
                    }
                }
            }
        }
    }
}
