// // "Communication.ic" // // Programmer: Ross Mead // Last modified: 08Aug2008 // // preprocessor directives #use "Packet.ic" // communication debug definitions //#define DEBUG_COMM 1 // communication compilation definitions //#define COMM_FULL_COMPILE 1 // communication timeout definitions #define COMM_NO_TIMEOUT MAX_FLOAT // byte definitions #define BYTE_CARRIAGE_RETURN 0xD // packet buffer definitions #define COMM_MAX_N_PACKETS 10 int _packetCount = 0; // API mode definitions #define COMM_TRANS_MODE 0x00 #define COMM_API_MODE 0x01 #define COMM_API_ESC_MODE 0x02 BOOL _apiModeEnabled = FALSE; // transparent communication definitions #define COMM_TRANS_GUARD_TIME 1000L BOOL _commandModeEnabled = FALSE; // 16-bit source address definition int _myAddr = 0; // defines an API-mode communication packet struct Packet { int frontIndex, dataLength, addr, params; BYTE type, ack, data[PACKET_BUFFER_SIZE]; } _commandPacket, _sendPacket, _recvPacket[COMM_MAX_N_PACKETS]; // Packet // enables the communication system with the parameterized ID, // returning TRUE if successful, FALSE otherwise BOOL commEnable(int id) { _packetCount = 0; _apiModeEnabled = commClearCommand() && commClearSend() && commClearReceive() && commSetBaudRate(BAUD_38K) && // set the baud rate to 38K commEnterCommandMode() && // enter command mode commSendCommand("AP1", PACKET_NO_PARAMS) && // enable API operation commSendCommand("AC", PACKET_NO_PARAMS) && // apply changes commExitCommandMode(); // exit command mode _apiModeEnabled &= commSetBaudRate(BAUD_57K); // set the baud rate to 57K if (!commSetID(id)) _apiModeEnabled &= commSetID(id); commFlush(); return _apiModeEnabled; } // commEnable(int) // disables the communication system, // resetting it to the parameterized ID, // returning TRUE if successful, FALSE otherwise BOOL commDisable(int id) { if ((!commSetID(id)) || (!commSendCommand("AP", 0))) return FALSE; commSetBaudRate(BAUD_38K); _apiModeEnabled = FALSE; return commSetBaudRate(IC_SERIAL); } // commDisable(int) // returns TRUE if the communication system is enabled, FALSE otherwise BOOL isCommEnabled() { return _apiModeEnabled; } // isCommEnabled() // updates the communication system, // returning TRUE if there are packets, // FALSE otherwise BOOL commUpdate() { _packetCount = 0; while (commReceivePacket()); return _packetCount > 0; } // commUpdate() // flushes the communication buffer void commFlush() { while (commUpdate()); } // commFlush() // clears the command buffer, // returning TRUE if successful, // FALSE otherwise BOOL commClearCommand() { return resetPacket(&_commandPacket); } // commClearCommand() // clears the send buffer, // returning TRUE if successful, // FALSE otherwise BOOL commClearSend() { return resetPacket(&_sendPacket); } // commClearSend() // clears the receive buffer, // returning TRUE if successful, // FALSE otherwise BOOL commClearReceive() { int i = 0, n = _array_size(_recvPacket); for (i = 0; i < n; ++i) if (!resetPacket(&_recvPacket[i])) return FALSE; return TRUE; } // commClearReceive() // returns the number of packets // in the communication buffer int commPacketCount() { return _packetCount; } // getPacketCount() // returns TRUE if the parameterized index // is valid with respect to the communication // buffer, FALSE otherwise BOOL commIsIndexValid(int index) { return isBetween(index, 0, commPacketCount() - 1); } // commIsIndexValid(int) // returns the length of the packet // with at parameterized index // within the communication buffer int commPacketLength(int index) { if (!commIsIndexValid(index)) return 0; return _recvPacket[index].dataLength; } // commPacketLength(int) // returns the ID of the sender // of the packet with at parameterized index // within the communication buffer int commSenderID(int index) { if (!commIsIndexValid(index)) return -1; return _recvPacket[index].addr; } // commSenderID(int) // returns the signal strength of the packet // with at parameterized index // within the communication buffer BYTE commSignalStrength(int index) { if (!commIsIndexValid(index)) return 0x00; return _recvPacket[index].ack; } // commSignalStrength(int) // broadcasts the current packet to be sent, // returning TRUE if successful, FALSE otherwise BOOL commBroadcastPacket() { return commSendPacket(PACKET_BROADCAST); } // commBroadcastPacket() // sends the current packet to the parameterized address, // returning TRUE if successful, FALSE otherwise BOOL commSendPacket(int destAddr) { int nBytes = 0, checksum = 0; if ((_apiModeEnabled) && (!_commandModeEnabled) && setPacketType( &_sendPacket, PACKET_TYPE_TRANSMIT)) { updatePacketID(&_sendPacket); // frame ID = 0x00 for no acknowledgement _sendPacket.addr = destAddr; //_sendPacket.params = PACKET_TRANSMIT_DISABLE_ACK; // length[BYTEs] = API identifier // + frame ID // + destination address // + options // + RF data nBytes = 5 + _sendPacket.dataLength; checksum = getPacketChecksum(&_sendPacket); #ifdef DEBUG_COMM printf("\n"); printf("START = 0x%x\n", PACKET_START_DELIMITER); printf("NBYTES = %d (%x+%x)\n", nBytes, msb(nBytes), lsb(nBytes)); printf("CHKSUM = %d (0x%x)\n", checksum, checksum); printPacket(&_sendPacket, "TRANSMIT"); #endif // API-specific structure commWriteByte(PACKET_START_DELIMITER); // start delimeter = 0x7E commWriteInt(nBytes); // length // frame data (bytes 4-n) commWriteByte(_sendPacket.type); // API identifier (0x08) // identifier-specific data commWriteByte(_sendPacket.ack); // frame ID commWriteInt(_sendPacket.addr); // destination address commWriteByte(_sendPacket.params); // options // RF data (byte(s) 9-n) commWritePacketData(&_sendPacket); // up to 100 bytes per packet // checksum (byte n + 1) commWriteByte(checksum); return clearPacketData(&_sendPacket); } return FALSE; } // commSendPacket(char [], int) // attempts to receive a packet from the communication system, // returning TRUE if successful, FALSE otherwise BOOL commReceivePacket() { BYTE byte = 0x00, type = PACKET_TYPE_NONE; int nBytes = 0, checksum = 0, i = 0; if ((_apiModeEnabled) && (!_commandModeEnabled) && (_packetCount < COMM_MAX_N_PACKETS)) { while ((byte = commReadByte()) != PACKET_START_DELIMITER) if (byte == 0x00) return FALSE; nBytes = bytesToInt(commReadByte(), commReadByte()); type = commReadByte(); // receive packet (16-bit address) if ((type == PACKET_TYPE_RECEIVE) && resetPacket( &_recvPacket[_packetCount]) && setPacketType(&_recvPacket[_packetCount], type)) { _recvPacket[_packetCount].addr = bytesToInt(commReadByte(), commReadByte()); _recvPacket[_packetCount].ack = commReadByte(); _recvPacket[_packetCount].params = commReadByte(); for (i = 0; i < nBytes - 5; ++i) packetPushByte(&_recvPacket[_packetCount], commReadByte()); if (!isPacketChecksumValid(&_recvPacket[_packetCount], checksum = commReadByte())) { resetPacket(&_recvPacket[_packetCount]); return FALSE; } #ifdef DEBUG_COMM printf("\n"); printf("START = 0x%x\n", PACKET_START_DELIMITER); printf("NBYTES = %d (%x+%x)\n", nBytes, msb(nBytes), lsb(nBytes)); printf("CHKSUM = %d (0x%x)\n", checksum, checksum); printPacket(&_recvPacket[_packetCount], "RECEIVE"); #endif ++_packetCount; return TRUE; } // transmit status else if ((type == PACKET_TYPE_TRANSMIT_RESPONSE) && resetPacket( &_commandPacket ) && setPacketType(&_commandPacket, type)) { _commandPacket.ack = commReadByte(); _commandPacket.params = commReadByte(); if (!isPacketChecksumValid(&_commandPacket, checksum = commReadByte())) { resetPacket(&_commandPacket); return FALSE; } #ifdef DEBUG_COMM printf("\n"); printf("START-r= 0x%x\n", PACKET_START_DELIMITER); printf("NBYTES = %d (%x+%x)\n", nBytes, msb(nBytes), lsb(nBytes)); printf("CHKSUM = %d (0x%x)\n", checksum, checksum); printPacket( &_commandPacket, "TRANSMIT_RESPONSE"); #endif return _commandPacket.params == PACKET_TRANSMIT_SUCCESS; } // AT command response else if ((type == PACKET_TYPE_COMMAND_RESPONSE) && resetPacket( &_commandPacket) && setPacketType(&_commandPacket, type)) { _commandPacket.ack = commReadByte(); packetPushByte( &_commandPacket, commReadByte()); // AT command [BYTE 0] packetPushByte( &_commandPacket, commReadByte()); // AT command [BYTE 1] _commandPacket.params = commReadByte(); for (i = 0; i < nBytes - 5; ++i) packetPushByte(&_commandPacket, commReadByte()); if (!isPacketChecksumValid(&_commandPacket, checksum = commReadByte())) { resetPacket( &_commandPacket); return FALSE; } #ifdef DEBUG_COMM printf("\n"); printf("START-r= 0x%x\n", PACKET_START_DELIMITER); printf("NBYTES = %d (%x+%x)\n", nBytes, msb(nBytes), lsb(nBytes)); printf("CHKSUM = %d (0x%x)\n", checksum, checksum); printPacket(&_commandPacket, "COMMAND_RESPONSE"); #endif return _commandPacket.params == PACKET_COMMAND_OK; } } return FALSE; } // commReceivePacket() // packs the parameterized byte onto the send-packet buffer, // returning TRUE if successful, FALSE otherwise BOOL commPackByte(BYTE byte) { return packetPushByte(&_sendPacket, byte); } // packetPackByte(BYTE) // packs the parameterized integer onto the send-packet buffer, // returning TRUE if successful, FALSE otherwise BOOL commPackInt(int i) { return packetPushInt(&_sendPacket, i); } // commPackInt(int) // packs the parameterized long integer onto the send-packet buffer, // returning TRUE if successful, FALSE otherwise BOOL commPackLong(long l) { return packetPushLong(&_sendPacket, l); } // commPackLong(long) // packs the parameterized floating-piont number // onto the send-packet buffer, returning // TRUE if successful, FALSE otherwise BOOL commPackFloat(float f) { return packetPushFloat(&_sendPacket, f); } // commPackFloat(float) // packs the parameterized character onto the send-packet buffer, // returning TRUE if successful, FALSE otherwise #ifdef COMM_FULL_COMPILE BOOL commPackChar(BYTE c) { return packetPushChar(&_sendPacket, c); } // commPackChar(BYTE) #endif // packs the parameterized string of characters // onto the send-packet buffer, returning // TRUE if successful, FALSE otherwise BOOL commPackStr(char str[]) { return packetPushStr(&_sendPacket, str); } // commPackStr(char []) // unpacks and returns a byte from the receive-buffer BYTE commUnpackByte(int index) { if (!commIsIndexValid(index)) return 0x00; return packetPopByte(&_recvPacket[index]); } // commUnpackByte(int) // unpacks and returns an integer from the receive-buffer int commUnpackInt(int index) { if (!commIsIndexValid(index)) return 0; return packetPopInt(&_recvPacket[index]); } // commUnpackInt(int) // unpacks and returns a long integer from the receive-buffer long commUnpackLong(int index) { if (!commIsIndexValid(index)) return 0L; return packetPopLong(&_recvPacket[index]); } // commUnpackLong(int) // unpacks and returns a floating-point number from the receive-buffer float commUnpackFloat(int index) { if (!commIsIndexValid(index)) return 0.0; return packetPopFloat(&_recvPacket[index]); } // commUnpackFloat(int) // unpacks and returns a character from the receive-buffer // // NOTE: crashes IC if return type is 'char'!?! #ifdef COMM_FULL_COMPILE BYTE commUnpackChar(int index) { if (!commIsIndexValid(index)) return 0x00; return packetPopChar(&_recvPacket[index]); } // commUnpackChar(int) #endif // unpacks a string of characters from the receive-buffer // and places it in the parameterized character buffer /*BOOL commUnpackStr(int, char str[]) { if (!commIsIndexValid(index)) return FALSE; return packetPopStr(&_recvPacket[index], str); } // commUnpackStr(int, char [])*/ // sets the communication ID to the parameterized ID, // returning TRUE if successful, FALSE otherwise BOOL commSetID(int id) { if (!commSendCommand("MY", id)) return FALSE; _myAddr = id; return TRUE; } // commSetID(int) // returns the ID of the communication system int commGetID() { return _myAddr; } // commGetID() // writes the parameterized byte to the serial port void commWriteByte(int byte) { byte = lsb(byte); // escapes interfering data bytes (API-mode = 2) /*if ((!_commandModeEnabled) && (_apiModeEnabled) && ((byte == PACKET_START_DELIMETER) || (byte == 0x7D) || (byte == 0x11) || (byte == 0x13))) { serial_write_byte(0x7D); byte ^= 0x20; }*/ serial_write_byte(byte); } // commWriteByte(int) // writes the parameterized integer to the serial port void commWriteInt(int i) { commWriteByte(msb(i)); commWriteByte(lsb(i)); } // commWriteInt(int) // writes the parameterized string of characters to the serial port void commWriteString(char str[]) { int i = 0; for (i = 0; i < strlen(str); ++i) commWriteByte(str[i]); } // commWriteString(char []) // writes the parameterized packet to the serial port BOOL commWritePacketData(struct Packet* p) { int i = 0, n = 0; if (p == NULL) return FALSE; for (i = 0, n = p->dataLength; i < n; ++i) commWriteByte(getPacketByte(p, i)); return TRUE; } // commWriteString(char []) // reads a byte from the serial port BYTE commReadByte() { return lsb(serial_read_byte()); } // commReadByte() // sets the baud rate of the communication system // to the parameterized baud rate, returning // TRUE if successful, FALSE otherwise BOOL commSetBaudRate(int baudRate) { int apiBaudRate = -1; if (_apiModeEnabled) { if (baudRate == BAUD_9600) apiBaudRate = 3; else if (baudRate == BAUD_19K) apiBaudRate = 4; else if (baudRate == BAUD_38K) apiBaudRate = 5; else if (baudRate == BAUD_57K) apiBaudRate = 6; commSendCommand("BD", apiBaudRate); } return serial_set_mode(baudRate); } // commSetBaudRate(int) // attempts to enter AT command mode (for initialization), // returning TRUE if successful, FALSE otherwise BOOL commEnterCommandMode() { if ((_apiModeEnabled) || (_commandModeEnabled)) return FALSE; msleep(COMM_TRANS_GUARD_TIME); commWriteString("+++"); msleep(COMM_TRANS_GUARD_TIME); _commandModeEnabled = TRUE; return _commandModeEnabled = commGetCommandResponse("+++"); } // commEnterCommandMode() // attempts to exit AT command mode (for initialization), // returning TRUE if successful, FALSE otherwise BOOL commExitCommandMode() { BOOL retVal = commSendCommand("CN", 0); if (retVal) _commandModeEnabled = FALSE; return retVal; } // commExitCommandMode() // attempts to send a command to the communication chip, // returning TRUE if successful, FALSE otherwise BOOL commSendCommand(char command[], int params) { struct Packet response; BYTE byte = 0x00; int nBytes = 0, checksum = 0, i = 0; if ((_apiModeEnabled) && (!_commandModeEnabled) && commClearCommand() && setPacketType( &_commandPacket, PACKET_TYPE_COMMAND) && packetPushStr( &_commandPacket, command)) { updatePacketID(&_commandPacket); // frame ID = 0x00 for no ack. _commandPacket.params = params; // length[BYTEs] = API identifier // + frame ID // + parameter value // + AT command nBytes = 2 + (_commandPacket.params != PACKET_NO_PARAMS) + (msb(_commandPacket.params) != 0x00) + _commandPacket.dataLength; checksum = getPacketChecksum(&_commandPacket); #ifdef DEBUG_COMM printf("\n"); printf("START = 0x%x\n", PACKET_START_DELIMITER); printf("NBYTES = %d (%x+%x)\n", nBytes, msb(nBytes), lsb(nBytes)); printf("CHKSUM = %d (0x%x)\n", checksum, checksum); printPacket(&_commandPacket, "COMMAND"); #endif // API-specific structure commWriteByte(PACKET_START_DELIMITER); // start delimeter = 0x7E commWriteInt(nBytes); // length // frame data (bytes 4-n) commWriteByte(_commandPacket.type); // API identifier (0x08) // identifier-specific data commWriteByte(_commandPacket.ack); // frame ID commWritePacketData(&_commandPacket); // AT command if (_commandPacket.params != PACKET_NO_PARAMS) // parameter value if (msb(_commandPacket.params) != 0x00) commWriteInt( _commandPacket.params); else commWriteByte(_commandPacket.params); // checksum (byte n + 1) commWriteByte(checksum); if (_commandPacket.params == PACKET_NO_PARAMS) return TRUE; } else if ((!_apiModeEnabled) && (_commandModeEnabled)) { commWriteString("AT"); commWriteString(command); commWriteByte(BYTE_CARRIAGE_RETURN); return commGetCommandResponse(command); } else return FALSE; return TRUE; return commGetCommandResponse(command); } // commSendCommand(char [], int) // returns TRUE if the response is 'OK', FALSE otherwise BOOL commGetCommandResponse(char command[]) { BYTE byte = 0x00; int nBytes = 0, checksum = 0, i = 0; #ifdef DEBUG_COMM printf("%s:", command); #endif if ((_apiModeEnabled) && (!_commandModeEnabled) && commClearCommand()) { _commandPacket.params = PACKET_COMMAND_ERROR; while ((byte = commReadByte()) != PACKET_START_DELIMITER) if (byte == 0x00) return FALSE; if (byte == PACKET_START_DELIMITER) { nBytes = bytesToInt(commReadByte(), commReadByte()); setPacketType(&_commandPacket, commReadByte()); _commandPacket.ack = commReadByte(); packetPushByte( &_commandPacket, commReadByte()); // AT commands packetPushByte( &_commandPacket, commReadByte()); // [BYTE 1&2] _commandPacket.params = commReadByte(); for (i = 0; i < nBytes - 5; ++i) packetPushByte(&_commandPacket, commReadByte()); if (!isPacketChecksumValid(&_commandPacket, checksum = commReadByte())) { resetPacket( &_commandPacket); return FALSE; } #ifdef DEBUG_COMM printf("\n"); printf("START-r= 0x%x\n", PACKET_START_DELIMITER); printf("NBYTES = %d (%x+%x)\n", nBytes, msb(nBytes), lsb(nBytes)); printf("CHKSUM = %d (0x%x)\n", checksum, checksum); printPacket(&_commandPacket, "COMMAND_RESPONSE"); #endif } return _commandPacket.params == PACKET_COMMAND_OK; } else if ((!_apiModeEnabled) && (_commandModeEnabled)) { while (!(byte = commReadByte())); if ( (byte == 'O') && ((byte = commReadByte()) == 'K') && ((byte = commReadByte()) == BYTE_CARRIAGE_RETURN)) { #ifdef DEBUG_COMM printf("OK\n"); #endif return TRUE; } else if ( (byte == 'E') && ((byte = commReadByte()) == 'R') && ((byte = commReadByte()) == 'R') && ((byte = commReadByte()) == 'O') && ((byte = commReadByte()) == 'R') && ((byte = commReadByte()) == BYTE_CARRIAGE_RETURN)) { #ifdef DEBUG_COMM printf("ERROR\n"); #endif } } return FALSE; } // commGetCommandResponse(char [])