首先看libgbdsrc/src中的dbdsrc.c文件
_gbdsrc_thread_func 开头函数 完成了用函数_connect_rsu连接天线,并且使用select 监听套接字 ,当接受到包时,使用trans_obj.c的函数gbdsrc_recv接收,然后调用protocol.c 中的gbdsrc_protocol_process 开始对接受到的包进行分析。
pkg_size = _package_decode(buf + 2, &pkg_p, buf_len - 4); 去掉包头的STX和包尾的BCC和ETX
然后流程如下:
1.先看如果是b2 b3 b4 指令,如果pkg[6]errorcode == 0x08 发送c2停止交易的指令
2.如果是b0(设备状态信息帧) 忽略
3如果是b1 (地感状态信息帧) 则会送c1指令
4 如果是b2 (vst)
memcpy(&v, pkg + 2, 4);
if (v == 0) {
_gbdsrc_send_c2_package(svc, pkg[0]);
break;
}
如果如法获取OBUID号,则发送c2指令
if ((pkg[32] >> 7) != 0) {
_gbdsrc_send_c2_package(svc, pkg[0]);
gbdsrc_on_trans_failed(svc, ERR_NO_ICCARD, ERR_NO_ICCARD_STR);
break;
}
如果通过判断OBUID发现无IC卡存在,发送c2指令
当pkg[6] errorcode ==0 时,记录 obuID 和obu状态 然后发送c1指令
5 如果是B3 (OBU信息帧)
判断svc->obu_id中存储的OBUID和B3信息帧中存储的ID是否相同,如果不同则发送C2指令
如果相同的话则首先查询黑名单,如果此OBUID在黑名单中,则终止交易,发送C1指令
如果此OBU正常则发送c1指令,并记录OBU记载的车牌号到svc->veh_num中
记录OBU存储的车辆类型到svc->veh_type 中
6 如果是B4 IC卡信息帧
先验证errorcode
然后是一个数据结构
typedef struct {
lane_type_t lane_type;
trans_type_t trans_type;
/* 交易开始和终止时间 */
struct timeval trans_begin;
struct timeval trans_end;
time_t last_trans_time;
unsigned char psam[6]; /* PSAM卡号 */
unsigned int obu_id; /* OBU序列号 */
char veh_num[12]; /* 车牌号码 */
char card_veh_num[12]; /* 卡内车牌号码 */
unsigned int veh_type; /* 车型 */
unsigned int card_balance; /* 交易后余额 */
time_t valid_begin_time; /* 启用日期 */
time_t valid_end_time; /* 到期日期 */
unsigned int TAC; /* TAC认证码 */
unsigned short card_trans_count; /* 卡交易计数 */
unsigned int psam_trans_count; /* PSAM交易计数 */
char msg[128];
trans_object_destroy_func_t destroy;
trans_object_duplicate_func_t duplicate;
} trans_head_t;
if (svc->trans) trans_bak = svc->trans; //如果svc中目前存在一个交易 则把目前的交易情况用trans_bak 保存下来??
svc->trans = gbdsrc_trans_object_new(svc, pkg[7]); //通过卡类型分配新的trans
void *
gbdsrc_trans_object_new(gbdsrc_svc_t *svc, unsigned char card_type)
{
void *result;
trans_head_t *head;
result = NULL;
head = NULL;
if (card_type == 0) { // 此卡是国标cpu卡
if (svc->cfg.lane_type == LANE_ENTRY) { //是进站口
result = malloc(sizeof(gb_entry_trans_t));
assert(result != NULL);
memset(result, 0, sizeof(gb_entry_trans_t));
head = &((gb_entry_trans_t *)result)->head;
head->trans_type = TRANS_GB_ENTRY; //国标 进站
}
else {
result = malloc(sizeof(gb_exit_trans_t));//出站
assert(result != NULL);
memset(result, 0, sizeof(gb_exit_trans_t));
head = &((gb_exit_trans_t *)result)->head;
head->trans_type = TRANS_GB_EXIT; //国标出站
}
}
else if (card_type == 1) {//北京市政一卡通
result = malloc(sizeof(bmac_trans_t));
assert(result != NULL);
memset(result, 0, sizeof(bmac_trans_t));
head = &((bmac_trans_t *)result)->head;
head->trans_type = TRANS_BMAC;
}
if (head) {
head->lane_type = svc->cfg.lane_type;
head->destroy = free;
head->duplicate = _gbdsrc_trans_object_duplicate;
}
return result;
}
head = (trans_head_t *)svc->trans;
head->trans_begin = svc->trans_begin;
head->obu_id = svc->obu_id;
head->veh_type = svc->veh_type;
memcpy(head->veh_num, svc->veh_num, sizeof(head->veh_num)); 对trans的交易开始时间,obuid,卡类型,OBU中记载的车牌号进行赋值
_gbdsrc_get_ic_info(svc, pkg); 从B4包中获取IC卡信息
首先获得IC卡内余额 memcpy(&head->card_balance, buf + 10, 4);
如果是一卡通车辆,暂时不做处理
memcpy(&card_net_no, buf + 28, 2); 获得卡片网络编号
user_type = buf[58]; 获得用户类型
memcpy(&head->card_veh_num, buf + 46, 12); 获得卡内存储的车牌号
memcpy(&head->valid_begin_time, buf + 38, 4); 获得启用日期
memcpy(&head->valid_end_time, buf + 42, 4); 获得到期日期
if (head->trans_type == TRANS_GB_ENTRY) { 如果交易类型是入口的话
trans->card_type = buf[26]; 获得卡片类型
if (trans->card_type == 22) 22:ETC储值卡 卡片类型是ETC储值卡
offset = 3; 如果是ETC储值卡,则偏移量是3 则读取0019文件
else
offset = 0; 不是ETC储值卡,则偏移量是0,则读取0012文件
然后上次(交易的时间,入口站网络编号,入口站号,入口收费员编号)赋值给tran
/* 卡片网络编码 */
trans->card_net_no = card_net_no;
/* 卡号 */
memcpy(trans->card_no, buf + 30, 8);
/* 入口车道号 */
trans->entry_lane_id = buf[offset + 65];
/* 入口班次 */
trans->entry_job_order = buf[offset + 84];
/* 入出口状态 */
trans->trans_state = buf[offset + 71];
if (trans->card_type == 23) ETC记账卡
trans->head.card_balance = 0;
else if (head->trans_type == TRANS_GB_EXIT) {如果是出口
和上一步一样,得到各种信息,然后写道trans结构中
/* 出口重取账单 */
/* 判断上一次交易是否为同一OBU,并且入口站号为本站则发送CA取B5 */
_gbdsrc_process_b4(svc, pkg[0]); //然后处理B4
/* 黑名单OBU */
if (gbdsrc_obu_blacklist_query(svc, head->obu_id) == 1) {
_gbdsrc_send_c2_package(svc, rs_ctl);//c2终止交易指令
gbdsrc_on_trans_failed(svc, ERR_OBU_BLACKLIST, ERR_OBU_BLACKLIST_STR);
return;
}
一卡通不以处理
以下是国标卡的处理流程
if (head->trans_type == TRANS_GB_EXIT) {
gb_exit_trans_t *trans = svc->trans;
memcpy(card_no, trans->card_no, 8);
card_type = trans->card_type;
trans_state = trans->trans_state;
user_type = trans->user_type;
}
else {
gb_entry_trans_t *trans = svc->trans;
memcpy(card_no, trans->card_no, 8);
card_type = trans->card_type;
trans_state = trans->trans_state;
user_type = trans->user_type;
}
/* 判断是否为黑名单卡 */
/* 启用日期判断 */
/* 到期日期判断 */
/* 判断车卡绑定 */
/* 公务卡判断 */
if (head->trans_type == TRANS_GB_EXIT) {
则如果是公务卡
则 _gbdsrc_send_c6_package(svc, rs_ctl);
/* 出口判断入口信息 */
/* check last transaction time */
/* 超时判断 */
trans->trans_amount = gbdsrc_toll_rate_query(svc, trans->entry_gate_id,trans->head.veh_type);
/* 无效入口 */
if (trans->trans_amount == -1) {
_gbdsrc_send_c2_package(svc, rs_ctl);
gbdsrc_on_trans_failed(svc, ERR_INVALID_ENTRY, ERR_INVALID_ENTRY_STR);
return;
}
/* 余额不足 */
if ((trans->trans_amount > trans->balance_before_trans) &&
(card_type == 22)) {
_gbdsrc_send_c2_package(svc, rs_ctl);
gbdsrc_on_trans_failed(svc, ERR_BALANCE_NOT_ENOUGH,
ERR_BALANCE_NOT_ENOUGH_STR);
return;
}
_gbdsrc_send_c6_package(svc, rs_ctl);
如果是入口
trans->entry_net_no = svc->cfg.net_no;
trans->entry_gate_id = svc->cfg.toll_gate_id;
trans->entry_lane_id = svc->cfg.lane_id;
trans->entry_job_num = svc->job_num;
trans->entry_job_order = svc->job_order;
trans->trans_state = 0x03; /* 封闭ETC入 */
_gbdsrc_send_c3_package(svc, rs_ctl); //c3是传统交易
如果是B5指令
if (pkg[6] == 0) {
_gbdsrc_get_trans_info(svc, pkg);
gbdsrc_on_trans_complete(svc);
_gbdsrc_send_c1_package(svc, pkg[0]);
}
else {
trans_head_t *head = (trans_head_t *)svc->trans;
if (head) {
(*head->destroy)(svc->trans);
svc->trans = NULL;
}
_gbdsrc_send_c2_package(svc, pkg[0]);
}
break;