📄 secs1btp.c
字号:
/*
* secs1btp.c
*
* SECS-1 Block Transfer protocol routines
*
* Code by David Lindauer, CIMple technologies
*
*/
#include "secs1.h"
#include "units.h"
#include <stdio.h>
#define LOG
#ifdef LOG
FILE *file;
BOOL cleared=FALSE;
#endif
// Define this if you want to disable all SECS-1 and SECS-2 timeouts
// #define DISABLE_SECS_TIMERS
/* Code for Block Transfer Protocol flow chart*/
extern int last_expected_block;
extern EXPECTED expected_blocks[NUMBER_EXPECTED_BLOCKS];
/* Send, receive buffer allocations */
SECS1_BLOCK send_blocks[NUMBER_SEND_BLOCKS];
SECS1_BLOCK receive_blocks[NUMBER_RECEIVE_BLOCKS];
/* Que insertion/deletion pointers */
int send_insert, send_delete;
/* Block being received into */
static int receiving_block;
// The host computer is a slave, the equipment a master.
// Should be false for equipment according to SECS1 BTP standards,
BOOL is_slave; // TRUE for HOST COMPUTER, FALSE for equipment
BOOL is_in_wait; // TRUE if slave is waiting for a reply to
// primary message
int expected_waiting; // The expected block we are waiting on
// We set this true each time after we succeed at a send
// So the SECS-2 establish will know...
BOOL send_success;
// We set this true during a receive, false afterward
BOOL btp_receiving;
// We set this true if we pass the retry limit
// SECS-2 will drop into the CR/CRA handshaking to try to establish
// communications if it goes true
BOOL secs1_retrylimit;
/* Following SECS-1 parameters must be setable, e.g. from touch-screen */
SECS_TIMER to_interchar, to_protocol;
int retries, device_id;
COMMSTATES CommStates;
NUMBER secspre_interchar = { 0.0F, UN_SECONDS };
NUMBER secspre_protocol = { 0.0F, UN_SECONDS };
NUMBER secspre_retries = { 0.0F, UN_NOUNIT | UNI_INTEGER };
NUMBER secspre_devid = { 0.0F, UN_NOUNIT | UNI_INTEGER };
// Baud rates
MODIFY secspre_baud = { 0 , 5 };
int baudlist[] = { 300, 1200, 2400, 4800, 9600 } ;
// First block allocated for this SECS2 message
// Used if SECS2 wants to deallocate everything on error
int send_first;
/* Routine to put a character out over serial port.
* Returns TRUE if character output
* MUST be non-buffering
*/
static BOOL BtpCharout(int data)
{
Pause();
#ifdef LOG
cleared = TRUE;
fprintf(file,"\n>>%02x ",(BYTE)data);
#endif
return(Secs1Charout(data));
}
/* Buffered version of the above.
*/
static BOOL BtpBufferedCharout(int data)
{
#ifdef LOG
cleared = TRUE;
fprintf(file,">>%02x ",(BYTE)data);
#endif
Pause();
return(Secs1BufferedCharout(data));
}
/* Routine to get a character. Returns -1 if no character.
* Note that binary data is being recieved, not ASCII.
*/
static int BtpCharin(void)
{
int data=Secs1Charin();
#ifdef LOG
if (data != BTP_NO_DATA) {
cleared = TRUE;
fprintf(file,"<<%02x ",(BYTE)data);
}
#endif
Pause();
return(data);
}
/*
* Clear all but last char from serial buffer, or last two if they
* are ACK and ENQ. My interpretation of A.4.1 takes it to mean the
* FIRST time the listen state is entered from above.
*/
static void BtpClearbuf(void)
{
#ifdef LOG
if (!cleared)
fprintf(file,"\n");
cleared = TRUE;
#endif
Secs1Clearbuf();
}
/* Start a timer
*/
void SecsTimestart(SECS_TIMER *timer)
{
timer->startval = GetBiosTicks();
// Timer->length is in 10ths of seconds, we convert to MS
timer->TickLength= CvtToTicks(timer->length*100);
timer->timing = TRUE;
}
/* Return true if timer timed out */
BOOL SecsTimeout(SECS_TIMER *timer)
{
#ifdef DISABLE_SECS_TIMERS
// Never times out if disabled!
return FALSE;
#else
BOOL retval;
// If timer is timing
if (timer->timing) {
int length;
// Get length we've been going and adjust if there was a rolloever
// This depends upon the max tick length being much less than
// the max value GetBiosTicks returns
length = GetBiosTicks()-timer->startval;
if (length <0)
length += TimerMax();
// Now if we've gone long enough stop the timer
if (length > timer->TickLength) {
timer->timing = FALSE;
retval = TRUE;
}
else
// Still going
retval = FALSE;
}
else
// Stopped timers are always timed out
retval = TRUE;
return(retval);
#endif // DISABLE_SECS_TIMERS
}
/* Calculate checksum. The 1992 specs indicate it should be the
* sum of all unsigned data bytes in the message excluding length and
* checksum bytes.
*/
static int BtpChecksum(SECS1_BLOCK *data)
{
int i, checksum=0,length;
// The length byte NEVER reflects the header length
length = data->length + SECS1_HEADLEN + 1;
// Notice the indice on the loop, also this is one example of why
// the 'data' 'header' and 'length' fields must follow each other
for (i=1; i< length; i++)
checksum+=*(&data->length+i);
return(checksum);
}
/*
* handle reception, at this point we've received an ENQ
*/
static void BtpReceive(void)
{
int checksum, read_checksum = 0, thischar, length;
BOOL skim_chars = FALSE;
btp_receiving = TRUE;
// EOT and start protocol timer and clear buffer
BtpCharout(EOT);
SecsTimestart(&to_protocol);
BtpClearbuf();
// If we don't get the length before the timeout, put a NAK & exit
while ((thischar = BtpCharin()) == BTP_NO_DATA)
if (SecsTimeout(&to_protocol)) {
// NO LENGTH BYTE
BtpCharout(NAK);
btp_receiving = FALSE;
return;
}
if ((thischar >= SECS1_HEADLEN) && (thischar <= MAX_BLOCK_LEN + SECS1_HEADLEN)) {
// Valid length byte
if ((receiving_block = MraAllocReceive()) != MRA_ALLOC_ERR) {
int i;
SECS1_BLOCK *bp = &receive_blocks[receiving_block];
// We have a block, set up the data length and receive length
bp->length = (BYTE) (thischar - SECS1_HEADLEN);
length = thischar + 2;
for (i=0; i<length; i++) {
// For each char, start the timer
SecsTimestart(&to_interchar);
while (TRUE) {
// Get it and decide what to do with it. Another reason for the
// specific ordering of fields in the block structure
thischar = BtpCharin();
if (thischar != BTP_NO_DATA) {
if (i < length-2)
*((BYTE *)(&bp->length)+i+1) = (BYTE) thischar;
else {
read_checksum = (read_checksum << 8) + thischar;
}
break;
}
else
if (SecsTimeout(&to_interchar)) {
// IF we get here there was a timeout, NAK the block and clean up
BtpCharout(NAK);
MraDeallocReceive(receiving_block);
btp_receiving = FALSE;
return;
}
}
}
// Got the whole block, verify the checksum
checksum = BtpChecksum(bp);
if (checksum != read_checksum) {
skim_chars = TRUE;
MraDeallocReceive(receiving_block);
}
else {
/* Happily got a block, do something with it and then ACK it */
MraReceive(receiving_block);
BtpCharout(ACK);
}
}
else // No blocks to allocate, ignore the message
// SECS-2 will time out eventually and any partial message will be purged
skim_chars = TRUE;
}
else // Length out of range
skim_chars = TRUE;
if (skim_chars) {
// Bad data, keep getting characters from the input stream until there
// is an intercharacter timeout
SecsTimestart(&to_interchar);
BtpClearbuf();
while (TRUE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -