home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- * 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;
- }
-