大理水控初始版本
diff --git a/supwisdom/sp_communicate.c b/supwisdom/sp_communicate.c
new file mode 100644
index 0000000..7e3ac69
--- /dev/null
+++ b/supwisdom/sp_communicate.c
@@ -0,0 +1,590 @@
+#include "sp_communicate.h"
+#include "sp_util.h"
+#include "sp_flash.h"
+#include "sp_constant.h"
+#include "sp_data.h"
+#include "sp_msgpack.h"
+#include "sp_display.h"
+#include "../sys_hw/drv_usart.h"
+
+static void sp_usart_send(sp_pos_t* pos, sp_protocol_request_t* req)
+{
+  uint8 sendBuff[264];
+  MEMCLEAR(sendBuff, sizeof(sendBuff));
+
+  pos->last_comm_status.command = req->excmd;
+  pos->last_comm_status.sendtime = sp_get_ticker();
+
+  sp_protocol_crc((uint8*)req +2, req->datalen, (uint8*)req +2 +req->datalen);
+  req->datalen += 2;
+  MEMCPY(sendBuff, req, req->datalen+2);
+  usart_send(sendBuff, req->datalen+2);
+}
+
+static uint8 sp_usart_recv(sp_pos_t* pos, sp_protocol_response_t* resp, int32 timeout_ms)
+{
+  uint32 tick = 0;
+  tick = sp_get_ticker();
+  while(1)
+  {
+    MEMCLEAR(resp, sizeof(sp_protocol_response_t));
+    usart_read((u8*)resp, sizeof(sp_protocol_response_t));
+    if(pos->last_comm_status.command == resp->excmd)
+    {
+      MEMCLEAR(&(pos->last_comm_status), sizeof(sp_comm_status_t));
+      return resp->retcode;
+    }
+    if((sp_get_ticker() - tick) >= timeout_ms)
+    {
+      return 1;
+    }
+  }
+}
+uint8 sp_comm_call(sp_pos_t* pos, sp_protocol_request_t* req,
+                   sp_protocol_response_t* resp, int32 timeout_ms)
+{
+  sp_usart_send(pos, req);
+  return sp_usart_recv(pos, resp, timeout_ms);
+}
+
+void sp_protocol_req_init(sp_protocol_request_t* req, uint8 command)
+{
+  MEMCLEAR(req,sizeof(sp_protocol_request_t));
+  req->command = PROTOCOL_COMMAND_V2;
+  req->excmd = command;
+  req->flag = PROTOCOL_FLAG_PACK(req->flag);
+  req->flag = PROTOCOL_WITHOUT_MAC(req->flag);
+  req->datalen = 3;
+}
+
+static uint16 sp_confirm_card_authentication(sp_pos_t* pos, sp_card_t* card)
+{
+  uint8 size;
+  uint16 ret;
+  int32 timeout_ms = COMM_WAIT_TIME;
+  cw_unpack_context unpack;
+  unpack_field_t field;
+  sp_protocol_response_t resp;
+
+  disp_hint_info(pos,"ÕýÔÚÉí·ÝÈÏÖ¤ÖÐ",DELAY_TIME2s);
+  ret = sp_usart_recv(pos, &resp, timeout_ms);
+  if(ret)
+  {
+    ret = RC_CARD_AUTHENTICATION;
+    return ret;
+  }
+
+  sp_unpack_init(&unpack,resp.data,resp.datalen);
+  size = sp_unpack_map_size(&unpack);
+  while(size-- > 0)
+  {
+    sp_unpack_value(&unpack,&field);
+    if(IS_KEY(PK_INT_WATERLIMIT,field.key))
+    {
+      card->waterlimit = field.val.intval;
+    }
+    else if(IS_KEY(PK_BIN_BILLNO,field.key))
+    {
+      MEMCPY(card->billno, field.val.binval, field.strlen);
+    }
+    else if(IS_KEY(PK_INT_FEEAMOUNT,field.key))
+    {
+      card->feepara.fee_amt = field.val.intval;
+    }
+    else if(IS_KEY(PK_INT_FEEUNIT, field.key))
+    {
+      card->feepara.fee_unit = field.val.intval;
+    }
+    else if(IS_KEY(PK_INT_FEESTART, field.key))
+    {
+      card->feepara.fee_start = field.val.intval;
+    }
+  }
+  disp_hint_info(pos,"Éí·ÝÈÏÖ¤³É¹¦",DELAY_TIME1s);
+  return 0;
+}
+
+//ºǫ́¶Ô¿¨µÄÉí·ÝÈÏÖ¤
+uint16 sp_card_authentication(sp_pos_t* pos, sp_card_t* card)
+{
+  uint8 ctime[6];
+  sp_protocol_request_t req;
+  cw_pack_context pack;
+  MEMCLEAR(&req, sizeof(req));
+  MEMCLEAR(&pack, sizeof(req));
+  MEMCLEAR(ctime, sizeof ctime);
+
+  sp_get_bcdtime(ctime);
+  sp_protocol_req_init(&req, SP_CMD_CARD_AUTHENTICATION);
+  sp_pack_init(&pack, req.data, sizeof(req.data));
+  cw_pack_map_size(&pack,4);
+
+  sp_pack_put_bin(&pack, PK_BIN_CARDPHYID, card->cardphyid, 4);
+  sp_pack_put_bin(&pack, PK_BIN_CITIZEN_CARDNO, card->citizen_cardno, 12);
+  sp_pack_put_bin(&pack, PK_BIN_DEVPHYID, pos->devphyid, 4);
+  sp_pack_put_bin(&pack, PK_BIN_DEVTIME, ctime, 6);
+
+  req.datalen += sp_pack_length(&pack);
+  sp_usart_send(pos, &req);
+  return sp_confirm_card_authentication(pos, card);
+}
+
+//É豸ǩµ½
+uint16 sp_async_equipment_login(sp_pos_t* pos)
+{
+  sp_protocol_request_t req;
+  cw_pack_context pack;
+  uint8 ctime[6];
+  MEMCLEAR(ctime, sizeof(ctime));
+  pos->heartbeat.heart_status = HEART_SEND;
+
+  sp_get_bcdtime(ctime);
+  sp_protocol_req_init(&req, SP_CMD_LOGIN);
+  sp_pack_init(&pack, req.data, sizeof(req.data));
+  cw_pack_map_size(&pack, 5);
+
+  sp_pack_put_bin(&pack, PK_BIN_DEVPHYID, pos->devphyid, 4);
+  sp_pack_put_bin(&pack, PK_BIN_DEVTIME, ctime, 6);
+  sp_pack_put_str(&pack, PK_STR_DEVTYPE, DEV_TYPE);
+  sp_pack_put_str(&pack, PK_STR_VERSION, PRO_VERSION);
+  sp_pack_put_bin(&pack, PK_BIN_DEVICEKEY, (pos->sysconf.deviceKey), 8);
+
+  req.datalen += sp_pack_length(&pack);
+  sp_usart_send(pos, &req);
+  return 0;
+}
+
+//ÐÄÌøÈ·ÈÏ£¬¼ì²âÍøÂçÊÇ·ñÕý³£
+uint16 sp_async_heartbeat(sp_pos_t* pos)
+{
+  uint8 ctime[6];
+  uint8 unconfirm_transnum = 0;
+  sp_protocol_request_t req;
+  cw_pack_context pack;
+
+  pos->heartbeat.heart_status = HEART_SEND;
+  if(pos->unconfirm_transdtl.transaddr <= pos->last_transdtl.transaddr)
+  {
+    unconfirm_transnum = ((pos->last_transdtl.transaddr - pos->unconfirm_transdtl.transaddr) /
+                          sizeof(sp_transdtl_t)) + 1;
+  }
+  else
+  {
+    unconfirm_transnum = 0;
+  }
+  sp_protocol_req_init(&req, SP_CMD_HEARTBEAT);
+  sp_pack_init(&pack, req.data, sizeof(req.data));
+  cw_pack_map_size(&pack, 6);
+
+  sp_get_bcdtime(ctime);
+  sp_pack_put_bin(&pack, PK_BIN_DEVPHYID, pos->devphyid, 4);
+  sp_pack_put_bin(&pack, PK_BIN_DEVTIME, ctime, 6);
+  sp_pack_put_str(&pack, PK_STR_DEVTYPE, DEV_TYPE);
+  sp_pack_put_str(&pack, PK_STR_VERSION, PRO_VERSION);
+  sp_pack_put_int(&pack, PK_INT_UNTRANSCONST, unconfirm_transnum);
+  sp_pack_put_int(&pack, PK_INT_WORKMODE, pos->sysconf.work_mode);
+
+  req.datalen += sp_pack_length(&pack);
+  sp_usart_send(pos, &req);
+  return 0;
+}
+
+static uint16 sp_confirm_qrcode_init(sp_pos_t* pos, sp_card_t* card)
+{
+  uint8 size;
+  uint16 ret;
+  int32 timeout_ms = COMM_WAIT_TIME;
+  cw_unpack_context unpack;
+  unpack_field_t field;
+  sp_protocol_response_t resp;
+
+  ret = sp_usart_recv(pos, &resp, timeout_ms);
+  if(ret)
+  {
+    ret = RC_QRCODE_FAILURE;
+    return ret;
+  }
+
+  sp_unpack_init(&unpack,resp.data,resp.datalen);
+  size = sp_unpack_map_size(&unpack);
+  while(size-- > 0)
+  {
+    sp_unpack_value(&unpack,&field);
+    if(IS_KEY(PK_STR_SHORT_URL, field.key))
+    {
+      MEMCPY(card->qrcode.qrcode_url, field.val.strval, field.strlen);
+    }
+    else if(IS_KEY(PK_BIN_BILLNO, field.key))
+    {
+      MEMCPY(card->billno, field.val.binval, field.strlen);
+    }
+    else if(IS_KEY(PK_INT_VAILDTIME, field.key))
+    {
+      card->qrcode.validtime = field.val.intval;
+    }
+  }
+  card->qrcode.starttime = sp_get_ticker();
+  return 0;
+}
+
+//¶þάÂë»ñÈ¡
+uint16 sp_qrcode_init(sp_pos_t* pos, sp_card_t* card)
+{
+  uint8 ctime[6];
+  sp_protocol_request_t req;
+  cw_pack_context pack;
+
+  sp_get_bcdtime(ctime);
+  sp_protocol_req_init(&req, SP_CMD_SHORTURL);
+  sp_pack_init(&pack, req.data, sizeof(req.data));
+  cw_pack_map_size(&pack, 2);
+
+  sp_pack_put_bin(&pack, PK_BIN_DEVPHYID, pos->devphyid, 4);
+  sp_pack_put_bin(&pack, PK_BIN_DEVTIME, ctime, 6);
+
+  req.datalen += sp_pack_length(&pack);
+  sp_usart_send(pos, &req);
+  return sp_confirm_qrcode_init(pos, card);
+}
+
+//¶þάÂëÈ·ÈÏ£¬»ñȡ֧¸¶×´Ì¬
+static uint16 sp_confirm_qrcode_query(sp_pos_t* pos, sp_card_t* card)
+{
+  uint8 size;
+  uint16 ret;
+  int32 timeout_ms = COMM_WAIT_TIME;
+  cw_unpack_context unpack;
+  unpack_field_t field;
+  sp_protocol_response_t resp;
+
+  ret = sp_usart_recv(pos, &resp, timeout_ms);
+  if(ret)
+  {
+    ret = RC_QRCODE_QUERY_FAIL;
+    return ret;
+  }
+
+  sp_unpack_init(&unpack,resp.data,resp.datalen);
+  size = sp_unpack_map_size(&unpack);
+  while(size-- > 0)
+  {
+    sp_unpack_value(&unpack,&field);
+    if(IS_KEY(PK_BIN_BILLNO, field.key))
+    {
+      MEMCPY(card->billno, field.val.binval, field.strlen);
+    }
+    else if(IS_KEY(PK_INT_AUTHSTATUS, field.key))
+    {
+      card->qrcode.authstatus = field.val.intval;
+    }
+    else if(IS_KEY(PK_INT_PAYSTATUS, field.key))
+    {
+      card->qrcode.paystatus = field.val.intval;
+    }
+    else if(IS_KEY(PK_INT_PAYAMT, field.key))
+    {
+      card->qrcode.paidAmount = field.val.intval;
+    }
+    else if(IS_KEY(PK_INT_FEEAMOUNT,field.key))
+    {
+      card->feepara.fee_amt = field.val.intval;
+    }
+    else if(IS_KEY(PK_INT_FEEUNIT, field.key))
+    {
+      card->feepara.fee_unit = field.val.intval;
+    }
+  }
+  return resp.retcode;
+}
+
+uint16 sp_qrcode_query(sp_pos_t* pos, sp_card_t* card)
+{
+  uint8 ctime[6];
+  sp_protocol_request_t req;
+  cw_pack_context pack;
+
+  sp_get_bcdtime(ctime);
+  sp_protocol_req_init(&req, SP_CMD_QRCODE_PAY_QUERY);
+  sp_pack_init(&pack, req.data, sizeof(req.data));
+  cw_pack_map_size(&pack, 2);
+
+  sp_pack_put_bin(&pack, PK_BIN_DEVPHYID, pos->devphyid, 4);
+  sp_pack_put_bin(&pack, PK_BIN_BILLNO, card->billno, sizeof(card->billno));
+
+  req.datalen += sp_pack_length(&pack);
+  sp_usart_send(pos, &req);
+  return sp_confirm_qrcode_query(pos, card);
+}
+
+//Á÷Ë®ÉÏ´«
+static uint8 transdtl_account_bilLno[10];
+static uint16 sp_async_upload_transdtl(sp_pos_t* pos, sp_transdtl_t* transdtl)
+{
+  uint8 crc[2];
+  cw_pack_context pack;
+  sp_protocol_request_t req;
+
+  MEMCPY(transdtl_account_bilLno, transdtl->billno, sizeof(transdtl->billno));
+  sp_protocol_req_init(&req, SP_CMD_TRANSDTL_ACCOUNT);
+  sp_pack_init(&pack,req.data,sizeof(req.data));
+  cw_pack_map_size(&pack,10);
+
+  sp_pack_put_bin(&pack, PK_BIN_DEVPHYID, transdtl->devphyid,4);
+  sp_pack_put_bin(&pack, PK_BIN_TRANSDATE, transdtl->transdate,3);
+  sp_pack_put_bin(&pack, PK_BIN_TRANSTIME, transdtl->transtime,3);
+  sp_pack_put_bin(&pack, PK_BIN_BILLNO, transdtl->billno, sizeof(transdtl->billno));
+  sp_pack_put_bin(&pack, PK_BIN_CARDPHYID, transdtl->cardphyid,
+                  sizeof(transdtl->cardphyid));
+  sp_pack_put_int(&pack, PK_INT_TRANSWAY, transdtl->transway);
+  sp_pack_put_int(&pack, PK_INT_AMOUNT, transdtl->amount);
+  sp_pack_put_int(&pack, PK_INT_PAYAMT, transdtl->paidAmount);
+  sp_pack_put_int(&pack, PK_INT_FLOWSENSORS, transdtl->flowsensors);
+  sp_pack_put_int(&pack, PK_INT_FLAG, transdtl->transtatus);
+
+  sp_protocol_crc((uint8*)transdtl, sizeof(sp_transdtl_t)-2,crc);
+  req.datalen += sp_pack_length(&pack);
+  sp_usart_send(pos, &req);
+  return 0;
+}
+
+//È·ÈÏÁ÷ˮ״̬
+static uint8 sp_confirm_transdtl_account(sp_protocol_response_t* resp, sp_pos_t* pos)
+{
+  uint8 size;
+  cw_unpack_context unpack;
+  unpack_field_t field;
+
+  if(!resp->retcode)
+  {
+    sp_unpack_init(&unpack, resp->data, resp->datalen);
+    size = sp_unpack_map_size(&unpack);
+    while(size-- > 0)
+    {
+      sp_unpack_value(&unpack,&field);
+      if(IS_KEY(PK_BIN_BILLNO,field.key))
+      {
+        if(MEMCMP(field.val.binval, transdtl_account_bilLno,
+                  sizeof(transdtl_account_bilLno)) == 0)
+        {
+          pos->unconfirm_transdtl.transaddr+= sizeof(sp_transdtl_t);
+          if(ADDR_TRANSDTL_END <= pos->unconfirm_transdtl.transaddr)
+          {
+            pos->unconfirm_transdtl.transaddr= ADDR_TRANSDTL_BEGIN;
+          }
+          return sp_write_unconfirm_record(pos);
+        }
+      }
+    }
+  }
+  return resp->retcode;
+
+}
+
+static uint8 sp_confirm_heartbeat(sp_protocol_response_t* resp, sp_pos_t* pos)
+{
+  uint8 size;
+  uint8 ctime[6];
+  uint8 systime[7];
+  uint8 login_flag = 0;
+  cw_unpack_context unpack;
+  unpack_field_t field;
+
+  if(resp->retcode)
+  {
+    return resp->retcode;
+  }
+  pos->heartbeat.heart_status = HEART_RECV;
+
+  sp_unpack_init(&unpack,resp->data,resp->datalen);
+  size = sp_unpack_map_size(&unpack);
+  while(size-- > 0)
+  {
+    sp_unpack_value(&unpack,&field);
+    if(IS_KEY(PK_BIN_SYSTIME, field.key))
+    {
+      if(field.strlen == 7)
+      {
+        MEMCPY(systime,field.val.binval,7);
+        sp_get_bcdtime(ctime);
+        if(MEMCMP(ctime,systime +1,5) != 0)
+        {
+          if(!sp_check_time_valid(systime +1))
+          {
+            sp_set_bcdtime(systime +1);
+          }
+        }
+      }
+    }
+    else if(IS_KEY(PK_STR_STATUS, field.key))
+    {
+      if(MEMCMP(field.val.strval, "normal", field.strlen) == 0)
+      {
+        login_flag = 1;
+      }
+      else if(MEMCMP(field.val.strval, "logout", field.strlen) == 0)
+      {
+        login_flag = 0;
+      }
+      else if(MEMCMP(field.val.strval, "closed", field.strlen) == 0)
+      {
+        login_flag = 2;
+      }
+    }
+  }
+  sp_save_heartbeat_info(pos, login_flag);
+  return resp->retcode;
+}
+
+uint8 sp_confirm_login(sp_protocol_response_t* resp, sp_pos_t* pos)
+{
+  uint8 size;
+  uint8 ctime[6];
+  uint8 systime[7];
+  uint8 login_flag = 0;
+  uint8 unit = 0;
+  uint8 offline_maxhour = 0;
+  cw_unpack_context unpack;
+  unpack_field_t field;
+
+  MEMCLEAR(ctime, sizeof(ctime));
+  MEMCLEAR(systime, sizeof(systime));
+  if(resp->retcode)
+  {
+    return resp->retcode;
+  }
+  pos->heartbeat.heart_status = HEART_RECV;
+
+  sp_unpack_init(&unpack,resp->data,resp->datalen);
+  size = sp_unpack_map_size(&unpack);
+  while(size-- > 0)
+  {
+    sp_unpack_value(&unpack,&field);
+    if(IS_KEY(PK_INT_OFFLINEMAXHOUR, field.key))
+    {
+      offline_maxhour = field.val.intval;
+    }
+    else if(IS_KEY(PK_INT_PULSEINHML, field.key))
+    {
+      unit = field.val.intval;
+    }
+    else if(IS_KEY(PK_BIN_SYSTIME, field.key))
+    {
+      if(field.strlen == 7)
+      {
+        MEMCPY(systime,field.val.binval,7);
+        sp_get_bcdtime(ctime);
+        if(MEMCMP(ctime,systime +1,5) != 0)
+        {
+          if(!sp_check_time_valid(systime +1))
+          {
+            sp_set_bcdtime(systime +1);
+          }
+        }
+      }
+    }
+  }
+
+  login_flag = 1;
+  sp_save_login_info(pos, login_flag, unit, offline_maxhour);
+  return resp->retcode;
+}
+
+static protocol_cmd_t protocol_cmds[] =
+{
+  {SP_CMD_TRANSDTL_ACCOUNT, sp_confirm_transdtl_account},
+  {SP_CMD_HEARTBEAT, sp_confirm_heartbeat},
+  {SP_CMD_LOGIN, sp_confirm_login},
+  {0, NULL}
+};
+
+static uint16 sp_async_confirm_process(sp_pos_t* pos)
+{
+  uint8 ret = 0;
+  uint8 i = 0;
+  int32 timeout_ms = COMM_WAIT_TIME;
+  sp_protocol_response_t resp;
+
+  ret = sp_usart_recv(pos, &resp, timeout_ms);
+  if(ret)
+  {
+    return ret;
+  }
+  while(protocol_cmds[i].func != NULL && protocol_cmds[i].cmd != 0)
+  {
+    if(protocol_cmds[i].cmd == resp.excmd)
+    {
+      return protocol_cmds[i].func(&resp, pos);
+    }
+    ++i;
+  }
+  return 1;
+}
+
+//¼ì²âÉ豸ͨѶ״̬£¬¿ÕÏÐʱ¼ä½øÐÐÁ÷Ë®´¦ÀíµÈ¹¤×÷
+static void sp_check_and_switch_linkstat(sp_pos_t* pos)
+{
+  if(pos->heartbeat.heart_status == HEART_SEND)
+  {
+    //ÒÑ·¢ËÍÐÄÌø£¬Î´ÊÕµ½Ó¦´ð
+    pos->link_stat = 0;
+    pos->heartbeat.heart_status = HEART_INIT;
+  }
+  else if(pos->heartbeat.heart_status == HEART_RECV)
+  {
+    //ÒÑ·¢ËÍÐÄÌø£¬ÊÕµ½Ó¦´ð
+    pos->link_stat = 1;
+    pos->heartbeat.heart_status = HEART_INIT;
+  }
+}
+
+void sp_communicate(sp_pos_t* pos)
+{
+  uint16 ret = 0;
+  uint32 ticker = 0;
+  sp_transdtl_t transdtl;
+
+  if(pos->deviceno == 0)
+  {
+    return;
+  }
+  ticker = sp_get_ticker();
+  if(ticker - pos->last_comm_status.sendtime > COMM_WAIT_TIME)
+  {
+    if(pos->devlogin.last_login_ticker == 0 || pos->devlogin.login_flag == 0
+        || (ticker - pos->devlogin.last_login_ticker) > DELAY_TIME60s*60*24)
+    {
+      pos->devlogin.last_login_ticker = ticker;
+      sp_async_equipment_login(pos);
+    }
+    else if(ticker < pos->heartbeat.last_heartbeat_ticker
+            || pos->heartbeat.last_heartbeat_ticker == 0
+            || (ticker - pos->heartbeat.last_heartbeat_ticker) > DELAY_TIME60s*2)
+    {
+      pos->heartbeat.last_heartbeat_ticker = ticker;
+      sp_async_heartbeat(pos);
+    }
+    else
+    {
+      sp_check_and_switch_linkstat(pos);
+      if(pos->link_stat)
+      {
+        //¼ì²âµ±Ç°ÊÇ·ñÓÐδÉÏ´«µÄÁ÷Ë®
+        if(pos->unconfirm_transdtl.transaddr <= pos->last_transdtl.transaddr)
+        {
+          ret = sp_flash_read((uint32)pos->unconfirm_transdtl.transaddr, (uint8*)&transdtl,
+                              sizeof(transdtl));
+          if(!ret)
+          {
+            if(!pos->sysconf.work_mode)
+            {
+              pos->heartbeat.last_heartbeat_ticker = ticker;
+              sp_async_upload_transdtl(pos, &transdtl);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  sp_async_confirm_process(pos);
+}