📄 secs1btp.c
字号:
if (BtpCharin() != BTP_NO_DATA)
SecsTimestart(&to_interchar);
if (SecsTimeout(&to_interchar))
break;
}
// Then NAK the block
BtpCharout(NAK);
}
btp_receiving = FALSE;
}
/*
* Allocate a send buffer */
// Note that we've implemented this as a circular que, however, very little
// of the code presumes this is the case, so it should be fairly simple to
// modify this stuff to use another implementation if desired
int BtpAllocSend(BOOL first)
{
int retval = send_insert;
// Send buffers are kept in a circular que
if (++send_insert >= NUMBER_SEND_BLOCKS)
send_insert = 0;
// If there are no more send blocks tell the caller
if (send_insert == send_delete) {
send_insert = retval;
return(BTP_ALLOC_ERR);
}
// if This is the first block of a message register it
if (first)
send_first = retval;
return(retval);
}
/*
* Deallocate a single send buffer, used during transmission to lose the
* sent block
*/
static void BtpDeallocSend(void)
{
if (send_insert == send_delete)
return;
send_blocks[send_delete].ready_to_send = 0;
if (++send_delete >= NUMBER_SEND_BLOCKS)
send_delete = 0;
}
/*
* Deallocate all blocks in this message, used prior to send to invalidate
* the message we were currently working on
*/
void BtpUnallocAll(void)
{
// Quit if none
if (send_first == BTP_NO_FIRST)
return;
// Back up one block at a time until all gone
while ((send_insert != send_delete) && (send_first != send_insert)) {
if (--send_insert < 0)
send_insert = NUMBER_SEND_BLOCKS - 1;
send_blocks[send_insert].ready_to_send = 0;
}
// Can't do this again
send_first = BTP_NO_FIRST;
}
// Flush all send buffers
void BtpFlushSend(void)
{
int i;
for (i=0; i< NUMBER_SEND_BLOCKS; i++) {
send_blocks[i].ready_to_send = 0;
}
send_insert = 0;
send_delete = 0;
send_first = BTP_NO_FIRST;
}
/* Put data out on the line, we get here after a block has been marked
* as ready to send
*/
static void BtpSend(void)
{
int i,length,checksum, thischar, total_tries;
BOOL reading_response, sending_enq;
SECS1_BLOCK *bp = &send_blocks[send_delete];
// We can attempt this several times
total_tries = retries;
// Until we succed or give up
while (TRUE) {
// Send ENQ, start protocol timer, clear input buffer
BtpCharout(ENQ);
SecsTimestart(&to_protocol);
BtpClearbuf();
sending_enq = TRUE;
while (sending_enq) {
if ((thischar = BtpCharin()) == EOT)
// If we get an EOT the ENQ was successful
sending_enq = FALSE;
else {
if (SecsTimeout(&to_protocol)) {
// IF we get a timeout try again
if (--total_tries < 0) {
// too many retries, LOSE BLOCK CONTENTS of entire multiblock message
// and exit
secs1_retrylimit = TRUE;
do {
BtpDeallocSend();
} while (!send_blocks[send_delete].h.E && (send_insert != send_delete));
return;
}
else {
// Else another retry, restart timer and send another ENQ
SecsTimestart(&to_protocol);
BtpCharout(ENQ);
}
}
else
if (is_slave && (thischar == ENQ)) {
// CONTENTION, go do receive logic
BtpReceive();
// Then try to send the thing again
SecsTimestart(&to_protocol);
BtpCharout(ENQ);
}
}
}
// ENQ resulted in EOT, get length and checksum
length = bp->length + SECS1_HEADLEN;
checksum = BtpChecksum(bp);
// Send length, header, data, checksum
// Note again the reliance on the order of fields in the block structure
BtpBufferedCharout(length);
for (i=0; i<length; i++)
BtpBufferedCharout(*((BYTE *)(&bp->length)+i+1));
BtpBufferedCharout(checksum>>8);
BtpCharout(checksum & 0xff);
// Start timer, wait for ACK
SecsTimestart(&to_protocol);
BtpClearbuf();
reading_response = TRUE;
while (reading_response) {
thischar = BtpCharin();
if (thischar == ACK) {
// ACK, block received, release it
if (bp->h.E && bp->h.W) {
// Register the block as expected and mark a wait
// for reply before sending anything else if you are the slave
// Note that this leaves us with the R and W bits set but with
// the SECS-2 func set to the reply value in the
// event an error is issued, which is fine, it may help diagnose
// problems at some point in the future
is_in_wait = is_slave;
expected_waiting = MraRegisterExpected(bp, TRUE);
}
BtpDeallocSend();
send_success = TRUE;
return;
}
if (SecsTimeout(&to_protocol) || (thischar != BTP_NO_DATA)) {
// OUT OF TIME or INVALID CHAR, do OUTER (RETRY) LOOP
reading_response = FALSE;
if (--total_tries < 0){
// too many retries, LOSE BLOCK CONTENTS of entire multiblock message
// and exit. This algorythm is one of the few places we make an
// assumption about the order in which blocks are allocated, if
// the allocation routines are changed this will need it too.
// This also depends upon the SECS-2 format not mixing the blocks
// of different messages, which, the current implementation will not
secs1_retrylimit = TRUE;
while (!bp->h.E && (send_insert != send_delete))
BtpDeallocSend();
return;
}
}
}
}
}
// Power-up init, init anything which might be a factory preset now
void Secs1pup(BOOL power_up)
{
int i;
if (power_up) {
is_slave = FALSE;
send_insert = 0;
send_delete = 0;
receiving_block = 0;
send_first = BTP_NO_FIRST;
is_in_wait = FALSE;
expected_waiting = 0;
send_success = FALSE;
secs1_retrylimit = FALSE;
// Clear buffers
BtpFlushSend();
for (i=0; i< NUMBER_RECEIVE_BLOCKS; i++) {
receive_blocks[i].ready_to_send = 0;
}
// Line initialization
Secs1CharInit();
}
retries = DF_RETRY;
to_interchar.timing = FALSE;
to_interchar.length = TO_INTERCHAR;
to_protocol.timing = FALSE;
to_protocol.length = TO_PROTOCOL;
device_id = DF_DEVID;
// Low level communication params
CommStates.BaudRate = DF_BAUD;
CommStates.MultiDropAddress = 0;
// This has to be done here in case the SECS menu is not included
secspre_interchar.value = ((INTVAL) TO_INTERCHAR) /10;
secspre_protocol.value = ((INTVAL) TO_PROTOCOL) / 10 ;
secspre_retries.value = ((INTVAL) DF_RETRY);
secspre_devid.value = ((INTVAL) DF_DEVID);
secspre_baud.value = 0;
while( baudlist[secspre_baud.value] && (baudlist[secspre_baud.value] != DF_BAUD))
secspre_baud.value++;
#ifdef LOG
file = fopen("data","w");
#endif
// MRA initialization
MraInit(power_up);
}
/* Idle routine, waits for data available either to receive from
* the line or send from a buffer. Note we've added code to prevent the
* host (slave) from sending more than one primary message at a time. Not in the
* specs but without this we get contention.
*/
void BtpIdle(void)
{
BOOL sent;
while (TRUE) {
sent = FALSE;
// Send data if ready and not waiting for a response
if (send_blocks[send_delete].ready_to_send) {
if (is_in_wait)
if (expected_blocks[expected_waiting].status == MRA_COMPLETE)
is_in_wait = FALSE;
if (!is_in_wait) {
sent = TRUE;
BtpSend();
}
}
// Specs specify that we don't try to receive while there is stuff to send
if (!sent) {
BtpClearbuf();
if (BtpCharin() == ENQ)
BtpReceive();
}
/* check interblock and reply timers */
MraTimeouts();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -