// returns the eqiv. array of bytes (with CRC checksum added) of a frame structure public byte[] frame2Bytes(EZFrame frame) { int framelen = 5 + frame.PayloadLength + 4; // 5 header bytes plus payload, plus starter, terminator and CRC checksum byte[] rawframe = new byte[framelen]; rawframe[0] = framestarter; rawframe[1] = frame.SenderID; rawframe[2] = frame.ReceiverID; rawframe[3] = frame.Ftype; rawframe[4] = (byte)(frame.PayloadLength & 0x0FF); rawframe[5] = (byte)((frame.PayloadLength >> 8) & 0x0FF); int i; for (i = 0; i < frame.PayloadLength; i++) { rawframe[6 + i] = frame.Payload[i]; } rawframe[framelen - 3] = frameterminator; // now adding CRC ushort crc = calculateCRC(rawframe, framelen - 2); rawframe[framelen - 2] = (byte)(crc & 0x0FF); rawframe[framelen - 1] = (byte)((crc >> 8) & 0x0FF); return(rawframe); }
// handle next frame public void receivedNewFrame(EZFrame frame) { // sending acknowledgement NetDevice.sendAcknowledge(PacketSenderID); // copying payload bytes into the packet int i; int startindex = EZRoboNetDevice.MAX_FRAME_PAYLOAD_LENGTH * FramesReceived; for (i = 0; i < frame.PayloadLength; i++) { CurrentPacket[startindex + i] = frame.Payload[i]; } // frame payload copied // increasing number of received frames FramesReceived++; // now changing state if (FramesReceived == TotalFrames) { state = EZRoboNetDevice.stPacketReady; } else { state = EZRoboNetDevice.stReceiving; // marking time for next frame arrival possible timeout FrameReceptionStartTime = DateTime.Now; } }
// handling internal state according to input and triggering appropriate actions public void transitionAction(EZFrame frame) { switch (state) { case EZRoboNetDevice.stReceiving: // in the process of receiving frames switch (frame.Ftype) { case EZRoboNetDevice.t_Ping: // just reply and go back to wait for the next frame in the sequence NetDevice.sendAcknowledge(frame.SenderID); state = EZRoboNetDevice.stReceiving; break; case EZRoboNetDevice.t_Data: // Data frame arrived. See if we can fill the packet some more if (PacketSenderID == frame.SenderID) // received a frame from the original sender { receivedNewFrame(frame); } else { // packet does not originate fron the current sender // disposing inetercepted frame state = EZRoboNetDevice.stReceiving; // still waiting for a new frame } break; case EZRoboNetDevice.t_Acknowledge: // acknowledgment packet arrived // do nothing. dispose the frame break; } break; case EZRoboNetDevice.stPacketReady: // a packet is ready to be handled switch (frame.Ftype) { case EZRoboNetDevice.t_Ping: // ping frame NetDevice.sendAcknowledge(frame.SenderID); state = EZRoboNetDevice.stPacketReady; break; case EZRoboNetDevice.t_Acknowledge: // acknowledge frame // ignore state = EZRoboNetDevice.stPacketReady; break; case EZRoboNetDevice.t_Data: // a data frame // ignore until packeready state has been served state = EZRoboNetDevice.stPacketReady; break; } break; } // end big state switch }
// create an acknowledgement frame public EZFrame makeAcknowledge(byte receiver_id) { EZFrame frame = new EZFrame(); frame.SenderID = NodeID; frame.ReceiverID = receiver_id; frame.Ftype = t_Acknowledge; frame.PayloadLength = 2; frame.Payload = new byte[frame.PayloadLength]; frame.Payload[0] = 0; frame.Payload[1] = 0; return(frame); }
// **************** handling the Incomplete Packets Queue ********************** // insert new packet reception FSM public void InsertNewIncompletePacket(EZFrame frame) { int i; // shifting the queue to the right for (i = IncompletePacketsNum; i > 0; i--) { IncompletePackets[i] = IncompletePackets[i - 1]; } // increasing number of Packets IncompletePacketsNum++; // adding new packet reception FSM IncompletePackets[0] = new EZStationPacketFSM(this, frame); }
// send acknowledgment public void sendAcknowledge(byte receiver_id) { EZFrame ackframe = makeAcknowledge(receiver_id); // converting struct to bytes byte[] rawackframe = frame2Bytes(ackframe); // retrieving length ushort framelength = getRawFrameLength(rawackframe); // sending bytes CommPort.Write(rawackframe, 0, framelength); // done }
public EZStationPacketFSM(EZRoboNetDevice device, EZFrame frame) { // registering the Net Device NetDevice = device; // capturing time of first reception ReceptionStartTime = DateTime.Now; // acknowledging NetDevice.sendAcknowledge(PacketSenderID); // retrieving sender id PacketSenderID = frame.SenderID; // calculating total packet length ushort packetlength = (ushort)(frame.Payload[3] + 256 * frame.Payload[4] + 5); CurrentPacketLength = packetlength; // calculating total number of frames required for full packet transmission TotalFrames = packetlength / EZRoboNetDevice.MAX_FRAME_PAYLOAD_LENGTH + 1; // allocating memory space for the packet being received CurrentPacket = new byte[packetlength]; // now filling initial space in CurrentPacket int i; for (i = 0; i < frame.PayloadLength; i++) { CurrentPacket[i] = frame.Payload[i]; } // done copying // setting number of frames received to 1 FramesReceived = 1; // sending an acknowledgement frame NetDevice.sendAcknowledge(frame.SenderID); if (FramesReceived < TotalFrames) { // need to receive more state = EZRoboNetDevice.stReceiving; // marrking time of acknowledgement FrameReceptionStartTime = DateTime.Now; } else { state = EZRoboNetDevice.stPacketReady; FramesReceived = 0; TotalFrames = 0; } }
// send the next frame of the current packet public void sendNextFrame() { // creating the first frame EZFrame frame = new EZFrame(); frame.SenderID = NodeID; frame.ReceiverID = PacketReceiverID; frame.Ftype = t_Data; ushort payloadlen, index; index = (ushort)(FramesSent * MAX_FRAME_PAYLOAD_LENGTH); if (FramesSent == TotalFrames - 1) { payloadlen = (ushort)(CurrentPacketLength % MAX_FRAME_PAYLOAD_LENGTH); } else { payloadlen = MAX_FRAME_PAYLOAD_LENGTH; } int i; frame.PayloadLength = payloadlen; frame.Payload = new byte[payloadlen]; for (i = 0; i < payloadlen; i++) { frame.Payload[i] = CurrentPacket[i + index]; } // frame created byte[] rawframe = frame2Bytes(frame); int rawframelen = getRawFrameLength(rawframe); // stream the packet through the serial port with a delay per character CommPort.Write(rawframe, 0, rawframelen); // god forbid, packet was sent. Changing state now state = stWaitingAcknowledge; // marking frame transmission time for possible acknowledge timeout FrameTransmissionStartTime = DateTime.Now; }
// Convert bytes to a Frame structure public EZFrame bytes2Frame(byte[] rawframe) { EZFrame frame = new EZFrame(); ushort payloadlen = (ushort)(rawframe[4] + 256 * rawframe[5]); frame.SenderID = rawframe[1]; frame.ReceiverID = rawframe[2]; frame.Ftype = rawframe[3]; frame.PayloadLength = payloadlen; frame.Payload = new byte[payloadlen]; int i; for (i = 0; i < payloadlen; i++) { frame.Payload[i] = rawframe[6 + i]; } return(frame); }
// processData. processData assembles the frames and calls to transitionAction public void processData(SerialBuffer sBuffer) { int i; int numBytesToRead = sBuffer.bytesAvailable(); // let's see what we 've got... do { if (remainingBytes == 0) // previous frame was fully read { if (numBytesToRead >= 6) // nead at least 6 bytes to read frame header // get the first 6 bytes (starter(1)+sender-receiverid(2)+frame type(1)+payload length (2)) // reading first 6 bytes into FrameHead { sBuffer.readBytes(FrameHead, 6); // now cheking for framestarter character mismatch if (FrameHead[0] != framestarter) { flushSerialBuffer(sBuffer); } else // reamaining bytes should be the payload length plus the terminator and two CRC bytes { remainingBytes = FrameHead[4] + FrameHead[5] * 256 + 3; } } } else if (numBytesToRead >= remainingBytes) { // it's time to get the remaining frame(s) int totalBytes = remainingBytes + 6; // calculate total length byte[] buffer = new byte[totalBytes]; byte[] remBuffer = new byte[remainingBytes]; // now reading remaining bytes as estimated using the frame header // going altogether sBuffer.readBytes(remBuffer, remainingBytes); // tailoring bufhead and rembuffer into buffer for (i = 0; i < totalBytes; i++) { if (i < 6) { buffer[i] = FrameHead[i]; } else { buffer[i] = remBuffer[i - 6]; } } // now handling the message... // checking terminator and CRC ushort CRC = (ushort)(buffer[totalBytes - 2] + 256 * buffer[totalBytes - 1]); if ((buffer[totalBytes - 3] == frameterminator) && (checkCRC(buffer, totalBytes - 2, CRC))) { EZFrame frame = bytes2Frame(buffer); // done if (frame.ReceiverID == NodeID) // packet addressed to this node { transitionAction(frame); // change internal state and act } } // clearing remaining bytes remainingBytes = 0; } numBytesToRead = sBuffer.bytesAvailable(); } while ((numBytesToRead >= remainingBytes) && (remainingBytes > 0)); }
// handling internal state according to input and triggering appropriate actions public void transitionAction(EZFrame frame) { switch (state) { case stIdle: // not in process process of receiving or sending if (frame.Ftype == t_Ping) { // received a ping frame. will acknowledge immediately... sendAcknowledge(frame.SenderID); state = stIdle; // state remains idle } else if (frame.Ftype == t_Acknowledge) // ignoring a random acknowledge { state = stIdle; } else { // any other type of frame // now looking up the incomplete Packets Queue EZStationPacketFSM incompletePack = findIncompletePacket(frame.SenderID); if (incompletePack != null) { incompletePack.transitionAction(frame); } else { // adding a new incomplete pack InsertNewIncompletePacket(frame); } state = stIdle; // still idle } break; case stSending: // in the process of sending a packet. still, handling the incoming if (frame.Ftype == t_Ping) { // received a ping frame. will acknowledge immediately... sendAcknowledge(frame.SenderID); state = stSending; // state remains stSending } else if (frame.Ftype == t_Acknowledge) // ignoring a random acknowledge { state = stSending; // keep on sending } else { // any other type of frame // now looking up the incomplete Packets Queue EZStationPacketFSM incompletePack = findIncompletePacket(frame.SenderID); if (incompletePack != null) { incompletePack.transitionAction(frame); } else { // adding a new incomplete pack InsertNewIncompletePacket(frame); } state = stSending; // still Sending } break; case stWaitingAcknowledge: // expecting a frame reception acknowledgement if (frame.Ftype == t_Ping) // casual ping. immediate reply { sendAcknowledge(frame.SenderID); // state remains state = stWaitingAcknowledge; } else if (frame.Ftype == t_Acknowledge) { // received and acknowledge frame if (frame.SenderID == PacketReceiverID) { // increasing number of sent frames FramesSent++; if (FramesSent == TotalFrames) { // all sent PacketReceiverID = 0; state = stIdle; } else { // need to send more frames state = stSending; sendNextFrame(); } } else { state = stWaitingAcknowledge; } } else { // assigning frame to proper Incomplete Packet recipient // any other type of frame // now looking up the incomplete Packets Queue EZStationPacketFSM incompletePack = findIncompletePacket(frame.SenderID); if (incompletePack != null) { incompletePack.transitionAction(frame); } else { // adding a new incomplete pack InsertNewIncompletePacket(frame); } state = stWaitingAcknowledge; // still Waiting for acknowledge } break; } // end big state switch }