home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pctchnqs
/
1990
/
number5
/
msg_pckt.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-06
|
11KB
|
264 lines
/****************************************************************
* MSG_PCKT.CPP - Listing 6
* Written by Kevin D. Weeks, August 1990
* Compiles and runs under Borland Turbo C++ and Zortech C++.
*/
#if defined(__TURCOC__)
#include <mem.h> // memset() prototype in Turbo
#else
#include <string.h> // memset() prototype in Zortech
#endif
#include "msg_pckt.hpp"
// timer function codes
#define MARK 1
#define ELAPSED 2
// protocol codes
#define ACK 6
#define NAK 21
// these two functions are not part of the class but are included
// here for convenience.
unsigned int timer(int function);
unsigned int calc_crc(void *buffer, int length);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Null constructor - the difference between this constructor and
* the next one is the use of Serial_Comm's default parameters. */
Msg_Packet::Msg_Packet(void) : Serial_Comm()
{
timeout = 50;
re_trys = 3;
memset(&recv_msg_buffer,'\0',sizeof(recv_msg_buffer));
memset(&send_msg_buffer,'\0',sizeof(send_msg_buffer));
// initialize the buffer size to the default plus the other
// packet members
Serial_Comm::set_buffer_size(DEFAULT_BUF_SIZE + sizeof(Msg_Type) +
sizeof(char *) + sizeof(int));
status.type_read = status.size_read = status.msg_read = FALSE;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constructor - communication parameters are specified. */
Msg_Packet::Msg_Packet(Com_Port port, Baud_Rate baud, Parity par,
Stop_Bits stop, Data_Bits data) :
Serial_Comm(port,baud,par,stop,data)
{
timeout = 50; re_trys = 3;
memset(&recv_msg_buffer,'\0',sizeof(recv_msg_buffer));
memset(&send_msg_buffer,'\0',sizeof(send_msg_buffer));
// initialize the buffer size to the default plus the other
// packet members
Serial_Comm::set_buffer_size(DEFAULT_BUF_SIZE + sizeof(Msg_Type) +
sizeof(char *) + sizeof(int));
status.type_read = status.size_read = status.msg_read = FALSE;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Provides support for message type and size. Will not return until
* either a message is received, or the timeout or retry values have
* been exceeded. */
Result Msg_Packet::read(Msg_Type *type, int *msg_size, void *buffer)
{
int bytes_read;
*type = get_recv_msg_type();
if ((*type == MSG_ERROR) || (*type == NO_MESSAGE))
return ERROR;
*msg_size = get_recv_msg_size();
get_recv_message(buffer);
status.type_read = status.size_read = status.msg_read = FALSE;
recv_msg_buffer.type = NO_MESSAGE;
recv_msg_buffer.length = 0;
return OK;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Provides support for message type and size. Will not return until
* the message is ACKnowledged or the retry and timeout values have
* been exceeded. */
Result Msg_Packet::write(Msg_Type type, int msg_size, void *buffer)
{
set_send_msg_type(type);
if (set_send_msg_size(msg_size) == ERROR)
return ERROR;
set_send_message(buffer);
return send_message();
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Returns the message type. If the type has already been read it is
* returned immediately, otherwise this method waits for up to
* timeout tenths of a second for a message to be received. */
Msg_Type Msg_Packet::get_recv_msg_type(void)
{
Msg_Type ret_value;
if (open_flag != this) return NO_MESSAGE;
if (status.type_read == TRUE) // type already acquired. return it.
return recv_msg_buffer.type;
timer(MARK); // start the timer
do { // loop until type is received or timeout
if (com_chars_recvd() >= 2) { // check for word size type
// first read the message type low byte
if ((recv_msg_buffer.type =
(Msg_Type)com_read_char()) == ERROR)
break;
com_read_char(); // throw away the high byte
status.type_read = TRUE;
return recv_msg_buffer.type;
}
} while (timer(ELAPSED) < timeout);
recv_msg_buffer.type = NO_MESSAGE;
return MSG_ERROR;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Returns the message size. If the size has already been read it is
* returned immediately, otherwise this method waits for up to
* timeout tenths of a second for a message to be received. */
int Msg_Packet::get_recv_msg_size(void)
{
int ret_value;
if (open_flag != this) return (int)ERROR;
// if the type hasn't been read yet, read it
if (get_recv_msg_type() == MSG_ERROR) return (int)ERROR;
// if the size has already been read return it
if (status.size_read == TRUE)
return (recv_msg_buffer.length);
timer(MARK); // start the timer
do { // loop until size is received or timeout
if (com_chars_recvd() >= 2) { // size is two bytes long
if ((recv_msg_buffer.length = com_read_char()) == ERROR)
break;
if ((ret_value = com_read_char()) == ERROR) break;
recv_msg_buffer.length &= ret_value << 8;
status.size_read = TRUE;
return recv_msg_buffer.length;
}
} while (timer(ELAPSED) < timeout);
recv_msg_buffer.type = MSG_ERROR;
return (int)ERROR;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Return the message received. This methods will try up to re_trys
* times to read a message. Once successfully read the message is re-
* turned but not destroyed. */
Result Msg_Packet::get_recv_message(void *buffer)
{
int retry_counter = 0;
int ret_value;
int bytes_read;
unsigned int crc;
if (open_flag != this) return ERROR;
// if the message has already been read then just return it
if (status.msg_read) {
memcpy(buffer,recv_msg_buffer.msg,recv_msg_buffer.length);
return OK;
}
// loop until either a complete message has
do { // been read or until re_trys is exceeded.
// get the message type
if (get_recv_msg_type() != MSG_ERROR)
if (get_recv_msg_size() != -1){ // get the message size
timer(MARK); // start the timer
bytes_read = 0;
do {
if ((ret_value = com_read
(&recv_msg_buffer.msg[bytes_read])) == ERROR)
break;
else {
bytes_read += ret_value;
if (bytes_read >= recv_msg_buffer.length) {
// add 4 to allow for type & size
crc = calc_crc(&recv_msg_buffer,
recv_msg_buffer.length + 4);
if (crc == (unsigned int) recv_msg_buffer
.msg[recv_msg_buffer.length]) {
com_write_char(ACK);
status.msg_read = TRUE;
memcpy(buffer,recv_msg_buffer.msg,
recv_msg_buffer.length);
return OK;
} else {
com_write_char(NAK);
status.type_read = FALSE;
status.size_read = FALSE;
}
}
}
} while (timer(ELAPSED) < timeout);
}
} while (++retry_counter < re_trys);
status.type_read = status.size_read = status.msg_read = FALSE;
return ERROR;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Sets the size of the message to be sent. */
Result Msg_Packet::set_send_msg_size(int size)
{
if (size <= get_buffer_size()) {
send_msg_buffer.length = size;
return OK;
}
return ERROR;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Result Msg_Packet::send_message(void)
{
int response;
int retry_counter;
unsigned int t;
if (send_msg_buffer.type == NO_MESSAGE) return ERROR;
// calculate the crc
send_msg_buffer.msg[send_msg_buffer.length] =
calc_crc(&send_msg_buffer,send_msg_buffer.length + 4);
// if we're currently sending wait until the current mesage is out
timer(MARK);
while (get_status().flag.sending_message)
if (timer(ELAPSED) > timeout) return ERROR;
// loop until the mesage has been sent or retrys has been exceeded
do {
if ((Result)com_write(send_msg_buffer.length + 6,
&send_msg_buffer) != ERROR) {
// wait until the message is gone
timer(MARK);
while (get_status().flag.sending_message)
if (timer(ELAPSED) > timeout) return ERROR;
// now wait until the ACK or NAK is received
timer(MARK);
while (!get_status().flag.char_received)
if (timer(ELAPSED) > timeout) break;
if (get_status().flag.char_received) {
response = com_read_char();
if (response == ACK) return OK;
}
}
} while (++retry_counter < re_trys);
return ERROR;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function is not a member of Msg_Packet. The clock is started
* when it is passed the MARK code. Thereafter it returns (approxima-
* tely) the number of tenths of a second that have passed since MARK
*/
unsigned int timer(int function)
{
static long reference;
static long far *bios_clock = (long far *)0x0040006c;
if (function == MARK) reference = *bios_clock;
return (unsigned int)((*bios_clock - reference) / 2);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This function is also not a member of Msg_Packet. It calculates a
* CRC value which is then used to detect message corruption. */
unsigned int calc_crc(unsigned char *buffer, int length)
{
unsigned int cur_crc;
int i, j;
for (i = 0; i < length; i++) {
// xor current byte with crc hi-byte
cur_crc ^= (unsigned int)*buffer << 8;
// shift crc left 8 times checking to see if MSB is on
for (j = 0; j < 8; j++)
if (cur_crc & 0x8000) // if MSB on
// shift left and xor with prime
cur_crc = (cur_crc << 1) ^ 0x1021;
else
cur_crc <<= 1; // just shift left
++buffer;
}
return cur_crc;
}