大理水控初始版本
diff --git a/supwisdom/main.c b/supwisdom/main.c
new file mode 100644
index 0000000..c5fdc97
--- /dev/null
+++ b/supwisdom/main.c
@@ -0,0 +1,53 @@
+//пªÆÕË®¿Ø³ÌÐò
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "sp_config.h"
+#include "sp_display.h"
+#include "sp_data.h"
+#include "sp_util.h"
+#include "sp_consume.h"
+#include "sp_communicate.h"
+
+static sp_pos_t POS;
+
+int main(void)
+{
+  uint32 tick = 0;
+  uint32 lasttick = 0;
+  sp_cardworkstate_t cardWorkState;
+  MEMCLEAR(&POS, sizeof(POS));
+  MEMCLEAR(&cardWorkState, sizeof(cardWorkState));
+  sp_init();
+  sp_key_init();
+  Delay_ms(DELAY_TIME1s);
+  sp_load_config(&POS);
+
+  show_home(&POS);
+
+  while(1)
+  {
+    tick = sp_get_ticker();
+    sp_feed_dog();
+    sp_valve_control();
+    sp_confirm_paymode(&POS, &cardWorkState);
+    sp_communicate(&POS);
+    if(POS.paymode == PAYMODE_QRCODE)
+    {
+      if(tick - lasttick >= DELAY_TIME100ms)
+      {
+        lasttick = tick;
+        sp_qrcode_handle(&POS, &cardWorkState);
+      }
+    }
+    else
+    {
+      if(tick - lasttick >= DELAY_TIME100ms)
+      {
+        lasttick = tick;
+        sp_test_card_state(&POS, &cardWorkState, tick);
+        sp_card_handle(&POS, &cardWorkState);
+      }
+    }
+  }
+}
diff --git a/supwisdom/sp_card.c b/supwisdom/sp_card.c
new file mode 100644
index 0000000..5c6796a
--- /dev/null
+++ b/supwisdom/sp_card.c
@@ -0,0 +1,98 @@
+#include "../nec_apdu.h"
+#include "sp_des.h"
+#include "sp_constant.h"
+#include "sp_util.h"
+#include "sp_card.h"
+
+static uint8* prcv_buff = NULL;
+static uint8 rcv_len = 0;
+
+uint16 sp_select_sfi(uint8 sfi[2])
+{
+  uint16 ret;
+  uint8  cmd_buff[10];
+
+  cmd_buff[0] = 0x00; //CLA
+  cmd_buff[1] = 0xA4; //INS
+  cmd_buff[2] = 0x00; //P1
+  cmd_buff[3] = 0x00; //P2
+  cmd_buff[4] = 0x02; //Lc
+  memcpy(cmd_buff + 5, sfi, 2);
+
+  ret = card_cpu_exchange(cmd_buff, 2 + 5, 0, &prcv_buff, &rcv_len);
+  if(ret != RETCODE_OK)
+  {
+    return ret;
+  }
+  return 0;
+}
+
+uint16 sp_select_adf(void)
+{
+  uint16 ret;
+  uint8  cmd_buff[] = {"\x00\xA4\x04\x00\x0F\xD1\x56\x00\x00\x01\xBD\xF0\xCA\xCB\xB4\xEF\xD6\xA7\xB8\xB6"};
+  ret = card_cpu_exchange(cmd_buff, sizeof(cmd_buff) - 1, 0, &prcv_buff, &rcv_len);
+  if(ret != RETCODE_OK)
+  {
+    return ret;
+  }
+  return 0;
+}
+
+uint8 sp_card_request(sp_card_t* cardpcd)
+{
+
+  uint8 sak;
+  uint8 snr[8];
+
+  if(!card_request(&sak, snr))
+  {
+    if((sak & 0x20))
+    {
+      if(!card_cpu_mode())
+      {
+        Delay_ms(200);
+		if(sp_select_sfi("\x3f\x00") == 0)
+        {
+          sp_select_adf();
+          cardpcd->cardphyid[0] = snr[3];
+          cardpcd->cardphyid[1] = snr[2];
+          cardpcd->cardphyid[2] = snr[1];
+          cardpcd->cardphyid[3] = snr[0];
+          cardpcd->cardtype = TAG_TYPE_CPU;
+          return 0;
+        }
+      }
+    }
+    else
+    {
+      cardpcd->cardtype = TAG_TYPE_UNKONWN;
+	  return 1;
+    }
+  }
+  return 1;
+}
+
+int8 sp_check_cpu_exist(void)
+{
+  return card_cpu_exist();
+}
+
+static uint16 sp_cpu_read(sp_card_t* card)
+{
+  uint16 ret = 0;
+  MEMCLEAR(card->citizen_cardno, sizeof(card->citizen_cardno));
+  MEMCPY(card->expiredate, "\x20\x22\x08\x02", 4);
+  return ret;
+}
+
+uint16 sp_card_read(sp_card_t* card)
+{
+  switch(card->cardtype)
+  {
+  case TAG_TYPE_CPU:
+    return sp_cpu_read(card);
+  default:
+    return 1;
+  }
+}
diff --git a/supwisdom/sp_card.h b/supwisdom/sp_card.h
new file mode 100644
index 0000000..5981cfa
--- /dev/null
+++ b/supwisdom/sp_card.h
@@ -0,0 +1,26 @@
+#ifndef _SP_CARD_H_
+#define _SP_CARD_H_
+
+#include "sp_config.h"
+
+#define SP_FILE09 0x01
+#define SP_FILE10 0x02
+#define SP_FILE12 0x04
+#define SP_FILE15 0x08
+
+#define WATER_RECORD_NO 4
+#define RETCODE_OK  0x9000
+#define RETCODE_INSUFFICIENT  0x9401    //Óà¶î²»×ã
+#define RC_CPU_FILENOTFOUND 0x6A82
+#define RC_CPU_NO_EXTAUTH   0x6982
+#define RC_CPU_FILE_NOT_EXIST 0x6A83
+#define RC_CPU_NOMAC        0x9406
+
+#define CARD_STATUS_OK 0
+
+uint8 sp_card_request(sp_card_t* cardpcd);
+int8 sp_check_cpu_exist(void);
+int8 sp_card_rf_reset(void);
+uint16 sp_card_read(sp_card_t* card);
+
+#endif
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);
+}
diff --git a/supwisdom/sp_communicate.h b/supwisdom/sp_communicate.h
new file mode 100644
index 0000000..b8daf77
--- /dev/null
+++ b/supwisdom/sp_communicate.h
@@ -0,0 +1,139 @@
+#ifndef _SP_COMMUNICATE_H_
+#define _SP_COMMUNICATE_H_
+
+#include "sp_config.h"
+
+#define PROTOCOL_COMMAND_V2 		0x80
+#define PROTOCOL_WITH_MAC(x) 		((x) | 0x80)
+#define PROTOCOL_WITHOUT_MAC(x) 	((x) & 0x7F)
+#define PROTOCOL_FLAG_PACK(x) 		((x) | 0x01)
+#define PROTOCOL_FLAG_DES_PACK(x) 	((x) & 0xFE)
+
+#define PK_BIN_DEVPHYID 			"a"
+#define PK_INT_CARDNO 				"b"
+#define PK_BIN_CARDVERNO 			"c"
+#define PK_INT_DEVSEQNO 			"d"
+#define PK_STR_VERSION 				"e"
+#define PK_INT_BLKINDEX 			"f"
+#define PK_BIN_TRANSDATE 			"g"
+#define PK_BIN_TRANSTIME 			"h"
+#define PK_INT_PAYAMT 				"i"
+#define PK_INT_AMOUNT 				"j"
+#define PK_INT_FLAG 				"k"
+#define PK_STR_AVAIABLE 			"l"
+#define PK_BIN_SYSTIME 				"m"
+#define PK_STR_UPGRADE 				"n"
+#define PK_BIN_BLKBITMAP 			"o"
+#define PK_BIN_FILECRC 				"p"
+#define PK_INT_FILESIZE 			"q"
+#define PK_INT_SEQNO 				"r"
+#define PK_BIN_FILEDATA 			"s"
+#define PK_INT_MAXSEQNO 			"t"
+#define PK_INT_SECONDS 				"u"
+#define PK_INT_CREDIT_TOTAL  		"v"
+#define PK_INT_CREDIT_PAYCNT  		"w"
+#define PK_INT_CREDIT_AVAILABAL  	"x"
+#define PK_INT_CREDIT_NO  			"y"
+#define PK_BIN_EXPIRE  				"z"
+#define PK_INT_FEETYPE  			"A"
+#define PK_BIN_CARDPHYID  			"B"
+#define PK_STR_STATUS  				"C"
+#define PK_INT_BALANCE  			"D"
+#define PK_INT_OFFLINE_FORBID_FLAG  "E"
+#define PK_INT_CREDIT_PAYCNT_LACK  	"F"
+#define PK_INT_ONCETIME_LIMIT  		"G"
+#define PK_INT_DAYTOTAL_LIMIT  		"H"
+#define PK_INT_COUNT 				"J"
+#define PK_BIN_BLKLIST 				"K"
+#define PK_INT_CREDIT_NEXT_NO 		"L"
+#define PK_BIN_RANDOM  				"M"
+#define PK_INT_DEVICENO  			"N"
+#define PK_BIN_DEVTIME  			"O"
+#define PK_STR_DEVTYPE  			"P"
+#define PK_BIN_SAMNO  				"Q"
+#define PK_INT_PARAVERNO  			"R"
+#define PK_INT_PARA_GROUPID  		"S"
+#define PK_INT_FEEVERNO  			"T"
+#define PK_INT_FEE_CFGID  			"U"
+#define PK_BIN_WSCLIENT_ID  		"V"
+#define PK_INT_WSCLIENT_STATUS  	"W"
+#define PK_INT_FLOWSENSORS			"X"
+#define PK_BIN_SOFT_MD5  			"Y"
+#define PK_INT_CUSTID				"Z"
+#define PK_STR_SHORT_URL			"0"
+#define PK_INT_WATERSTATUS  		"1"
+#define PK_INT_WATERMUCH  			"2"
+
+#define PK_BIN_BILLNO 				"3"
+#define PK_INT_TRANSWAY 			"4"
+#define PK_INT_UNTRANSCONST 		"5"
+#define PK_BIN_DEVICEKEY 			"6"
+#define PK_INT_WORKMODE 			"7"
+#define PK_INT_OFFLINEMAXHOUR 		"8"
+#define PK_INT_PULSEINHML 			"9"
+#define PK_BIN_CITIZEN_CARDNO		"10"
+#define PK_INT_WATERLIMIT 	 		"11"
+#define PK_INT_FEEAMOUNT 			"12"
+#define PK_INT_FEEUNIT 				"13"
+#define PK_INT_VAILDTIME			"14"
+#define PK_INT_AUTHSTATUS			"15"
+#define PK_INT_PAYSTATUS			"16"
+#define PK_INT_FEESTART				"17"
+
+#define SP_CMD_UPGRADE 0x20         	//ÔÚÏßÉý¼¶
+#define SP_CMD_TRANSDTL_ACCOUNT 0x22    //¼ÇÕËÁ÷Ë®
+#define SP_CMD_HEARTBEAT 0x24 			//ÐÄÌø
+#define SP_CMD_CARD_AUTHENTICATION 0x26	//¿¨ÔÚÏßÈÏÖ¤
+#define SP_CMD_LOGIN	0x2C			//怬
+#define SP_CMD_FACTORY_LINK_TEST 0x2E	//¹¤³§Á´Â·²âÊÔ
+#define SP_CMD_SHORTURL	0x28			//»ñÈ¡¶þάÂë¶ÌµØÖ·
+#define SP_CMD_QRCODE_PAY_QUERY	0x2A	//¶þάÂëÏû·ÑÈ·ÈÏ
+
+#define IS_PUSH_FLOW(cmd) (0x1&(cmd))
+
+#pragma pack(push)
+#pragma pack(1)
+
+typedef struct
+{
+  uint16 datalen;
+  uint8 command;
+  uint8 excmd; // ÇëÇóÃüÁîÒªÇóżÊý
+  uint8 flag;
+  uint8 data[256];
+} sp_protocol_request_t;
+
+typedef struct
+{
+  uint16 datalen;
+  uint8 command;
+  uint8 excmd; // ÇëÇóÃüÁîÒªÇóżÊý
+  uint8 flag;
+  uint8 retcode;
+  uint8 data[256];
+} sp_protocol_response_t;
+
+#pragma pack(pop)
+
+typedef uint8(* protocol_cmd_func_t)(sp_protocol_response_t* resp, sp_pos_t* pos);
+
+typedef struct
+{
+  uint8 cmd;
+  protocol_cmd_func_t func;
+} protocol_cmd_t;
+
+void sp_communicate(sp_pos_t* pos);
+uint16 sp_card_authentication(sp_pos_t* pos, sp_card_t* card);
+uint16 sp_async_equipment_login(sp_pos_t* pos);
+uint16 sp_async_heartbeat(sp_pos_t* pos);
+uint16 sp_async_upload_transdtl(sp_pos_t* pos, sp_transdtl_t* dtl);
+uint16 sp_qrcode_init(sp_pos_t* pos, sp_card_t* card);
+uint16 sp_qrcode_query(sp_pos_t* pos, sp_card_t* card);
+
+//ͨѶ
+uint8 sp_comm_call(sp_pos_t* pos, sp_protocol_request_t* req,
+                   sp_protocol_response_t* resp, int32 timeout_ms);
+void sp_protocol_req_init(sp_protocol_request_t* req, uint8 command);
+#endif
+
diff --git a/supwisdom/sp_config.h b/supwisdom/sp_config.h
new file mode 100644
index 0000000..81f4140
--- /dev/null
+++ b/supwisdom/sp_config.h
@@ -0,0 +1,280 @@
+#ifndef _SP_CONFIG_H
+#define _SP_CONFIG_H
+
+#include "sp_version.h"
+#include "../nec_hardware.h"
+
+#ifndef int8
+#define int8 signed char
+#endif
+
+#ifndef uint8
+#define uint8 unsigned char
+#endif
+
+#ifndef int16
+#define int16 signed short
+#endif
+
+#ifndef uint16
+#define uint16 unsigned short
+#endif
+
+#ifndef int32
+#define int32 signed int
+#endif
+
+#ifndef uint32
+#define uint32 unsigned int
+#endif
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define DEV_TYPE "G401302"
+#define DEV_OFFLINE_DEFAULT_HOUR 168
+#define DEV_BLKBITMAP_DONE 1984
+#define DEV_MAX_DEVICENO 99
+
+#define PRO_VERSION GIT_VERSION
+#define BUILD_DATE __DATE__ 		// " " __TIME__
+#ifdef FLOWSENSOR
+#define PURCHASE_FLOWSENSOR 1
+#else
+#define PURCHASE_FLOWSENSOR 0
+#endif
+
+enum
+{
+  SP_KEY_NONE = 0xFF,
+  SP_KEY_0 = 0,
+  SP_KEY_1 = 1,
+  SP_KEY_2 = 2,
+  SP_KEY_3 = 3,
+  SP_KEY_4 = 4,
+  SP_KEY_5 = 5,
+  SP_KEY_6 = 6,
+  SP_KEY_7 = 7,
+  SP_KEY_8 = 8,
+  SP_KEY_9 = 9,
+  SP_KEY_ENTER = 12,
+  SP_KEY_CLEAR = 11
+};
+
+typedef enum
+{
+  PAYMODE_INIT = 0,
+  PAYMODE_CARD = 1,
+  PAYMODE_QRCODE = 2,
+} sp_paymode_e;
+
+#pragma pack(push)
+#pragma pack(1)
+
+typedef struct
+{
+  uint8 command;
+  uint32 sendtime;
+} sp_comm_status_t;
+
+typedef struct
+{
+  uint32 last_heartbeat_ticker;
+  uint8 hwVer[16];				//É豸°æ±¾ºÅ
+  uint8 offlineRecordCount;		//δÉÏ´«Á÷Ë®ÊýÁ¿
+  uint8 workMode;				//µ±Ç°×´Ì¬£¬0-¿ÕÏУ¬1-ÕýÔÚʹÓã¬9-ÒÉËÆ¹ÊÕÏ
+  uint8 heart_status;	//ÐÄÌø×´Ì¬£¬0-³õʼ»¯£¬1-·¢ËÍ£¬2-½ÓÊÕ
+} sp_heartbeat_t;
+
+typedef struct
+{
+  uint32 last_login_ticker;
+  uint8 login_flag;			//0-δǩµ½£¬1-ÒÑÇ©µ½£¬2-×¢Ïú
+  uint8 hwVer[16];			//É豸°æ±¾ºÅ
+  uint8 deviceKey;			//É豸¹¤×÷ÃÜÔ¿
+} sp_login_t;
+
+//Ïû·ÑÁ÷Ë®ÐÅÏ¢½á¹¹
+typedef struct
+{
+  uint8 devphyid[4];	//É豸±àºÅ
+  uint8 transdate[3];	//YYDDMM¸ñʽÈÕÆÚ
+  uint8 transtime[3];
+  uint8 billno[10];		//½»Ò×¶©µ¥±àºÅ
+  uint8 cardphyid[4];	//¿¨ÎïÀíid
+  uint8 transway;		//½»Ò×·½Ê½£¬0-³õʼ£¬1-Ë¢¿¨£¬2-ɨÂë
+  uint8 amount;			//ʵ¼ÊÖ§¸¶½ð¶î
+  uint8 paidAmount;		//ÒÑÖ§¸¶½ð¶î£¬µ±ÊÇÏȿ۷ÑģʽÏ£¬¼Ç¼ÒÑÖ§¸¶µÄ½ð¶î
+  uint8 flowsensors;	//ʵ¼ÊʹÓüÆÁ¿£¨µ¥Î»£º°ÙºÁÉý£©
+  uint8 transtatus;		//Á÷ˮ״̬£¬0-³õʼ£¬1-³É¹¦£¬2-ʧ°Ü
+  uint8 reverse[1];		//ռλ·û
+  uint8 crc[2]; 		//len=32
+} sp_transdtl_t;
+
+typedef struct
+{
+  uint8 offline_work_hour;   	//ÔÊÐíÍÑ»ú¹¤×÷×î´óСʱ	  0 ~ 168 Сʱ£¬0 ±íʾ²»ÏÞÖÆ
+  uint8 deviceno; 				//»úºÅ
+  uint8 devphyid[4];			//ÎïÀíID
+  uint8 flowsensor_unit; 		// 100ml¶ÔÓ¦Âö³åÊý
+  uint8 unused[54];
+  uint8 login_flag; 			//0-δǩµ½£¬1-ÒÑÇ©µ½£¬2-ÒÑ×¢Ïú
+  uint8 crc[2];
+} sp_config_t;
+
+typedef struct
+{
+  uint32 transaddr;		//µØÖ·
+  uint16 this_offset;	//Ò³Æ«ÒÆÎ»
+  uint8 crc[2]; 		//len=8
+} sp_last_transdtl_t;
+
+typedef struct
+{
+  uint32 transaddr;		//µØÖ·
+  uint16 this_offset;	//Ò³Æ«ÒÆÎ»
+  uint8 crc[2]; 		//len=8
+} sp_unconfirm_transdtl_t;
+
+//Ïû·ÑÐÅÏ¢
+typedef struct
+{
+  uint32 free_used_num; //ÒÑÃâ·ÑʹÓüÆÁ¿(µ¥Î»:100ml)
+
+  uint8 starttime[6];  	//Ë¢¿¨Ê±¼ä
+  /*Ïȿۿîºó³öË®*/
+  uint16 prepaid_num;	//µ¥´Î¿ÉÓüÆÁ¿(µ¥Î»:100ml)
+  uint16 prepaid_amt;	//µ¥´ÎÔ¤¸¶½ðÇ®
+
+  uint16 paid_num; 		//ÀۼƿÉÓüÆÁ¿(µ¥Î»:100ml)
+  uint16 paid_sum;  	//ÀÛ¼ÆÖ§¸¶½ð¶î
+  uint16 used_num; 		//ÒÑʹÓüÆÁ¿(µ¥Î»:100ml)
+} sp_purchase_t;
+
+//¶þάÂëÐÅÏ¢
+typedef struct
+{
+  char qrcode_url[32]; 	///¶þάÂë¶ÌÂë
+  uint32 starttime;		//¶þάÂ뿪ʼʱ¼ä
+  uint32 nowtime;		//¶þάÂ뵱ǰʱ¼ä
+  uint32 validtime;		//¶þάÂëÓÐЧʱ¼ä
+  uint8 authstatus;		//Óû§È·ÈÏ״̬£¨0-δȷÈÏ£¬1-ÒÑÈ·ÈÏ£©
+  uint8 paystatus;		//Ö§¸¶×´Ì¬£¨0-´ýÖ§¸¶£¬ 1-ÒÑÖ§¸¶£¬ 2-´ú¿Û£¬3 - ¹Ø±Õ£©
+  uint8 paidAmount;		//µ±¶©µ¥ÊÇÒÑÖ§¸¶×´Ì¬£¬·µ»ØÖ§¸¶³É¹¦½ð¶î £¬ ·ñÔòÊÇ 0
+} sp_qrcode_t;
+
+//É豸²ÎÊý
+typedef struct
+{
+  uint8 dev_offline_maxhour;	//É豸ÍÑ»ú×î´ó¹¤×÷ʱ¼ä(Сʱ),0-²»ÏÞÖÆ,168-ĬÈÏʱ¼ä
+  uint8 flowsensor_unit; 		//100ml¶ÔÓ¦Âö³åÊý
+  uint8 hwVer[16];				//É豸°æ±¾ºÅ
+  uint8 deviceKey[8];				//É豸¹¤×÷ÃØÔ¿
+  uint8 work_mode;				//É豸¹¤×÷״̬
+} sp_sysconf_t;
+
+
+typedef struct
+{
+  uint8 tag_type;
+  uint8 cur_state;
+  uint8 snr[8];
+  uint32 firsttick;	//Ê״ζÁ¿¨Ê±¼ä
+  uint32 lasttick;	//×îºó¶Á¿¨Ê±¼ä
+} sp_cardstate_t;
+
+typedef struct
+{
+  uint8 current_state;	//µ±Ç°¹¤×÷״̬
+  uint16 errcode;
+  uint32 tick;
+  uint8 last_state;		//ÉÏÒ»´Î״̬
+
+  uint8 pause_status;	//Óû§Ê¹ÓÃ״̬£¬0--ʹÓÃÖУ¬!0--ÔÝÍ£
+  uint32 pause_tick;		//ÔÝͣʱµÄʱ¼ä
+} sp_cardworkstate_t;
+
+//Ë®¿ØÆ÷É豸ÐÅÏ¢
+typedef struct
+{
+  uint8 link_stat;			//0--Á´Â·¹¤×÷ÖУ¬1---Á´Â·¿ÉÓÃ
+  uint8 load_para_status;	//0--Õý³££¬!0--´íÎó
+  uint8 deviceno;
+  uint8 local_deviceno;		
+  uint8 devphyid[4];
+
+  sp_cardstate_t cardState;
+  sp_sysconf_t sysconf;
+  sp_comm_status_t last_comm_status;
+  sp_heartbeat_t heartbeat;
+  sp_login_t devlogin;
+  sp_last_transdtl_t last_transdtl;
+  sp_unconfirm_transdtl_t unconfirm_transdtl;
+
+  sp_paymode_e paymode;
+  sp_purchase_t purchase;
+} sp_pos_t;
+
+//·ÑÂÊÐÅÏ¢
+typedef struct
+{
+  uint8 fee_start;	//T°ÙºÁÉý¿ªÊ¼;
+  uint8 fee_unit;	//µ¥´Î¿Û·Ñ¿ÉÓÃÁ÷Á¿£¨µ¥Î»:100ml£©
+  uint8 fee_amt;	//µ¥´Î¿Û·Ñ½ð¶î£¬ÒÔ·ÖΪµ¥Î»
+} sp_feepara_t;
+
+//¿¨½á¹¹ÐÅÏ¢
+typedef struct
+{
+  uint8 cardphyid[4];
+  uint8 citizen_cardno[12];	//ÊÐÃñºÅ
+  uint8 cardtype;
+  uint8 expiredate[4];
+
+  uint8 waterlimit;		//µ¥´Î³öË®ÉÏÏÞ£¨100ml£©
+  uint8 billno[10];		//½»Ò×¶©µ¥±àºÅ,BCDÂë
+  sp_qrcode_t qrcode;	//¶þάÂë
+  sp_feepara_t feepara;
+} sp_card_t;
+
+#pragma pack(pop)
+
+typedef enum
+{
+  HEART_INIT = 0,
+  HEART_SEND = 1,
+  HEART_RECV = 2
+} sp_heart_status_t;
+
+typedef enum
+{
+  TAG_TYPE_UNKONWN = 0,  	//δ֪¿¨ÀàÐÍ
+  TAG_TYPE_M1,         		//M1¿¨
+  TAG_TYPE_CPU         		//CPU¿¨
+} sp_cardTag_type;
+
+typedef enum
+{
+  STATE_NONE = 0,
+  STATE_EXIST,
+  STATE_ERROR=0xFF
+} sp_cardState_type;
+
+typedef enum
+{
+  CARDWORKSTATUS_NONE = 0,
+  CARDWORKSTATUS_READY,
+  CARDWORKSTATUS_WORKING,
+  CARDWORKSTATUS_WORKING_WITHOUTCARD,
+  CARDWORKSTATUS_PAUSE,
+  CARDWORKSTATUS_STOPPING,
+  CARDWORKSTATUS_STOPPED,
+  CARDWORKSTATUS_TAKEOFF,
+  CARDWORKSTATUS_WORKERROR,
+  CARDWORKSTATUS_FEECARD_WORKING,
+  CARDWORKSTATUS_SET_DEV,
+  CARDWORKSTATUS_ERROR=0xff
+} sp_cardWorkState_type;
+
+#endif
diff --git a/supwisdom/sp_constant.h b/supwisdom/sp_constant.h
new file mode 100644
index 0000000..3081fc0
--- /dev/null
+++ b/supwisdom/sp_constant.h
@@ -0,0 +1,58 @@
+#ifndef _SP_CONSTANT_H_
+#define _SP_CONSTANT_H_
+
+///////////////////////////////////////////////////////////////////////////////
+#define RC_CPU_FILENOTFOUND 0x6A82
+#define RC_CPU_RECORDNOTFOUND 0x6A83
+#define RC_CPU_NOMAC        0x9406
+
+////////////////////////////////////////////////////////////////////////////////
+#define RC_SUCCESS 						0 	// ³É¹¦
+#define RC_PSAM_ERR						1   //SAM¸´Î»Ê§°Ü
+#define RC_CARD_LOGIN					2	//ÑéÖ¤ÃÜԿʧ°Ü
+#define RC_CARD_READ					3	//¶Á¿¨Ê§°Ü
+#define RC_CARD_WRITE					4	//д¿¨Ê§°Ü
+#define RC_FLASH_ERR					5	//FLASH´íÎó
+#define RC_HARDWARE_ERR					6  //Ó²¼þ¼ÓÔØ´íÎó
+#define RC_FLASH_NO_RIGHT				7 //·Ç¿Éдflash
+
+#define RC_CARD_NORIGHT 				11	//¿¨ÎÞȨÏÞ
+#define RC_CARD_EXPIRED					12 	//¹ýÆÚ¿¨
+#define RC_CARD_AUTHENTICATION			13	//¿¨ÈÏ֤ʧ°Ü
+#define RC_CARD_LOST					14	//ºÚÃûµ¥¿¨
+#define RC_CARDNO_EXCEPT				17	//¿¨ºÅÒì³£
+#define RC_CARD_TIMEOUT					18	//ʹÓÃʱ¼äÌ«³¤
+#define RC_CARDBAL_EXCEPT				19	//¿¨Óà¶îÒì³£
+#define RC_CARDBAL_LACK					20	//¿¨Óà¶î²»×ã
+
+#define RC_DEVPHYID_NOTSET				21 	//É豸µØÖ·Î´ÉèÖÃ
+#define RC_FEERATE_NOTSET				22 	//·ÑÂÊδ³õʼ»¯
+#define RC_DEV_OFFLINE_ERROR			23  // É豸ÍÑ»ú¹¤×÷Ì«³¤
+#define RC_FILE09_CRC_ERR				25	////¼Ç¼CRC´íÎó
+#define RC_FILE10_CRC_ERR				26 	//Ë®¿ØÇ®°üCRC´íÎó
+#define RC_CARD_INVALID					27	//ÎÞЧ¿¨
+#define RC_FEENUM_ERROR					28	//·ÑÂʸöÊý´íÎó
+#define RC_NOTSUPPORT					29	//²»Ö§³Ö		
+#define RC_NOT_SAME_CARD				30	//²»Í¬¿¨
+
+#define RC_MODE_NOT_SUPPORT				42	//Ïû·Ñģʽ²»Ö§³Ö
+#define RC_UPDPROG_ERR					43	//Éý¼¶Ê§°Ü
+
+#define RC_CONFPARA_CRC_ERR   			55  //ÅäÖòÎÊýcrc´íÎó
+#define RC_TRANSDTL_FULL				58	//	Á÷Ë®ÒÑÂú
+#define RC_TRANSDTL_NO_ERR				59	//Á÷Ë®ºÅÒì³£
+#define RC_DEVICENO_OUT					60	// »úºÅ¹ý´ó
+
+#define RC_QRCODE_FAILURE				61	//¶þάÂë»ñȡʧ°Ü
+#define RC_QRCODE_TIMEOUT				62	//¶þάÂ볬ʱ
+#define RC_QRCODE_QUERY_FAIL			63	//¶þάÂëÈÏ֤ʧ°Ü
+
+#define RC_DEV_LOGIN_FAIL				64	//É豸µÇ¼ʧ°Ü
+#define RC_DEV_NOT_LOGIN				65	//É豸δǩµ½
+#define RC_DEV_FAULT					66  //É豸ÒÉËÆ¹ÊÕÏ
+#define RC_DEV_NOSET_FLOWSENSOR_UNIT	67  //É豸Á÷Á¿¼ÆË㵥λδÉèÖÃ
+#define STATUS_KEEPOPEN					1	//³£¿ª¿¨
+#define STATUS_CLOSED					0	//È¡Ïû³£¿ª¿¨
+
+#endif
+
diff --git a/supwisdom/sp_consume.c b/supwisdom/sp_consume.c
new file mode 100644
index 0000000..587e2a4
--- /dev/null
+++ b/supwisdom/sp_consume.c
@@ -0,0 +1,729 @@
+#include "sp_util.h"
+#include "sp_constant.h"
+#include "sp_display.h"
+#include "sp_flash.h"
+#include "sp_card.h"
+#include "sp_des.h"
+#include "sp_msgpack.h"
+#include "sp_menu.h"
+#include "sp_data.h"
+#include "sp_consume.h"
+#include "sp_communicate.h"
+
+static int count = 0;
+static uint16 sp_calc_payamt_by_flowsensor(sp_pos_t* pos, sp_card_t* card)
+{
+  uint32 usedcount = 0;
+
+  if(pos->purchase.paid_num < 1)
+  {
+    //Ê×ÏÈÔ¤¿ÛÒ»±Ê
+    if(card->feepara.fee_start > 0)
+    {
+      //ǰnË®Ãâ·Ñ
+      pos->purchase.prepaid_num = card->feepara.fee_start;
+      pos->purchase.prepaid_amt = 0;
+    }
+    else
+    {
+      pos->purchase.prepaid_num = card->feepara.fee_unit;
+      pos->purchase.prepaid_amt = card->feepara.fee_amt;
+    }
+    pos->purchase.used_num = 0;
+    return 0;
+  }
+  //usedcount = sp_flowsensor_get_count()/pos->sysconf.flowsensor_uint;
+  usedcount = count/pos->sysconf.flowsensor_unit;
+  count++;
+  if(usedcount < pos->purchase.paid_num)
+  {
+    //ûÓдﵽ¿Û·ÑÁ÷Á¿
+    return 0;
+  }
+  pos->purchase.used_num = pos->purchase.paid_num;
+  pos->purchase.prepaid_num = card->feepara.fee_unit;
+  pos->purchase.prepaid_amt = card->feepara.fee_amt;
+  return 0;
+}
+
+//¼ÇÕËģʽÏû·Ñ
+uint16 sp_account_purchase(uint16 amount)
+{
+  return 0;
+}
+
+static uint8 gPICC_SNR[4];			   /* ¿¨Æ¬SNºÅ */
+
+void sp_test_card_state(sp_pos_t* pos, sp_cardworkstate_t* cardWorkState, uint32 tick)
+{
+  uint8 ret = 0;
+  sp_card_t cardpcd;
+  switch(pos->cardState.cur_state)
+  {
+  case STATE_NONE:
+    MEMCLEAR(&cardpcd, sizeof(cardpcd));
+    if(sp_card_request(&cardpcd) == 0)
+    {
+      MEMCPY(pos->cardState.snr, cardpcd.cardphyid, sizeof(cardpcd.cardphyid));
+      MEMCPY(gPICC_SNR, cardpcd.cardphyid, sizeof(cardpcd.cardphyid));
+      pos->cardState.tag_type = cardpcd.cardtype;
+      pos->cardState.cur_state = STATE_EXIST;
+      pos->cardState.firsttick = tick;
+      pos->cardState.lasttick = tick;
+    }
+    else
+    {
+      cardWorkState->errcode = RC_CARD_INVALID;
+    }
+    break;
+  case STATE_EXIST:
+    //¼ì²â¿¨ÊÇ·ñ¼ÌÐø´æÔÚ
+    if(pos->cardState.tag_type == TAG_TYPE_CPU)
+    {
+      ret = sp_check_cpu_exist();
+      if(ret)
+      {
+        pos->cardState.cur_state = STATE_NONE;
+        break;
+      }
+      else
+      {
+        memcpy(pos->cardState.snr, gPICC_SNR, 8);
+        pos->cardState.lasttick = tick;
+      }
+    }
+    break;
+  default:
+    pos->cardState.cur_state = STATE_NONE;
+    break;
+  }
+}
+
+static uint16 sp_dev_config_check(const sp_pos_t* pos)
+{
+  uint8 devphyid[4];
+  MEMCLEAR(devphyid, sizeof(devphyid));
+  if(MEMCMP(pos->devphyid, devphyid, sizeof(devphyid)) == 0)
+  {
+    return RC_DEVPHYID_NOTSET;
+  }
+  if(pos->devlogin.login_flag != 1)
+  {
+    return RC_DEV_NOT_LOGIN;
+  }
+  if(pos->sysconf.work_mode == 9)
+  {
+    return RC_DEV_FAULT;
+  }
+  if(pos->sysconf.flowsensor_unit == 0)
+  {
+    return RC_DEV_NOSET_FLOWSENSOR_UNIT;
+  }
+  return 0;
+}
+
+//¶ÁÈ¡µÚÒ»±ÊδÉÏ´«Á÷Ë®Ïû·ÑÈÕÆÚʱ¼ä
+static uint8 sp_read_unconfirm_first_record(uint8 termtime[6])
+{
+  return 1;
+}
+
+static uint16 sp_dev_offline_check(const sp_pos_t* pos)
+{
+  uint8 ret;
+  uint8 record_termtime[6];
+  uint8 ctime[6];
+  int32 nowtime;
+  int32 dtltime;
+
+  if(pos->sysconf.dev_offline_maxhour == 0)
+  {
+    return 0;
+  }
+  memset(record_termtime,0,sizeof(record_termtime));
+  ret = sp_read_unconfirm_first_record(record_termtime);
+  if(ret)
+  {
+    return 0;
+  }
+  sp_get_bcdtime(ctime);
+  nowtime = format_time_covert_secs(ctime);
+  dtltime = format_time_covert_secs(record_termtime);
+
+  /**
+  *Á÷ˮʱ¼ä´óÓÚÉ豸ʱÖÓÇÒ³¬¹ý24Сʱ
+  **/
+  if((dtltime > nowtime) &&
+      ((dtltime - nowtime) > (24*60*DELAY_TIME60s)))
+  {
+    if(sp_valve_state())
+    {
+      sp_valve_off();
+    }
+    return RC_DEV_OFFLINE_ERROR;
+  }
+  /**
+  *Á÷ˮʱ¼äСÓÚÉ豸ʱÖÓÇÒ³¬¹ýãÐÖµ
+  **/
+  if((dtltime < nowtime) &&
+      ((nowtime - dtltime) > (pos->sysconf.dev_offline_maxhour*3600)))
+  {
+    if(sp_valve_state())
+    {
+      sp_valve_off();
+    }
+    return RC_DEV_OFFLINE_ERROR;
+  }
+  return 0;
+}
+
+static uint16 sp_card_valid_check(const sp_card_t* card)
+{
+  uint8 ctime[6];
+  /*
+  if(card->cardno < 1)
+  {
+    return RC_CARDNO_EXCEPT;
+  }
+  */
+  sp_get_bcdtime(ctime);
+  if(memcmp(card->expiredate +1, ctime, 3) < 0)
+  {
+    return RC_CARD_EXPIRED;
+  }
+  return 0;
+}
+
+static uint16 sp_check_dev(const sp_pos_t* pos)
+{
+  uint16 ret = 0;
+  uint8 ctime[6];
+  MEMCLEAR(ctime, sizeof(ctime));
+  sp_get_bcdtime(ctime);
+  if(pos->load_para_status)
+  {
+    return pos->load_para_status;
+  }
+  ret = sp_dev_config_check(pos);
+  if(ret)
+  {
+    return ret;
+  }
+  ret = sp_dev_offline_check(pos);
+  if(ret)
+  {
+    return ret;
+  }
+
+  return 0;
+}
+
+static uint16 do_idle(sp_pos_t* pos)
+{
+  uint8 ctime[6];
+  MEMCLEAR(ctime, sizeof(ctime));
+  sp_get_bcdtime(ctime);
+  show_home(pos);
+  return 0;
+}
+
+static uint16 do_new(sp_pos_t* pos, sp_card_t* card)
+{
+  uint16 ret = 0;
+  sp_transdtl_t record;
+  MEMCLEAR(&record, sizeof(record));
+  card->cardtype = pos->cardState.tag_type;
+  MEMCPY(card->cardphyid, pos->cardState.snr, 4);
+  ret = sp_card_read(card);
+  if(ret)
+  {
+    ret = RC_CARD_INVALID;
+    return ret;
+  }
+  ret = sp_card_authentication(pos, card);
+  if(ret)
+  {
+    ret = RC_CARD_AUTHENTICATION;
+    return ret;
+  }
+  if(pos->load_para_status)
+  {
+    return pos->load_para_status;
+  }
+  ret = sp_dev_config_check(pos);
+  if(ret)
+  {
+    return ret;
+  }
+  ret = sp_dev_offline_check(pos);
+  if(ret)
+  {
+    return ret;
+  }
+
+  ret = sp_card_valid_check(card);
+  if(ret)
+  {
+    return ret;
+  }
+  ret = sp_prepare_behalf_transdtl(pos, card, &record);
+  if(ret)
+  {
+    return ret;
+  }
+  pos->sysconf.work_mode = 1;
+  pos->paymode = PAYMODE_CARD;
+  return 0;
+}
+
+static uint16 do_start(sp_pos_t* pos)
+{
+  MEMCLEAR(&pos->purchase,sizeof(sp_purchase_t));
+  sp_flowsensor_count_clear();
+  sp_get_bcdtime(pos->purchase.starttime);
+  sp_valve_on();
+  show_money(pos, pos->purchase.paid_sum);
+  return 0;
+}
+
+static uint16 do_work_check(const sp_pos_t* pos)
+{
+  //ÅжÏÏû·Ñ½ð¶îÈç¹û´óÓÚ20»òÕßÁ¬ÐøÏû·Ñ³¬¹ý2Сʱ£¬ÔòÍ£Ö¹³öË®
+  if(pos->purchase.used_num >= 1000 || pos->purchase.paid_sum >= 1000)
+  {
+    return RC_CARD_TIMEOUT;
+  }
+  return 0;
+}
+
+static uint16 do_work(sp_pos_t* pos, sp_card_t* card)
+{
+  uint16 ret = 0;
+  sp_valve_on();
+  ret = do_work_check(pos);
+  if(ret)
+  {
+    return ret;
+  }
+  //¼ÆËãÏû·Ñ½ð¶î
+  ret = sp_calc_payamt_by_flowsensor(pos, card);
+  if(ret)
+  {
+    return ret;
+  }
+  if(pos->purchase.prepaid_amt > 0)
+  {
+    //ĬÈϼÇÕËģʽ
+    ret = sp_account_purchase(pos->purchase.prepaid_amt);
+    if(ret)
+    {
+      return ret;
+    }
+  }
+
+  if(pos->purchase.prepaid_num > 0)
+  {
+    pos->purchase.paid_num += pos->purchase.prepaid_num;
+    pos->purchase.paid_sum += pos->purchase.prepaid_amt;
+    pos->purchase.prepaid_num = 0;
+    pos->purchase.prepaid_amt = 0;
+  }
+  show_money(pos, pos->purchase.paid_sum);
+  return 0;
+}
+
+static uint16 do_stop(sp_pos_t* pos, sp_card_t* card)
+{
+  uint16 ret;
+  sp_transdtl_t record;
+  sp_valve_off();
+
+  if(pos->purchase.paid_num > 0)
+  {
+    MEMCLEAR(&record, sizeof(record));
+    ret = sp_prepare_below_transdtl(pos, card, &record);
+    if(ret)
+    {
+      return ret;
+    }
+  }
+  pos->paymode = PAYMODE_INIT;
+  pos->sysconf.work_mode = 0;
+  count = 0;
+  MEMCLEAR(&pos->purchase, sizeof(sp_purchase_t));
+  MEMCLEAR(card, sizeof(sp_card_t));
+  return 0;
+}
+
+static void do_pause(sp_pos_t* pos)
+{
+  char msg[17];
+  MEMCLEAR(msg, sizeof(msg));
+  sp_valve_off();
+  if(pos->purchase.paid_sum > 0)
+  {
+    sprintf(msg,"¹²¼Æ %0.2fÔª",pos->purchase.paid_sum/100.0f);
+    disp_hint_info_two(pos,"½áÊø¼Æ·Ñ",msg,DELAY_TIME2s);
+  }
+  else
+  {
+    disp_hint_info_two(pos,"½áÊø¼Æ·Ñ","Ãâ·ÑʹÓÃ",DELAY_TIME2s);
+  }
+}
+
+static void do_error(sp_pos_t* pos, uint16 errcode)
+{
+  if(errcode)
+  {
+    show_error(pos,"²Ù×÷ʧ°Ü:",errcode);
+    pos->paymode = PAYMODE_INIT;
+    pos->sysconf.work_mode = 0;
+    count = 0;
+    MEMCLEAR(&pos->purchase, sizeof(sp_purchase_t));
+  }
+}
+
+static uint16 sp_card_exist_handle(sp_pos_t* pos, sp_card_t* card,
+                                   sp_cardworkstate_t* cardWorkState)
+{
+  uint16 ret = 0;
+  uint16 err = 0;
+  sp_card_t cardpcd;
+  switch(cardWorkState->current_state)
+  {
+  case CARDWORKSTATUS_NONE:
+    if(timer_get_ticker() - pos->cardState.firsttick < 1500)
+    {
+      break;
+    }
+    ret = do_new(pos, card);
+    if(ret)
+    {
+      if(0x1018 == ret || 0x2001 == ret||
+          0x1014 == ret || 0x1030 == ret)
+      {
+        if(0 == sp_card_request(&cardpcd))
+        {
+          break;
+        }
+      }
+      cardWorkState->errcode = ret;
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+      break;
+    }
+    cardWorkState->current_state = CARDWORKSTATUS_READY;
+    break;
+  case CARDWORKSTATUS_READY:
+    if(MEMCMP(pos->cardState.snr, card->cardphyid, 4) != 0)
+    {
+      cardWorkState->current_state = CARDWORKSTATUS_NONE;
+      break;
+    }
+    ret = do_start(pos);
+    if(ret)
+    {
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+      break;
+    }
+    cardWorkState->current_state = CARDWORKSTATUS_WORKING;
+    break;
+  case CARDWORKSTATUS_PAUSE:
+    cardWorkState->current_state = CARDWORKSTATUS_WORKING;
+    break;
+  case CARDWORKSTATUS_WORKING:
+    if(MEMCMP(pos->cardState.snr, card->cardphyid, 4) != 0)
+    {
+      ret = RC_NOT_SAME_CARD;
+      cardWorkState->current_state = CARDWORKSTATUS_STOPPING;
+      break;
+    }
+    cardWorkState->pause_status = 0;
+    ret = do_work(pos, card);
+    if(ret)
+    {
+      show_error(pos,"Ïû·Ñʧ°Ü",ret);
+      err = do_stop(pos, card);
+      if(err != 0)
+      {
+        ret = err;
+      }
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+      break;
+    }
+    if(pos->purchase.paid_num > card->waterlimit)
+    {
+      disp_hint_info(pos,"ÒÑ´ïµ¥´Î³öË®ÉÏÏÞ",DELAY_TIME2s);
+      cardWorkState->current_state = CARDWORKSTATUS_STOPPING;
+    }
+    cardWorkState->pause_tick = timer_get_ticker();
+    break;
+  case CARDWORKSTATUS_STOPPING:
+    ret = do_stop(pos, card);
+    if(ret)
+    {
+      cardWorkState->errcode = ret;
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+      break;
+    }
+    cardWorkState->current_state = CARDWORKSTATUS_STOPPED;
+    break;
+  case CARDWORKSTATUS_STOPPED:
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    break;
+  case CARDWORKSTATUS_FEECARD_WORKING:
+    if(MEMCMP(pos->cardState.snr, card->cardphyid, 4) != 0)
+    {
+      cardWorkState->current_state = CARDWORKSTATUS_NONE;
+      break;
+    }
+    //show_menu_options();
+    break;
+  case CARDWORKSTATUS_ERROR:
+    do_error(pos, cardWorkState->errcode);
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    break;
+  default:
+    Delay_ms(DELAY_TIME200ms);
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    break;
+  }
+  cardWorkState->errcode = ret;
+  return ret;
+}
+
+static uint16 sp_card_noexist_handle(sp_pos_t* pos, sp_card_t* card,
+                                     sp_cardworkstate_t* cardWorkState)
+{
+  //Óп¨µ½ÎÞ¿¨
+  uint16 ret = 0;
+  switch(cardWorkState->current_state)
+  {
+  case CARDWORKSTATUS_NONE:
+    do_idle(pos);
+    break;
+  case CARDWORKSTATUS_READY:
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    break;
+  case CARDWORKSTATUS_WORKING:
+    cardWorkState->current_state = CARDWORKSTATUS_PAUSE;
+    break;
+  case CARDWORKSTATUS_PAUSE:
+    if(MEMCMP(pos->cardState.snr, card->cardphyid, 4) == 0)
+    {
+      //¿¨ÄÃ×ßÒ»·ÖÖÓÖ®ÄÚĬÈÏÔÝͣʹÓÃ
+      if((timer_get_ticker() - cardWorkState->pause_tick) <= DELAY_TIME60s)
+      {
+        if(!cardWorkState->pause_status)
+        {
+          do_pause(pos);
+          show_home(pos);
+        }
+        show_home(pos);
+        cardWorkState->pause_status = 1;
+      }
+      else
+      {
+        cardWorkState->current_state = CARDWORKSTATUS_STOPPING;
+        cardWorkState->pause_status = 0;
+      }
+    }
+    else
+    {
+      cardWorkState->current_state = CARDWORKSTATUS_STOPPING;
+      cardWorkState->pause_status = 0;
+    }
+    cardWorkState->last_state = CARDWORKSTATUS_PAUSE;
+    break;
+  case CARDWORKSTATUS_STOPPING:
+    ret = do_stop(pos, card);
+    if(ret)
+    {
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+      break;
+    }
+    cardWorkState->current_state = CARDWORKSTATUS_STOPPED;
+    cardWorkState->tick = timer_get_ticker();
+    break;
+  case CARDWORKSTATUS_STOPPED:
+    if(timer_get_ticker() - cardWorkState->tick > DELAY_TIME3s)
+    {
+      cardWorkState->current_state = CARDWORKSTATUS_NONE;
+      cardWorkState->last_state = cardWorkState->current_state;
+      cardWorkState->tick = 0;
+    }
+    break;
+  case CARDWORKSTATUS_SET_DEV:
+    if(sp_check_passwd(pos, "É豸¹ÜÀíÃÜÂë", "\x9\x1\x4\x3\x8\x7") == 0)
+    {
+      sp_menu_options(pos);
+    }
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    break;
+  case CARDWORKSTATUS_ERROR:
+    do_error(pos,cardWorkState->errcode);
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    break;
+  default:
+    Delay_ms(DELAY_TIME200ms);
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    break;
+  }
+  cardWorkState->errcode = ret;
+  return ret;
+}
+
+static sp_card_t CARD;
+void sp_card_handle(sp_pos_t* pos, sp_cardworkstate_t* cardWorkState)
+{
+  if(pos->cardState.cur_state)
+  {
+    sp_card_exist_handle(pos, &CARD, cardWorkState);
+  }
+  else
+  {
+    sp_card_noexist_handle(pos, &CARD, cardWorkState);
+  }
+}
+
+void sp_confirm_paymode(sp_pos_t* pos, sp_cardworkstate_t* cardWorkState)
+{
+  uint8 keycode = SP_KEY_NONE;
+  keycode = sp_get_key();
+  //ÔÚ¿¨Ïû·ÑÔÝÍ£Çé¿öϰ´ÈÎÒâ¼üΪ½áÊøµ±Ç°Ïû·Ñ״̬
+  if(keycode >= SP_KEY_0 && keycode <= SP_KEY_ENTER && pos->cardState.cur_state == STATE_NONE
+      && cardWorkState->current_state == CARDWORKSTATUS_PAUSE && pos->paymode == PAYMODE_CARD)
+  {
+  	cardWorkState->current_state = CARDWORKSTATUS_STOPPING;
+	return;
+  }
+  //Ïû·Ñģʽ³õʼ»¯×´Ì¬Ï°´È·ÈϼüÑ¡Ôñ¶þάÂëÏû·Ñ
+  if((keycode == SP_KEY_ENTER) && (pos->paymode == PAYMODE_INIT))
+  {
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    pos->paymode = PAYMODE_QRCODE;
+	return;
+  }
+  //¶þάÂëģʽϰ´È¡Ïû¼üΪֹͣ¹¤×÷
+  if((pos->paymode == PAYMODE_QRCODE) && (keycode == SP_KEY_CLEAR))
+  {
+    cardWorkState->current_state = CARDWORKSTATUS_STOPPING;
+	return;
+  }
+  //°´0¼ü½øÈëÉ豸²Ù×÷½çÃæ
+  if(keycode == SP_KEY_0 && (pos->paymode == PAYMODE_INIT))
+  {
+    cardWorkState->current_state = CARDWORKSTATUS_SET_DEV;
+	return;
+  }
+}
+
+//¶þάÂëÏû·Ñ´¦Àí
+uint32 tick = 0;
+void sp_qrcode_handle(sp_pos_t* pos, sp_cardworkstate_t* cardWorkState)
+{
+  uint16 ret = 0;
+  sp_transdtl_t record;
+  MEMCLEAR(&record, sizeof(record));
+  switch(cardWorkState->current_state)
+  {
+  case CARDWORKSTATUS_NONE:
+    ret = sp_check_dev(pos);
+    if(ret)
+    {
+      cardWorkState->errcode = ret;
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+      break;
+    }
+    ret = sp_qrcode_init(pos, &CARD);
+    if(ret)
+    {
+      cardWorkState->errcode = ret;
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+      break;
+    }
+    ret = sp_prepare_behalf_transdtl(pos, &CARD, &record);
+    if(ret)
+    {
+      cardWorkState->errcode = RC_QRCODE_TIMEOUT;
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+      break;
+    }
+    pos->sysconf.work_mode = 1;
+    CARD.qrcode.starttime = sp_get_ticker();
+    disp_hint_info(pos, "ÕýÔÚÉú³É¶þάÂë", DELAY_TIME2s);
+    cardWorkState->last_state = cardWorkState->current_state;
+    cardWorkState->current_state = CARDWORKSTATUS_READY;
+    break;
+  case CARDWORKSTATUS_READY:
+    CARD.qrcode.nowtime = sp_get_ticker();
+    if((CARD.qrcode.nowtime - CARD.qrcode.starttime) > CARD.qrcode.validtime)
+    {
+      show_home(pos);
+      show_home_qrcode(CARD.qrcode.qrcode_url);
+      if(CARD.qrcode.nowtime - tick > DELAY_TIME3s)
+      {
+        tick = CARD.qrcode.nowtime;
+        ret = sp_qrcode_query(pos, &CARD);
+        if(!ret && CARD.qrcode.authstatus)
+        {
+          do_start(pos);
+          cardWorkState->last_state = cardWorkState->current_state;
+          cardWorkState->current_state = CARDWORKSTATUS_WORKING;
+        }
+      }
+    }
+    else
+    {
+      cardWorkState->errcode = RC_QRCODE_TIMEOUT;
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+    }
+    break;
+  case CARDWORKSTATUS_WORKING:
+    ret = do_work(pos, &CARD);
+    if(ret)
+    {
+      show_error(pos,"Ïû·Ñʧ°Ü",ret);
+      ret = do_stop(pos, &CARD);
+      if(ret)
+      {
+        cardWorkState->errcode = ret;
+      }
+      cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+      break;
+    }
+    cardWorkState->last_state = cardWorkState->current_state;
+    cardWorkState->pause_tick = sp_get_ticker();
+    break;
+  case CARDWORKSTATUS_STOPPING:
+    if(cardWorkState->last_state == CARDWORKSTATUS_NONE
+        || cardWorkState->last_state == CARDWORKSTATUS_READY)
+    {
+      disp_hint_info(pos,"È¡ÏûË¢Âë!", DELAY_TIME2s);
+      pos->paymode = PAYMODE_INIT;
+      pos->sysconf.work_mode = 0;
+    }
+    else
+    {
+      if(cardWorkState->last_state != CARDWORKSTATUS_PAUSE)
+        do_pause(pos);
+      ret = do_stop(pos, &CARD);
+      if(ret)
+      {
+        cardWorkState->errcode = ret;
+        cardWorkState->current_state = CARDWORKSTATUS_ERROR;
+        break;
+      }
+    }
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    cardWorkState->last_state = cardWorkState->current_state;
+    break;
+  case CARDWORKSTATUS_ERROR:
+    do_error(pos,cardWorkState->errcode);
+    cardWorkState->current_state = CARDWORKSTATUS_NONE;
+    cardWorkState->last_state = cardWorkState->current_state;
+    break;
+  default:
+    Delay_ms(DELAY_TIME200ms);
+    break;
+  }
+}
diff --git a/supwisdom/sp_consume.h b/supwisdom/sp_consume.h
new file mode 100644
index 0000000..e6ba62c
--- /dev/null
+++ b/supwisdom/sp_consume.h
@@ -0,0 +1,12 @@
+#ifndef CONSUME_H_
+#define CONSUME_H_
+
+#include "sp_config.h"
+
+void sp_card_handle(sp_pos_t* pos, sp_cardworkstate_t* cardWorkState);
+void sp_test_card_state(sp_pos_t* pos, sp_cardworkstate_t* cardWorkState, uint32 tick);
+void sp_qrcode_handle(sp_pos_t* pos, sp_cardworkstate_t* cardWorkState);
+void sp_confirm_paymode(sp_pos_t* pos, sp_cardworkstate_t* cardWorkState);
+
+#endif
+
diff --git a/supwisdom/sp_data.c b/supwisdom/sp_data.c
new file mode 100644
index 0000000..020b476
--- /dev/null
+++ b/supwisdom/sp_data.c
@@ -0,0 +1,366 @@
+#include "sp_data.h"
+#include "sp_util.h"
+#include "sp_flash.h"
+#include "sp_constant.h"
+#include "sp_display.h"
+
+#define record_behalf_len 25
+#define record_below_len 7
+
+//Ñ­»·¼Ç¼ÿһ±ÊÁ÷Ë®¼Ç¼µÄµØÖ·
+static uint16 sp_write_last_record(sp_pos_t* pos)
+{
+  uint8 crc[2];
+  uint8 buff[sizeof(sp_last_transdtl_t)];
+  MEMCLEAR(buff, sizeof(buff));
+
+  pos->last_transdtl.this_offset += sizeof(sp_last_transdtl_t);
+  if(pos->last_transdtl.this_offset >= DEF_FLASH_PageSize)
+  {
+    sp_flash_erase(ADDR_LAST_TRANSNO);
+    pos->last_transdtl.this_offset = 0;
+  }
+  sp_protocol_crc((uint8*)&pos->last_transdtl, sizeof(buff)-2, pos->last_transdtl.crc);
+  sp_flash_write(pos->last_transdtl.this_offset+ADDR_LAST_TRANSNO,
+                 (uint8*)&pos->last_transdtl, sizeof(buff));
+
+  sp_flash_read(pos->last_transdtl.this_offset+ADDR_LAST_TRANSNO, buff, sizeof(buff));
+  sp_protocol_crc(buff, sizeof(buff)-2, crc);
+  if(MEMCMP(pos->last_transdtl.crc,crc,2)!=0)
+  {
+    pos->load_para_status = RC_FLASH_ERR;
+    return RC_FLASH_ERR;
+  }
+  return 0;
+}
+
+static uint16 sp_write_behalf_record(sp_pos_t* pos, sp_transdtl_t* record)
+{
+  uint8 buf[record_behalf_len];
+  MEMCLEAR(buf, sizeof(buf));
+
+  pos->last_transdtl.transaddr += sizeof(sp_transdtl_t);
+  if(pos->last_transdtl.transaddr % DEF_FLASH_PageSize == 0)
+  {
+    if(pos->last_transdtl.transaddr >= ADDR_TRANSDTL_END)
+    {
+      pos->last_transdtl.transaddr = ADDR_TRANSDTL_BEGIN;
+    }
+    sp_flash_erase(pos->last_transdtl.transaddr);
+  }
+  sp_flash_write(pos->last_transdtl.transaddr, (uint8*)record, sizeof(buf));
+  return 0;
+}
+
+static uint16 sp_write_below_record(sp_pos_t* pos, sp_transdtl_t* record)
+{
+  uint8 crc[2];
+  uint8 buff[sizeof(sp_transdtl_t)];
+  MEMCLEAR(crc, sizeof(crc));
+  MEMCLEAR(buff, sizeof(buff));
+
+  sp_protocol_crc((uint8*)record, sizeof(buff)-2, record->crc);
+  sp_flash_write(pos->last_transdtl.transaddr+record_behalf_len,
+                 (uint8*)record+record_behalf_len, record_below_len);
+  sp_flash_read(pos->last_transdtl.transaddr, buff, sizeof(buff));
+  sp_protocol_crc(buff, sizeof(buff)-2, crc);
+  if(MEMCMP(record->crc, crc, 2) != 0)
+  {
+    pos->load_para_status = RC_FLASH_ERR;
+    return RC_FLASH_ERR;
+  }
+  return 0;
+}
+
+//Ïû·Ñ³õʼ»¯ºó´æ´¢Éϰ벿·ÖÁ÷Ë®£¬·ÀÖ¹Ïû·Ñʧ°ÜÎÞÁ÷Ë®ÐÅÏ¢
+uint16 sp_prepare_behalf_transdtl(sp_pos_t* pos, sp_card_t* card, sp_transdtl_t* record)
+{
+  uint8 ret = 0;
+  uint8 ctime[6];
+  MEMCLEAR(ctime, sizeof(ctime));
+
+  sp_get_bcdtime(ctime);
+  memcpy(record->devphyid, pos->devphyid, sizeof(pos->devphyid));
+  memcpy(record->transdate, ctime, 3);
+  memcpy(record->transtime, ctime+3, 3);
+  memcpy(record->billno, card->billno, sizeof(card->billno));
+  memcpy(record->cardphyid, card->cardphyid, sizeof(card->cardphyid));
+  if(pos->paymode == PAYMODE_QRCODE)
+  {
+    record->transway = 2;
+  }
+  else
+  {
+    record->transway = 1;
+  }
+  ret = sp_write_behalf_record(pos, record);
+  if(ret)
+    return ret;
+  return sp_write_last_record(pos);
+}
+
+//ÈôÏû·Ñ³É¹¦£¬´æ´¢Ï°벿·ÖÁ÷Ë®ÐÅÏ¢
+uint16 sp_prepare_below_transdtl(sp_pos_t* pos, sp_card_t* card, sp_transdtl_t* record)
+{
+  uint8 buff[record_behalf_len];
+  MEMCLEAR(buff, sizeof(buff));
+
+  record->amount = pos->purchase.paid_sum;
+  if(pos->paymode == PAYMODE_QRCODE)
+  {
+    record->paidAmount = card->qrcode.paidAmount;
+  }
+  else
+  {
+    record->paidAmount = 0;
+  }
+  record->flowsensors = pos->purchase.paid_num;
+  record->transtatus = 1;
+  sp_flash_read(pos->last_transdtl.transaddr, buff, sizeof(buff));
+  MEMCPY(record, buff, sizeof(buff));
+  return sp_write_below_record(pos, record);
+}
+
+//Ñ­»·´æ´¢Ã¿Ò»±ÊδÉÏ´«Á÷Ë®¼Ç¼µÄµØÖ·
+uint16 sp_write_unconfirm_record(sp_pos_t* pos)
+{
+  uint8 crc[2];
+  uint8 buff[sizeof(sp_unconfirm_transdtl_t)];
+  MEMCLEAR(buff, sizeof(buff));
+
+  pos->unconfirm_transdtl.this_offset += sizeof(buff);
+  if(pos->unconfirm_transdtl.this_offset >= DEF_FLASH_PageSize)
+  {
+    sp_flash_erase(ADDR_UNCONFIRM_TRANSNO);
+    pos->unconfirm_transdtl.this_offset = 0;
+  }
+  sp_protocol_crc((uint8*)&pos->unconfirm_transdtl, sizeof(buff)-2,
+                  pos->unconfirm_transdtl.crc);
+  sp_flash_write(pos->unconfirm_transdtl.this_offset+ADDR_UNCONFIRM_TRANSNO,
+                 (uint8*)&pos->unconfirm_transdtl, sizeof(buff));
+
+  sp_flash_read(pos->unconfirm_transdtl.this_offset+ADDR_UNCONFIRM_TRANSNO, buff,
+                sizeof(buff));
+  sp_protocol_crc(buff, sizeof(buff)-2, crc);
+  if(MEMCMP(pos->unconfirm_transdtl.crc, crc, 2) !=0)
+  {
+    pos->load_para_status = RC_FLASH_ERR;
+    return RC_FLASH_ERR;
+  }
+  return 0;
+}
+
+static uint16 sp_init_last_transdtl_ptr(sp_last_transdtl_t* record)
+{
+  record->transaddr = ADDR_TRANSDTL_BEGIN -sizeof(sp_transdtl_t);
+  record->this_offset = 0;
+  sp_protocol_crc((uint8*)record,sizeof(sp_last_transdtl_t) -2,record->crc);
+  return sp_flash_page_write(ADDR_LAST_TRANSNO,(uint8*)record,sizeof(sp_last_transdtl_t));
+}
+
+static uint16 sp_init_unconfirm_transdtl_ptr(sp_unconfirm_transdtl_t* record)
+{
+  record->transaddr = ADDR_TRANSDTL_BEGIN;
+  record->this_offset = 0;
+  sp_protocol_crc((uint8*)record,sizeof(sp_unconfirm_transdtl_t) -2,record->crc);
+  return sp_flash_page_write(ADDR_UNCONFIRM_TRANSNO,(uint8*)record,
+                             sizeof(sp_unconfirm_transdtl_t));
+}
+
+static uint8 sp_load_last_transdtl_ptr(sp_pos_t* pos)
+{
+  uint8 crc[2];
+  sp_flash_page_read(ADDR_LAST_TRANSNO,(uint8*)&pos->last_transdtl,
+                     sizeof(sp_last_transdtl_t));
+  sp_protocol_crc((uint8*)&pos->last_transdtl,sizeof(sp_last_transdtl_t) -2,crc);
+  if(MEMCMP(pos->last_transdtl.crc,crc,2) != 0)
+  {
+    sp_init_last_transdtl_ptr(&pos->last_transdtl);
+  }
+  return 0;
+}
+static uint8 sp_load_unconfirm_transdtl_ptr(sp_pos_t* pos)
+{
+  uint8 crc[2];
+  sp_flash_page_read(ADDR_UNCONFIRM_TRANSNO,(uint8*)&pos->unconfirm_transdtl,
+                     sizeof(sp_unconfirm_transdtl_t));
+  sp_protocol_crc((uint8*)&pos->unconfirm_transdtl,sizeof(sp_unconfirm_transdtl_t) -2,crc);
+  if(MEMCMP(pos->unconfirm_transdtl.crc,crc,2) != 0)
+  {
+    sp_init_unconfirm_transdtl_ptr(&pos->unconfirm_transdtl);
+  }
+  return 0;
+}
+
+static uint16 sp_parse_config(sp_pos_t* pos, sp_config_t* config)
+{
+  pos->sysconf.dev_offline_maxhour = config->offline_work_hour;
+  if(pos->sysconf.dev_offline_maxhour == 0)
+  {
+    pos->sysconf.dev_offline_maxhour = DEV_OFFLINE_DEFAULT_HOUR;
+  }
+  pos->sysconf.flowsensor_unit = config->flowsensor_unit;
+  pos->deviceno = config->deviceno;
+  pos->devlogin.login_flag = config->login_flag;
+  MEMCPY(pos->devphyid,config->devphyid,4);
+  return 0;
+}
+static uint16 sp_read_config(sp_pos_t* pos, sp_config_t* config)
+{
+  uint8 crc[2];
+  sp_flash_read(ADDR_CONFIG_PARA,(uint8*)config,sizeof(sp_config_t));
+  sp_protocol_crc((uint8*)config,sizeof(sp_config_t) -2,crc);
+  if(memcmp(config->crc,crc,2) != 0)
+  {
+    return RC_CONFPARA_CRC_ERR;
+  }
+  sp_parse_config(pos, config);
+  return 0;
+}
+
+uint16 sp_clear_transdtl(sp_pos_t* pos)
+{
+  uint32 i;
+  uint16 ret = sp_flash_erase(ADDR_LAST_TRANSNO);
+  ret |= sp_flash_erase(ADDR_UNCONFIRM_TRANSNO);
+  for(i = ADDR_TRANSDTL_BEGIN; i < ADDR_TRANSDTL_END; i += DEF_FLASH_PageSize)
+  {
+    ret |= sp_flash_erase(i);
+  }
+  return ret;
+}
+
+static uint16 sp_init_device(sp_pos_t* pos)
+{
+  uint16 ret;
+  disp_hint_info_two(pos,"É豸³õʼ»¯","Çå¿ÕÁ÷Ë®",0);
+  ret |= sp_clear_transdtl(pos);
+  return  ret;
+}
+
+void sp_reset_factory(sp_pos_t* pos)
+{
+  uint16 ret;
+  disp_hint_info_two(pos,"»Ö¸´³ö³§ÖÐ","ÇëÉÔµÈ...",0);
+  ret = sp_flash_erase(ADDR_CONFIG_PARA);
+  ret |=sp_clear_transdtl(pos);
+  if(!ret)
+  {
+    disp_hint_info_two(pos,"³õʼ»¯³É¹¦","µÈ´ýÖØÆô",0);
+  }
+  else
+  {
+    disp_hint_info_two(pos,"³õʼ»¯Ê§°Ü","µÈ´ýÖØÆô",0);
+  }
+  sp_reset();
+}
+
+uint16 sp_load_config(sp_pos_t* pos)
+{
+  uint16 ret;
+  sp_config_t config;
+  MEMCLEAR(&config,sizeof config);
+  ret |= sp_read_config(pos, &config);
+  if(ret)
+  {
+    sp_config_init(pos);
+    sp_init_device(pos);
+  }
+  ret |= sp_load_last_transdtl_ptr(pos);
+  ret |= sp_load_unconfirm_transdtl_ptr(pos);
+  return ret;
+}
+
+uint16 sp_save_config(sp_pos_t* pos, sp_config_t* config)
+{
+  uint8 buffer[sizeof(sp_config_t)];
+  uint8 crc[2];
+  sp_protocol_crc((uint8*)config,sizeof(sp_config_t)-2,config->crc);
+  sp_flash_erase(ADDR_CONFIG_PARA);
+  sp_flash_write(ADDR_CONFIG_PARA,(uint8*)config,sizeof(sp_config_t));
+  sp_flash_read(ADDR_CONFIG_PARA,buffer,sizeof buffer);
+  sp_protocol_crc(buffer,sizeof(buffer)-2,crc);
+  if(memcmp(config->crc,crc,2) != 0)
+  {
+    return RC_CONFPARA_CRC_ERR;
+  }
+  sp_parse_config(pos, config);
+  return 0;
+}
+
+uint16 sp_save_deviceno(sp_pos_t* pos, uint8 deviceno)
+{
+  uint16 ret;
+  sp_config_t config;
+  MEMCLEAR(&config, sizeof config);
+  ret = sp_read_config(pos, &config);
+  if(ret)
+  {
+    return ret;
+  }
+  config.deviceno = deviceno;
+  return sp_save_config(pos, &config);
+}
+uint16 sp_save_devphyid(sp_pos_t* pos, uint8 devphyid[4])
+{
+  uint16 ret;
+  sp_config_t config;
+  MEMCLEAR(&config, sizeof config);
+  ret = sp_read_config(pos, &config);
+  if(ret)
+  {
+    return ret;
+  }
+  MEMCPY(config.devphyid,devphyid,4);
+  return sp_save_config(pos, &config);
+}
+uint16 sp_save_login_info(sp_pos_t* pos, uint8 flag, uint8 unit, uint8 offline_maxhour)
+{
+  uint16 ret;
+  sp_config_t config;
+  MEMCLEAR(&config, sizeof config);
+  ret = sp_read_config(pos, &config);
+  if(ret)
+  {
+    return ret;
+  }
+  config.login_flag = flag;
+  config.flowsensor_unit = unit;
+  config.offline_work_hour = offline_maxhour;
+  return sp_save_config(pos, &config);
+}
+
+uint16 sp_save_heartbeat_info(sp_pos_t* pos, uint8 flag)
+{
+  uint16 ret;
+  sp_config_t config;
+  MEMCLEAR(&config, sizeof config);
+  ret = sp_read_config(pos, &config);
+  if(ret)
+  {
+    return ret;
+  }
+  config.login_flag = flag;
+  return sp_save_config(pos, &config);
+
+}
+
+uint16 sp_config_init(sp_pos_t* pos)
+{
+  uint16 ret = 0;
+  uint8 crc[2];
+  sp_config_t config;
+  MEMCLEAR(&config, sizeof(config));
+  disp_hint_info(pos,"É豸²ÎÊý³õʼ»¯", DELAY_TIME2s);
+  sp_protocol_crc((uint8*)&config,sizeof(sp_config_t)-2,config.crc);
+  sp_flash_erase(ADDR_CONFIG_PARA);
+  sp_flash_write(ADDR_CONFIG_PARA,(uint8*)&config,sizeof(sp_config_t));
+  sp_flash_read(ADDR_CONFIG_PARA,(uint8*)&config,sizeof(config));
+  sp_protocol_crc((uint8*)&config,sizeof(sp_config_t)-2,crc);
+  if(memcmp(config.crc,crc,2) != 0)
+  {
+    return RC_CONFPARA_CRC_ERR;
+  }
+  ret = sp_flash_erase(ADDR_CONFIG_PARA);
+  return ret;
+}
diff --git a/supwisdom/sp_data.h b/supwisdom/sp_data.h
new file mode 100644
index 0000000..1ed4942
--- /dev/null
+++ b/supwisdom/sp_data.h
@@ -0,0 +1,30 @@
+#ifndef _SP_DATA_H_
+#define _SP_DATA_H_
+
+#include "sp_config.h"
+#include "sp_communicate.h"
+
+//Á÷Ë®´¦Àí
+uint16 sp_prepare_behalf_transdtl(sp_pos_t* pos, sp_card_t* card, sp_transdtl_t* record);
+uint16 sp_prepare_below_transdtl(sp_pos_t* pos, sp_card_t* card, sp_transdtl_t* record);
+uint16 sp_read_lastrecord(const sp_pos_t* pos, sp_transdtl_t* dtl);
+uint16 sp_confirm_record(const sp_pos_t* pos, sp_transdtl_t* dtl);
+uint16 sp_query_record(const sp_pos_t* pos, uint8 refno[16], sp_transdtl_t* dtl);
+uint16 sp_clear_transdtl(sp_pos_t* pos);
+uint16 sp_write_unconfirm_record(sp_pos_t* pos);
+
+//ϵͳ²ÎÊýÉèÖÃ
+void sp_reset_factory(sp_pos_t* pos);
+uint16 sp_load_config(sp_pos_t* pos);
+uint16 sp_save_config(sp_pos_t* pos, sp_config_t* config);
+uint16 sp_save_deviceno(sp_pos_t* pos, uint8 deviceno);
+uint16 sp_save_devphyid(sp_pos_t* pos, uint8 devphyid[4]);
+uint16 sp_config_init(sp_pos_t* pos);
+uint16 sp_save_login_info(sp_pos_t* pos, uint8 flag, uint8 unit, uint8 offline_maxhour);
+uint16 sp_save_heartbeat_info(sp_pos_t* pos, uint8 flag);
+
+//É豸ÊÖ¶¯²Ù×÷½Ó¿Ú
+uint8 sp_confirm_login(sp_protocol_response_t* resp, sp_pos_t* pos);
+
+#endif
+
diff --git a/supwisdom/sp_des.c b/supwisdom/sp_des.c
new file mode 100644
index 0000000..5d19916
--- /dev/null
+++ b/supwisdom/sp_des.c
@@ -0,0 +1,39 @@
+#include "string.h"
+#include "../icc_apdu_lib/des.h"
+
+#include "sp_des.h"
+
+static des_context desctx;
+static des3_context des3ctx;
+
+uint8 single_des_set_keys(uint8 key[8])
+{
+  return des_set_key(&desctx, key);
+}
+
+void single_des_encrypt(uint8 src[8], uint8 dest[8])
+{
+  des_encrypt(&desctx, src, dest);
+}
+
+void single_des_decrypt(uint8 src[8], uint8 dest[8])
+{
+  des_decrypt(&desctx, src, dest);
+}
+
+uint8 triple_des_set_keys(uint8 key[16])
+{
+  return des3_set_2keys(&des3ctx, key, key+8);
+}
+
+void triple_des_encrypt(uint8 src[8], uint8 dest[8])
+{
+  des3_encrypt(&des3ctx, src, dest);
+}
+
+void triple_des_decrypt(uint8 src[8], uint8 dest[8])
+{
+  des3_decrypt(&des3ctx, src, dest);
+}
+
+
diff --git a/supwisdom/sp_des.h b/supwisdom/sp_des.h
new file mode 100644
index 0000000..bc8a7c7
--- /dev/null
+++ b/supwisdom/sp_des.h
@@ -0,0 +1,27 @@
+#ifndef _SP_DES_H_
+#define _SP_DES_H_
+
+#include "../config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif 
+
+uint8 single_des_set_keys(uint8 key[8]);
+
+void single_des_encrypt(uint8 src[8], uint8 dest[8]);
+
+void single_des_decrypt(uint8 src[8], uint8 dest[8]);
+
+uint8 triple_des_set_keys(uint8 key[16]);
+
+void triple_des_encrypt(uint8 src[8], uint8 dest[8]);
+
+void triple_des_decrypt(uint8 src[8], uint8 dest[8]);
+
+#ifdef __cplusplus
+}
+#endif 
+
+#endif
+
diff --git a/supwisdom/sp_display.c b/supwisdom/sp_display.c
new file mode 100644
index 0000000..fb0417c
--- /dev/null
+++ b/supwisdom/sp_display.c
@@ -0,0 +1,356 @@
+#include "glcd.h"
+#include "../zk/gb2312_16.h"
+#include "../libqr/qrencode.h"
+#include "sp_util.h"
+#include "sp_constant.h"
+#include "sp_display.h"
+
+#define GLCD_TITLE_X 0
+#define GLCD_TITLE_Y 0
+#define GLCD_TITLE_LINE 8
+#define GLCD_CONTENT_Y_ONE 0x10
+#define GLCD_CONTENT_Y_TWO 0x20
+#define GLCD_CONTENT_Y_THREE 0x30
+#define GLCD_BUTTOM_Y 56
+#define GLCD_LINE_LENGTH 0x10
+
+static char line_buff[17];
+
+/********************************************************************************************************
+* º¯Êý(Name)      : void  Show_Money(uint32 money)
+* ¹¦ÄÜ(Function)  : ÏÔʾ½ð¶î
+* ²ÎÊý(Parameter) : money--¿¨Óà¶î(µ¥Î»:Ôª)
+* ·µ»Ø(Return)    : ÎÞ
+**********************************************************************************************************/
+void show_money(sp_pos_t* pos, uint32 money)
+{
+  char msg[32];
+  sprintf(msg,"     %.02f Ԫ",money/100.0f);
+  disp_hint_info_two(pos,"ÀÛ¼ÆË®·Ñ:",msg,0);
+}
+
+void glcd_tiny_init(void)
+{
+  uint8 retry;
+  glcd_tiny_set_font(Font5x7,5,7,32,127);
+  glcd_clear_buffer();
+  glcd_write();
+  for(retry=0; retry<3; retry++)
+  {
+    if(gb2312_16_verify() == 0)
+    {
+      break;
+    }
+  }
+  glcd_write();
+}
+static void show_title(void)
+{
+  uint8 ctime[7];
+  glcd_tiny_set_font(Font5x7,5,7,32,127);
+  glcd_clear_buffer();
+  sp_get_bcdtime(ctime);
+  sprintf(line_buff, "%02x-%02x-%02x %02x:%02x:%02x",
+          ctime[0],ctime[1],ctime[2],
+          ctime[3],ctime[4],ctime[5]);
+  glcd_draw_string_xy(0, 0, line_buff);
+  glcd_draw_line(0, GLCD_TITLE_LINE, 127, 8, BLACK);
+}
+
+static void show_bottom(sp_pos_t* pos)
+{
+  sprintf(line_buff,"%02d:%02x%02x%02x%02x",pos->deviceno, pos->devphyid[0],
+          pos->devphyid[1], pos->devphyid[2], pos->devphyid[3]);
+  glcd_draw_string_xy(0, GLCD_BUTTOM_Y, line_buff);
+}
+
+static char last_qrcode_url[32]= {0};
+void show_home_qrcode(char* qrcode_url)
+{
+  uint8 i,j;
+  if(MEMCMP(qrcode_url,last_qrcode_url,(int)strlen(qrcode_url)) != 0)
+  {
+    sprintf(last_qrcode_url,"%s",qrcode_url);
+    //¶þάÂëÉú³ÉµãÕó
+    QRencode(last_qrcode_url, NULL);
+  }
+  //¶þάÂëµãÕóÏÔʾ
+  for(i=0; i<MAX_MODULESIZE*2; i++)
+  {
+    for(j=0; j<MAX_MODULESIZE*2; j++)
+    {
+      uint8_t pixel = m_byModuleData[i/2][j/2];
+
+      glcd_set_pixel(j+70, 12+i, pixel);
+      glcd_set_pixel(j+70, 12+i+1, pixel);
+      j ++;
+      glcd_set_pixel(j+70, 12+i, pixel);
+      glcd_set_pixel(j+70, 12+i+1, pixel);
+    }
+    i ++;
+  }
+  glcd_write();
+
+}
+static uint8 last_ctime[6];
+void show_home(sp_pos_t* pos)
+{
+  uint8 ctime[6];
+  sp_get_bcdtime(ctime);
+  if(MEMCMP(ctime,last_ctime,6) != 0)
+  {
+    MEMCPY(last_ctime,ctime,6);
+    disp_hint_info_two(pos,"F°æ±¾",PRO_VERSION,0);
+	/*
+    if(pos->sysconf.register_flag)
+    {
+      if(pos->dynamic.ws_client_stat)
+      {
+        show_home_qrcode(pos->dynamic.qrcode_url);
+      }
+    }
+	*/
+  }
+}
+
+void show_set_devno(sp_pos_t* pos, uint8 devno)
+{
+  char msg[32];
+  sprintf(msg,"»úºÅ=%d",devno);
+  disp_hint_info_two(pos, "ÉèÖûúºÅ³É¹¦",msg,DELAY_TIME1s);
+}
+void show_set_devphyid(sp_pos_t* pos, uint8 devphyid[4])
+{
+  char msg[32];
+  sprintf(msg,"ID=%02x%02x%02x%02x",
+          devphyid[0],devphyid[1],devphyid[2],devphyid[3]);
+  disp_hint_info_two(pos,"ÉèÖÃÎïÀíID³É¹¦",msg,DELAY_TIME1s);
+}
+void show_set_dev_offline_maxhour(sp_pos_t* pos, uint16 maxhour)
+{
+  char msg[32];
+  sprintf(msg,"ÍÑ»ú¹¤×÷ʱ¼ä=%d",maxhour);
+  disp_hint_info_two(pos, "ÉèÖÃÍÑ»ú¹¤×÷ʱ¼ä³É¹¦",msg,DELAY_TIME1s);
+}
+
+void show_manage_passwd(sp_pos_t* pos, const char* hint,uint8 passwd[],uint8 len)
+{
+  char msg[32];
+  switch(len)
+  {
+  case 0:
+    sprintf(msg,"");
+    break;
+  case 1:
+    sprintf(msg,"%d",passwd[0]);
+    break;
+  case 2:
+    sprintf(msg,"%d%d",passwd[0],passwd[1]);
+    break;
+  case 3:
+    sprintf(msg,"%d%d%d",passwd[0],passwd[1],passwd[2]);
+    break;
+  case 4:
+    sprintf(msg,"%d%d%d%d",passwd[0],passwd[1],passwd[2],passwd[3]);
+    break;
+  case 5:
+    sprintf(msg,"%d%d%d%d%d",passwd[0],passwd[1],passwd[2],passwd[3],passwd[4]);
+    break;
+  case 6:
+    sprintf(msg,"%d%d%d%d%d%d",passwd[0],passwd[1],passwd[2],passwd[3],passwd[4],passwd[5]);
+    break;
+  default:
+    sprintf(msg,"");
+  }
+  disp_hint_info_two(pos,hint,msg,0);
+}
+
+void show_error(sp_pos_t* pos, const char* hint, uint16 errcode)
+{
+  char msg[32];
+  switch(errcode)
+  {
+  case RC_PSAM_ERR:
+    sprintf(msg,"%s", "SAM¸´Î»Ê§°Ü");
+    break;
+  case RC_CARD_LOGIN:
+    sprintf(msg,"%s", "ÑéÖ¤ÃØÔ¿Ê§°Ü");
+    break;
+  case RC_CARD_READ:
+    sprintf(msg,"%s", "¶Á¿¨Ê§°Ü");
+    break;
+  case RC_CARD_WRITE:
+    sprintf(msg,"%s", "д¿¨Ê§°Ü");
+    break;
+  case RC_FLASH_ERR:
+    sprintf(msg,"%s", "FLASHÒì³£");
+    break;
+  case RC_HARDWARE_ERR:
+    sprintf(msg,"%s", "¹Ì¼þÒì³£");
+    break;
+  case RC_FLASH_NO_RIGHT:
+    sprintf(msg,"%s", "FLASHÏÞÖÆ");
+    break;
+  case RC_CARD_NORIGHT:
+    sprintf(msg,"%s", "¿¨ÎÞȨÏÞ");
+    break;
+  case RC_CARD_EXPIRED:
+    sprintf(msg,"%s", "¿¨ÒѹýÆÚ");
+    break;
+  case RC_CARD_LOST:
+    sprintf(msg,"%s", "¿¨ÒÑËø¶¨");
+    break;
+  case RC_CARDNO_EXCEPT:
+    sprintf(msg,"%s", "¿¨Òì³£");
+    break;
+  case RC_CARD_TIMEOUT:
+    sprintf(msg,"%s", "ʹÓÃÌ«¾Ã");
+    break;
+  case RC_CARDBAL_EXCEPT:
+    sprintf(msg,"%s", "Óà¶îÒì³£");
+    break;
+  case RC_CARDBAL_LACK:
+    sprintf(msg,"%s", "ÇëÁª»úÏû·Ñ");
+    break;
+  case RC_DEVPHYID_NOTSET:
+    sprintf(msg,"%s", "δÉèÖûúºÅ");
+    break;
+  case RC_FEERATE_NOTSET:
+    sprintf(msg,"%s", "δÉèÖ÷ÑÂÊ");
+    break;
+  case RC_DEV_OFFLINE_ERROR:
+    sprintf(msg,"%s", "É豸ÍÑ»úÌ«¾Ã");
+    break;
+  case RC_TRANSDTL_FULL:
+    sprintf(msg,"%s", "Á÷Ë®ÒÑÂú");
+    break;
+  case RC_FILE09_CRC_ERR:
+    sprintf(msg,"%s", "09CRC´íÎó");
+    break;
+  case RC_FILE10_CRC_ERR:
+    sprintf(msg,"%s", "10CRC´íÎó");
+    break;
+  case RC_CARD_INVALID:
+    sprintf(msg,"%s", "ÎÞЧ¿¨");
+    break;
+  case RC_FEENUM_ERROR:
+    sprintf(msg,"%s", "·ÑÂʸöÊý´íÎó");
+    break;
+  case RC_NOTSUPPORT:
+    sprintf(msg,"%s", "²»Ö§³Ö");
+    break;
+  case RC_NOT_SAME_CARD:
+    sprintf(msg,"%s", "²»Í¬¿¨");
+    break;
+  case RC_MODE_NOT_SUPPORT:
+    sprintf(msg,"%s", "ģʽ²»Ö§³Ö");
+    break;
+  case RC_UPDPROG_ERR:
+    sprintf(msg,"%s", "Éý¼¶Ê§°Ü");
+    break;
+  case RC_CONFPARA_CRC_ERR:
+    sprintf(msg,"%s", "ÅäÖÃCRC´íÎó");
+    break;
+  case RC_TRANSDTL_NO_ERR:
+    sprintf(msg,"%s", "Á÷Ë®ºÅÒì³£");
+    break;
+  case RC_DEVICENO_OUT:
+    sprintf(msg,"%s", "»úºÅ¹ý´ó");
+    break;
+  case RC_QRCODE_FAILURE:
+  	sprintf(msg,"%s", "¶þάÂë»ñȡʧ°Ü");
+	break;
+  case RC_QRCODE_TIMEOUT:
+  	sprintf(msg,"%s", "¶þάÂ볬ʱ");
+	break;
+  case RC_QRCODE_QUERY_FAIL:
+  	sprintf(msg,"%s", "¶þάÂëÈÏ֤ʧ°Ü");
+	break;
+  case RC_DEV_NOT_LOGIN:
+  	sprintf(msg,"%s", "É豸δǩµ½");
+	break;
+  case RC_DEV_FAULT:
+  	sprintf(msg,"%s", "É豸ÒÉËÆ¹ÊÕÏ");
+	break;
+  case RC_DEV_NOSET_FLOWSENSOR_UNIT:
+  	sprintf(msg,"%s", "Á÷Á¿¼ÆË㵥λδÉèÖÃ");
+	break;
+  case RC_CARD_AUTHENTICATION:
+  	sprintf(msg,"%s", "¿¨ÈÏ֤ʧ°Ü");
+	break;
+  default:
+    sprintf(msg,"´íÎóÂë=0x%04x",errcode);
+  }
+  disp_hint_info_two(pos,hint,msg,DELAY_TIME3s);
+}
+
+void disp_hint_info_three(sp_pos_t* pos,const char* msg1,const char* msg2,const char* msg3,uint32 ms)
+{
+  show_title();
+  show_bottom(pos);
+
+  snprintf(line_buff,sizeof line_buff,"%s               ",msg1);
+  gb2312_16_draw_str(0, GLCD_CONTENT_Y_ONE, line_buff);
+  snprintf(line_buff,sizeof line_buff,"%s               ",msg2);
+  gb2312_16_draw_str(0, GLCD_CONTENT_Y_TWO, line_buff);
+  snprintf(line_buff,sizeof line_buff,"%s               ",msg3);
+  gb2312_16_draw_str(0, GLCD_CONTENT_Y_THREE, line_buff);
+
+  glcd_write();
+  if(ms > 0)
+  {
+    Delay_ms(ms);
+  }
+}
+
+void disp_hint_info_two(sp_pos_t* pos,const char* msg1,const char* msg2,uint32 ms)
+{
+  show_title();
+  show_bottom(pos);
+
+  snprintf(line_buff,sizeof line_buff,"%s               ",msg1);
+  gb2312_16_draw_str(0, GLCD_CONTENT_Y_ONE, line_buff);
+  snprintf(line_buff,sizeof line_buff,"%s               ",msg2);
+  gb2312_16_draw_str(0, GLCD_CONTENT_Y_TWO, line_buff);
+
+  glcd_write();
+  if(ms > 0)
+  {
+    Delay_ms(ms);
+  }
+}
+void disp_hint_info(sp_pos_t* pos,const char* msg1,uint32 ms)
+{
+  show_title();
+  show_bottom(pos);
+
+  snprintf(line_buff,sizeof line_buff,"%s               ",msg1);
+  gb2312_16_draw_str(0, GLCD_CONTENT_Y_ONE, line_buff);
+  snprintf(line_buff,sizeof line_buff,"                  ");
+  gb2312_16_draw_str(0, GLCD_CONTENT_Y_TWO, line_buff);
+
+  glcd_write();
+  if(ms > 0)
+  {
+    Delay_ms(ms);
+  }
+}
+void disp_server_errmsg(sp_pos_t* pos,const char* hint,uint8 data[],uint16 len)
+{
+  uint8 strlen;
+  char errmsg[64];
+  strlen = data[0];
+  //command+canid+excmd+flag+retcode+len+crc
+  if((strlen +8) != len)
+  {
+    disp_hint_info_two(pos,hint,"ÇëÇó³¬Ê±",DELAY_TIME3s);
+    return;
+  }
+  if(strlen > 32)
+  {
+    strlen = 32;
+  }
+  snprintf(errmsg,strlen+1,"%s",data +1);
+  disp_hint_info_two(pos,hint,errmsg,DELAY_TIME3s);
+}
+
diff --git a/supwisdom/sp_display.h b/supwisdom/sp_display.h
new file mode 100644
index 0000000..3160248
--- /dev/null
+++ b/supwisdom/sp_display.h
@@ -0,0 +1,36 @@
+#ifndef _SP_DISPLAY_H_
+#define _SP_DISPLAY_H_
+
+#include "sp_config.h"
+
+/*******************************************************************************************************
+* º¯Êý(Name)	  : void  Show_Error(uint32 errcode)
+* ¹¦ÄÜ(Function)  : ÏÔʾ´íÎó´úÂë
+* ²ÎÊý(Parameter) : errcode -- ´íÎó´úºÅ
+* ·µ»Ø(Return)	  : ÎÞ
+********************************************************************************************************/
+void glcd_tiny_init(void);
+
+/*******************************************************************************************************
+* º¯Êý(Name)	  : void  Show_Pass(void)
+* ¹¦ÄÜ(Function)  : ÏÔʾPASS
+* ²ÎÊý(Parameter) : NULL
+* ·µ»Ø(Return)	  : ÎÞ
+********************************************************************************************************/
+	void show_set_devno(sp_pos_t* pos, uint8 devno);
+	void show_set_devphyid(sp_pos_t* pos, uint8 devphyid[4]);
+	void show_set_dev_offline_maxhour(sp_pos_t* pos, uint16 maxhour);
+	void show_error(sp_pos_t* pos, const char* hint,uint16 code);
+	void show_home(sp_pos_t* pos);
+	void show_money(sp_pos_t* pos, uint32 money);
+	void show_manage_passwd(sp_pos_t* pos, const char* hint,uint8 passwd[],uint8 len);
+	void show_home_qrcode(char* qrcode_url);
+	
+	void disp_hint_info(sp_pos_t* pos, const char* msg1,uint32 ms);
+	void disp_hint_info_two(sp_pos_t* pos, const char* msg1,const char* msg2,uint32 ms);
+	void disp_hint_info_three(sp_pos_t* pos, const char* msg1,const char* msg2,
+							  const char* msg3,uint32 ms);
+	void disp_server_errmsg(sp_pos_t* pos, const char* hint,uint8 data[],uint16 len);
+
+
+#endif
diff --git a/supwisdom/sp_flash.c b/supwisdom/sp_flash.c
new file mode 100644
index 0000000..0788aed
--- /dev/null
+++ b/supwisdom/sp_flash.c
@@ -0,0 +1,123 @@
+#include "sp_constant.h"
+#include "sp_util.h"
+
+#include "sp_flash.h"
+
+uint16 sp_flash_read(uint32 addr,uint8 buf[],uint32 len)
+{
+  return HW_Flash_Read(addr,len,buf);
+}
+uint16 sp_flash_write(uint32 addr,uint8 buf[],uint32 len)
+{
+  if(addr < DEF_IAP_BASE_ADDR)
+  {
+    return RC_FLASH_NO_RIGHT;
+  }
+  return HW_Flash_NotEraseWrite(addr,len,buf);
+}
+uint16 sp_flash_erase(uint32 addr)
+{
+  if(addr < DEF_IAP_BASE_ADDR)
+  {
+    return RC_FLASH_NO_RIGHT;
+  }
+  return HW_Flash_PageErase(addr / FLASH_PAGE_SIZE);
+}
+
+/**
+**¶ÁȡһҳÊý¾Ý,È«FF±íʾÎÞÊý¾Ý
+**@param len > 128 error
+**@return ·µ»Ø0±íʾ²éÕÒÊý¾Ý³É¹¦
+**@return ·µ»Ø·Ç0±íʾÎÞÓÐЧÊý¾Ý
+**/
+uint16 sp_flash_page_read(uint32 addr,uint8 buf[],uint32 len)
+{
+  uint32 i;
+  uint32 offset = 0;
+  uint8 temp[128];
+
+  if(len > sizeof(temp))
+  {
+    return 1;
+  }
+
+  while(1)
+  {
+    i = 0;
+    sp_flash_read(addr +offset,temp, len);
+    while(i < len)
+    {
+      if(0xFF == temp[i])
+      {
+        ++i;
+      }
+      else
+      {
+        break;
+      }
+    }
+    if(len == i)
+    {
+      if(0 == offset)
+      {
+        //ÎÞÊý¾Ý
+        return 1;
+      }
+      else
+      {
+        sp_flash_read(addr +offset -len,buf, len);
+        return 0;
+      }
+    }
+    offset += len;
+    if(DEF_FLASH_PageSize < (offset +len)) //  ³¬¹ýµ±Ò³Î´ÕÒµ½·µ»Ø1
+    {
+      return 1;
+    }
+  }
+}
+/**
+**дһҳÊý¾Ý
+**@param len > 32 error
+**@return ·µ»Ø0±íʾ¼Ç¼Êý¾Ý³É¹¦
+**@return ·µ»Ø·Ç0±íʾдFLASHʧ°Ü
+**/
+uint16 sp_flash_page_write(uint32 addr,uint8 buf[],uint32 len)
+{
+  uint32 i;
+  uint32 offset = 0;
+  uint8 temp[64];
+
+  if(len > 64)
+  {
+    return 1;
+  }
+  while(1)
+  {
+    i = 0;
+    sp_flash_read(addr +offset,temp, len);
+    while(i < len)
+    {
+      if(0xFF == temp[i])
+      {
+        ++i;
+      }
+      else
+      {
+        break;
+      }
+    }
+    if(DEF_FLASH_PageSize < (offset +len)) //  ³¬¹ýµ±Ò³±íʾÒÑдÂú,²Á³ýÖØÐ´
+    {
+      sp_flash_erase(addr);
+      return sp_flash_write(addr,buf, len);
+    }
+    if(len == i)
+    {
+      //ÎÞÊý¾Ý
+      return sp_flash_write(addr +offset,buf, len);
+    }
+    offset += len;
+  }
+}
+
diff --git a/supwisdom/sp_flash.h b/supwisdom/sp_flash.h
new file mode 100644
index 0000000..f01517d
--- /dev/null
+++ b/supwisdom/sp_flash.h
@@ -0,0 +1,63 @@
+#ifndef _SP_FLASH_H_
+#define _SP_FLASH_H_
+
+#include "../sys_hw/Prj_FlashCfg.H"
+#include "sp_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////EEPROM ¿Õ¼ä/////////////////////////////
+///////////////////FLASH ¿Õ¼ä////////////////////////////////////////////////////
+
+#if 0
+#define ADDR_FLASH_BEGIN 			0x17000 	// base addr 
+#define ADDR_CONFIG_PARA			0x17000		//ÅäÖòÎÊý
+
+#define ADDR_TRANSDTL_PTR 			0x18000		//Á÷ˮָÕë
+#define ADDR_TRANSDTL_BEGIN 		0x200000	//Á÷Ë®Æðʼ
+#define ADDR_TRANSDTL_END 			0x350000	//Á÷Ë®½áÊø
+#define ADDR_MAX 					0x400000
+#endif
+//###############################################################
+/*********Ô¶³ÌÉý¼¶Îļþ´æ´¢100Ò³*********************/
+/*********×¢ÒâÉý¼¶µØÖ·ÓëBOOTÉý¼¶µØÖ·±£³ÖÒ»ÖÂ**/
+#define DEF_IAP_BASE_ADDR 			(DEF_FLASH_IAP_AppCodeStartAdd)
+#define DEF_IapMarkAddr				( DEF_IAP_BASE_ADDR + 1 * DEF_FLASH_PageSize )			//IAPÉý¼¶±ê¼ÇµØÖ·
+#define DEF_EraMarkAddr				( DEF_IAP_BASE_ADDR + 2 * DEF_FLASH_PageSize )			//²Á³ýFLASH±ê¼Ç
+#define	DEF_IapDataAddr				( DEF_IAP_BASE_ADDR + 3 * DEF_FLASH_PageSize )			//IAPÊý¾ÝÇøÆðʼµØÖ·
+
+#define DEF_FLASH_codeStartAdd	 	(DEF_IapDataAddr)
+
+#define ADDR_UPGRADE_UPINFO 		(ADDR_FLASH_END + DEF_FLASH_PageSize *1)
+#define ADDR_KEY_PARA				(ADDR_UPGRADE_UPINFO + DEF_FLASH_PageSize *1)
+
+#define ADDR_UPGRADE_BEGIN 			(DEF_FLASH_codeStartAdd)
+#define ADDR_UPGRADE_END 			(DEF_FLASH_IAP_AppCodeEndAdd -DEF_FLASH_PageSize)
+
+#define ADDR_APPLICATION_BASE		0x130000  //base addr
+#define ADDR_APP_VERSION			(ADDR_APPLICATION_BASE)  //°æ±¾±êʶ
+
+#define ADDR_CONFIG_PARA			(ADDR_APP_VERSION +DEF_FLASH_PageSize *1)//ÅäÖòÎÊý
+
+#define ADDR_LAST_TRANSNO			(ADDR_CONFIG_PARA +DEF_FLASH_PageSize *10)
+#define ADDR_UNCONFIRM_TRANSNO		(ADDR_LAST_TRANSNO +DEF_FLASH_PageSize *1)
+#define ADDR_TRANSDTL_BEGIN			(ADDR_UNCONFIRM_TRANSNO +DEF_FLASH_PageSize *1)
+#define ADDR_TRANSDTL_END 			(ADDR_TRANSDTL_BEGIN +DEF_FLASH_PageSize *100)
+#define ADDR_FLASH_END				(ADDR_TRANSDTL_END)
+#define ADDR_MAX 					0x400000
+
+//#########################################
+
+uint16 sp_flash_read(uint32 addr,uint8 buf[],uint32 len);
+uint16 sp_flash_write(uint32 addr,uint8 buf[],uint32 len);
+uint16 sp_flash_erase(uint32 addr);
+uint16 sp_flash_page_read(uint32 addr,uint8 buf[],uint32 len);
+uint16 sp_flash_page_write(uint32 addr,uint8 buf[],uint32 len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/supwisdom/sp_menu.c b/supwisdom/sp_menu.c
new file mode 100644
index 0000000..4447d52
--- /dev/null
+++ b/supwisdom/sp_menu.c
@@ -0,0 +1,655 @@
+#include "sp_menu.h"
+#include "sp_util.h"
+#include "sp_data.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "sp_constant.h"
+#include "sp_communicate.h"
+#include "sp_display.h"
+#include "sp_upgrade.h"
+#include "../nec_hardware.h"
+
+typedef void(*menu_func_t)(sp_pos_t* pos);
+typedef struct
+{
+  char* hit;
+  menu_func_t func;
+} menu_t;
+
+static void sp_show_syspara(sp_pos_t* pos)
+{
+  uint32 ticker;
+  uint8 keycode;
+  uint8 key_press = 1;
+  uint8 max_cnt = 0;
+  uint8 offset = 0;
+  uint8 unconfirm_transnum;
+  char syspara[9][17];
+
+  MEMCLEAR(syspara, sizeof(syspara));
+  sprintf(syspara[offset++], "É豸״̬:");
+  if(pos->devlogin.login_flag == 1)
+  {
+    sprintf(syspara[offset++], "ÒÑÇ©µ½");
+  }
+  else if(pos->devlogin.login_flag == 0)
+  {
+    sprintf(syspara[offset++], "δǩµ½");
+  }
+  else if(pos->devlogin.login_flag == 2)
+  {
+    sprintf(syspara[offset++], "ÒÑ×¢Ïú");
+  }
+  sprintf(syspara[offset++], "Á´Â·×´Ì¬:");
+  if(pos->link_stat)
+  {
+    sprintf(syspara[offset++], "ÁªÍø");
+  }
+  else
+  {
+    sprintf(syspara[offset++], "ÖжÏ");
+  }
+  sprintf(syspara[offset++], "δÉÏ´«Á÷Ë®:");
+  if(pos->unconfirm_transdtl.transaddr <= pos->last_transdtl.transaddr)
+  {
+    if(pos->unconfirm_transdtl.transaddr == pos->last_transdtl.transaddr)
+    {
+      unconfirm_transnum = 1;
+    }
+    else
+    {
+      unconfirm_transnum = ((pos->last_transdtl.transaddr -
+                             pos->unconfirm_transdtl.transaddr)/sizeof(sp_transdtl_t));
+    }
+  }
+  else
+  {
+    unconfirm_transnum = 0;
+  }
+  sprintf(syspara[offset++], "%d±Ê", unconfirm_transnum);
+  sprintf(syspara[offset++], "Ïû·ÑÀàÐÍ:");
+  sprintf(syspara[offset++], "¼ÇÕËÏû·Ñ");
+
+  max_cnt = sizeof(syspara)/sizeof(syspara[0])/2;
+  offset = 0;
+  ticker = sp_get_ticker();
+  while(sp_get_ticker()-ticker <= DELAY_TIME60s)
+  {
+    keycode = sp_get_key();
+    if(keycode != SP_KEY_NONE)
+    {
+      key_press = 1;
+      switch(keycode)
+      {
+      case SP_KEY_0:
+        if(offset < max_cnt-1)
+        {
+          offset++;
+        }
+        break;
+      case SP_KEY_1:
+      case SP_KEY_2:
+      case SP_KEY_3:
+      case SP_KEY_4:
+      case SP_KEY_5:
+      case SP_KEY_6:
+      case SP_KEY_7:
+      case SP_KEY_8:
+      case SP_KEY_9:
+        offset = keycode -SP_KEY_0;
+        if(offset >= max_cnt)
+        {
+          offset = max_cnt -1;
+        }
+        break;
+      case SP_KEY_CLEAR:
+        return;
+      }
+    }
+    if(key_press)
+    {
+      disp_hint_info_two(pos, syspara[2*offset],syspara[2*offset+1],0);
+      key_press = 0;
+      ticker = sp_get_ticker();
+    }
+  }
+}
+
+static uint8 sp_link_test(sp_pos_t* pos)
+{
+  uint8 ret;
+  sp_protocol_request_t req;
+  sp_protocol_response_t resp;
+  MEMCLEAR(&req, sizeof(req));
+  MEMCLEAR(&resp, sizeof(resp));
+
+  disp_hint_info_two(pos, "ÕýÔÚÁ´Â·¼ì²â", "ÇëÉÔµÈ.....", 0);
+  sp_protocol_req_init(&req, SP_CMD_FACTORY_LINK_TEST);
+  req.data[0] = 0;
+  req.data[1] = 0x55;
+  req.data[2] = 0xAA;
+  req.datalen += 3;
+  ret = sp_comm_call(pos, &req, &resp, DELAY_TIME3s);
+  if(!ret)
+  {
+    if(resp.data[0] == 0x55 && resp.data[1] == 0xAA)
+    {
+      if(sp_check_time_valid(resp.data +2))
+      {
+        disp_hint_info_two(pos, "Á´Â·¼ì²â³É¹¦","ʱÖÓ²»ºÏ·¨", DELAY_TIME3s);
+        return ret;
+      }
+      sp_set_bcdtime(resp.data +2);
+      disp_hint_info_two(pos, "Á´Â·¼ì²â³É¹¦","ÒÑͬ²½Ê±ÖÓ", DELAY_TIME3s);
+      return ret;
+    }
+    disp_hint_info_two(pos, "Á´Â·¼ì²âʧ°Ü","ÊÕµ½´íÎó°ü", DELAY_TIME3s);
+    return 1;
+  }
+  disp_hint_info_two(pos, "Á´Â·¼ì²âʧ°Ü","Çë¼ì²âÏß·", DELAY_TIME3s);
+  return ret;
+}
+
+static void show_keyboard_test(sp_pos_t* pos, uint8 offset)
+{
+  char msg[]= {"0123456789C"};
+  char temp[17];
+  snprintf(temp,offset+1,"%s",msg);
+  disp_hint_info_three(pos, "¼üÅÌÒÀ´ÎÊäÈë","0123456789C",temp,0);
+}
+
+static uint8 sp_keyboard_test(sp_pos_t* pos)
+{
+  uint8 kcode;
+  uint32 tick;
+  uint8 offset = 0;
+  uint8 keybuf[12]= {SP_KEY_0,SP_KEY_1,SP_KEY_2,SP_KEY_3,
+                     SP_KEY_4,SP_KEY_5,SP_KEY_6,SP_KEY_7,
+                     SP_KEY_8,SP_KEY_9,SP_KEY_CLEAR,SP_KEY_ENTER
+                    };
+  show_keyboard_test(pos, offset);
+  tick = sp_get_ticker();
+  while((sp_get_ticker()-tick) < DELAY_TIME60s)
+  {
+    sp_feed_dog();
+    kcode = sp_get_key();
+    if(kcode != SP_KEY_NONE)
+    {
+      tick = sp_get_ticker();
+      switch(kcode)
+      {
+      case SP_KEY_0:
+        if(keybuf[offset] == SP_KEY_0)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_1:
+        if(keybuf[offset] == SP_KEY_1)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_2:
+        if(keybuf[offset] == SP_KEY_2)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_3:
+        if(keybuf[offset] == SP_KEY_3)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_4:
+        if(keybuf[offset] == SP_KEY_4)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_5:
+        if(keybuf[offset] == SP_KEY_5)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_6:
+        if(keybuf[offset] == SP_KEY_6)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_7:
+        if(keybuf[offset] == SP_KEY_7)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_8:
+        if(keybuf[offset] == SP_KEY_8)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_9:
+        if(keybuf[offset] == SP_KEY_9)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_CLEAR:
+        if(offset == 0)
+        {
+          disp_hint_info(pos, "È¡Ïû°´¼ü¼ì²â",DELAY_TIME2s);
+          return 1;
+        }
+        if(keybuf[offset] == SP_KEY_CLEAR)
+        {
+          ++offset;
+          show_keyboard_test(pos, offset);
+        }
+        break;
+      case SP_KEY_ENTER:
+        if(keybuf[offset] == SP_KEY_ENTER)
+        {
+          disp_hint_info_two(pos, "¼üÅ̼ì²âÕýÈ·","¼üÅÌУ׼Õý³£",DELAY_TIME3s);
+          return 0;
+        }
+        break;
+      default:
+        break;
+      }
+    }
+  }
+  return 1;
+
+}
+
+static void sp_factory_check(sp_pos_t* pos)
+{
+  sp_link_test(pos);
+  sp_keyboard_test(pos);
+}
+
+static void sp_set_devtime(sp_pos_t* pos)
+{
+  uint32 ticker;
+  uint8 kcode;
+  uint8 key_press = 1;
+  uint8 ctime[6];
+  uint8 offset;
+  char str[13];
+  char msg[17];
+
+  MEMCLEAR(str,sizeof str);
+  sp_get_bcdtime(ctime);
+  offset = 10;
+  sp_hex_to_str(ctime,5,str);
+  ticker = sp_get_ticker();
+  while(sp_get_ticker() -ticker < DELAY_TIME60s)
+  {
+    kcode = sp_get_key();
+    if(kcode != SP_KEY_NONE)
+    {
+      key_press = 1;
+      switch(kcode)
+      {
+      case SP_KEY_0:
+      case SP_KEY_1:
+      case SP_KEY_2:
+      case SP_KEY_3:
+      case SP_KEY_4:
+      case SP_KEY_5:
+      case SP_KEY_6:
+      case SP_KEY_7:
+      case SP_KEY_8:
+      case SP_KEY_9:
+        if(offset < 10)
+        {
+          str[offset++] = '0' + (kcode- SP_KEY_0);
+        }
+        break;
+      case SP_KEY_ENTER:
+        if(offset >= 10)
+        {
+          MEMCLEAR(ctime,sizeof ctime);
+          sp_str_to_bcd(str,10,ctime);
+          if(sp_check_time_valid(ctime))
+          {
+            disp_hint_info_two(pos,"ÉèÖÃʱ¼äʧ°Ü","ʱ¼ä²»ºÏ·¨", DELAY_TIME3s);
+          }
+          else
+          {
+            sp_set_bcdtime(ctime);
+            disp_hint_info_two(pos,"ÉèÖÃʱ¼ä³É¹¦"," ", DELAY_TIME2s);
+            return;
+          }
+        }
+        break;
+      case SP_KEY_CLEAR:
+        if(offset == 0)
+        {
+          return;
+        }
+        offset--;
+        str[offset] = 0;
+        break;
+      }
+    }
+    if(key_press)
+    {
+      sprintf(msg,"%s",str);
+      disp_hint_info_two(pos,"ÉèÖÃʱ¼ä(ymdHm)",msg,0);
+      ticker = sp_get_ticker();
+      key_press = 0;
+    }
+  }
+}
+
+static void sp_manual_login(sp_pos_t* pos)
+{
+  uint16 ret;
+  uint32 tick;
+  sp_protocol_response_t resp;
+  MEMCLEAR(&resp, sizeof(resp));
+  disp_hint_info_two(pos,"ÕýÔڵǼ","ÇëÉÔµÈ...",0);
+  sp_async_equipment_login(pos);
+  tick = sp_get_ticker();
+  while(sp_get_ticker() - tick < DELAY_TIME3s*2)
+  {
+    MEMCLEAR(&resp, sizeof(resp));
+    usart_read((u8*)&resp, sizeof(resp));
+    if(resp.excmd == SP_CMD_LOGIN)
+    {
+      ret = sp_confirm_login(&resp, pos);
+      break;
+    }
+    else
+    {
+      ret = RC_DEV_LOGIN_FAIL;
+    }
+  }
+  if(ret)
+  {
+    char msg[32];
+    sprintf(msg,"´íÎóÂë=%d",ret);
+    disp_hint_info_two(pos,"Ç©µ½Ê§°Ü",msg,DELAY_TIME3s);
+  }
+  else
+  {
+    disp_hint_info(pos,"Ç©µ½³É¹¦",DELAY_TIME3s);
+  }
+}
+
+static void sp_set_devphyid(sp_pos_t* pos)
+{
+  uint32 ticker;
+  uint8 kcode;
+  uint16 ret = 0;
+  uint8 key_press = 1;
+  char msg[17];
+  uint8 devphyid[4];
+  uint8 offset;
+  char str[9];
+  MEMCPY(devphyid,pos->devphyid,sizeof(pos->devphyid));
+  MEMCLEAR(str,sizeof str);
+
+  ticker = sp_get_ticker();
+  offset = 8;
+  sp_hex_to_str(devphyid,4,str);
+  while(sp_get_ticker() -ticker < DELAY_TIME60s)
+  {
+    kcode = sp_get_key();
+    if(kcode != SP_KEY_NONE)
+    {
+      key_press = 1;
+      switch(kcode)
+      {
+      case SP_KEY_0:
+      case SP_KEY_1:
+      case SP_KEY_2:
+      case SP_KEY_3:
+      case SP_KEY_4:
+      case SP_KEY_5:
+      case SP_KEY_6:
+      case SP_KEY_7:
+      case SP_KEY_8:
+      case SP_KEY_9:
+        if(offset < 8)
+        {
+          str[offset++] = '0' +(kcode -SP_KEY_0);
+        }
+        break;
+      case SP_KEY_ENTER:
+        if(offset >= 8)
+        {
+          sp_str_to_hex(str,8,devphyid);
+          if(0 != MEMCMP(pos->devphyid,devphyid,4))
+          {
+            ret = sp_save_devphyid(pos, devphyid);
+          }
+          if(!ret)
+          {
+            MEMCPY(pos->devphyid,devphyid,4);
+            sprintf(msg,"ID: %02x%02x%02x%02x",devphyid[0],devphyid[1],devphyid[2],devphyid[3]);
+            disp_hint_info_two(pos,"ÉèÖÃÎïÀíID³É¹¦",msg, DELAY_TIME2s);
+          }
+          else
+          {
+            show_error(pos,"±£´æÎïÀíIDʧ°Ü",ret);
+          }
+          return;
+        }
+        break;
+      case SP_KEY_CLEAR:
+        if(offset > 0)
+        {
+          offset--;
+          str[offset] = 0;
+        }
+        else
+        {
+          return;
+        }
+        break;
+      }
+    }
+    if(key_press)
+    {
+      sprintf(msg,"%s",str);
+      disp_hint_info_two(pos,"ÉèÖÃÎïÀíID:",msg,0);
+      ticker = sp_get_ticker();
+      key_press = 0;
+    }
+  }
+  return;
+}
+static void sp_set_deviceno(sp_pos_t* pos)
+{
+  uint32 ticker;
+  uint8 kcode;
+  uint16 ret = 0;
+  uint8 key_press = 1;
+  uint16 tempno;
+  uint8 deviceno = pos->deviceno;
+  char msg[17];
+  char temp[17];
+  ticker = sp_get_ticker();
+  while(sp_get_ticker() -ticker < DELAY_TIME60s)
+  {
+    kcode = sp_get_key();
+    if(kcode != SP_KEY_NONE)
+    {
+      key_press = 1;
+      switch(kcode)
+      {
+      case SP_KEY_0:
+      case SP_KEY_1:
+      case SP_KEY_2:
+      case SP_KEY_3:
+      case SP_KEY_4:
+      case SP_KEY_5:
+      case SP_KEY_6:
+      case SP_KEY_7:
+      case SP_KEY_8:
+      case SP_KEY_9:
+        tempno = (uint16)deviceno;
+        tempno *=10;
+        tempno += (kcode-SP_KEY_0);
+        if(tempno > 0 && tempno < DEV_MAX_DEVICENO)
+        {
+          deviceno = (uint8)tempno;
+        }
+        break;
+      case SP_KEY_ENTER:
+        if(deviceno > 0 && deviceno <= DEV_MAX_DEVICENO)
+        {
+          if(pos->deviceno != deviceno)
+          {
+            ret = sp_save_deviceno(pos,deviceno);
+          }
+          if(!ret)
+          {
+            pos->deviceno = deviceno;
+            sprintf(msg,"»úºÅ: %d",deviceno);
+            disp_hint_info_two(pos,"ÉèÖûúºÅ³É¹¦",msg, DELAY_TIME2s);
+          }
+          else
+          {
+            show_error(pos,"±£´æ»úºÅʧ°Ü",ret);
+          }
+          return;
+        }
+        else
+        {
+          sprintf(msg,"·¶Î§(1-%d)",DEV_MAX_DEVICENO);
+          disp_hint_info_two(pos,"»úºÅ´íÎó",msg, DELAY_TIME3s);
+        }
+      case SP_KEY_CLEAR:
+        if(deviceno == 0)
+        {
+          return;
+        }
+        deviceno = 0;
+        break;
+      }
+    }
+    if(key_press)
+    {
+      sprintf(temp,"ÉèÖûúºÅ(1-%d)",DEV_MAX_DEVICENO);
+      sprintf(msg,"%d",deviceno);
+      disp_hint_info_two(pos,temp,msg,0);
+      ticker = sp_get_ticker();
+      key_press = 0;
+    }
+  }
+  return;
+}
+
+static void clear_transdtl(sp_pos_t* pos)
+{
+  if(0 == sp_check_passwd(pos,"Çå¿ÕÁ÷Ë®ÃÜÂë:","\x9\x1\x4\x3\x8\x7"))
+  {
+    disp_hint_info_two(pos,"Çå¿ÕÁ÷Ë®","ÇëÉÔµÈ...",0);
+    sp_clear_transdtl(pos);
+  }
+}
+
+static void manual_upgrade(sp_pos_t* pos)
+{
+  if(0 == sp_check_passwd(pos, "ÔÚÏßÉý¼¶ÃÜÂë:","\x9\x1\x4\x3\x8\x7"))
+  {
+    sp_manual_upgrade(pos);
+  }
+}
+
+static void reset_factory(sp_pos_t* pos)
+{
+  if(0 == sp_check_passwd(pos, "»Ö¸´³ö³§ÃÜÂë:","\x9\x1\x4\x3\x8\x7"))
+  {
+    sp_reset_factory(pos);
+  }
+}
+
+void sp_menu_options(sp_pos_t* pos)
+{
+  uint32 ticker = 0;
+  uint8 keycode;
+  uint8 page;
+  uint8 max_cnt;
+  uint8 key_press = 1;
+
+  menu_t menus[] =
+  {
+    {"1.²é¿´²ÎÊý", sp_show_syspara},
+    {"2.¹¤³§²âÊÔ", sp_factory_check},
+    {"3.ÉèÖÃʱ¼ä", sp_set_devtime},
+    {"4.ÊÖ¶¯µÇ¼", sp_manual_login},
+    {"5.ÉèÖÃÎïÀíid", sp_set_devphyid},
+    {"6.ÉèÖûúºÅ", sp_set_deviceno},
+    {"7.Çå¿ÕÁ÷Ë®", clear_transdtl},
+    {"8.ÔÚÏßÉý¼¶", manual_upgrade},
+    {"9.»Ö¸´³ö³§", reset_factory}
+  };
+  max_cnt = sizeof(menus)/sizeof(menu_t)/3;
+  page = 0;
+  ticker = sp_get_ticker();
+  while(sp_get_ticker()-ticker <= DELAY_TIME60s*5)
+  {
+    sp_feed_dog();
+    keycode = sp_get_key();
+    if(keycode != SP_KEY_NONE)
+    {
+      key_press = 1;
+      switch(keycode)
+      {
+      case SP_KEY_0:
+        if(page < (max_cnt-1))
+        {
+          page++;
+        }
+        break;
+      case SP_KEY_1:
+      case SP_KEY_2:
+      case SP_KEY_3:
+      case SP_KEY_4:
+      case SP_KEY_5:
+      case SP_KEY_6:
+      case SP_KEY_7:
+      case SP_KEY_8:
+      case SP_KEY_9:
+        if(menus[keycode-SP_KEY_1].func != NULL)
+        {
+          menus[keycode-SP_KEY_1].func(pos);
+        }
+        break;
+      case SP_KEY_CLEAR:
+        if(page == 0)
+        {
+          return;
+        }
+        page--;
+        break;
+      default:
+        break;
+      }
+    }
+    if(key_press)
+    {
+      disp_hint_info_three(pos, menus[page*3].hit, menus[page*3+1].hit, menus[page*3+2].hit, 0);
+      key_press = 0;
+      ticker = sp_get_ticker();
+    }
+  }
+}
diff --git a/supwisdom/sp_menu.h b/supwisdom/sp_menu.h
new file mode 100644
index 0000000..75f8f32
--- /dev/null
+++ b/supwisdom/sp_menu.h
@@ -0,0 +1,8 @@
+#ifdef _SP_MENU_H_
+#define _SP_MENU_H_
+
+#include "sp_config.h"
+
+void sp_menu_options(sp_pos_t* pos);
+
+#endif
diff --git a/supwisdom/sp_msgpack.c b/supwisdom/sp_msgpack.c
new file mode 100644
index 0000000..d1258a9
--- /dev/null
+++ b/supwisdom/sp_msgpack.c
@@ -0,0 +1,87 @@
+#include "string.h"
+#include "sp_msgpack.h"
+
+int32 sp_pack_init(cw_pack_context* pack,uint8* buf,uint16 len)
+{
+  memset(buf,0,len);
+  return cw_pack_context_init(pack,buf,len,0);
+}
+
+uint16 sp_pack_length(cw_pack_context* pack)
+{
+  if(pack->current != NULL && pack->start != NULL)
+  {
+    return (pack->current -pack->start);
+  }
+  return 256;
+}
+void sp_pack_put_str(cw_pack_context* pack,const char* parakey,const char* paraval)
+{
+  cw_pack_str(pack,parakey,strlen(parakey));
+  cw_pack_str(pack,paraval,strlen(paraval));
+}
+void sp_pack_put_int(cw_pack_context* pack,const char* parakey,const int paraval)
+{
+  cw_pack_str(pack,parakey,strlen(parakey));
+  cw_pack_signed(pack,paraval);
+}
+void sp_pack_put_bin(cw_pack_context* pack,const char* parakey,const uint8* paraval,
+                     const uint16 len)
+{
+  cw_pack_str(pack,parakey,strlen(parakey));
+  cw_pack_bin(pack,paraval,len);
+}
+int32 sp_unpack_init(cw_unpack_context* unpack,uint8* buf,uint16 len)
+{
+  cw_unpack_context_init(unpack,buf,len,0);
+  return unpack->return_code;
+}
+
+uint8 sp_unpack_map_size(cw_unpack_context* unpack)
+{
+  cw_unpack_next(unpack);
+  if(unpack->item.type == CWP_ITEM_MAP)
+  {
+    return (uint8)unpack->item.as.map.size;
+  }
+  return 0;
+}
+
+uint8 sp_unpack_value(cw_unpack_context* unpack,unpack_field_t* field)
+{
+  cw_unpack_next(unpack);
+  if(unpack->item.type == CWP_ITEM_STR)
+  {
+    field->key = unpack->item.as.str.start;
+    cw_unpack_next(unpack);
+    if(unpack->item.type == CWP_ITEM_STR)
+    {
+      field->val.strval = unpack->item.as.str.start;
+      field->strlen = unpack->item.as.str.length;
+      return 0;
+    }
+    else if(unpack->item.type == CWP_ITEM_POSITIVE_INTEGER)
+    {
+      field->val.intval= (int32)unpack->item.as.i64;
+      field->strlen = 0;
+      return 0;
+    }
+    else if(unpack->item.type == CWP_ITEM_BIN)
+    {
+      field->val.binval = unpack->item.as.str.start;
+      field->strlen = unpack->item.as.str.length;
+      return 0;
+    }
+    else
+    {
+      field->strlen = 0;
+      field->val.intval = 0;
+      return 1;
+    }
+  }
+  return 1;
+}
+
+
+
+
diff --git a/supwisdom/sp_msgpack.h b/supwisdom/sp_msgpack.h
new file mode 100644
index 0000000..c07a021
--- /dev/null
+++ b/supwisdom/sp_msgpack.h
@@ -0,0 +1,40 @@
+#ifndef _SP_MSGPACK_H_
+#define _SP_MSGPACK_H_
+
+
+#include "../msgpack/cwpack.h"
+#include "sp_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+  const char* key;
+  union
+  {
+    int32 intval;
+    const char* strval;
+	const uint8* binval;
+  } val;
+  int32 strlen;
+} unpack_field_t;
+
+int32 sp_pack_init(cw_pack_context* pack,uint8* buf,uint16 len);
+void sp_pack_put_str(cw_pack_context* pack,const char* parakey,const char* paraval);
+void sp_pack_put_int(cw_pack_context* pack,const char* parakey,const int paraval);
+void sp_pack_put_bin(cw_pack_context* pack,const char* parakey,const uint8* paraval,
+                     const uint16 len);
+uint16 sp_pack_length(cw_pack_context* pack);
+
+int32 sp_unpack_init(cw_unpack_context* unpack,uint8* buf,uint16 len);
+uint8 sp_unpack_map_size(cw_unpack_context* unpack);
+uint8 sp_unpack_value(cw_unpack_context* unpack,unpack_field_t* field);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/supwisdom/sp_upgrade.c b/supwisdom/sp_upgrade.c
new file mode 100644
index 0000000..6f2fdb8
--- /dev/null
+++ b/supwisdom/sp_upgrade.c
@@ -0,0 +1,416 @@
+#include "sp_msgpack.h"
+#include "sp_flash.h"
+#include "sp_util.h"
+#include "sp_display.h"
+#include "sp_communicate.h"
+#include "sp_upgrade.h"
+
+extern uint16 crc_table[];
+
+#pragma pack(push)
+#pragma pack(1)
+typedef struct
+{
+  uint32 file_size;
+  uint8 file_crc[2];
+  uint8 file_md5[16];
+} sp_upgrade_info_t;
+#pragma pack(pop)
+
+/*
+**************************************************************************************************************
+*										      CRC У Ñé
+* Ãè Êö:  УÑéÒ»´®charÊý¾ÝµÄCRC
+*
+* Êä Èë:  CPU_CHAR   *str  		- ҪУÑéÊý¾ÝµÄÖ¸Õë
+*         CPU_INT16U size		- ҪУÑéÊý¾ÝµÄ³¤¶È
+*		  CPU_INT08U mode		- УÑéµÄģʽ
+*						         1:  Ϊ¸Ã´®Êý¾ÝÔö¼ÓCRCУÑé  Í¬Ê±·µ»ØÐ£ÑéµÄCRCÖµ
+*							     0:  ¸Ã´®Êý¾ÝÊÇ·ñͨ¹ýУÑé	·µ»ØÐ£ÑéµÄCRCÖµ
+* ·µ »Ø:
+*
+* ×¢ Òâ:
+*
+**************************************************************************************************************
+*/
+//CRCʹÓÃ
+typedef struct
+{
+  uint8	 L;
+  uint8	 H;
+} INT_08BIT_2;
+
+typedef union
+{
+  uint16   Int16Bit;
+  INT_08BIT_2  Int08Bit;
+} INT_16BIT_08BIT;
+
+uint16 AH_CRC_Verify(uint8 str[], uint16  size, uint8 mode)
+{
+  uint32       i;
+  INT_16BIT_08BIT	 crc;
+  INT_16BIT_08BIT	 y;
+
+  crc.Int16Bit = 0;
+  for(i = 0 ; i < size ; i++)
+  {
+    y.Int16Bit    = crc_table[ str[ i ] ^ crc.Int08Bit.H ];
+    y.Int08Bit.H ^= crc.Int08Bit.L;
+    crc.Int16Bit  = y.Int16Bit;
+  }
+  if(mode == 1)
+  {
+    str[ i++ ] = y.Int08Bit.H ;
+    str[ i ]   = y.Int08Bit.L ;
+  }
+  return(crc.Int16Bit);
+}
+
+static uint16 update_upgrade_mark(uint32 CheckSum, uint32 size)
+{
+  uint16 ret,i;
+  uint8 buff[18] = { 0x5a,0x4b,0x3c,0x2d,0x1e,0x0f } ;
+
+  //дÉý¼¶Êý¾Ý³É¹¦Ð´ÈëFLASH±ê¼Ç, ºÍУÑéÂë, ÓÐЧ´úÂ볤¶ÈдÈëÊý¾ÝFLASH
+  memcpy(buff+6, (unsigned char*)&(CheckSum), 4) ;	    //УÑéºÍ
+  memcpy(buff+10,(unsigned char*)&(size) ,4) ;		    //Êý¾Ý³¤¶È
+  AH_CRC_Verify(buff, 14, 1);
+
+  for(i = 0; i<5; i++)
+  {
+    ret = sp_flash_erase(DEF_IapMarkAddr);
+    if(ret)
+    {
+      continue;
+    }
+    ret = sp_flash_write(DEF_IapMarkAddr, buff, 16);
+    if(!ret)
+    {
+      break;
+    }
+  }
+  if(i >= 5)
+  {
+    return 1;
+  }
+  return 0;
+}
+/**********************************************************************************************
+º¯ÊýÃû³Æ: U32 APP_IapDataSumCheck( U32 staaddr, U32 len, U08 mode )
+º¯Êý×÷ÓÃ: ¶Á³öFLASHÖеÄÊý¾Ý£¬²¢ÐγÉУÑé
+º¯ÊýÊäÈë: staaddr 	- ¿ªÊ¼µØÖ·
+		  len	  	- Êý¾Ý³¤¶È
+		  mode		- УÑéģʽ 0 È¡·´ºÍУÑé 1 ÆÕͨºÍУÑé
+º¯ÊýÊä³ö: ÎÞ
+º¯Êý·µ»ØÖµ: 0 ³É¹¦ ÆäËûʧ°Ü
+**********************************************************************************************/
+uint32 do_APP_IapDataSumCheck(uint32 staaddr, uint32 len, uint8 mode)
+{
+  uint32 Sum;
+  uint32 app_len, checksize, size;
+  uint16 rcode, i;
+  uint8 buffer[1024];//IAP_MAXLEN
+
+  app_len = len;
+  checksize = 0;
+  Sum = 0;
+  while(checksize < app_len)
+  {
+    if(len < 1024)
+    {
+      size = len;
+    }
+    else
+    {
+      size = 1024;
+    }
+
+    for(i=0; i<5; i++)
+    {
+      rcode = sp_flash_read((staaddr + checksize), buffer, size);
+      if(!rcode)
+      {
+        break;
+      }
+    }
+
+    if(mode == 0)
+    {
+      for(i = 0; i < size; i++)
+      {
+        Sum += ((~buffer[i]) & 0xFF);    //еÄÊÇÈ¡·´ºÍ
+      }
+    }
+    else
+    {
+      for(i = 0; i < size; i++)
+      {
+        Sum += buffer[i]; 				//ÀϵÄÊÇÖ±½ÓºÍ
+      }
+    }
+    checksize += size;
+    len -= size;
+  }
+
+  return (Sum);
+}
+static uint8 get_file_info(sp_pos_t* pos, sp_upgrade_info_t* upgradeinfo)
+{
+  uint8 ret;
+  uint8 size;
+  char temp[32];
+  sp_protocol_request_t req;
+  sp_protocol_response_t resp;
+  cw_pack_context pack;
+  cw_unpack_context unpack;
+  unpack_field_t field;
+
+  sp_flash_read(ADDR_UPGRADE_UPINFO,(uint8*)upgradeinfo,sizeof(sp_upgrade_info_t));
+
+  /*¶ÁÈ¡Îļþ³¤¶ÈºÍCRC*/
+  sp_protocol_req_init(&req,SP_CMD_UPGRADE);
+  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, sizeof(pos->devphyid));
+  sp_pack_put_int(&pack,PK_INT_SEQNO ,0xFFFF);
+  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_SOFT_MD5,upgradeinfo->file_md5,16);
+
+  req.datalen += sp_pack_length(&pack);
+  ret = sp_comm_call(pos, &req, &resp, COMM_WAIT_TIME);
+  if(!ret)
+  {
+    sp_unpack_init(&unpack,resp.data,resp.datalen);
+    //erase
+    sp_flash_erase(ADDR_UPGRADE_UPINFO);
+    size	= sp_unpack_map_size(&unpack);
+    while(size-- > 0)
+    {
+      sp_unpack_value(&unpack,&field);
+      // 4 byte file_length,2 crc
+      if(IS_KEY(PK_INT_FILESIZE,field.key))
+      {
+        upgradeinfo->file_size = (uint32)field.val.intval;
+      }
+      else if(IS_KEY(PK_BIN_FILECRC,field.key))
+      {
+        if(field.strlen != 2)
+        {
+          sprintf(temp,"CRC³¤¶È=%d",field.strlen);
+          disp_hint_info_two(pos, "Éý¼¶Ê§°Ü",temp,DELAY_TIME3s);
+          return 1;
+        }
+        MEMCPY(upgradeinfo->file_crc,field.val.binval,field.strlen);
+      }
+      else if(IS_KEY(PK_BIN_SOFT_MD5,field.key))
+      {
+        MEMCPY(upgradeinfo->file_md5,field.val.binval,field.strlen);
+      }
+    }
+  }
+  else
+  {
+    disp_server_errmsg(pos, "Éý¼¶Ê§°Ü",resp.data,resp.datalen);
+  }
+  return ret;
+}
+static uint8 download_file(sp_pos_t* pos)
+{
+  uint8 ret;
+  uint8 timeout_trycnt = 0;
+  uint8 sameseq_trycnt = 0;
+  uint8 data_len = 0;
+  uint16 seqno = 0;
+  uint16 resp_seqno = 0;
+  uint32 offset = 0;
+  uint8 endflag = 0;
+  uint8 size;
+  char temp[32];
+  uint8 buf[128];
+  sp_protocol_request_t req;
+  sp_protocol_response_t resp;
+  cw_pack_context pack;
+  cw_unpack_context unpack;
+  unpack_field_t field;
+
+  for(offset = ADDR_UPGRADE_BEGIN; offset < ADDR_UPGRADE_END; offset +=DEF_FLASH_PageSize)
+  {
+    sp_flash_erase(offset);
+  }
+  offset = 0;
+  while(1)
+  {
+    sp_feed_dog();
+    sp_protocol_req_init(&req,SP_CMD_UPGRADE);
+    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, sizeof(pos->devphyid));
+    sp_pack_put_int(&pack,PK_INT_SEQNO,seqno);
+
+    req.datalen += sp_pack_length(&pack);
+    ret = sp_comm_call(pos, &req,&resp, COMM_WAIT_TIME);
+    if(!ret)
+    {
+      timeout_trycnt = 0;//success reset
+      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_SEQNO,field.key))
+        {
+          resp_seqno = (uint32)field.val.intval;
+        }
+        else if(IS_KEY(PK_INT_FLAG,field.key))
+        {
+          if(0 == MEMCMP("end",field.val.strval,field.strlen))
+          {
+            // ÎļþÏÂÔØÍê³É
+            endflag = 1;
+          }
+        }
+        else if(IS_KEY(PK_BIN_FILEDATA,field.key))
+        {
+          data_len = field.strlen;
+          if(data_len > sizeof(buf))
+          {
+            sprintf(temp,"´íÎ󳤶È=%d",data_len);
+            disp_hint_info_two(pos, "Éý¼¶Ê§°Ü",temp,DELAY_TIME3s);
+            return 1;
+          }
+          MEMCLEAR(buf,sizeof buf);
+          MEMCPY(buf,field.val.binval,data_len);
+        }
+      }
+
+      if(resp_seqno != seqno +1)
+      {
+        if(10 < sameseq_trycnt)
+        {
+          return 1;
+        }
+        ++sameseq_trycnt;
+        continue;
+      }
+      sameseq_trycnt = 0;
+
+      ++seqno;
+      snprintf(temp,sizeof temp,"seqno = %04d",seqno);
+      disp_hint_info_two(pos, "ÕýÔÚÉý¼¶...",temp,0);
+
+      sp_flash_write(ADDR_UPGRADE_BEGIN+offset,buf,data_len);
+      if(endflag)
+      {
+        return 0;
+      }
+
+      offset += (uint32)data_len;
+      if(ADDR_UPGRADE_BEGIN + offset >= ADDR_UPGRADE_END)
+      {
+        disp_hint_info(pos, "ÏÂÔØÎļþ¹ý´ó",DELAY_TIME3s);
+        return 1;
+      }
+    }
+    else
+    {
+      if(3 < timeout_trycnt)
+      {
+        disp_hint_info(pos, "ÏÂÔØÎļþ³¬Ê±",DELAY_TIME3s);
+        return 1;
+      }
+      Delay_ms(DELAY_TIME1s);
+      ++timeout_trycnt;
+    }
+  }
+}
+static uint8 check_file_and_upgrade(sp_pos_t* pos, sp_upgrade_info_t* upgradeinfo)
+{
+  uint16 ret;
+  uint8 crc[2];
+  uint8 temp_crc[2];
+  uint8 buf[128];
+  uint32 sumcrc;
+
+  uint32 page_index = 0;
+  uint32 page_num = (upgradeinfo->file_size-1)/sizeof(buf) + 1;
+  while(1)
+  {
+    if(page_num == page_index +1)
+    {
+      sp_flash_read(ADDR_UPGRADE_BEGIN +page_index*sizeof(buf),buf,
+                    sizeof buf);
+      memcpy(temp_crc,crc,2);
+      if(upgradeinfo->file_size%sizeof(buf) == 0)
+      {
+        sp_protocol_crc_init(buf,sizeof(buf),temp_crc,crc);
+      }
+      else
+      {
+        sp_protocol_crc_init(buf,upgradeinfo->file_size%sizeof(buf),temp_crc,crc);
+      }
+      if(0 == MEMCMP(upgradeinfo->file_crc,crc,2))
+      {
+        sp_flash_write(ADDR_UPGRADE_UPINFO,(uint8*)upgradeinfo,sizeof(sp_upgrade_info_t));
+
+        sumcrc = do_APP_IapDataSumCheck(ADDR_UPGRADE_BEGIN,upgradeinfo->file_size,0);
+        /*Éý¼¶ºó,boot »á²Á³ý¸ÃÒ³¼Ç¼ */
+        //¸üбê־λÖÃλ
+        ret = update_upgrade_mark(sumcrc,upgradeinfo->file_size);
+        if(ret)
+        {
+          disp_hint_info_two(pos, "Éý¼¶Ê§°Ü","¸üбê־ʧ°Ü",DELAY_TIME2s);
+          return 1;
+        }
+        else
+        {
+          disp_hint_info_two(pos, "ÕýÔÚÉý¼¶","ÇëÎð¶Ïµç",DELAY_TIME2s);
+          sp_reset();
+          return 0;
+        }
+      }
+      else
+      {
+        disp_hint_info(pos, "ÎļþУÑé´íÎó",DELAY_TIME3s);
+        return 1;
+      }
+    }
+    else
+    {
+      sp_flash_read(ADDR_UPGRADE_BEGIN+page_index*sizeof(buf),buf,sizeof buf);
+      if(0 == page_index)
+      {
+        sp_protocol_crc(buf,sizeof buf,crc);
+      }
+      else
+      {
+        memcpy(temp_crc,crc,2);
+        sp_protocol_crc_init(buf,sizeof buf,temp_crc,crc);
+      }
+      ++page_index;
+    }
+  }
+}
+void sp_manual_upgrade(sp_pos_t* pos)
+{
+  uint8 ret;
+  sp_upgrade_info_t upgradeinfo;
+
+  disp_hint_info_two(pos, "ÕýÔÚÉý¼¶..","Îð¶Ïµç!!",0);
+  MEMCLEAR(&upgradeinfo,sizeof upgradeinfo);
+  ret = get_file_info(pos, &upgradeinfo);
+  if(ret)
+  {
+    return;
+  }
+  ret = download_file(pos);
+  if(ret)
+  {
+    return;
+  }
+  check_file_and_upgrade(pos, &upgradeinfo);
+}
+
diff --git a/supwisdom/sp_upgrade.h b/supwisdom/sp_upgrade.h
new file mode 100644
index 0000000..2cd8160
--- /dev/null
+++ b/supwisdom/sp_upgrade.h
@@ -0,0 +1,14 @@
+#ifndef _SP_UPGRADE_H_
+#define _SP_UPGRADE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void sp_manual_upgrade(sp_pos_t* pos);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/supwisdom/sp_util.c b/supwisdom/sp_util.c
new file mode 100644
index 0000000..df70b13
--- /dev/null
+++ b/supwisdom/sp_util.c
@@ -0,0 +1,530 @@
+#include "../sys_hw/keypad.h"
+#include "../sys_hw/drv_adc.h"
+#include "sp_display.h"
+
+#include "sp_util.h"
+
+uint16 crc_table[] =
+{
+  0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+  0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+  0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+  0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+  0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+  0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+  0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+  0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+  0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+  0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+  0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+  0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+  0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+  0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+  0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+  0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+  0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+  0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+  0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+  0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+  0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+  0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+  0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+  0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+  0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+  0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+  0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+  0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+  0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+  0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+  0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+  0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+void sp_protocol_crc(const uint8* buf, uint16 len, uint8 crc[2])
+{
+  //uint16	accnum = 0xc78c;
+  uint8 temp_crc[2];
+  temp_crc[0] = 0xc7;
+  temp_crc[1] = 0x8c;
+  sp_protocol_crc_init(buf,len,temp_crc,crc);
+}
+
+void sp_protocol_crc_init(const uint8* buf, uint16 len,uint8 init[2], uint8 crc[2])
+{
+  uint16 accnum = (uint16)init[0]<<8 |(uint16)init[1];
+  uint16 i;
+  for(i = 0; i < len; ++i)
+  {
+    accnum = (accnum << 8) ^ crc_table[((accnum >> 8)
+                                        ^ buf[i]) & 0xFF];
+  }
+  crc[0] = (uint8)((accnum >> 8) & 0xFF);
+  crc[1] = (uint8)(accnum & 0xFF);
+}
+
+void sp_key_calibrate(void)
+{
+  calibrate_key(0);
+}
+
+uint8 sp_key_init(void)
+{
+  adc_init();
+  return keypad_init();
+}
+uint8 sp_get_key(void)
+{
+  uint8 key = keypad_get_key();
+  switch(key)
+  {
+  case KEY_NONE:
+    return SP_KEY_NONE;
+  case KEY_DIG0:
+    return SP_KEY_0;
+  case KEY_DIG1:
+    return SP_KEY_1;
+  case KEY_DIG2:
+    return SP_KEY_2;
+  case KEY_DIG3:
+    return SP_KEY_3;
+  case KEY_DIG4:
+    return SP_KEY_4;
+  case KEY_DIG5:
+    return SP_KEY_5;
+  case KEY_DIG6:
+    return SP_KEY_6;
+  case KEY_DIG7:
+    return SP_KEY_7;
+  case KEY_DIG8:
+    return SP_KEY_8;
+  case KEY_DIG9:
+    return SP_KEY_9;
+  case KEY_ENTER:
+    return SP_KEY_ENTER;
+  case KEY_CANCEL:
+    return SP_KEY_CLEAR;
+  default:
+    return SP_KEY_NONE;
+  }
+}
+void sp_reset(void)
+{
+  while(1);
+}
+void sp_bcd_to_str(const uint8* bcd, uint8 bcd_len, char* str)
+{
+  uint8 i;
+  uint16 j;
+  for(i = 0; i < bcd_len; ++i)
+  {
+    j = i << 1;
+    str[j] = ((bcd[i] >> 4) & 0x0F) + 0x30;
+    str[j + 1] = (bcd[i] & 0x0F) + 0x30;
+  }
+  str[i << 1] = 0;
+}
+void sp_str_to_bcd(const char* str, uint8 str_len, uint8* bcd)
+{
+  uint8 i,j;
+  for(i = 0; i < str_len; i += 2)
+  {
+    j = i/2;
+    bcd[j] = (((str[i]-0x30) & 0x0F) <<4) | ((str[i+1]-0x30) & 0x0F);
+  }
+}
+static uint8 charTohex(char ch)
+{
+  if(ch >= '0' && ch <= '9')
+  {
+    return (ch -'0');
+  }
+  if(ch >= 'a' && ch <= 'f')
+  {
+    return (ch -'a' +10);
+  }
+  if(ch >= 'A' && ch <= 'F')
+  {
+    return (ch -'A' +10);
+  }
+  return 0;
+}
+void sp_str_to_hex(const char* str,const uint16 len,uint8* hex)
+{
+  uint8 t,temp;
+  uint16 i;
+  for(i = 0; i < len; i += 2)
+  {
+    temp = charTohex(str[i]);
+    t = temp << 4;
+    temp = charTohex(str[i+1]);
+    t += temp;
+    hex[i/2] = t;
+  }
+}
+
+static char hexToCharTable[]= {"0123456789ABCDEF"};
+void sp_hex_to_str(const uint8* hex,const uint8 len,char* str)
+{
+  uint8 i,j;
+  for(i = 0; i < len; i++)
+  {
+    j = i << 1;
+    str[j] = hexToCharTable[(hex[i] >> 4) &0x0F];
+    str[j +1] = hexToCharTable[hex[i] &0x0F];
+  }
+  str[i << 1] = 0;
+}
+
+void sp_get_bcdtime(uint8 ctime[6])
+{
+  _SystemTime time;
+  memset(&time,0,sizeof time);
+  rtc_get_time(&time); //bcd
+  ctime[0] = time.year;
+  ctime[1] = time.month;
+  ctime[2] = time.day;
+  ctime[3] = time.hour;
+  ctime[4] = time.minute;
+  ctime[5] = time.second;
+}
+void sp_set_bcdtime(uint8 ctime[6])
+{
+  _SystemTime time;
+  memset(&time,0,sizeof time);
+  time.year = ctime[0];
+  time.month = ctime[1];
+  time.day = ctime[2];
+  time.hour = ctime[3];
+  time.minute = ctime[4];
+  time.second = ctime[5];
+
+  rtc_set_time(&time);
+}
+uint8 sp_check_time_valid(uint8 ctime[6])
+{
+  if(BCD2Dec(ctime[0]) < 18)
+    return 1;
+  if(BCD2Dec(ctime[1]) > 12)
+    return 1;
+  if(BCD2Dec(ctime[2]) > 31)
+    return 1;
+  if(BCD2Dec(ctime[3]) > 23)
+    return 1;
+  if(BCD2Dec(ctime[4]) > 59)
+    return 1;
+  if(BCD2Dec(ctime[5]) > 59)
+    return 1;
+
+  return 0;
+}
+uint8 sp_crc_sum(uint8 buf[],uint8 len)
+{
+  uint8 i;
+  uint8 sum = 0;
+  //¼ÆËãУÑéºÍ
+  for(i = 0; i < len; i++)
+  {
+    sum = sum + buf[i];
+  }
+  return sum;
+}
+
+int8 isFF(uint8 buf[],uint16 len)
+{
+  uint16 i;
+  for(i = 0; i < len; i++)
+  {
+    if(0xFF != buf[i])
+    {
+      return -1;
+    }
+  }
+  return 0;
+}
+
+//ms
+uint32 sp_get_ticker(void)
+{
+  return timer_get_ticker();
+}
+
+void Delay_ms(uint32 ms)
+{
+  uint32 t = sp_get_ticker();
+  while(sp_get_ticker() - t < ms);
+}
+void sp_valve_on(void)
+{
+  valve_sta_set(valve_state_on);
+  valve_ctrl();
+}
+void sp_valve_off(void)
+{
+  valve_sta_set(valve_state_off);
+  valve_ctrl();
+}
+uint8 sp_valve_state(void)
+{
+  return valve_sta_get();
+}
+
+int16 get_2byte_int(uint8 value_str[2])
+{
+  int32 r = 0, t = 0;
+  t = value_str[0];
+  r = t << 8;
+  r |= value_str[1];
+  return (int16)r;
+}
+int32 get_3byte_int(uint8 value_str[3])
+{
+  int32 r = 0, t = 0;
+  t = value_str[0];
+  r = t << 16;
+  t = value_str[1];
+  r |= t << 8;
+  r |= value_str[2];
+  return r;
+}
+int32 get_4byte_int(uint8 value_str[4])
+{
+  int32 r = 0, t = 0;
+  t = value_str[0];
+  r = t << 24;
+  t = value_str[1];
+  r |= t << 16;
+  t = value_str[2];
+  r |= t << 8;
+  r |= value_str[3];
+  return r;
+}
+void set_2byte_int(uint8 value_str[2], int num)
+{
+  value_str[0] = (num >> 8) & 0xFF;
+  value_str[1] = num & 0xFF;
+}
+void set_3byte_int(uint8 value_str[3], int num)
+{
+  value_str[0] = (num >> 16) & 0xFF;
+  value_str[1] = (num >> 8) & 0xFF;
+  value_str[2] = num & 0xFF;
+}
+void set_4byte_int(uint8 value_str[4], int num)
+{
+  value_str[0] = (num >> 24) & 0xFF;
+  value_str[1] = (num >> 16) & 0xFF;
+  value_str[2] = (num >> 8) & 0xFF;
+  value_str[3] = num & 0xFF;
+}
+
+//»ñµÃµ¥×Ö½ÚÖÐijһλµÄÖµ
+int32 Get1Bit(uint8 buf, int n)
+{
+  return (buf >> n) & 0x01;
+}
+
+int16 get_2byte_int_le(uint8 value_str[2])
+{
+  int32 r = 0, t = 0;
+  t = value_str[1];
+  r = t << 8;
+  r |= value_str[0];
+  return (int16)r;
+}
+//С×Ö½ÚÐò
+int32 get_3byte_int_le(uint8 value_str[3])
+{
+  int32 r = 0, t = 0;
+  t = value_str[2];
+  r = t << 16;
+  t = value_str[1];
+  r |= t << 8;
+  r |= value_str[0];
+  return r;
+}
+//С×Ö½ÚÐò
+int32 get_4byte_int_le(uint8 value_str[4])
+{
+  int32 r = 0, t = 0;
+  t = value_str[3];
+  r = t << 24;
+  t = value_str[2];
+  r |= t << 16;
+  t = value_str[1];
+  r |= t << 8;
+  r |= value_str[0];
+  return r;
+}
+
+void set_2byte_int_le(uint8 value_str[2], int num)
+{
+  value_str[1] = (num >> 8) & 0xFF;
+  value_str[0] = num & 0xFF;
+}
+
+void set_3byte_int_le(uint8 value_str[3], int num)
+{
+  value_str[2] = (num >> 16) & 0xFF;
+  value_str[1] = (num >> 8) & 0xFF;
+  value_str[0] = num & 0xFF;
+}
+
+/*¼ÆËã´Óbcd starttime µ½ÏÖÔÚµÄÃëÊý*/
+uint32 diff_time(uint8 starttime[6])
+{
+  uint8 ctime[6];
+  uint32 start_second;
+  uint32 end_second;
+
+  sp_get_bcdtime(ctime);
+  start_second = format_time_covert_secs(starttime);
+  end_second = format_time_covert_secs(ctime);
+  if(end_second < start_second)
+  {
+    return 0;
+  }
+  return (end_second - start_second);
+}
+
+void mycpy(void* dest, const void* src, uint32 len)
+{
+  char* tmp_dest = (char*)dest;
+  char* tmp_src = (char*)src;
+  while(len--)
+  {
+    *tmp_dest = *tmp_src++;
+    tmp_dest++;
+  }
+}
+
+void sp_bcd2asc(const uint8 bcdbuf[], uint8 bcdlen, uint8* ascstr)
+{
+  uint8 i;
+  uint8 lch, hch;
+  for(i = 0; i < bcdlen; i++)
+  {
+    hch = (bcdbuf[i] & 0x0F);
+    lch = (bcdbuf[i] & 0xF0);
+    lch = lch >> 4;
+    ascstr[2 * i] = lch + '0';
+    ascstr[2 * i + 1] = hch + '0';
+  }
+  ascstr[2*i] = 0;
+}
+int32 sp_atoi(const char* src)
+{
+  int i = 0;
+  while(*src != 0)
+  {
+    i = i * 10 + *src - '0';
+    src++;
+  }
+  return i;
+}
+/**
+**2000.0.0:0.0.0ʱ¼äΪ»ùÊý
+**/
+static int MINUTE_SECS = 60;
+static int HOUR_SECS = 3600;
+static int DAY_SECS = 24*3600;
+static int YEAR_SECS = 365*24*3600;
+static int FOURYEAR_SECS = (365*3+366)*24*3600;
+static int norMoth[] = {0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static int leapMoth[] = {0,31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+/*time: string(yyyyMMddHHmmss) to int */
+int format_time_covert_secs(uint8 ctime[6])
+{
+  int secs;
+  int i;
+  int remain;
+  int year = BCD2Dec(ctime[0]);
+  int month = BCD2Dec(ctime[1]);
+  int day = BCD2Dec(ctime[2]);
+  int hour = BCD2Dec(ctime[3]);
+  int minute = BCD2Dec(ctime[4]);
+  int second = BCD2Dec(ctime[5]);
+
+  secs = year/4 *FOURYEAR_SECS;
+  remain = year%4;
+  secs += remain*YEAR_SECS;
+
+  if(remain == 0)
+  {
+    for(i = 0; i < month; ++i)
+    {
+      secs += leapMoth[i] *DAY_SECS;
+    }
+  }
+  else
+  {
+    for(i = 0; i < month; ++i)
+    {
+      secs += norMoth[i] *DAY_SECS;
+    }
+  }
+  secs += day*DAY_SECS;
+  secs += hour *HOUR_SECS;
+  secs += minute*MINUTE_SECS;
+  secs += second;
+  return secs;
+}
+
+uint8 sp_check_passwd(sp_pos_t* pos,const char* hint,uint8 passwd[6])
+{
+  uint8 temp[6];
+  uint8 offset = 0;
+  uint8 kcode;
+  uint32 ticker = sp_get_ticker();
+
+  show_manage_passwd(pos,hint,temp,offset);
+  while(sp_get_ticker() -ticker < DELAY_TIME60s)
+  {
+    sp_feed_dog();
+    kcode = sp_get_key();
+    if(kcode != SP_KEY_NONE)
+    {
+      switch(kcode)
+      {
+      case SP_KEY_0:
+      case SP_KEY_1:
+      case SP_KEY_2:
+      case SP_KEY_3:
+      case SP_KEY_4:
+      case SP_KEY_5:
+      case SP_KEY_6:
+      case SP_KEY_7:
+      case SP_KEY_8:
+      case SP_KEY_9:
+        if(offset < 6)
+        {
+          temp[offset++] = (uint8)(kcode-SP_KEY_0);
+          show_manage_passwd(pos,hint,temp,offset);
+        }
+        if(offset >= 6)
+        {
+          if(0 == MEMCMP(temp,passwd,6))
+          {
+            return 0;
+          }
+          else
+          {
+            disp_hint_info_two(pos,hint,"ÃÜÂë´íÎó",DELAY_TIME2s);
+            MEMCLEAR(temp, sizeof temp);
+            offset = 0;
+          }
+        }
+        break;
+      case SP_KEY_CLEAR:
+        if(offset == 0)
+        {
+          return 1;
+        }
+        --offset;
+        temp[offset] = 0;
+        show_manage_passwd(pos,hint,temp,offset);
+        break;
+      }
+    }
+  }
+  return 1;
+}
diff --git a/supwisdom/sp_util.h b/supwisdom/sp_util.h
new file mode 100644
index 0000000..d54b929
--- /dev/null
+++ b/supwisdom/sp_util.h
@@ -0,0 +1,70 @@
+#ifndef _SP_UTIL_H_
+#define _SP_UTIL_H_
+
+#include "string.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "sp_config.h"
+
+#define DELAY_TIME100ms 100
+#define DELAY_TIME200ms 200
+#define DELAY_TIME1s 1000
+#define DELAY_TIME2s 2000
+#define DELAY_TIME3s 3000
+#define DELAY_TIME15s 15000
+#define DELAY_TIME60s 60000
+#define COMM_WAIT_TIME 5000
+
+#define STR_COPY_N(x,y,z) do{snprintf(x,z+1,"%s",y);}while(0);
+#define MEMCLEAR(x,z) memset(x,0,z)
+#define MEMCMP(x,y,z) memcmp(x,y,z)
+#define MEMCPY(x,y,z) memcpy(x,y,z)
+#define IS_KEY(expect,val) (strncmp(expect,val,strlen(expect)) == 0)
+
+#define Dec2BCD(x) (((x) / 10) * 16 + (x) % 10)
+#define BCD2Dec(x) (((x) / 16) * 10 + (x) % 16)
+
+void sp_get_bcdtime(uint8 ctime[6]);
+void sp_set_bcdtime(uint8 ctime[6]);
+uint8 sp_check_time_valid(uint8 ctime[6]);
+uint8 sp_crc_sum(uint8 buf[],uint8 len);
+uint32 sp_get_ticker(void);
+void Delay_ms(uint32 ms);
+void sp_valve_on(void);
+void sp_valve_off(void);
+uint8 sp_valve_state(void);
+int16 get_2byte_int(uint8 value_str[2]);
+int32 get_3byte_int(uint8 value_str[3]);
+int32 get_4byte_int(uint8 value_str[4]);
+void set_2byte_int(uint8 value_str[2], int num);
+void set_3byte_int(uint8 value_str[3], int num);
+void set_4byte_int(uint8 value_str[4], int num);
+//»ñµÃµ¥×Ö½ÚÖÐijһλµÄÖµ
+int32 Get1Bit(uint8 buf, int n);
+int16 get_2byte_int_le(uint8 value_str[2]);
+//С×Ö½ÚÐò
+int32 get_3byte_int_le(uint8 value_str[3]);
+//С×Ö½ÚÐò
+int32 get_4byte_int_le(uint8 value_str[4]);
+void set_2byte_int_le(uint8 value_str[2], int num);
+void set_3byte_int_le(uint8 value_str[3], int num);
+/*¼ÆËã´Óstarttime µ½ÏÖÔÚµÄÃëÊý*/
+uint32 diff_time(uint8 starttime[6]);
+void mycpy(void* dest, const void* src, uint32 len);
+int32 sp_atoi(const char* src);
+void sp_bcd2asc(const uint8 bcdbuf[], uint8 bcdlen, uint8* ascstr);
+int format_time_covert_secs(uint8 ctime[6]);
+void sp_protocol_crc(const uint8* buf, uint16 len, uint8 crc[2]);
+void sp_protocol_crc_init(const uint8* buf, uint16 len,uint8 init[2], uint8 crc[2]);
+uint8 sp_get_key(void);
+uint8 sp_key_init(void);
+void sp_key_calibrate(void);
+void sp_reset(void);
+void sp_bcd_to_str(const uint8* bcd, uint8 bcd_len, char* str);
+void sp_str_to_bcd(const char* str, uint8 str_len, uint8* bcd);
+void sp_str_to_hex(const char* str,const uint16 len,uint8* hex);
+void sp_hex_to_str(const uint8* hex,const uint8 len,char* str);
+uint8 sp_check_passwd(sp_pos_t* pos,const char* hint,uint8 passwd[6]);
+int8 isFF(uint8 buf[],uint16 len);
+
+#endif