📄 tclfsmcode.c
字号:
/* ============================================================================ Project Name : jayaCard Module Name : proto/bios/tcl/tclfsmcode.c Version : $Id: tclfsmcode.c,v 1.11 2004/01/11 09:56:31 dgil Exp $ Description: Function code for the Finite State Machine of the TCL protocol The Original Code is jayaCard code. The Initial Developer of the Original Code is Gilles Dumortier. Portions created by the Initial Developer are Copyright (C) 2002-2004 the Initial Developer. All Rights Reserved. Contributor(s): This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see http://www.gnu.org/licenses/gpl.html History Rev Description 012603 dgil wrote it from scratch the basic architecture of the FSM ============================================================================*/#include "precomp.h"/* ============================================================================ tcl_ffsm_start() ========================================================================= */jbyte tcl_ffsm_start(void){ LOG("TCLFSM","tcl_ffsm_start()"); tcl_ofs = 0; tcl_block = 1; return TCL_FSM_RECEIVE;}/* ============================================================================ tcl_ffsm_receive() ========================================================================= */jbyte tcl_ffsm_receive(void){ LOG("TCLFSM","tcl_ffsm_receive()"); /* catch protocol error */ if (tcl_inproc == TCL_INPROC_ERROR) { LOG("TCLFSM","tcl_ffsm_receive() TCL_INPROC_ERROR / reset tcl_apdu"); tcl_inproc = TCL_INPROC_NONE; tcl_apdu = 0; } if (tcl_getmsg) { tcl_cnt = HAL_TCL_RECEIVE(&gInBuffer.b[tcl_apdu],sizeof(gInBuffer)-tcl_apdu,jfalse); if (tcl_cnt<2) { LOG3("TCLFSM","tcl_ffsm_receive: ERROR pcb=0x%.2X cid=%d tcl_cnt=%d",tcl_pcb,tcl_cid,tcl_cnt); return TCL_FSM_RECEIVE; } } else { tcl_getmsg = jtrue; } /* remove the CRC count */ tcl_cnt -= 2; LOG3("TCLFSM","tcl_ffsm_receive: pcb=0x%.2X cid=%d tcl_cnt=%d",tcl_pcb,tcl_cid,tcl_cnt); // CID checking if ((tcl_pcb&TCL_MASK_CID)!=0) { /* CID must match ! */ if (tcl_cid!=cos_cid) { return TCL_FSM_RECEIVE; } else { tcl_has_cid = jtrue; } } if (((tcl_pcb&TCL_MASK_CID)==0) && (cos_cid==0)) { /* a PICC which does support CID shall in case its CID is 0 answer also to blocks containing no CID by using no CID */ tcl_has_cid = jfalse; } // IBLOCK detection ===================================================== if ((tcl_pcb&TCL_MASK_IBLOCK)==TCL_TYPE_IBLOCK) { if (tcl_inproc == TCL_INPROC_WTX) { return TCL_FSM_RECEIVE; } if (((tcl_pcb&TCL_MASK_NAD)!=0) && (tcl_inproc!=TCL_INPROC_CHAINING_PCD)) { /* NAD following, NAD supported, first IBLOCK (or first of the chain) */ tcl_has_nad = jtrue; return TCL_FSM_RECEIVE_IBLOCK; } if (((tcl_pcb&TCL_MASK_NAD)==0) && (tcl_inproc!=TCL_INPROC_CHAINING_PCD)) { /* NAD not following, NAD supported, first IBLOCK (or first of the chain) */ tcl_has_nad = jfalse; return TCL_FSM_RECEIVE_IBLOCK; } if (((tcl_pcb&TCL_MASK_NAD)!=0) && (tcl_inproc==TCL_INPROC_CHAINING_PCD)) { /* NAD following, NAD supported, PCD is chaining - protocol error */ tcl_inproc = TCL_INPROC_ERROR; return TCL_FSM_RECEIVE; } if (((tcl_pcb&TCL_MASK_NAD)==0) && (tcl_inproc==TCL_INPROC_CHAINING_PCD)) { /* NAD not following, NAD supported, PCD is chaining */ return TCL_FSM_RECEIVE_IBLOCK; } } // RBLOCK-NAK detection ================================================= if ((tcl_pcb&TCL_MASK_RBLOCK)==TCL_TYPE_RBLOCK_NAK) { if (tcl_cnt!=0) { return TCL_FSM_RECEIVE; } else { return TCL_FSM_RECEIVE_NAK; } } // RBLOCK-ACK detection ================================================= if ((tcl_pcb&TCL_MASK_RBLOCK)==TCL_TYPE_RBLOCK_ACK) { if (tcl_cnt!=0) { return TCL_FSM_RECEIVE; } else { return TCL_FSM_RECEIVE_ACK; } } // SBLOCK-WTX detection ================================================= if ((tcl_pcb&TCL_MASK_SBLOCK)==TCL_TYPE_SBLOCK_WTX) { if (tcl_cnt!=1) { return TCL_FSM_RECEIVE; } else { return TCL_FSM_RECEIVE_WTX; } } // SBLOCK-DESELECT detection ============================================ if ((tcl_pcb&TCL_MASK_SBLOCK)==TCL_TYPE_SBLOCK_DESELECT) { if (tcl_cnt!=0) { return TCL_FSM_RECEIVE; } else { return TCL_FSM_SEND_DESELECT; } } // NO DETECTION - UNKNOWN BLOCK TYPE ==================================== return TCL_FSM_RECEIVE;}/* ============================================================================ tcl_ffsm_send_wtx() ========================================================================= */jbyte tcl_ffsm_send_wtx(void){ LOG("TCLFSM","tcl_ffsm_send_wtx()"); #ifdef JAYA_TCL_WTX // required WTX answer tcl_inproc = TCL_INPROC_WTX; // send the PCB if (tcl_has_cid) { HAL_TCL_INITSEND((jbyte)(TCL_MASK_CID|TCL_TYPE_SBLOCK_WTX)); HAL_TCL_SEND((jbyte)(tcl_cid | HAL_POWER_LEVEL_MEASURE())); } else { HAL_TCL_INITSEND((jbyte)(TCL_TYPE_SBLOCK_WTX)); } // send power level and wtxm HAL_TCL_SEND((jbyte)(HAL_POWER_LEVEL_MEASURE() | tcl_wtxm)); HAL_TCL_SENDGO(jfalse); #endif /* JAYA_TCL_WTX */ return TCL_FSM_RECEIVE;}/* ============================================================================ tcl_ffsm_retransmit() ========================================================================= */jbyte tcl_ffsm_retransmit(void){ LOG("TCLFSM","tcl_ffsm_retransmist()"); HAL_TCL_INITSEND(sav_pcb); if ((sav_pcb & TCL_MASK_CID)!=0) { HAL_TCL_SEND((jbyte)(HAL_POWER_LEVEL_MEASURE() | tcl_cid)); } if ((sav_pcb & TCL_MASK_NAD)!=0) { HAL_TCL_SEND((jbyte)((tcl_nad<<4)|(tcl_nad>>4))); } HAL_TCL_SENDBUF(&gOutBuffer.apdu.info[sav_apdu],tcl_ofs); HAL_TCL_SENDGO(jfalse); return TCL_FSM_RECEIVE;}/* ============================================================================ tcl_ffsm_send_iblock() ========================================================================= */jbyte tcl_ffsm_send_iblock(void){ LOCAL(jbyte,headofs); LOG("TCLFSM","tcl_ffsm_send_iblock()"); /* PCB + CRC */ headofs = 3; /* PCB */ tcl_pcb = TCL_TYPE_IBLOCK | tcl_block; if (tcl_has_cid) { /* set the CID-following bit */ headofs++; tcl_pcb |= TCL_MASK_CID; } if (tcl_has_nad && (tcl_apdu==0)) { /* set the NAD-following bit */ headofs++; tcl_pcb |= TCL_MASK_NAD; } if ( (headofs + ( gOutBuffer.apdu.len - tcl_apdu)) > tcl_fsd) { tcl_pcb |= TCL_MASK_CHAINING; } /* save tcl_apdu and tcl_pcb for retransmit */ sav_pcb = tcl_pcb; sav_apdu = tcl_apdu; /* chaining ? => pre-calculate offset value before sending */ if ((tcl_pcb&TCL_MASK_CHAINING)==0) { /* no chaining or no more chaining (last frame) */ tcl_ofs = gOutBuffer.apdu.len - tcl_apdu; } else { /* chaining required on the PICC side */ tcl_inproc = TCL_INPROC_CHAINING_PICC; tcl_ofs = tcl_fsd - headofs; } /* send PCB, (CID) and (NAD) */ HAL_TCL_INITSEND(tcl_pcb); if ((tcl_pcb&TCL_MASK_CID)!=0) { HAL_TCL_SEND((jbyte)(HAL_POWER_LEVEL_MEASURE() | tcl_cid)); } if ((tcl_pcb&TCL_MASK_NAD)!=0) { HAL_TCL_SEND((jbyte)((tcl_nad<<4)|(tcl_nad>>4))); } /* PICC chaining ? */ if ((tcl_pcb&TCL_MASK_CHAINING)==0) { /* no chaining or no more chaining (last frame) */ HAL_TCL_SENDBUF(&gOutBuffer.apdu.info[tcl_apdu],tcl_ofs); HAL_TCL_SENDGO(jfalse); /* reset */ tcl_apdu = 0; } else { HAL_TCL_SENDBUF(&gOutBuffer.apdu.info[tcl_apdu],tcl_ofs); HAL_TCL_SENDGO(jfalse); /* adjust pointer with number of bytes */ tcl_apdu = tcl_apdu + tcl_ofs; } return TCL_FSM_RECEIVE;}/* ============================================================================ tcl_ffsm_application() ========================================================================= */jbyte tcl_ffsm_application(void){ LOG("TCLFSM","tcl_ffsm_application()"); /* internal clock is better to calculate */ HAL_INTERNAL_CLOCK(); /* reset pointer to the beginning of the buffer ! */ tcl_apdu = 0; /* call the OS to manage the received buffer */ cos_main(); /* encapsulation management */ if ((cfg_config_flag1&CONFIG_FLAG1_T1_ENCAPS)==CONFIG_FLAG1_T1_ENCAPS) { if ((gSeqVal&SEQVAL_GETRESPONSE)==SEQVAL_GETRESPONSE) { /* put the answer in the buffer */ tcl_apdu = 0; BIOS_SEND_BUF(&gOutBuffer.apdu.info[BIOS_GETRESPONSE_OFS],BIOS_GETRESPONSE_LEN); BIOS_SEND(0x90); BIOS_SEND(0x00); /* getresponse has been done ! */ BIOS_BITCLR_SEQVAL(SEQVAL_GETRESPONSE); } } /* re-init for receiving next blocks */ tcl_apdu = 0; tcl_inproc = TCL_INPROC_NONE; /* no need for co-processors : stop/reset them */ HAL_HARDWARE(HARDWARE_NONE); /* external clock is better to communicate */ HAL_EXTERNAL_CLOCK(); return TCL_FSM_SEND_IBLOCK;}/* ============================================================================ tcl_ffsm_receive_iblock() ========================================================================= */jbyte tcl_ffsm_receive_iblock(void){ LOG("TCLFSM","tcl_ffsm_receive_iblock()"); if ( (tcl_inproc != TCL_INPROC_NONE) && (tcl_inproc != TCL_INPROC_CHAINING_PCD) && (tcl_inproc != TCL_INPROC_CHAINED_PICC) ) { /* IBLOCK allowed only in case of PCD uses chaining or start of new exchange */ return TCL_FSM_RECEIVE; } /* block number */ tcl_block = !tcl_block; /* PCD chaining ? */ if ((tcl_pcb&TCL_MASK_CHAINING)==0) { /* no chaining or last part of the chain */ return TCL_FSM_APPLICATION; } else { /* mark PCD chaining */ tcl_inproc = TCL_INPROC_CHAINING_PCD; /* update tcl_apdu pointer */ tcl_apdu = tcl_apdu + tcl_cnt; /* ACK the reception to receive the next frame */ return TCL_FSM_SEND_ACK; }}/* ============================================================================ tcl_ffsm_receive_wtx() ========================================================================= */jbyte tcl_ffsm_receive_wtx(void){ LOG("TCLFSM","tcl_ffsm_receive_wtx()"); #ifdef JAYA_TCL_WTX if (tcl_inproc != TCL_INPROC_WTX) { tcl_inproc = TCL_INPROC_ERROR; return TCL_FSM_RECEIVE; } if ((gInBuffer.b[0]&TCL_MASK_WTXM)!=tcl_wtxm) { /* not the correct WTX multiplier ! */ return TCL_FSM_RECEIVE; } tcl_inproc = TCL_INPROC_NONE; #endif /* JAYA_TCL_WTX */ return TCL_FSM_HALT; /* __x FIXME */}/* ============================================================================ tcl_ffsm_send_deselect() ========================================================================= */jbyte tcl_ffsm_send_deselect(void){ LOG("TCLFSM","tcl_ffsm_send_deselect()"); if (tcl_has_cid) { HAL_TCL_INITSEND((jbyte)(TCL_TYPE_SBLOCK_DESELECT | TCL_MASK_CID)); HAL_TCL_SEND((jbyte)(tcl_cid | HAL_POWER_LEVEL_MEASURE())); } else { HAL_TCL_INITSEND((jbyte)TCL_TYPE_SBLOCK_DESELECT); } HAL_TCL_SENDGO(jtrue); HAL_TCL_SETBAUDRATE(BAUDRATE_106); return TCL_FSM_HALT;}/* ============================================================================ tcl_ffsm_send_ack() ========================================================================= */jbyte tcl_ffsm_send_ack(void){ LOG("TCLFSM","tcl_ffsm_send_ack()"); if (tcl_has_cid) { HAL_TCL_INITSEND((jbyte)(TCL_TYPE_RBLOCK_ACK | TCL_MASK_CID | tcl_block)); HAL_TCL_SEND((jbyte)(tcl_cid | HAL_POWER_LEVEL_MEASURE())); } else { HAL_TCL_INITSEND((jbyte)(TCL_TYPE_RBLOCK_ACK | tcl_block)); } HAL_TCL_SENDGO(jtrue); return TCL_FSM_RECEIVE;}/* ============================================================================ tcl_ffsm_receive_nak() ========================================================================= */jbyte tcl_ffsm_receive_nak(void){ LOG("TCLFSM","tcl_ffsm_receive_nak()"); if ((tcl_pcb&TCL_MASK_BLOCK_NUMBER)!=tcl_block) { return TCL_FSM_SEND_ACK; } else { if (tcl_inproc==TCL_INPROC_WTX) { return TCL_FSM_SEND_WTX; } else { if (tcl_inproc==TCL_INPROC_CHAINING_PCD) { return TCL_FSM_SEND_ACK; } } } return TCL_FSM_RETRANSMIT;}/* ============================================================================ tcl_ffsm_receive_ack() ========================================================================= */jbyte tcl_ffsm_receive_ack(void){ LOG("TCLFSM","tcl_ffsm_receive_ack()"); if ( (tcl_inproc != TCL_INPROC_CHAINING_PICC) && (tcl_inproc != TCL_INPROC_CHAINED_PICC)) { if (tcl_inproc!=TCL_INPROC_WTX) { tcl_inproc = TCL_INPROC_ERROR; } return TCL_FSM_RECEIVE; } if ((tcl_pcb&TCL_MASK_BLOCK_NUMBER)!=tcl_block) { /* last block of the chain already sent ! */ if (tcl_inproc==TCL_INPROC_CHAINED_PICC) return TCL_FSM_RECEIVE; tcl_block = !tcl_block; /* suppose this is the last block of the chain (send_iblock can change this asumption) */ tcl_inproc = TCL_INPROC_CHAINED_PICC; return TCL_FSM_SEND_IBLOCK; } return TCL_FSM_RETRANSMIT;}/* ========================================================================= That's all folks ! ========================================================================= */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -