#include "serial_communications.h" /** @name low-level.c This file contains functions pertaining to the bottom layer of the communications structure. @author Daniel Storey, UWA, 1998 @version 1.0 */ /*@{*/ /*************************************************************************/ /** Checks if we can send. Determines the status of the token flag and returns true if we can send. @param channel Channel, the variable holding the channel data. @return bool, true if we can send. */ /*************************************************************************/ bool can_send(Channel *channel) { return channel->token; } /*************************************************************************/ /** Send all packets in the outgoing queues. Get packets from the outgoing queues, then send them , along with the token packet to transfer control to the next station in the network. Increment the value of the "sent" field of every regular packet. Remove those packets which are too old. @param channel Channel, the variable holding the channel data. @return void. */ /*************************************************************************/ void low_send(Channel *channel) { Packet packet; int i = 0, j = 0; char c = (char) 0x55; /* check token status */ if(channel->token==FALSE) { #if DEBUG LCDPrintf("Error: low send called before token received\n"); #endif return; /* Do Not Send */ } /* send preamble */ send_string(channel->preamble, PREAMBLE_BYTES, channel); /* Check queue for packets which are too old */ for(j=0; jsending, j)) { increment_packet_in_queue(&channel->sending, j); packet = get_from_queue(&channel->sending, j); if(packet.sent >= MAXIMUM_NUMBER_OF_RESENDS ) { remove_from_queue(&channel->sending, j); /* LCDPrintf("Err: '%s'\n", packet.data); */ /* KEYWait(KEY1); */ } else { /* Send Packets */ send_packet(packet, FALSE, channel); } } } /* Send Special Packets */ while(special_queue_length(&channel->special_sending)!=0) { packet = special_dequeue(&channel->special_sending); send_packet(packet, TRUE, channel); } /* Pass the token */ packet = generate_token_packet(channel); send_packet(packet, TRUE, channel); /* Change token status */ channel->token = FALSE; /* Add some dummy characters */ for(i=0; ibroadcast_address[0]); if(temp==0) { return TRUE; /* Destination is this machine */ } /* Compare machine address and packet address */ temp = strcmp(&destination_address[0], &channel->my_address[0]); if(temp==0) { return TRUE; /* Destination is this machine */ } else { return FALSE; /* Destination is not this machine */ } } /*************************************************************************/ /** Determine if the CRC in a packet that has been received is correct. Get the CRC from a packet that has been received, generate the correct CRC and compare this with the CRC that has been received. @param packet Packet, the packet for which the crc is to be compared. @return bool, true if the CRC is correct. */ /*************************************************************************/ bool check_crc(Packet *packet) { char calc_crc[9]; int i; crc(&calc_crc[0], &packet->data[0]); /* Compare Strings */ for(i=0; i<7; i++) { if(calc_crc[i]!=packet->crc[i]) { return FALSE; } } return TRUE; } /*************************************************************************/ /** Determine if a raw packet string is long enough to allow conversion. Get the length field from a raw packet string, then determine whether their is sufficient string left to justify conversion of this string into a packet. @param string string, the raw packet string. @return bool, true if there is sufficient packet length. */ /*************************************************************************/ bool enough_string_left(char* string) { char* pack_len; int string_left; string_left = string_length(string); /* First check there are enough bytes to allow for minimum length */ if (string_left < (1 + ADDRESS_LEN + ADDRESS_LEN + 1 + 2 + 1)) { return FALSE; } /* set pointer to where packet length should be */ pack_len = &string[ 1 + ADDRESS_LEN + ADDRESS_LEN + 1]; if (string_left < total_packet_length(pack_len)) { return FALSE; } else { return TRUE; } } /*************************************************************************/ /** Determine if the end chracter of a raw string is correct. Get the length field from a raw packet string, then read the character at the end of the packet as determined by this length. @param string string, the raw packet string. @return bool, true if the end byte is correct. */ /*************************************************************************/ bool end_packet_correct(char* string) { char* pack_len; /* set pointer to where packet length should be */ pack_len = &string[1+ADDRESS_LEN+ADDRESS_LEN+1]; /* Length of string until end byte */ if (string[total_packet_length(pack_len)-1] == PACKET_END) /* Length of string until end byte */ return TRUE; else return FALSE; } /*************************************************************************/ /** Find the total length of a packet. From the packet length string that is passed, determine the length of a total packet containing this string. @param packet_len string, an ASCII encoded string representing packet length. @return int, the total length of the packet. */ /*************************************************************************/ int total_packet_length(char* pack_len) { int length = 0; if(is_special_packet(pack_len)) { length = 1 + ADDRESS_LEN + ADDRESS_LEN + 1 + PACKET_TYPE_BYTES + packet_length(pack_len) + 1; } else { length = 1 + ADDRESS_LEN + ADDRESS_LEN + 1 + PACKET_TYPE_BYTES + packet_length(pack_len) + CRC_BYTES + 1; } return length; } /*************************************************************************/ /** Check if a token has been received. Access the channel variable to see if this station holds the token. @param channel Channel, the variable holding the channel data. @return bool, true if the token is held by this station. */ /*************************************************************************/ bool free_to_send(Channel *channel) { return channel->token; } /*************************************************************************/ /** Extract a packet from a raw string. Perform checks on a raw packet string. If the string passes these tests, place the decoded data string in the receiving queue, and an ok packet in the special packet sending queue. @param channel Channel, the variable holding the channel data. @param string string, the raw packet string. @return void. */ /*************************************************************************/ void extract_packet(char* string, Channel *channel) { Packet packet, ok; bool a; #if PC_SERIAL_CHECK char message[10]; #endif #if PC_SERIAL_CHECK send_check_str("Extract\n", 8); #endif /* Check if there is sufficient packet left according to packet.length */ if(enough_string_left(&string[0])) { #if PC_SERIAL_CHECK send_check_str("Enough String\n", 14); #endif /* Check if this machine is the packet owner */ if(packet_owner(&string[0], channel)) { #if PC_SERIAL_CHECK send_check_str("Own\n", 4); #endif /* Check if the end of packet marker is correct */ if(end_packet_correct(&string[0])) { #if PC_SERIAL_CHECK send_check_str("End\n", 4); #endif /* Break the string into a packet */ packet = receive_packet(packet, &string[0]); /* Check if the packet is a special packet */ if(is_special_packet(packet.type)) { #if PC_SERIAL_CHECK send_check_str("Special\n", 8); #endif /* do some stuff if its a special packet */ switch(packet.type[1]) { case('R'): /* Packet has been received ok */ a = match_and_remove(&channel->sending, packet.number[0]); #if PC_SERIAL_CHECK if(a) send_check_str("Removed\n", 8); else send_check_str("Rem: Couldn't find\n", 19); #endif return; case('T'): /* Token - change channel v'ble 'token' so we can send */ channel->token=TRUE; #if TOKEN_MSG LCDPrintf("TOKEN RECEIVED\n"); #endif #if PC_SERIAL_CHECK send_check_str("Token Wrong Place\n", 18); #endif /* Increment the age of all received frames in the received frames list */ recframe_increment_age(&channel->recframe_queue); return; } } else { /* Normal packet */ /* Check the CRC of the incoming packet */ #if PC_SERIAL_CHECK send_check_str("Normal\n", 7); #endif if(check_crc(&packet)) { /* Frame structure is sound. Check recent packets for duplicate */ #if PC_SERIAL_CHECK send_check_str("CRC\n", 4); #endif if(!recframe_match(&channel->recframe_queue,packet.number,packet.source_address)) { #if PC_SERIAL_CHECK send_check_str("Not a Duplicate\n", 16); #endif /* Add this frame to recent arrivals */ recframe_enqueue(&channel->recframe_queue,packet.number,packet.source_address); string_enqueue(&channel->string_receiving, packet.data, packet.source_address); } /* Generate & queue response */ ok = generate_packet_ok(packet, channel); #if PC_SERIAL_CHECK send_check_str("Response\n", 9); #endif special_enqueue(&channel->special_sending, ok); } } } } } return; } /*************************************************************************/ /** Check a raw frame for a token. Quickly check for the most common frame type to improve efficiency. @param string string, the raw frame. @param channel Channel, the variable holding the channel data. @return bool, True if the raw frame is a token. */ /*************************************************************************/ bool fast_token_check(char* string, Channel *channel) { if(string_length(string)==7) if(strncmp(&string[1], channel->my_address, ADDRESS_LEN)==0) if(string[5]=='T') { /* Token - change channel v'ble 'token' so we can send */ channel->token=TRUE; #if TOKEN_MSG LCDPrintf("TOKEN RECEIVED\n"); send_check_str("Token\n", 6); #endif /* Increment the age of all received frames in the received frames list */ recframe_increment_age(&channel->recframe_queue); return TRUE; } return FALSE; } /*************************************************************************/ /** Receive data at the lowest level. Read raw packets from the seria port, then decode and queue these until a token that passes control to send to this station is received. @param channel Channel, the variable holding the channel data. @return int, always 0. */ /*************************************************************************/ int low_receive(Channel *channel) { /* Check if a token is present */ if(can_send(channel)) return 0; /* Read raw packet from port */ if(read_until_packet_end(channel)!=-1) { if(!fast_token_check(channel->raw, channel)) extract_packet(channel->raw, channel); #if DEBUG LCDPrintf("Extracting\n"); #endif channel->timeout=0; } else channel->timeout++; /* Check if a timeout is called */ if(channel->timeout>MAX_TIMEOUT_DELAY) { if(channel->master==TRUE) { force_send(channel); /* Generate another token at master */ } #if TOKEN_MSG LCDPrintf("Timeout Error\n"); LCDPrintf("Partial:'%s'\n", channel->raw); KEYWait(KEY1); #endif channel->timeout = 0; } return 0; }