// // "Packet.ic" // // Programmer: Ross Mead // Last modified: 08Aug2008 // // preprocessor directives #use "Array.ic" #use "Byte.ic" #use "xbcserial.ic" // communication debug definitions //#define DEBUG_PACKET 1 // packet compilation definitions //#define PACKET_FULL_COMPILE 1 // packet communication definitions #define PACKET_MAX_N_BYTES 100 #define PACKET_BUFFER_SIZE 50 /* ((PACKET_MAX_N_BYTES + 1) / 2) */ #define PACKET_BROADCAST 0xFFFF #define PACKET_ID_MIN 0x21 #define PACKET_ID_MAX 0x7A BYTE _packetNextID = PACKET_ID_MIN; // API packet type definitions #define PACKET_TYPE_NONE MAX_BYTE #define PACKET_TYPE_COMMAND 0x08 #define PACKET_TYPE_COMMAND_RESPONSE 0x88 #define PACKET_TYPE_TRANSMIT 0x01 #define PACKET_TYPE_TRANSMIT_RESPONSE 0x89 #define PACKET_TYPE_RECEIVE 0x81 // API packet codes #define PACKET_START_DELIMITER 0x7E #define PACKET_NO_ACK 0x00 #define PACKET_NO_PARAMS -1 #define PACKET_TRANSMIT_DISABLE_ACK 0x01 #define PACKET_TRANSMIT_BROADCAST 0x04 #define PACKET_TRANSMIT_SUCCESS 0 #define PACKET_TRANSMIT_NO_ACK 1 #define PACKET_TRANSMIT_CCA_FAILURE 2 #define PACKET_TRANSMIT_PURGED 3 #define PACKET_COMMAND_OK 0 #define PACKET_COMMAND_ERROR 1 // numerical data type packet size definitions #define B_PACKET_SIZE 1 #define I_PACKET_SIZE I_BYTE_SIZE #define L_PACKET_SIZE (B_PACKET_SIZE + L_BYTE_SIZE) #define F_PACKET_SIZE (B_PACKET_SIZE + L_BYTE_SIZE) #define C_PACKET_SIZE B_PACKET_SIZE // defines an API-mode communication packet struct Packet { int frontIndex, dataLength, addr, params; BYTE type, ack, data[PACKET_BUFFER_SIZE]; }; // Packet // initializes the parameterized packet, // returning TRUE if successful, FALSE otherwise BOOL initPacket(struct Packet* p) { return resetPacket(p); } // initVector(struct Vector*) // resets the data members of the parameterized packet, // returing TRUE if successful, FALSE otherwise BOOL resetPacket(struct Packet* p) { if (p == NULL) return FALSE; p->addr = 0; p->ack = PACKET_NO_ACK; p->params = PACKET_NO_PARAMS; return setPacketType(p, PACKET_TYPE_NONE) && clearPacketData(p); } // resetPacket(struct Packet*) // sets the type of the parameterized packet // to the parameterized packet, returning // TRUE if successful, FALSE otherwise BOOL setPacketType(struct Packet* p, int type) { if ( (p == NULL ) || ((type != PACKET_TYPE_NONE ) && (type != PACKET_TYPE_COMMAND ) && (type != PACKET_TYPE_COMMAND_RESPONSE ) && (type != PACKET_TYPE_TRANSMIT ) && (type != PACKET_TYPE_TRANSMIT_RESPONSE) && (type != PACKET_TYPE_RECEIVE ))) return FALSE; p->type = type; return TRUE; } // setPacketType(struct Packet*, int) // clears the data of the parameterized packet, // returing TRUE if successful, FALSE otherwise BOOL clearPacketData(struct Packet* p) { if ((p == NULL) || (!arrayClear(p->data))) return FALSE; p->frontIndex = p->dataLength = 0; return TRUE; } // clearPacketData(struct Packet*) // updates and returns the ID of the parameterized packet BYTE updatePacketID(struct Packet* p) { if (p == NULL) return 0x00; p->ack = _packetNextID++; if (_packetNextID > PACKET_ID_MAX) _packetNextID = PACKET_ID_MIN; return p->ack; } // updatePacketID(struct Packet*) // pushes the parameterized byte into the buffer // of the parameterized packet, returning TRUE // if successful, FALSE otherwise BOOL packetPushByte(struct Packet* p, BYTE byte) { if ((p == NULL) || (p->dataLength + B_PACKET_SIZE > PACKET_MAX_N_BYTES) || (!setPacketByte(p, p->dataLength, byte))) return FALSE; ++p->dataLength; return TRUE; } // packetPushByte(struct Packet*, BYTE) // pushes the parameterized integer into the buffer // of the parameterized packet, returning TRUE // if successful, FALSE otherwise BOOL packetPushInt(struct Packet* p, int i) { return (p != NULL) && (p->dataLength + I_PACKET_SIZE <= PACKET_MAX_N_BYTES) && packetPushByte(p, msb(i)) && packetPushByte(p, lsb(i)); } // packetPushInt(struct Packet*, int) // pushes the parameterized long integer into the // buffer of the parameterized packet, returning // TRUE if successful, FALSE otherwise BOOL packetPushLong(struct Packet* p, long l) { BYTE sgn = BYTE_POS; if ((p == NULL) || (p->dataLength + L_PACKET_SIZE > PACKET_MAX_N_BYTES)) return FALSE; if (l < 0L) sgn = BYTE_NEG; if (!packetPushByte(p, sgn)) return FALSE; l = labs(l); return packetPushByte(p, lgetByte(l, 3)) && packetPushByte( p, lgetByte(l, 2)) && packetPushByte( p, lgetByte(l, 1)) && packetPushByte( p, lgetByte(l, 0)); } // packetPushLong(struct Packet*, long) // pushes the parameterized floating-point number // into the buffer of the parameterized packet, // returning TRUE if successful, FALSE otherwise BOOL packetPushFloat(struct Packet* p, float f) { long mantissa = 0L; int signMask = MASK_POS, exponent = 0, signAndExp = 0; if ((p == NULL) || (p->dataLength + F_PACKET_SIZE > PACKET_MAX_N_BYTES)) return FALSE; if (!fisEqualToZero(f)) { if (f < 0.0) { signMask = MASK_NEG; f *= -1.0; } // maximizes the precision of digits in the mantissa // by generating the longest long-integer possible; // NOTE: one would assume that when the max. long-integer is exceeded, // values would become negative; however, it has been discovered // that this is not the case on the XBC--it is simply MAX_LONG //for (exponent = 0; // (long)(f * fpow(10.0, (float)(exponent + 1))) > 0L; // ++exponent); for (exponent = 0; (long)(f * fpow(10.0, (float)(exponent + 1))) != MAX_LONG; ++exponent); mantissa = (long)(f * fpow(10.0, (float)exponent)); signAndExp = signMask | exponent; } return packetPushByte(p, signAndExp) && packetPushByte( p, lgetByte(mantissa, 3)) && packetPushByte( p, lgetByte(mantissa, 2)) && packetPushByte( p, lgetByte(mantissa, 1)) && packetPushByte( p, lgetByte(mantissa, 0)); } // packetPushFloat(struct Packet*, float) // pushes the parameterized character into the buffer // of the parameterized packet, returning TRUE // if successful, FALSE otherwise #ifdef PACKET_FULL_COMPILE BOOL packetPushChar(struct Packet* p, BYTE c) { return (p != NULL) && (p->dataLength + C_PACKET_SIZE <= PACKET_MAX_N_BYTES) && packetPushByte(p, c); } // packetPushChar(struct Packet*, BYTE) #endif // pushes the parameterized string of characters // into the buffer of the parameterized packet, // if successful, FALSE otherwise BOOL packetPushStr(struct Packet* p, char str[]) { int i = 0, n = strlen(str); for (i = 0; i < n; ++i) if (!packetPushByte(p, lsb(str[i]))) return FALSE; return TRUE; } // packetPushStr(struct Packet*, char []) // pops and returns a byte from the // buffer of the parameterized packet BYTE packetPopByte(struct Packet* p) { BYTE byte = 0x00; if (p != NULL) { byte = getPacketByte(p, p->frontIndex); p->frontIndex = clip(++p->frontIndex, 0, p->dataLength); } return byte; } // packetPopByte(struct Packet*) // pops and returns an integer from the // buffer of the parameterized packet int packetPopInt(struct Packet* p) { if (p == NULL) return 0; if (p->dataLength - p->frontIndex >= I_PACKET_SIZE) return bytesToInt(packetPopByte(p), packetPopByte(p)); return packetPopByte(p); } // packetPopInt(struct Packet*) // pops and returns a long integer from the // buffer of the parameterized packet long packetPopLong(struct Packet* p) { long l = 0L; BYTE sgn = MAX_BYTE; if (p == NULL) return 0L; if (p->dataLength - p->frontIndex >= L_PACKET_SIZE) { sgn = packetPopByte(p); l = bytesToLong(packetPopByte(p), packetPopByte(p), packetPopByte(p), packetPopByte(p)); if (sgn == BYTE_NEG) return -l; return l; } return (long)packetPopByte(p); } // packetPopLong(struct Packet*) // pops and returns a floating-point number from the // buffer of the parameterized packet float packetPopFloat(struct Packet* p) { float f = 0.0; long mantissa = 0L; int signMask = MASK_POS, exponent = 0, signAndExp = 0; if ((p != NULL) && (p->dataLength - p->frontIndex >= F_PACKET_SIZE)) { signAndExp = packetPopByte(p); mantissa = bytesToLong(packetPopByte(p), packetPopByte(p), packetPopByte(p), packetPopByte(p)); if (signAndExp & MASK_NEG) signMask = MASK_NEG; exponent = signMask ^ signAndExp; f = (float)mantissa * fpow(10.0, (float)(-exponent)); if (signMask == MASK_NEG) f *= -1.0; } return f; } // packetPopFloat(struct Packet*) // pops and returns a character (byte) from the // buffer of the parameterized packet // // NOTE: returning a 'char' crashes IC!?! #ifdef PACKET_FULL_COMPILE BYTE packetPopChar(struct Packet* p) { return packetPopByte(p); } // packetPopChar(struct Packet*) #endif // pops a string of characters from the // buffer of the parameterized packet // and places it in the parameterized // character buffer, returning TRUE // if successful, FALSE otherwise /*BOOL packetPopStr(struct Packet* p, char str[]) { return FALSE; } // packetPopStr(struct Packet*, char [])*/ // sets the byte with the parameterized index of the buffer // of the parameterized packet to the parameterized byte, // returning TRUE if successful, FALSE otherwise BOOL setPacketByte(struct Packet* p, int index, BYTE byte) { int i = index / 2; if ((p == NULL) || (index > p->dataLength)) return FALSE; byte = lsb(byte); if (isEven(index)) p->data[i] = (byte << 8) + lsb(p->data[i]); else p->data[i] = (msb(p->data[i]) << 8) + byte; return TRUE; } // getPacketByte(struct Packet*, int) // returns the byte with the parameterized index // of the buffer of the parameterized packet BYTE getPacketByte(struct Packet* p, int index) { if ((p == NULL) || (index >= p->dataLength)) return 0x00; if (isEven(index)) return msb(p->data[index / 2]); return lsb(p->data[index / 2]); } // getPacketByte(struct Packet*, int) // returns the length of the parameterized packet int getPacketLength(struct Packet* p) { if (p == NULL) return 0x00; return p->dataLength; } // getPacketLength(struct Packet*) // returns the checksum of the parameterized packet // // NOTE: to test data integrity, a checksum is calculated // and verified on non-escaped data: // ~ to calculate - not including frame delimiters and length, // add all bytes keeping only the lowest 8 bits // of the result and subtract from 0xFF // ~ to verify - add all bytes (include checksum, but not // the delimiter and length); if the checksum // is correct, the sum will equal 0xFF BYTE getPacketChecksum(struct Packet* p) { int checksum = 0xFF; if (p != NULL) checksum -= lsb( p->type + p->ack + msb(p->addr) + lsb(p->addr) + p->params + sumPacketBytes(p)); return checksum; } // getPacketChecksum(struct Packet*) // returns TRUE if the parameterized checksum is correct // for the parameterized packet, FALSE otherwise // // NOTE: to test data integrity, a checksum is calculated // and verified on non-escaped data: // ~ to calculate - not including frame delimiters and length, // add all bytes keeping only the lowest 8 bits // of the result and subtract from 0xFF // ~ to verify - add all bytes (include checksum, but not // the delimiter and length); if the checksum // is correct, the sum will equal 0xFF BOOL isPacketChecksumValid(struct Packet* p, int checksum) { checksum += lsb( p->type + p->ack + msb(p->addr) + lsb(p->addr) + p->params + sumPacketBytes(p)); return checksum == 0xFF; } // isPacketChecksumValid(struct Packet*, int) // returns the sum of all of the bytes in the parameterized packet int sumPacketBytes(struct Packet* p) { int i = 0, n = 0, sum = 0; if (p != NULL) for (i = 0, n = p->dataLength; i < n; ++i) sum += getPacketByte(p, i); return sum; } // sumPacketBytes(struct Packet*) // copies the contents of the parameterized source // packet into the parameterized destination packet, // returning TRUE if successful, FALSE otherwise int copyPacket(struct Packet* src, struct Packet* dest) { if (src == NULL) return FALSE; dest->frontIndex = src->frontIndex; dest->dataLength = src->dataLength; dest->addr = src->addr; dest->ack = src->ack; dest->params = src->params; return setPacketType(dest, src->type) && arrayCopy(src->data, dest->data); } // copyPacket(struct Packet*, struct Packet*) // prints the parameterized packet (with an optional label) to the screen #ifdef PACKET_FULL_COMPILE BOOL printPacket(struct Packet* p, char label[]) { int i = 0, n = 0; if (p == NULL) return FALSE; printf("%s:\n", label); printf("length = %d\n", n = p->dataLength); printf("addr = %d\n", p->addr); printf("type = 0x%x\n", p->type); printf("ack = 0x%x\n", p->ack); printf("params = 0x%x\n", p->params); printf("data = "); for (i = 0; i < n; ++i) printf("%c", getPacketByte(p, i)); printf("\n"); return TRUE; } // printPacket(struct Packet*) #endif