static void sendTokenImmediate() { uartTransmit(RAP_SYNC); uartTransmit(0xff); uartState = RAP_idle; in_packetTimer = -1; }
void comms_main() { sendMessage(1); sendDataByte('G'); sendDataByte('O'); endMessage(); uartTransmit(0x54); uartTransmit(0xff); }
static void sendCurrentOutBuffer() { byte i; if (flags1.xmitBufferSent) { printf("Sending already sent packet!\n"); fflush(stdout); return; } if (!flags1.xmitBufferReady) { printf("Transmit buffer not ready!!\n"); fflush(stdout); return; } flags1.xmitBufferSent = 1; uartTransmit(RAP_SYNC); crc = 0; uartTransmit(computeCRC(out_hdb1)); uartTransmit(computeCRC(address)); uartTransmit(computeCRC(out_dest)); uartTransmit(computeCRC(out_hdb2)); uartTransmit(crc); if (out_length > 0) { for(i = 0; i < out_length; i++) uartTransmit(computeCRC(out_buffer[i])); uartTransmit(crc); } }
void uartReceiveError() { byte i; if ((serialStatus & msgAbortedBit) == 0) { //wipe the corrupt-message out of the receive-buffers of the nodes for (i=0; i<8; i++) { //if we are sending too much for the transmit-buffer, it is discarded uartTransmit(0); } //TODO: remove //uartTransmit(serialStatus); } /* serialStatus &= ~serialErrorBit; //clear serialStatus &= ~inTransmitMsgBit; //clear serialStatus &= ~ackRequestedBit; //clear serialStatus &= ~inSendQueueMsgBit; //clear serialStatus &= ~processingLockBit; //clear, maybe we should not do that */ serialStatus = (serialStatus & msgAbortedBit); //clear all bits except msgAbortedBit; uartState = SNAP_idle; }
static void endMessageIntern() { byte i; if (serialStatus & inSendQueueMsgBit) { //test if inSendQueueMsgBit is set, otherwise it has been resetted by serialError // Send the message uartTransmit(SNAP_SYNC); crc = 0; uartTransmit(computeCRC(BIN(01010001))); // Request ACK uartTransmit(computeCRC(BIN(00110000) | sendPacketLength)); uartTransmit(computeCRC(sendPacketDestination)); uartTransmit(computeCRC(deviceAddress)); for(i = 0; i < sendPacketLength; i++) uartTransmit(computeCRC(sendPacket[i])); uartTransmit(crc); /// @todo crc here serialStatus &= ~inSendQueueMsgBit; //clear } }
void uartNotifyReceive() { byte c; c = RCREG; // If error occurred then reset by clearing CREN, but // attempt to continue processing anyway. /// @todo Should we do something else in this situation? if (OERR) { CREN = 0; //don't set the error: serialStatus |= serialErrorBit //because c and the next RCREG will be ok and maybe //we got a correct message } CREN = 1; if (serialStatus & serialErrorBit) { uartReceiveError(); return; } switch(uartState) { // ----------------------------------------------------------------------- // case SNAP_idle: // In the idle state, we wait for a sync byte. If none is // received, we remain in this state. if (c == SNAP_SYNC) { uartState = SNAP_haveSync; serialStatus &= ~msgAbortedBit; //clear } break; // ----------------------------------------------------------------------- // case SNAP_haveSync: // In this state we are waiting for header definition bytes. First // HDB2. We currently insist that all packets meet our expected // format which is 1 byte destination address, 1 byte source // address, and no protocol specific bytes. The ACK/NAK bits may // be anything. in_hdb2 = c; if ((c & BIN(11111100)) != BIN(01010000)) { // Unsupported header. Drop it an reset serialStatus |= serialErrorBit; //set serialError serialStatus |= wrongByteErrorBit; uartReceiveError(); } else { // All is well if ((c & BIN(00000011)) == BIN(00000001)) serialStatus |= ackRequestedBit; //set ackRequested-Bit else serialStatus &= ~ackRequestedBit; //clear crc = 0; computeCRC(c); uartState = SNAP_haveHDB2; } break; // ----------------------------------------------------------------------- // case SNAP_haveHDB2: // For HDB1, we insist on high bits are 0011 and low bits are the length // of the payload. in_hdb1 = c; if ((c & BIN(11110000)) != BIN(00110000)) { serialStatus |= serialErrorBit; //set serialError serialStatus |= wrongByteErrorBit; uartReceiveError(); } else { packetLength = c & 0x0f; if (packetLength > MAX_PAYLOAD) packetLength = MAX_PAYLOAD; computeCRC(c); uartState = SNAP_haveHDB1; } break; // ----------------------------------------------------------------------- // case SNAP_haveHDB1: // We should be reading the destination address now if (c != deviceAddress) { uartTransmit(SNAP_SYNC); uartTransmit(in_hdb2); uartTransmit(in_hdb1); uartTransmit(c); uartState = SNAP_haveDABPass; serialStatus &= ~ackRequestedBit; //clear serialStatus |= inTransmitMsgBit; } else { computeCRC(c); uartState = SNAP_haveDAB; } break; // ----------------------------------------------------------------------- // case SNAP_haveDAB: // We should be reading the source address now if (c == deviceAddress) { // If we receive a packet from ourselves, that means it went // around the ring and was never picked up, ie the device we // sent to is off-line or unavailable. /// @todo Deal with this situation } if (serialStatus & processingLockBit) { //we have not finished the last order, reject uartTransmit(SNAP_SYNC); crc = 0; uartTransmit(computeCRC(BIN(01010011))); //HDB2 // HDB1: 0 bytes, with 8 bit CRC uartTransmit(computeCRC(BIN(00110000))); //HDB1 uartTransmit(computeCRC(sourceAddress)); // Return to sender uartTransmit(computeCRC(deviceAddress)); // From us //TODO: remove /*for debugging add serialStatus uartTransmit(computeCRC(BIN(00110001))); //HDB1 uartTransmit(computeCRC(sourceAddress)); // Return to sender uartTransmit(computeCRC(deviceAddress)); // From us uartTransmit(computeCRC(serialStatus)); // Return to sender */ uartTransmit(crc); // CRC serialStatus &= ~ackRequestedBit; //clear serialStatus |= msgAbortedBit; //set uartState = SNAP_idle; } else { sourceAddress = c; bufferIndex = 0; computeCRC(c); uartState = SNAP_readingData; } break; // ----------------------------------------------------------------------- // case SNAP_readingData: buffer[bufferIndex] = c; bufferIndex++; computeCRC(c); if (bufferIndex == packetLength) uartState = SNAP_dataComplete; break; // ----------------------------------------------------------------------- // case SNAP_dataComplete: // We should be receiving a CRC after data, and it // should match what we have already computed { byte hdb2 = BIN(01010000); // 1 byte addresses if (c == crc) { // All is good, so process the command. Rather than calling the // appropriate function directly, we just set a flag to say // something is ready for processing. Then in the main loop we // detect this and process the command. This allows further // comms processing (such as passing other tokens around the // ring) while we're actioning the command. hdb2 |= BIN(10); serialStatus |= processingLockBit; //set processingLockBit receivedSourceAddress = sourceAddress; } else { // CRC mismatch, so we will NAK the packet hdb2 |= BIN(11); } if (serialStatus & ackRequestedBit) { // Send ACK or NAK back to source uartTransmit(SNAP_SYNC); crc = 0; uartTransmit(computeCRC(hdb2)); // HDB1: 0 bytes, with 8 bit CRC uartTransmit(computeCRC(BIN(00110000))); uartTransmit(computeCRC(sourceAddress)); // Return to sender uartTransmit(computeCRC(deviceAddress)); // From us uartTransmit(crc); // CRC serialStatus &= ~ackRequestedBit; //clear } } uartState = SNAP_idle; break; // ----------------------------------------------------------------------- // case SNAP_haveHDB2Pass: uartTransmit(c); // We will be reading HDB1; pass it on packetLength = c & 0x0f; if (packetLength > MAX_PAYLOAD) packetLength = MAX_PAYLOAD; uartState = SNAP_haveHDB1Pass; break; // ----------------------------------------------------------------------- // case SNAP_haveHDB1Pass: uartTransmit(c); // We will be reading dest addr; pass it on uartState = SNAP_haveDABPass; break; // ----------------------------------------------------------------------- // case SNAP_haveDABPass: uartTransmit(c); // We will be reading source addr; pass it on // Increment data length by 1 so that we just copy the CRC // at the end as well. packetLength++; uartState = SNAP_readingDataPass; break; // ----------------------------------------------------------------------- // case SNAP_readingDataPass: uartTransmit(c); // This is a data byte; pass it on if (packetLength > 1) packetLength--; else { uartState = SNAP_idle; serialStatus &= ~inTransmitMsgBit; //clear } break; default: serialStatus |= serialErrorBit; //set serialError serialStatus |= wrongStateErrorBit; uartReceiveError(); } }
void uartNotifyReceive() { byte c = RCREG; printTime(); if (address) printf(" "); printf(" <-- %d rx %02x in state %d\n", address, c, uartState); fflush(stdout); switch(uartState) { // ----------------------------------------------------------------------- // case RAP_idle: // In the idle state, we wait for a sync byte. If none is // received, we remain in this state. if (c == RAP_SYNC) { uartState = RAP_expectHDB1; in_packetTimer = PKT_RECEIVE_TIMEOUT; } break; // ----------------------------------------------------------------------- // case RAP_expectHDB1: if (c == 0xff) { // We have received a token, so if we have any data to send we // can send it now. in_tokenTimer = 0; if (flags1.xmitBufferReady && !flags1.xmitBufferSent) { sendCurrentOutBuffer(); uartState = RAP_idle; in_packetTimer = -1; flags1.out_bufferBusy = 0; } else if (flags1.out_timedout) { // If our last send timed out, send it again out_resendTimer = PKT_SEND_TIMEOUT; flags1.out_timedout = 0; flags1.xmitBufferSent = 0; sendCurrentOutBuffer(); uartState = RAP_idle; in_packetTimer = -1; flags1.in_bufferBusy = 0; } else { // Nothing to send, so pass the token on sendTokenImmediate(); } } else { // Header of a normal packet if (flags1.in_bufferBusy) { // Inward buffer still busy, so have to drop packet. printf("%d Buffer busy, drop %02x\n", address, c); fflush(stdout); uartState = RAP_expectSRCDrop; flags1.in_dropAction = Drop_None; } else { flags1.in_bufferBusy = 1; in_hdb1 = c; crc = 0; computeCRC(c); uartState = RAP_expectSRC; } } break; // ----------------------------------------------------------------------- // case RAP_expectSRC: in_src = c; computeCRC(c); uartState = RAP_expectDST; break; // ----------------------------------------------------------------------- // case RAP_expectDST: in_dest = c; computeCRC(c); uartState = RAP_expectHDB2; break; // ----------------------------------------------------------------------- // case RAP_expectHDB2: in_hdb2 = c; computeCRC(c); uartState = RAP_expectHCRC; break; // ----------------------------------------------------------------------- // case RAP_expectHCRC: in_bufferIndex = 0; if (c == crc) { byte tseq; byte ok = 1; flags1.in_dropAction = Drop_None; printf("Valid header CRC\n"); fflush(stdout); // Restart timer in_packetTimer = PKT_RECEIVE_TIMEOUT; // We now have a valid header, so we can process it if (in_src == address) { printf("Packet has cycled, so drop it\n"); fflush(stdout); uartState = RAP_readingDataDrop; flags1.in_dropAction = Drop_None; ok = 0; } else if (in_dest != address) { printf("Not for me (%d), forward it on\n", in_dest); fflush(stdout); uartTransmit(RAP_SYNC); uartTransmit(in_hdb1); uartTransmit(in_src); uartTransmit(in_dest); uartTransmit(in_hdb2); uartTransmit(c); flags1.in_bufferBusy = 0; uartState = RAP_readingDataPass; ok = 0; } if (in_hdb1 & RAP_HDB1_RST) lastReceive = lastTransmit = -1; if (ok) { // Deal with incoming transmit sequence (incoming data) byte lastrs, nextrs; lastrs = (lastReceive & 3); nextrs = (lastrs + 1) & 3; printf("tseq is %d, lastrec is %d\n", tseq, lastReceive); fflush(stdout); tseq = RAP_TSEQ(in_hdb2); if (tseq == lastrs && ((in_hdb2 & RAP_HDB2_LENMASK) == 0)) { // They are sending a bare ACK printf("Bare ACK received\n"); fflush(stdout); } else if (tseq == lastrs) { // They are re-sending data, so our previous packet must have been // lost. Retransmit it. out_resendTimer = -1; // Also kill the resend timer if we had one printf("Lost previous packet, retransmit\n"); fflush(stdout); uartState = RAP_readingDataDrop; flags1.in_dropAction = Drop_ResendLast; ok = 0; } else if (tseq == nextrs) { printf("Valid sequence\n"); fflush(stdout); } else { printf("Invalid tsequence %d (lastReceive=%d), drop and reset\n", tseq, lastReceive); fflush(stdout); flags1.in_dropAction = Drop_Reset; uartState = RAP_readingDataDrop; ok = 0; } } if (ok && (in_hdb1 & RAP_HDB1_NAK)) { // TODO: check sequence of NAK printf("Received NAK, resend last packet\n"); fflush(stdout); flags1.xmitBufferSent = 0; sendCurrentOutBuffer(); uartState = RAP_idle; in_packetTimer = -1; flags1.in_bufferBusy = 0; out_resendTimer = PKT_SEND_TIMEOUT; flags1.out_timedout = 0; break; } // Deal with incoming receive sequence (responded to outgoing data) if (ok && (in_hdb1 & RAP_HDB1_ACK)) { byte rseq; rseq = RAP_RSEQ(in_hdb2); if (rseq == (lastTransmit & 3)) { printf("Previous data acknowledged\n"); flags1.xmitBufferReady = 0; fflush(stdout); out_resendTimer = 255; flags1.out_timedout = 0; } else { printf("Invalid rsequence, dropping packet\n"); fflush(stdout); } } if (ok) { if ((in_hdb2 & RAP_HDB2_LENMASK) == 0) { // We don't bother with the second CRC if there is // no data payload. sendTokenImmediate(); } else uartState = RAP_readingData; } } else { printf("Header CRC failure (got %02x, expected %02x), drop packet\n", c, crc); fflush(stdout); flags1.in_dropAction = Drop_None; uartState = RAP_readingDataDrop; } break; // ----------------------------------------------------------------------- // case RAP_readingData: in_buffer[in_bufferIndex] = c; in_bufferIndex++; // Restart timer in_packetTimer = PKT_RECEIVE_TIMEOUT; computeCRC(c); if (in_bufferIndex == (in_hdb2 & RAP_HDB2_LENMASK)) uartState = RAP_expectDCRC; break; // ----------------------------------------------------------------------- // case RAP_expectDCRC: if (c == crc) { if ((in_hdb2 & RAP_HDB2_LENMASK) > 0) lastReceive = (lastReceive + 1) & 3; packetNotifyReceive((byte *)in_buffer, (in_hdb2 & RAP_HDB2_LENMASK)); sendTokenImmediate(); } else { // Failure, so NAK the packet. Possible optimisation: rather // than putting a token out, just NAK immediately. printf("Data CRC failure (got %02x, expected %02x), NAK packet\n", c, crc); fflush(stdout); if (flags1.out_bufferBusy) { // Already waiting to send a packet, so just drop it. printf("Outward buffer already busy, drop\n"); fflush(stdout); } else { flags1.out_bufferBusy = 1; out_hdb1 = RAP_HDB1_NAK; out_hdb2 = 0; out_length = 0; out_dest = in_src; flags1.xmitBufferReady = 1; flags1.xmitBufferSent = 0; flags1.in_bufferBusy = 0; // Put out a new token sendTokenImmediate(); } } break; // ----------------------------------------------------------------------- // case RAP_expectHDB2Pass: uartTransmit(c); in_bufferIndex = 0; uartState = RAP_readingDataPass; break; // ----------------------------------------------------------------------- // case RAP_readingDataPass: uartTransmit(c); in_bufferIndex++; if (in_bufferIndex == (in_hdb2 & RAP_HDB2_LENMASK)) uartState = RAP_expectDCRCPass; break; // ----------------------------------------------------------------------- // case RAP_expectDCRCPass: uartTransmit(c); uartState = RAP_idle; in_packetTimer = -1; break; // ----------------------------------------------------------------------- // case RAP_readingDataDrop: in_bufferIndex++; if (in_bufferIndex == (in_hdb2 & RAP_HDB2_LENMASK)) uartState = RAP_expectDCRCDrop; break; // ----------------------------------------------------------------------- // case RAP_expectDCRCDrop: flags1.in_bufferBusy = 0; switch(flags1.in_dropAction) { case Drop_None: // Drop and do nothing. Except of course, we still // need to put a token back into circulation sendTokenImmediate(); break; case Drop_ResendLast: flags1.xmitBufferSent = 0; sendCurrentOutBuffer(); uartState = RAP_idle; in_packetTimer = -1; flags1.in_bufferBusy = 0; out_resendTimer = PKT_SEND_TIMEOUT; flags1.out_timedout = 0; break; case Drop_NAK: case Drop_Reset: default: printf("Unknown drop action %d\n", flags1.in_dropAction); fflush(stdout); } break; // ----------------------------------------------------------------------- // default: printf("%d Unimplemented state %d\n", address, uartState); fflush(stdout); break; } }