blob: 98d6096ec528ba7e58e005e19f75e411ebc20a35 [file] [log] [blame]
#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 "sp_upgrade.h"
#include "../sys_hw/drv_usart.h"
static uint8 rxBuf[512] = {0};
static uint16 rxBufLen = 0;
static void sp_usart_send(sp_pos_t* pos, sp_protocol_request_t* req)
{
uint8 buf[sizeof(sp_protocol_request_t)];
MEMCLEAR(buf, sizeof(buf));
sp_protocol_crc((uint8*)req +2, req->datalen, (uint8*)req +2 +req->datalen);
req->datalen += 2;
MEMCPY(buf, req, req->datalen+2);
usart_send(buf, req->datalen+2);
pos->last_comm_status.command = req->excmd;
pos->last_comm_status.sendtime = sp_get_ticker();
MEMCLEAR(rxBuf,sizeof rxBuf);
rxBufLen = 0;
}
static uint8 sp_usart_recv(sp_pos_t* pos, sp_protocol_response_t* resp,
uint32 timeout_ms)
{
uint32 tick;
uint16 len;
int16 datalen;
uint8 crc[2];
uint8 temp[sizeof(sp_protocol_response_t)];
tick = sp_get_ticker();
MEMCLEAR(temp,sizeof temp);
while(1)
{
len = usart_read((u8*)temp,sizeof temp);
if(len > 0)
{
MEMCPY(rxBuf +rxBufLen, temp,len);
rxBufLen += len;
datalen = get_2byte_int_le(rxBuf);
if((datalen+2) <= rxBufLen)
{
MEMCLEAR(resp, sizeof(sp_protocol_response_t));
MEMCPY((uint8*)resp,rxBuf,rxBufLen);
MEMCLEAR(rxBuf,sizeof rxBuf);
rxBufLen = 0;
if(pos->last_comm_status.command == resp->excmd)
{
sp_protocol_crc((uint8*)resp +2,datalen -2, crc);
if(MEMCMP((uint8*)resp +datalen,crc,2) == 0)
{
MEMCLEAR(&(pos->last_comm_status), sizeof(sp_comm_status_t));
return resp->retcode;
}
}
}
}
if((sp_get_ticker() - tick) >= timeout_ms)
{
return RC_COMM_TIMEOUT;
}
}
}
uint8 sp_comm_call(sp_pos_t* pos, sp_protocol_request_t* req,
sp_protocol_response_t* resp, uint32 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;
cw_unpack_context unpack;
unpack_field_t field;
sp_protocol_response_t resp;
disp_hint_info_two(pos,"Éí·ÝÈ·ÈÏÖÐ","ÇëÉÔµÈ...",0);
ret = sp_usart_recv(pos, &resp, COMM_WAIT_TIME);
if(ret)
{
return RC_CARD_AUTHENTICATION;
}
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_PERMIT, field.key))
{
card->permit = (uint8)field.val.intval;
}
else if(IS_KEY(PK_STR_LIMITMSG, field.key))
{
MEMCLEAR(card->limitmsg,sizeof card->limitmsg);
MEMCPY(card->limitmsg,field.val.strval, field.strlen);
}
else if(IS_KEY(PK_INT_WATERLIMIT,field.key))
{
card->waterlimit = (uint16)field.val.intval;
}
else if(IS_KEY(PK_INT_COBILLNO,field.key))
{
card->cobillno = (uint32)field.val.intval;
}
else if(IS_KEY(PK_INT_FEEAMOUNT,field.key))
{
card->feepara.fee_amt = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_FEEUNIT, field.key))
{
card->feepara.fee_unit = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_FEESTART, field.key))
{
card->feepara.fee_start = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_AMOUNT_LIMIT,field.key))
{
card->amountlimit = (uint32)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+8, 4);
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;
}
void sp_login(sp_pos_t* pos)
{
uint16 ret;
char msg[20];
sp_protocol_response_t resp;
disp_hint_info_two(pos,"ÕýÔڵǼ","ÇëÉÔµÈ...",0);
ret = sp_async_equipment_login(pos);
if(ret)
{
sprintf(msg,"´íÎóÂë=%d",ret);
disp_hint_info_two(pos,"µÇ¼ʧ°Ü",msg,DELAY_TIME3s);
return;
}
MEMCLEAR(&resp,sizeof resp);
ret = sp_usart_recv(pos,&resp,COMM_WAIT_TIME);
if(ret)
{
disp_hint_info_two(pos,"µÇ¼ʧ°Ü","µÇ¼³¬Ê±",DELAY_TIME3s);
return;
}
ret = sp_confirm_login(&resp,pos);
if(ret)
{
disp_server_errmsg(pos,"µÇ¼ʧ°Ü",resp.data,resp.datalen);
return;
}
disp_hint_info(pos,"µÇ¼³É¹¦",DELAY_TIME3s);
}
//ÐÄÌøÈ·ÈÏ£¬¼ì²âÍøÂçÊÇ·ñÕý³£
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;
cw_unpack_context unpack;
unpack_field_t field;
sp_protocol_response_t resp;
ret = sp_usart_recv(pos, &resp, COMM_WAIT_TIME);
if(ret)
{
return RC_QRCODE_FAILURE;
}
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))
{
MEMCLEAR(card->qrcode.qrcode_url,sizeof card->qrcode.qrcode_url);
MEMCPY(card->qrcode.qrcode_url, field.val.strval, field.strlen);
}
else if(IS_KEY(PK_INT_COBILLNO, field.key))
{
card->cobillno = (uint32)field.val.intval;
}
else if(IS_KEY(PK_INT_VAILDTIME, field.key))
{
card->qrcode.validtime = (uint32)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;
cw_unpack_context unpack;
unpack_field_t field;
sp_protocol_response_t resp;
ret = sp_usart_recv(pos, &resp, COMM_WAIT_TIME);
if(ret)
{
return RC_QRCODE_QUERY_FAIL;
}
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_PERMIT, field.key))
{
card->permit = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_COBILLNO, field.key))
{
card->cobillno = (uint32)field.val.intval;
}
else if(IS_KEY(PK_INT_AUTHSTATUS, field.key))
{
card->qrcode.authstatus = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_PAYSTATUS, field.key))
{
card->qrcode.paystatus = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_PAYAMT, field.key))
{
card->qrcode.paidAmount = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_FEEAMOUNT,field.key))
{
card->feepara.fee_amt = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_FEEUNIT, field.key))
{
card->feepara.fee_unit = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_WATERLIMIT, field.key))
{
card->waterlimit = (uint16)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_int(&pack, PK_INT_COBILLNO, card->cobillno);
req.datalen += sp_pack_length(&pack);
sp_usart_send(pos, &req);
return sp_confirm_qrcode_query(pos, card);
}
//Á÷Ë®ÉÏ´«
static uint32 transdtl_account_cobilLno = 0;
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;
transdtl_account_cobilLno = transdtl->cobillno;
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_int(&pack, PK_INT_COBILLNO, transdtl->cobillno);
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_INT_COBILLNO,field.key))
{
if(field.val.intval == transdtl_account_cobilLno)
{
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;
cw_unpack_context unpack;
unpack_field_t field;
if(resp->retcode)
{
return resp->retcode;
}
pos->heartbeat.heart_status = HEART_RECV;
login_flag = 0;
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;
}
}
else if(IS_KEY(PK_STR_UPGRADE, field.key))
{
if(MEMCMP("true",field.val.strval,4) == 0)
{
sp_manual_upgrade(pos);
}
}
}
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 = (uint8)field.val.intval;
}
else if(IS_KEY(PK_INT_PULSEINHML, field.key))
{
unit = (uint8)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;
sp_protocol_response_t resp;
ret = sp_usart_recv(pos, &resp, 100);
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;
uint32 ticker;
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*30)
{
pos->devlogin.last_login_ticker = ticker;
sp_async_equipment_login(pos);
}
if(pos->heartbeat.last_heartbeat_ticker == 0
|| ticker - pos->heartbeat.last_heartbeat_ticker > DELAY_TIME60s)
{
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);
}