remaniement des drivers xbee et commands

This commit is contained in:
vezde 2023-03-24 18:18:43 +01:00
parent 85bf7179df
commit f319857e0d
10 changed files with 279 additions and 1454 deletions

View file

@ -1,625 +0,0 @@
/*
* xbee.c
*
* Created on: 4 avr. 2022
* Author: dimercur
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "xbee.h"
#include "xbee_ll.h"
#include "cmsis_os.h"
#include "config.h"
uint16_t XBEE_panID;
uint8_t XBEE_chanID;
uint64_t XBEE_uid;
char tx_frame_buffer[18+20]; /* space for a tx frame with 20 bytes of data */
char rx_frame_buffer[18+0x80]; /* space for a rx frame with 0x80 bytes of data (max possible rx frame length) */
#define XBEE_TIMEOUT_FOR_STATUS_FRAME 500 // 500 ms for receiving a TX or AT status frame
int XBEE_EnterCommandMode_PARANOIA() {
char buffer[5];
uint8_t index;
int status;
for (index=0; index < 5; index++)
buffer[index]=0;
// flush eventual furbish
status=XBEE_LL_ReceiveData(buffer, 1, 50); // 50ms
/* Enter AT command mode */
if (XBEE_LL_SendData("+++",strlen("+++")) != XBEE_LL_OK)
return XBEE_CONFIG_ERROR;
status=XBEE_LL_ReceiveData(buffer, 3, 2000); // 50ms
if ((status!=XBEE_LL_ERROR_RX_TIMEOUT) && (status!=XBEE_LL_OK)) // no timeout
return XBEE_CONFIG_ERROR;
if ((buffer[1]!='O') && (buffer[1]!='K')) // error setting configuration mode
return XBEE_CONFIG_ERROR;
// wait for an eventual \r at the end
status=XBEE_LL_ReceiveData(buffer, 1, 50); // 50ms
if ((status!=XBEE_LL_ERROR_RX_TIMEOUT)&& (status!=XBEE_LL_OK))
return XBEE_CONFIG_ERROR;
return XBEE_OK;
}
int XBEE_EnterCommandMode() {
char buffer[5];
uint8_t index;
int status;
for (index=0; index < 5; index++)
buffer[index]=0;
/* Enter AT command mode */
if (XBEE_LL_SendData("+++",strlen("+++")) != XBEE_LL_OK)
return XBEE_CONFIG_ERROR;
status=XBEE_LL_ReceiveData(buffer, 3, 2000); // 2s
if (status!=XBEE_LL_OK) // timeout
return XBEE_CONFIG_ERROR;
if (strstr(buffer, "OK")==NULL) // error setting configuration mode
return XBEE_CONFIG_ERROR;
return XBEE_OK;
}
int XBEE_SetATCommand(char* atcmd) {
char buffer[5];
uint8_t index;
for (index=0; index < 5; index++)
buffer[index]=0;
/* Send AT command */
if (XBEE_LL_SendData(atcmd,strlen(atcmd)) != XBEE_LL_OK)
return XBEE_AT_CMD_ERROR;
if (XBEE_LL_ReceiveData(buffer, 3, 500) != XBEE_LL_OK) // Timeout: 500 ms
return XBEE_AT_CMD_ERROR;
if (strcmp(buffer,"OK\r")!=0) // error setting configuration mode
return XBEE_AT_CMD_ERROR;
return XBEE_OK;
}
int XBEE_GetATValue(char* atcmd, char* value) {
char tmp;
uint8_t index;
for (index=0; index < 20; index++)
value[index]=0;
/* Send AT Cmd */
if (XBEE_LL_SendData(atcmd,strlen(atcmd)) != XBEE_LL_OK)
return XBEE_AT_CMD_ERROR;
/* Problem. We don't know the length of received data, only that answer end with \n
* So, we must loop until we have received all data
*/
tmp = 0;
index=0;
while (tmp!='\r') {
if (XBEE_LL_ReceiveData(&tmp, 1, 500) != XBEE_LL_OK) // timeout 500 ms
return XBEE_AT_CMD_ERROR;
if (index >=20 ) return XBEE_AT_CMD_ERROR; // too much data received
value[index] = (char)tmp;
index++;
}
return XBEE_OK;
}
void XBEE_EncodeTransmissionFrame(char* frame, char* data, uint64_t destination, uint8_t frame_id, uint8_t pan_broadcast) {
int i;
int data_length = strlen(data);
uint8_t checksum;
frame[0] = '~';
frame[1] = (char)((uint16_t)(14+data_length)>>8);
frame[2] = (char)((uint16_t)(14+data_length));
frame[3] = (char)XBEE_TX_REQUEST_TYPE;
frame[4] = (char)frame_id;
for (i=5; i<5+8; i++) {
frame[i] = (char)(destination >>(64-8));
destination = destination <<8;
}
frame[13] = 0xFF;
frame[14] = 0xFE;
frame[15] = 0;
frame[16] = pan_broadcast ? 0x2 : 0x0;
for (i=0; i<data_length; i++) {
frame[17+i]= data[i];
}
/* calcul du checksum */
checksum =0;
for (i=3; i<17+data_length; i++) {
checksum += (uint8_t)frame[i];
}
frame[17+data_length] = 0xFF-checksum;
frame[17+data_length+1] = 0x0; /* End string*/
}
void XBEE_EncodeATFrame(char* frame, char* at_cmd, uint8_t* data, uint8_t data_length, uint8_t frame_id ) {
int i;
uint8_t checksum;
frame[0] = '~';
frame[1] = (char)((uint16_t)(4+data_length)>>8);
frame[2] = (char)((uint16_t)(4+data_length));
frame[3] = (char)XBEE_LOCAL_AT_CMD_TYPE;
frame[4] = (char)frame_id;
frame[5] = at_cmd[0];
frame[6] = at_cmd[1];
for (i=0; i<data_length; i++) {
frame[7+i]= data[i];
}
/* calcul du checksum */
checksum =0;
for (i=3; i<7+data_length; i++) {
checksum += (uint8_t)frame[i];
}
frame[7+data_length] = 0xFF-checksum;
frame[7+data_length+1] = 0x0; /* End string*/
}
int XBEE_DecodeFrame(char* frame, XBEE_GENERIC_FRAME** decoded_frame) {
uint8_t frame_type = (uint8_t)frame[3];
uint16_t frame_length;
uint8_t checksum;
int i;
frame_length = (((uint16_t)frame[1])<<8) + (uint16_t)frame[2];
/* virification du checksum */
checksum =0;
for (i=3; i<3+frame_length+1; i++) {
checksum += (uint8_t)frame[i];
}
if (checksum != 0xFF)
return XBEE_INVALID_FRAME;
switch (frame_type) {
case XBEE_RX_PACKET_TYPE:
*decoded_frame = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_RX_PACKET_FRAME)+(frame_length-12)+1); // +1 for 0 ending in data frame
memset((void*)*decoded_frame, 0, sizeof(XBEE_RX_PACKET_FRAME)+(frame_length-12)+1);
((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->type = frame_type;
((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->data_length = frame_length-12;
((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->options = frame[14];
((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->source_addr =0;
for (i=0; i<8; i++) {
((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->source_addr = ((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->source_addr<<8;
((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->source_addr +=(uint64_t)frame[4+i];
}
for (i=0; i<((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->data_length; i++) {
((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->data[i] =(char)frame[15+i];
}
((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->data[((XBEE_RX_PACKET_FRAME*)(*decoded_frame))->data_length]=0x0; // 0 ending frame
break;
case XBEE_MODEM_STATUS_TYPE:
*decoded_frame = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_MODEM_STATUS_FRAME));
((XBEE_MODEM_STATUS_FRAME*)(*decoded_frame))->type = frame_type;
((XBEE_MODEM_STATUS_FRAME*)(*decoded_frame))->status = frame[4];
break;
case XBEE_TX_STATUS_TYPE:
case XBEE_EXTENDED_TX_STATUS_TYPE:
*decoded_frame = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_TX_STATUS_FRAME));
((XBEE_TX_STATUS_FRAME*)(*decoded_frame))->type = frame_type;
((XBEE_TX_STATUS_FRAME*)(*decoded_frame))->frame_id = frame[4];
if (frame_type == XBEE_TX_STATUS_TYPE) {
((XBEE_TX_STATUS_FRAME*)(*decoded_frame))->status = frame[5];
((XBEE_TX_STATUS_FRAME*)(*decoded_frame))->retry_count = 0;
} else {
((XBEE_TX_STATUS_FRAME*)(*decoded_frame))->status = frame[8];
((XBEE_TX_STATUS_FRAME*)(*decoded_frame))->retry_count = frame[7];
}
break;
case XBEE_AT_CMD_RESPONSE_TYPE:
*decoded_frame = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_AT_CMD_RESPONSE_FRAME)+(frame_length-5));
((XBEE_AT_CMD_RESPONSE_FRAME*)(*decoded_frame))->type = frame_type;
((XBEE_AT_CMD_RESPONSE_FRAME*)(*decoded_frame))->data_length = frame_length-5;
((XBEE_AT_CMD_RESPONSE_FRAME*)(*decoded_frame))->status = frame[7];
for (i=0; i<((XBEE_AT_CMD_RESPONSE_FRAME*)(*decoded_frame))->data_length; i++) {
((XBEE_AT_CMD_RESPONSE_FRAME*)(*decoded_frame))->data[i] =(uint8_t)frame[8+i];
}
break;
default:
*decoded_frame = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_GENERIC_FRAME));
((XBEE_GENERIC_FRAME*)(*decoded_frame))->type = frame_type;
return XBEE_INVALID_FRAME;
};
return XBEE_OK;
}
int XBEE_SendFrame (char* frame) {
int frame_length;
frame_length = (((int)frame[1]<<8))+(int)frame[2];
frame_length = frame_length + 4;
if (XBEE_LL_SendData(frame,frame_length) != XBEE_LL_OK)
return XBEE_TX_ERROR;
return XBEE_OK;
}
int XBEE_GetFrame (char* frame, int timeout) {
int status;
status = XBEE_LL_ReceiveData(frame, -1,timeout);
if (status == XBEE_LL_ERROR_RX_TIMEOUT)
return XBEE_RX_TIMEOUT;
else if (status != XBEE_LL_OK)
return XBEE_RX_ERROR;
return XBEE_OK;
}
int XBEE_ConfigureDevice(void) {
#define RXBUFFERSIZE 30
if (XBEE_EnterCommandMode()!=XBEE_OK)
return XBEE_CONFIG_ERROR;
/* Now configure the device
* 1 - Enable API mode (AP)
* 2 - Change baudrate to 57600 (BD)
* 3 - Get UID of Device (SH+SL)
* 4 - End AT command mode (CN)
*/
// Set API mode
if (XBEE_SetATCommand("ATAP=1\r")!=XBEE_OK)
return XBEE_CONFIG_ERROR;
// disable legacy mode for API mode
if (XBEE_SetATCommand("ATAO=0\r")!=XBEE_OK)
return XBEE_CONFIG_ERROR;
// Set baudrate to 115200
if (XBEE_SetATCommand("ATBD=7\r")!=XBEE_OK)
return XBEE_CONFIG_ERROR;
// Finally, exit configuration mode
if (XBEE_SetATCommand("ATCN\r")!=XBEE_OK)
return XBEE_CONFIG_ERROR;
return XBEE_OK;
}
int XBEE_Init (void) {
/* First, init GPIO */
XBEE_LL_ConfigureGPIO();
/* then configure timer for timeout */
//XBEE_LL_ConfigureTimer();
/* Then, setup usart at 9600 bauds and configure the device */
XBEE_LL_ConfigureUart(XBEE_USART, 9600);
if (XBEE_ConfigureDevice() != XBEE_OK)
return XBEE_CONFIG_ERROR;
/* If it is OK, reconf USART to 115200 bauds */
XBEE_LL_ConfigureUart(XBEE_USART, 115200);
/* Wait 100 ms for xbee module to reconf */
//HAL_Delay(100);
vTaskDelay(msToTicks(100));
/* Xbee module is ready to be used */
return XBEE_OK;
}
int XBEE_SendData(uint64_t destination, uint8_t frame_id, uint8_t pan_broadcast, char* data, uint8_t *status) {
XBEE_GENERIC_FRAME* tx_status;
// Format frame for sending data
XBEE_EncodeTransmissionFrame(tx_frame_buffer, data, destination, frame_id, pan_broadcast);
// Send Frame
if (XBEE_SendFrame(tx_frame_buffer) != XBEE_OK)
return XBEE_TX_ERROR;
// Wait for transmit status
if (XBEE_GetFrame(rx_frame_buffer, XBEE_TIMEOUT_FOR_STATUS_FRAME) != XBEE_OK) //500ms
return XBEE_RX_ERROR;
// Decode frame
if (XBEE_DecodeFrame(rx_frame_buffer, &tx_status) != XBEE_OK)
return XBEE_INVALID_FRAME;
if ((tx_status->type != XBEE_TX_STATUS_TYPE) && (tx_status->type != XBEE_EXTENDED_TX_STATUS_TYPE)) {
// Free frame structure
free((void*)tx_status);
return XBEE_INVALID_FRAME;
}
*status = ((XBEE_TX_STATUS_FRAME*)tx_status)->status;
// Free frame structure
free((void*)tx_status);
return XBEE_OK;
}
int XBEE_GetData (XBEE_GENERIC_FRAME** frame, int timeout) {
int status;
status = XBEE_LL_ReceiveData(rx_frame_buffer, -1, timeout);
if (status == XBEE_LL_ERROR_RX_TIMEOUT)
return XBEE_RX_TIMEOUT;
else if (status != XBEE_LL_OK)
return XBEE_RX_ERROR;
if (XBEE_DecodeFrame(rx_frame_buffer, frame) != XBEE_OK) {
free (*frame);
return XBEE_INVALID_FRAME;
}
return XBEE_OK;
}
int XBEE_GetATValueU32(char* at_cmd, uint32_t *value, uint8_t *status) {
XBEE_GENERIC_FRAME* at_status;
int com_status;
// Format frame for sending data
XBEE_EncodeATFrame(tx_frame_buffer, at_cmd, (uint8_t*)0x0, 0, 1);
// Send Frame
if (XBEE_SendFrame(tx_frame_buffer) != XBEE_OK)
return XBEE_TX_ERROR;
// Wait for transmit status
com_status = XBEE_GetFrame(rx_frame_buffer, XBEE_TIMEOUT_FOR_STATUS_FRAME);
if (com_status != XBEE_OK)
return com_status;
// Decode frame
if (XBEE_DecodeFrame(rx_frame_buffer, &at_status) != XBEE_OK)
return XBEE_INVALID_FRAME;
if (at_status->type != XBEE_AT_CMD_RESPONSE_TYPE) {
// Free frame structure
free((void*)at_status);
return XBEE_INVALID_FRAME;
}
*status = ((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->status;
*value = 0;
for (int i=0; i<((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->data_length; i++) {
*value = (*value)<<8;
*value += ((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->data[i];
}
// Free frame structure
free((void*)at_status);
return XBEE_OK;
}
int XBEE_GetATValueU16(char* at_cmd, uint16_t *value, uint8_t *status) {
XBEE_GENERIC_FRAME* at_status;
int com_status;
// Format frame for sending data
XBEE_EncodeATFrame(tx_frame_buffer, at_cmd, (uint8_t*)0x0, 0, 1);
// Send Frame
if (XBEE_SendFrame(tx_frame_buffer) != XBEE_OK)
return XBEE_TX_ERROR;
// Wait for transmit status
com_status = XBEE_GetFrame(rx_frame_buffer, XBEE_TIMEOUT_FOR_STATUS_FRAME);
if (com_status != XBEE_OK)
return com_status;
// Decode frame
if (XBEE_DecodeFrame(rx_frame_buffer, &at_status) != XBEE_OK)
return XBEE_INVALID_FRAME;
if (at_status->type != XBEE_AT_CMD_RESPONSE_TYPE) {
// Free frame structure
free((void*)at_status);
return XBEE_INVALID_FRAME;
}
*status = ((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->status;
*value = 0;
if (((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->data_length ==1)
*value = ((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->data[0];
else if (((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->data_length ==2) {
*value = ((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->data[0];
*value = (*value)<<8;
*value += ((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->data[1];
}
// Free frame structure
free((void*)at_status);
return XBEE_OK;
}
int XBEE_GetATValueU8(char* at_cmd, uint8_t *value, uint8_t *status) {
XBEE_GENERIC_FRAME* at_status;
int com_status;
// Format frame for sending data
XBEE_EncodeATFrame(tx_frame_buffer, at_cmd, (uint8_t*)0x0, 0, 1);
// Send Frame
if (XBEE_SendFrame(tx_frame_buffer) != XBEE_OK)
return XBEE_TX_ERROR;
// Wait for transmit status
com_status = XBEE_GetFrame(rx_frame_buffer, XBEE_TIMEOUT_FOR_STATUS_FRAME);
if (com_status != XBEE_OK)
return com_status;
// Decode frame
if (XBEE_DecodeFrame(rx_frame_buffer, &at_status) != XBEE_OK)
return XBEE_INVALID_FRAME;
if (at_status->type != XBEE_AT_CMD_RESPONSE_TYPE) {
// Free frame structure
free((void*)at_status);
return XBEE_INVALID_FRAME;
}
*status = ((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->status;
*value = 0;
if (((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->data_length ==1)
*value = ((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->data[0];
else
return XBEE_INVALID_FRAME;
// Free frame structure
free((void*)at_status);
return XBEE_OK;
}
int XBEE_SetATValueU16(char* at_cmd, uint16_t value, uint8_t *status) {
XBEE_GENERIC_FRAME* at_status;
uint8_t data[2];
int com_status;
// Format frame for sending data
data[0] = (uint8_t)(value >>8);
data[1] = (uint8_t)(value & 0xFF);
XBEE_EncodeATFrame(tx_frame_buffer, at_cmd, data, 2, 1);
// Send Frame
if (XBEE_SendFrame(tx_frame_buffer) != XBEE_OK)
return XBEE_TX_ERROR;
// Wait for transmit status
com_status = XBEE_GetFrame(rx_frame_buffer, XBEE_TIMEOUT_FOR_STATUS_FRAME);
if (com_status != XBEE_OK)
return com_status;
// Decode frame
if (XBEE_DecodeFrame(rx_frame_buffer, &at_status) != XBEE_OK)
return XBEE_INVALID_FRAME;
if (at_status->type != XBEE_AT_CMD_RESPONSE_TYPE) {
// Free frame structure
free((void*)at_status);
return XBEE_INVALID_FRAME;
}
*status = ((XBEE_AT_CMD_RESPONSE_FRAME*)at_status)->status;
// Free frame structure
free((void*)at_status);
return XBEE_OK;
}
int XBEE_SetChannel(uint8_t channel) {
uint8_t status;
int com_status;
if ((channel < XBEE_CHANNEL_FIRST) || (channel > XBEE_CHANNEL_LAST)) // Invalid channel value
return XBEE_AT_CMD_ERROR;
com_status = XBEE_SetATValueU16("CH", (uint16_t)channel, &status);
if (com_status != XBEE_OK)
return com_status;
if (status != XBEE_AT_STATUS_SUCCESS)
return XBEE_AT_CMD_ERROR;
return XBEE_OK;
}
int XBEE_SetPanID(uint16_t panid) {
uint8_t status;
int com_status;
com_status=XBEE_SetATValueU16("ID", panid, &status);
if (com_status != XBEE_OK)
return com_status;
if (status != XBEE_AT_STATUS_SUCCESS)
return XBEE_AT_CMD_ERROR;
return XBEE_OK;
}
int XBEE_GetRSSI(uint8_t *rssi) {
uint8_t status;
int com_status;
com_status=XBEE_GetATValueU8("DB", rssi, &status);
if (com_status != XBEE_OK)
return com_status;
if (status != XBEE_AT_STATUS_SUCCESS)
return XBEE_AT_CMD_ERROR;
return XBEE_OK;
}
int XBEE_GetUID(uint64_t *uid) {
uint8_t status;
uint32_t id=0;
int com_status;
com_status = XBEE_GetATValueU32("SH", &id, &status);
if (com_status != XBEE_OK)
return com_status;
*uid = ((uint64_t)id<<32);
com_status = XBEE_GetATValueU32("SL", &id, &status);
if (com_status != XBEE_OK)
return com_status;
*uid += id;
if (status != XBEE_AT_STATUS_SUCCESS)
return XBEE_AT_CMD_ERROR;
return XBEE_OK;
}

View file

@ -1,101 +0,0 @@
/*
* xbee.h
*
* Created on: 4 avr. 2022
* Author: dimercur
*/
#ifndef BSP_XBEE_XBEE_H_
#define BSP_XBEE_XBEE_H_
#include "stm32l4xx_hal.h"
#define XBEE_OK 0
#define XBEE_CONFIG_ERROR 2
#define XBEE_AT_CMD_ERROR 3
#define XBEE_RX_TIMEOUT 4
#define XBEE_RX_ERROR 5
#define XBEE_TX_ERROR 6
#define XBEE_INVALID_FRAME 7
#define XBEE_RX_PACKET_TYPE 0x90
#define XBEE_RX_EXPLICIT_TYPE 0x91
#define XBEE_TX_STATUS_TYPE 0x89
#define XBEE_AT_CMD_RESPONSE_TYPE 0x88
#define XBEE_MODEM_STATUS_TYPE 0x8A
#define XBEE_EXTENDED_TX_STATUS_TYPE 0x8B
#define XBEE_LOCAL_AT_CMD_TYPE 0x08
#define XBEE_TX_REQUEST_TYPE 0x10
#define XBEE_TX_EXPLICIT_TYPE 0x11
#define XBEE_AT_STATUS_SUCCESS 0
#define XBEE_AT_STATUS_ERROR 1
#define XBEE_AT_STATUS_INVALID_COMMAND 2
#define XBEE_AT_STATUS_INVALID_PARAMETER 3
#define XBEE_TX_STATUS_SUCCESS 0x00
#define XBEE_TX_STATUS_NO_ACK 0x01
#define XBEE_TX_STATUS_CCA_FAILURE 0x02
#define XBEE_TX_STATUS_NETWORK_NO_ACK 0x21
#define XBEE_MODEM_STATUS_HW_RST 0x00
#define XBEE_MODEM_STATUS_JOINED 0x02
#define XBEE_RX_OPTIONS_ACKNOWLEDGED 0x01
#define XBEE_RX_OPTIONS_BRODCASTED 0x02
#define XBEE_RX_OPTIONS_PAN_BROADCASTED 0x04
#define XBEE_CHANNEL_FIRST 0x0B
#define XBEE_CHANNEL_LAST 0x1A
#define XBEE_BROADCAST_ADDRESS 0x000000000000FFFF
#define XBEE_PANID_BROADCAST SET
#define XBEE_NO_PANID_BROADCAST RESET
typedef struct {
uint8_t type;
} XBEE_GENERIC_FRAME;
typedef struct {
uint8_t type;
uint64_t source_addr;
uint8_t options;
uint8_t data_length;
char data[];
} XBEE_RX_PACKET_FRAME;
typedef struct {
uint8_t type;
uint8_t frame_id;
uint16_t at_cmd;
uint8_t status;
uint8_t data_length;
char data[];
} XBEE_AT_CMD_RESPONSE_FRAME;
typedef struct {
uint8_t type;
uint8_t frame_id;
uint8_t status;
uint8_t retry_count;
} XBEE_TX_STATUS_FRAME;
typedef struct {
uint8_t type;
uint8_t status;
} XBEE_MODEM_STATUS_FRAME;
int XBEE_ConfigureDevice(void);
int XBEE_Init (void);
int XBEE_DecodeFrame(char* frame, XBEE_GENERIC_FRAME** decoded_frame);
int XBEE_GetData (XBEE_GENERIC_FRAME** frame, int timeout); // timeout in ms
int XBEE_SendData(uint64_t destination, uint8_t frame_id, uint8_t pan_broadcast, char* data, uint8_t *status);
int XBEE_SetChannel(uint8_t channel);
int XBEE_SetPanID(uint16_t panid);
int XBEE_GetRSSI(uint8_t *rssi);
int XBEE_GetUID(uint64_t *uid);
#endif /* BSP_XBEE_XBEE_H_ */

View file

@ -1,390 +0,0 @@
/*
* xbee_ll.c
*
* Created on: Apr 6, 2022
* Author: dimercur
*/
#include "xbee_ll.h"
#include "stm32l4xx_hal.h"
#include "cmsis_os.h"
#include "config.h"
UART_HandleTypeDef XBEE_LL_Uart;
//LPTIM_HandleTypeDef XBEE_LL_Timer;
char* XBEE_LL_RxBuffer;
static TaskHandle_t xbee_ll_rx_thread_handler;
static TaskHandle_t xbee_ll_tx_thread_handler;
typedef enum {
XBEE_LL_MODE_TRANSPARENT=0,
XBEE_LL_MODE_API
} XBEE_LL_ModeType;
XBEE_LL_ModeType XBEE_LL_Mode;
FlagStatus XBEE_LL_RxReady;
FlagStatus XBEE_LL_TxReady;
typedef enum
{
XBEE_LL_RX_STATE_OK=0,
XBEE_LL_RX_STATE_WAIT_DATA,
XBEE_LL_RX_STATE_WAIT_HEADER,
XBEE_LL_RX_STATE_WAIT_EOF,
XBEE_LL_RX_STATE_TIMEOUT,
XBEE_LL_RX_STATE_ERROR,
} XBEE_LL_RxStatus;
XBEE_LL_RxStatus XBEE_LL_RXState;
typedef struct {
uint8_t startChar;
uint16_t frameLength;
} API_LENGTH_ST;
volatile uint16_t tmp; // to be used by XBEE_LL_ConfigureUart
void XBEE_LL_StartTimeout(uint32_t timeout);
void XBEE_LL_StopTimeout(void);
int XBEE_LL_ConfigureUart(USART_TypeDef* usart, uint32_t baudrate) {
__HAL_RCC_USART1_FORCE_RESET();
__HAL_RCC_USART1_RELEASE_RESET();
XBEE_LL_Uart.Instance = usart;
XBEE_LL_Uart.Init.BaudRate = baudrate;
XBEE_LL_Uart.Init.WordLength = UART_WORDLENGTH_8B;
XBEE_LL_Uart.Init.StopBits = UART_STOPBITS_1;
XBEE_LL_Uart.Init.Parity = UART_PARITY_NONE;
XBEE_LL_Uart.Init.Mode = UART_MODE_TX_RX;
XBEE_LL_Uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
XBEE_LL_Uart.Init.OverSampling = UART_OVERSAMPLING_16;
XBEE_LL_Uart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
XBEE_LL_Uart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&XBEE_LL_Uart) != HAL_OK)
{
return XBEE_LL_ERROR_USART_CFG;
}
/* Debug usart */
tmp = usart->CR1;
tmp = usart->CR2;
tmp = usart->CR3;
tmp = usart->BRR;
tmp = usart->ICR;
tmp = usart->ISR;
tmp = usart->GTPR;
tmp = usart->RDR;
tmp = usart->TDR;
XBEE_LL_TxReady = SET;
XBEE_LL_RxReady = SET;
return XBEE_LL_OK;
}
void XBEE_LL_ConfigureGPIO(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**USART1 GPIO Configuration
PA8 ------> XBEE_RESET
PA11 ------> XBEE_SLEEP_RQ
PB3 -------> XBEE_SLEEP
*/
GPIO_InitStruct.Pin = XBEE_RST_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(XBEE_RST_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = XBEE_SLEEP_RQ_PIN;
HAL_GPIO_Init(XBEE_SLEEP_RQ_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = XBEE_SLEEP_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(XBEE_SLEEP_PORT, &GPIO_InitStruct);
/* Set SLEEP_REQ pin to 0 (disable sleep mode)
*
*/
HAL_GPIO_WritePin(XBEE_SLEEP_RQ_PORT, XBEE_SLEEP_RQ_PIN, GPIO_PIN_RESET);
//HAL_Delay(300);
vTaskDelay(msToTicks(300));
/* Reset XBEE module
* Pin to 0 -> wait 100 ms -> pin to 1 -> wait 300 ms
*/
HAL_GPIO_WritePin(XBEE_RST_PORT, XBEE_RST_PIN, GPIO_PIN_RESET);
//HAL_Delay(50);
vTaskDelay(msToTicks(100));
HAL_GPIO_WritePin(XBEE_RST_PORT, XBEE_RST_PIN, GPIO_PIN_SET);
//HAL_Delay(400);
vTaskDelay(msToTicks(400));
}
//void XBEE_LL_ConfigureTimer(void) {
// /* Peripheral reset */
// __HAL_RCC_LPTIM1_FORCE_RESET();
// __HAL_RCC_LPTIM1_RELEASE_RESET();
//
// XBEE_LL_Timer.Instance = LPTIM1;
// XBEE_LL_Timer.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
// XBEE_LL_Timer.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV128;
// XBEE_LL_Timer.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
// XBEE_LL_Timer.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
// XBEE_LL_Timer.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
// XBEE_LL_Timer.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
// XBEE_LL_Timer.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO;
// XBEE_LL_Timer.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO;
//
// HAL_LPTIM_Init(&XBEE_LL_Timer);
// __HAL_LPTIM_ENABLE(&XBEE_LL_Timer);
// __HAL_LPTIM_ENABLE_IT(&XBEE_LL_Timer, LPTIM_IT_CMPM);
// __HAL_LPTIM_AUTORELOAD_SET(&XBEE_LL_Timer, 0xFFFF); /* full scale for timer */
// __HAL_LPTIM_DISABLE(&XBEE_LL_Timer);
//}
/**
* @brief Start the Counter mode in interrupt mode.
* @param hlptim LPTIM handle
* @param Period Specifies the Autoreload value.
* This parameter must be a value between 0x0000 and 0xFFFF.
* @retval HAL status
*/
//void XBEE_LL_StartTimeout(uint32_t timeout)
//{
// uint16_t compare_val;
// uint16_t period;
//
// if (timeout>0) {
// /* Enable the Peripheral */
// __HAL_LPTIM_ENABLE(&XBEE_LL_Timer);
//
// /* Clear Compare match flag */
// __HAL_LPTIM_CLEAR_FLAG(&XBEE_LL_Timer,LPTIM_IT_CMPM);
// /* Load the period value + current counter in the compare register */
// period = (uint16_t)((timeout*(4000000UL/128UL))/1000UL);
//
// if (XBEE_LL_Timer.Instance->CNT>period)
// compare_val = (uint16_t)(((uint32_t)XBEE_LL_Timer.Instance->CNT)+period-65536);
// else
// compare_val = (uint16_t)(((uint32_t)XBEE_LL_Timer.Instance->CNT)+period);
// __HAL_LPTIM_COMPARE_SET(&XBEE_LL_Timer, compare_val);
//
// /* Start timer in continuous mode */
// __HAL_LPTIM_START_CONTINUOUS(&XBEE_LL_Timer);
// }
//}
/**
* @brief Stop the Counter mode in interrupt mode.
* @param hlptim LPTIM handle
* @retval HAL status
*/
//void XBEE_LL_StopTimeout(void)
//{
// /* Disable the Peripheral */
// __HAL_LPTIM_DISABLE(&XBEE_LL_Timer);
//
// /* Clear Compare match flag */
// __HAL_LPTIM_CLEAR_FLAG(&XBEE_LL_Timer,LPTIM_IT_CMPM);
//}
int XBEE_LL_SendData(char* data, int length) {
int data_length;
xbee_ll_tx_thread_handler = xTaskGetCurrentTaskHandle();
if (length == -1) {
/* Envoi d'un trame API, donc, recherche de la longueur dans la trame */
data_length = ((API_LENGTH_ST*)data)->frameLength + 3 +1; //+3 for header and + 1 for checksum
}
else data_length = length;
//while (XBEE_LL_TxReady != SET); // wait for last transfert to end
ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS(100)); // wait max 100 ms
/* Restore huart->gState to ready */
//XBEE_LL_Uart.gState = HAL_UART_STATE_READY;
XBEE_LL_TxReady = RESET;
if(HAL_UART_Transmit_DMA(&XBEE_LL_Uart, (uint8_t*)data, data_length)!= HAL_OK) {
XBEE_LL_TxReady = SET;
return XBEE_LL_ERROR_TX;
}
xbee_ll_tx_thread_handler = NULL;
return XBEE_LL_OK;
}
int XBEE_LL_ReceiveData(char* data, int length, int timeout) {
uint32_t ulNotificationValue;
int data_length;
xbee_ll_rx_thread_handler = xTaskGetCurrentTaskHandle();
while (XBEE_LL_RxReady != SET); // wait for last RX to end
if (length == -1) {
// set API mode
XBEE_LL_Mode = XBEE_LL_MODE_API;
data_length = 3; // 3 bytes for api header (start char and length)
XBEE_LL_RxBuffer = data;
XBEE_LL_RXState = XBEE_LL_RX_STATE_WAIT_HEADER;
} else {
// set TRANSPARENT mode
XBEE_LL_Mode = XBEE_LL_MODE_TRANSPARENT;
XBEE_LL_RXState = XBEE_LL_RX_STATE_WAIT_DATA;
data_length = length;
}
//XBEE_LL_StartTimeout(timeout);
XBEE_LL_RxReady = RESET;
if(HAL_UART_Receive_DMA(&XBEE_LL_Uart, (uint8_t*)data, data_length)!= HAL_OK) {
//XBEE_LL_StopTimeout();
HAL_UART_DMAStop(&XBEE_LL_Uart);
XBEE_LL_RXState = XBEE_LL_RX_STATE_ERROR;
XBEE_LL_RxReady = SET;
return XBEE_LL_ERROR_RX;
}
//while (XBEE_LL_RxReady != SET); // wait for RX to end
if (timeout == 0)
ulNotificationValue = ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS(portMAX_DELAY)); // wait max 100 ms
else
ulNotificationValue = ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS(timeout)); // wait max 100 ms
//XBEE_LL_StopTimeout();
if (ulNotificationValue != 1) {
/* The reception timed out. */
HAL_UART_DMAStop(&XBEE_LL_Uart);
XBEE_LL_RXState = XBEE_LL_RX_STATE_TIMEOUT;
XBEE_LL_RxReady = SET;
}
xbee_ll_rx_thread_handler = NULL;
if (XBEE_LL_RXState == XBEE_LL_RX_STATE_ERROR)
return XBEE_LL_ERROR_RX;
else if (XBEE_LL_RXState == XBEE_LL_RX_STATE_TIMEOUT) {
HAL_UART_DMAStop(&XBEE_LL_Uart);
return XBEE_LL_ERROR_RX_TIMEOUT;
}
else
return XBEE_LL_OK;
}
/**
* @brief Rx Transfer completed callback
* @param UartHandle: UART handle
* @note This example shows a simple way to report end of DMA Rx transfer, and
* you can add your own implementation.
* @retval None
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
int frame_length;
if (XBEE_LL_Mode == XBEE_LL_MODE_TRANSPARENT){
/* Set reception flag: transfer complete*/
XBEE_LL_RXState = XBEE_LL_RX_STATE_OK;
XBEE_LL_RxReady = SET;
if (xbee_ll_rx_thread_handler != NULL) {
/* Notify the task that an event has been emitted. */
vTaskNotifyGiveFromISR(xbee_ll_rx_thread_handler, &xHigherPriorityTaskWoken );
/* There are no more eventin progress, so no tasks to notify. */
xbee_ll_rx_thread_handler = NULL;
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch
should be performed to ensure the interrupt returns directly to the highest
priority task. The macro used for this purpose is dependent on the port in
use and may be called portEND_SWITCHING_ISR(). */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
} else {
if (XBEE_LL_RXState == XBEE_LL_RX_STATE_WAIT_EOF) {
/* Set reception flag: transfer complete*/
XBEE_LL_RXState = XBEE_LL_RX_STATE_OK;
XBEE_LL_RxReady = SET;
if (xbee_ll_rx_thread_handler != NULL) {
/* Notify the task that an event has been emitted. */
vTaskNotifyGiveFromISR(xbee_ll_rx_thread_handler, &xHigherPriorityTaskWoken );
/* There are no more eventin progress, so no tasks to notify. */
xbee_ll_rx_thread_handler = NULL;
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch
should be performed to ensure the interrupt returns directly to the highest
priority task. The macro used for this purpose is dependent on the port in
use and may be called portEND_SWITCHING_ISR(). */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
} else {
frame_length = 1+(((int)XBEE_LL_RxBuffer[1]<<8))+(int)XBEE_LL_RxBuffer[2];
XBEE_LL_RXState = XBEE_LL_RX_STATE_WAIT_EOF;
if(HAL_UART_Receive_DMA(&XBEE_LL_Uart, (uint8_t*)(XBEE_LL_RxBuffer+3), frame_length)!= HAL_OK) {
// Something went wrong
//XBEE_LL_StopTimeout();
XBEE_LL_RXState = XBEE_LL_RX_STATE_ERROR;
XBEE_LL_RxReady = SET;
}
}
}
}
/**
* @brief Tx Transfer completed callback
* @param UartHandle: UART handle
* @note This example shows a simple way to report end of DMA Rx transfer, and
* you can add your own implementation.
* @retval None
*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Set transmission flag: transfer complete*/
XBEE_LL_TxReady = SET;
/* Restore huart->gState to ready */
//UartHandle->gState = HAL_UART_STATE_READY;
if (xbee_ll_tx_thread_handler != NULL) {
/* Notify the task that an event has been emitted. */
vTaskNotifyGiveFromISR(xbee_ll_tx_thread_handler, &xHigherPriorityTaskWoken );
/* There are no more eventin progress, so no tasks to notify. */
xbee_ll_tx_thread_handler = NULL;
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch
should be performed to ensure the interrupt returns directly to the highest
priority task. The macro used for this purpose is dependent on the port in
use and may be called portEND_SWITCHING_ISR(). */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}
/**
* @brief This function handles LPTIM1 global interrupt.
*/
//void LPTIM1_IRQHandler(void)
//{
// /* Clear Compare match flag */
// __HAL_LPTIM_CLEAR_FLAG(&XBEE_LL_Timer,LPTIM_IT_CMPM);
//
// XBEE_LL_StopTimeout();
//
// /* Set reception flag: Timeout*/
// XBEE_LL_RXState = XBEE_LL_RX_STATE_TIMEOUT;
// XBEE_LL_RxReady = SET;
//}

View file

@ -1,37 +0,0 @@
/*
* xbee_ll.h
*
* Created on: Apr 6, 2022
* Author: dimercur
*/
#ifndef BSP_XBEE_XBEE_LL_H_
#define BSP_XBEE_XBEE_LL_H_
#include "stm32l4xx_hal.h"
typedef void (*RXCallback)(char* data, int length);
#define XBEE_USART USART1
#define XBEE_RST_PIN GPIO_PIN_8
#define XBEE_RST_PORT GPIOA
#define XBEE_SLEEP_RQ_PIN GPIO_PIN_11
#define XBEE_SLEEP_RQ_PORT GPIOA
#define XBEE_SLEEP_PIN GPIO_PIN_3
#define XBEE_SLEEP_PORT GPIOB
#define XBEE_LL_OK 0
#define XBEE_LL_ERROR_USART_CFG 1
#define XBEE_LL_ERROR_TX 2
#define XBEE_LL_ERROR_RX 3
#define XBEE_LL_ERROR_RX_TIMEOUT 4
int XBEE_LL_ConfigureUart(USART_TypeDef* usart, uint32_t baudrate);
void XBEE_LL_ConfigureGPIO(void);
void XBEE_LL_ConfigureTimer(void);
int XBEE_LL_SendData(char* data, int length) ;
int XBEE_LL_ReceiveData(char* data, int length, int timeout);
#endif /* BSP_XBEE_XBEE_LL_H_ */

View file

@ -63,16 +63,18 @@ typedef struct {
char powerOffRequired; char powerOffRequired;
} APPLICATION_Infos; } APPLICATION_Infos;
APPLICATION_Infos systemInfos = {0}; APPLICATION_Infos systemInfos = {0};
void APPLICATION_Init(void) { void APPLICATION_Init(void) {
/* Init des messages box */ /* Init des messages box */
MESSAGE_Init(); MESSAGE_Init();
/* Init de l'afficheur */
LEDS_Init(); LEDS_Init();
//LEDS_Tests(); //LEDS_Tests();
//XBEE_Init(); /* Init de la partie RF / reception des messages */
XBEE_Init();
//BATTERIE_Init(); //BATTERIE_Init();
//MOTEURS_Init(); //MOTEURS_Init();
//SEQUENCEUR_Init(); //SEQUENCEUR_Init();
@ -91,8 +93,7 @@ void APPLICATION_Init(void) {
&xTaskApplicationMain); /* Variable to hold the task's data structure. */ &xTaskApplicationMain); /* Variable to hold the task's data structure. */
vTaskResume(xHandleApplicationMain); vTaskResume(xHandleApplicationMain);
/* Create the task without using any dynamic memory allocation. */ /* Create a periodic task without using any dynamic memory allocation. */
xHandleTimerTimeout = xTimerCreateStatic( xHandleTimerTimeout = xTimerCreateStatic(
"Seq Timer", "Seq Timer",
//pdMS_TO_TICKS(100), //pdMS_TO_TICKS(100),

View file

@ -12,139 +12,81 @@
/* Definition des commandes */ /* Definition des commandes */
//void cmdAddChecksum(char* ans) {
// uint16_t j;
// unsigned char checksum=0;
//
// for (j = 0; ans[j] != END_OF_CMD; j++)
// checksum ^= ans[j];
// if (checksum == END_OF_CMD)
// checksum++;
// ans[j] = checksum;
// ans[j + 1] = END_OF_CMD;
//}
/**
* @brief Verifie le checksum de la commande recue
*
* Vérifie le dernier carctére de receiptString sensé être le checksum.
* Si celui-ci est bon, ll retournera 0 et supprimera le checksum du tableau receiptString
* sinon il retournera 1 sans faire de modification.
* @param None
* @retval 0 ou 1
*
*/
ANS_Type cmdVerifyChecksum(char* cmd) {
uint16_t j;
uint16_t length;
unsigned char checksum=0;
length = strlen(cmd);
for (j = 0; j < length - 2; j++) {
checksum ^= cmd[j];
}
if (checksum == END_OF_CMD)
checksum++;
if (cmd[j] == checksum) {
cmd[length - 2] = 0;
cmd[length - 1] = 0;
cmd[length] = 0;
return okANS;
} else
return errANS;
}
ANS_Type cmdIsValid(char* cmd) {
uint16_t j;
uint16_t length;
unsigned char checksum=0;
length = strlen(cmd);
for (j = 0; j < length - 2; j++) {
checksum ^= cmd[j];
}
if (checksum == END_OF_CMD)
checksum++;
if (cmd[j] == checksum)
return okANS;
else
return errANS;
}
CMD_Generic* cmdDecode(char* cmd) { CMD_Generic* cmdDecode(char* cmd) {
CMD_Generic* decodedCmd; CMD_Generic* decodedCmd;
if (cmdVerifyChecksum(cmd) != okANS) switch (cmd[0])
return CMD_DECODE_INVALID; {
else if (cmd[0] == moveCMD) { case CMD_MOVE:
int32_t laps; decodedCmd = (CMD_Generic*)malloc(sizeof(CMD_Move));
uint16_t testReception = sscanf(cmd, "M=%li", &laps); ((CMD_Move*)decodedCmd)->distance = ((uint16_t)cmd[1]<<8) + (uint16_t)cmd[2];
break;
if (testReception!=1) return CMD_DECODE_INVALID; case CMD_TURN:
else { decodedCmd = (CMD_Generic*)malloc(sizeof(CMD_Turn));
decodedCmd=(CMD_Generic*)malloc(sizeof(CMD_Move));
((CMD_Move*)decodedCmd)->type = moveCMD;
((CMD_Move*)decodedCmd)->distance = laps;
}
} else if (cmd[0] == turnCMD) {
int32_t degree;
uint16_t testReception = sscanf(cmd, "T=%li", &degree);
if (testReception != 1) return CMD_DECODE_INVALID; ((CMD_Turn*)decodedCmd)->turns = ((uint16_t)cmd[1]<<8) + (uint16_t)cmd[2];
else { ((CMD_Turn*)decodedCmd)->turns = ((CMD_Turn*)decodedCmd)->turns * 1.4;
degree = degree * 1.40;
decodedCmd=(CMD_Generic*)malloc(sizeof(CMD_Turn));
((CMD_Turn*)decodedCmd)->type = moveCMD;
((CMD_Turn*)decodedCmd)->turns= degree;
}
} else if (cmd[0] == setMotorCMD) {
int32_t moteurG,moteurD;
uint16_t testReception = sscanf(cmd, "m=%li,%li", &moteurG, &moteurD);
if (testReception != 1) return CMD_DECODE_INVALID; break;
else {
decodedCmd=(CMD_Generic*)malloc(sizeof(CMD_SetMotor)); case CMD_PING:
((CMD_SetMotor*)decodedCmd)->type = moveCMD; case CMD_RESET:
((CMD_SetMotor*)decodedCmd)->motor_left= moteurG; case CMD_START_WITHOUT_WATCHDOG:
((CMD_SetMotor*)decodedCmd)->motor_right= moteurD; case CMD_START_WITH_WATCHDOG:
} case CMD_RESET_WATCHDOG:
} else if ((cmd[0] == pingCMD) || (cmd[0] == resetCMD) || (cmd[0] == startWWatchDogCMD) || (cmd[0] == resetWatchdogCMD) || case CMD_GET_BATTERY:
(cmd[0] == getBatteryVoltageCMD) || (cmd[0] == getVersionCMD) || (cmd[0] == startWithoutWatchCMD) || (cmd[0] == busyStateCMD) || case CMD_GET_BUSY_STATE:
(cmd[0] == testCMD) || (cmd[0] == debugCMD) || (cmd[0] == powerOffCMD)) { case CMD_GET_VERSION:
decodedCmd=(CMD_Generic*)malloc(sizeof(CMD_Generic)); case CMD_TEST:
case CMD_DEBUG:
case CMD_POWER_OFF:
decodedCmd = (CMD_Generic*)malloc(sizeof(CMD_Generic));
decodedCmd->type = cmd[0]; decodedCmd->type = cmd[0];
} else return CMD_DECODE_UNKNOWN;
default:
decodedCmd = CMD_DECODE_UNKNOWN;
}
return decodedCmd; return decodedCmd;
} }
void cmdSendAnswer(ANS_Type ans) { void cmdSendAnswer(uint8_t ans) {
char cmdStr[4]; ANS_Generic answer;
cmdStr[0] = (char)ans;
cmdStr[1] = (char)ans; answer.ans = ans;
cmdStr[2] = END_OF_CMD; XBEE_SendData((char*)&answer, sizeof (answer));
cmdStr[3] = 0; // end of string
XBEE_SendData(cmdStr, 3);
} }
void cmdSendBatteryLevel(char level) { void cmdSendBatteryLevel(char level) {
char cmdStr[4]; ANS_Battery answer;
char localLevel=level; char localLevel=level;
if (localLevel<0) localLevel=0; if (localLevel<0) localLevel=0;
else if (localLevel>2) localLevel=2; else if (localLevel>2) localLevel=2;
cmdStr[0] = localLevel+'0'; answer.ans = ANS_OK;
cmdStr[1] = localLevel+'0'; answer.bat_level = localLevel;
cmdStr[2] = END_OF_CMD;
cmdStr[3] = 0; // end of string XBEE_SendData((char*)&answer, sizeof (answer));
XBEE_SendData(cmdStr, 3);
} }
void cmdSendVersion() { void cmdSendVersion() {
XBEE_SendData(SYSTEM_VERSION_STR, strlen(SYSTEM_VERSION_STR)); ANS_Version answer;
answer.ans = ANS_OK;
answer.version = SYSTEM_VERSION;
XBEE_SendData((char*)&answer, sizeof (answer));
} }
void cmdBusyState(uint8_t state) {
ANS_Busy_State answer;
answer.ans = ANS_OK;
answer.state = state;
if (answer.state >1) answer.state=0;
XBEE_SendData((char*)&answer, sizeof (answer));
}

View file

@ -10,61 +10,71 @@
#include "application.h" #include "application.h"
typedef enum { #define CMD_PING 0x1
pingCMD = 'p', #define CMD_RESET 0x2
resetCMD = 'r', #define CMD_START_WITH_WATCHDOG 0x3
setMotorCMD = 'm', #define CMD_RESET_WATCHDOG 0x4
startWWatchDogCMD = 'W', #define CMD_GET_BATTERY 0x5
resetWatchdogCMD = 'w', #define CMD_GET_VERSION 0x6
getBatteryVoltageCMD = 'v', #define CMD_START_WITHOUT_WATCHDOG 0x7
getVersionCMD = 'V', #define CMD_MOVE 0x8
startWithoutWatchCMD = 'u', #define CMD_TURN 0x9
moveCMD = 'M', #define CMD_GET_BUSY_STATE 0xA
turnCMD = 'T', #define CMD_TEST 0xB
busyStateCMD = 'b', #define CMD_DEBUG 0xC
testCMD = 't', #define CMD_POWER_OFF 0xD
debugCMD = 'a',
powerOffCMD = 'z'
} CMD_Type;
typedef enum { #define ANS_OK 0x80
okANS = 'O', #define ANS_ERR 0x81
errANS = 'E', #define ANS_UNKNOWN 0x82
unknownANS = 'C',
batOK = '2',
batLOW = '1',
batEMPTY = '0'
} ANS_Type;
#define END_OF_CMD '\r' #define ANS_BAT_OK 0x2
#define ANS_BAT_LOW 0x1
#define ANS_BAT_EMPTY 0x0
typedef struct { #define ANS_STATE_NOT_BUSY 0x0
CMD_Type type; #define ANS_STATE_BUSY 0x1
typedef struct __attribute__((packed)) {
uint8_t type;
} CMD_Generic; } CMD_Generic;
typedef struct { typedef struct __attribute__((packed)) {
CMD_Type type; uint8_t type;
int32_t motor_left; int16_t distance;
int32_t motor_right;
} CMD_SetMotor;
typedef struct {
CMD_Type type;
int32_t distance;
} CMD_Move; } CMD_Move;
typedef struct { typedef struct __attribute__((packed)) {
CMD_Type type; uint8_t type;
int32_t turns; int16_t turns;
} CMD_Turn; } CMD_Turn;
typedef struct __attribute__((packed)) {
uint8_t ans;
} ANS_Generic;
typedef struct __attribute__((packed)) {
uint8_t ans;
uint8_t version;
} ANS_Version;
typedef struct __attribute__((packed)) {
uint8_t ans;
uint8_t bat_level;
} ANS_Battery;
typedef struct __attribute__((packed)) {
uint8_t ans;
uint8_t state;
} ANS_Busy_State;
#define CMD_DECODE_INVALID ((CMD_Generic*)NULL) #define CMD_DECODE_INVALID ((CMD_Generic*)NULL)
#define CMD_DECODE_UNKNOWN ((CMD_Generic*)UINT32_MAX) #define CMD_DECODE_UNKNOWN ((CMD_Generic*)UINT32_MAX)
ANS_Type cmdIsValid(char* cmd);
CMD_Generic* cmdDecode(char* cmd); CMD_Generic* cmdDecode(char* cmd);
void cmdSendAnswer(ANS_Type ans); void cmdSendAnswer(uint8_t ans);
void cmdSendBatteryLevel(char level); void cmdSendBatteryLevel(char level);
void cmdSendVersion(); void cmdSendVersion();
void cmdBusyState(uint8_t state);
#endif /* INC_CMD_H_ */ #endif /* INC_CMD_H_ */

View file

@ -8,6 +8,7 @@
#include "cmsis_os.h" #include "cmsis_os.h"
#define SYSTEM_VERSION_STR "version 2.0\r" #define SYSTEM_VERSION_STR "version 2.0\r"
#define SYSTEM_VERSION 0x20
#define STACK_SIZE 0x100 #define STACK_SIZE 0x100

View file

@ -34,7 +34,11 @@ SemaphoreHandle_t xHandleSemaphoreRX = NULL;
StaticSemaphore_t xSemaphoreRx; StaticSemaphore_t xSemaphoreRx;
uint8_t* rxBuffer; uint8_t* rxBuffer;
uint32_t rxBufferIndex; uint8_t rxWaitForACK;
uint8_t rxPhase;
#define XBEE_RX_PHASE_HEADER 1
#define XBEE_RX_PHASE_BODY 2
/****** TX part ******/ /****** TX part ******/
SemaphoreHandle_t xHandleSemaphoreTX = NULL; SemaphoreHandle_t xHandleSemaphoreTX = NULL;
@ -50,11 +54,7 @@ void XBEE_Init(void) {
xSemaphoreGive(xHandleSemaphoreTX); xSemaphoreGive(xHandleSemaphoreTX);
rxBuffer=(uint8_t*)malloc(XBEE_RX_BUFFER_MAX_LENGTH); rxBuffer=(uint8_t*)malloc(XBEE_RX_BUFFER_MAX_LENGTH);
rxBufferIndex=0; rxWaitForACK = 0;
if(HAL_UART_Receive_IT(&hlpuart1, rxBuffer, 1)!= HAL_OK) {
while(1);
}
} }
/**** Support functions ****/ /**** Support functions ****/
@ -119,10 +119,10 @@ char* XBEE_EncodeWithEscapeChar(char* data, int length, int *encodedLength) {
* \return new buffer allocated without escaped char * \return new buffer allocated without escaped char
*/ */
char* XBEE_DecodeWithoutEscapeChar(char* encodedData, int encodedLength, int *length) { char* XBEE_DecodeWithoutEscapeChar(char* encodedData, int encodedLength, int *length) {
char* data = (char*)malloc(encodedLength); // on prevoit un buffer aussi grand que celui avec caractere d'echappement, char* data = (char*)malloc(encodedLength); // on prévoit un buffer aussi grand que celui avec caractère d'echappement,
// au cas où aucun caractere d'echappement ne serait present // au cas où aucun caractère d'echappement ne serait present
*length = encodedLength; // par defaut, on considére que les données brutes ont la même taille que *length = encodedLength; // par défaut, on considère que les données brutes ont la même taille que
// celles avec caractéres d'echappement. // celles avec caractères d'echappement.
for (char* p=data; p< (data + encodedLength); p++) { for (char* p=data; p< (data + encodedLength); p++) {
if (*encodedData == (char)XBEE_API_ESCAPE_CHAR) { if (*encodedData == (char)XBEE_API_ESCAPE_CHAR) {
@ -185,95 +185,94 @@ char* XBEE_EncodeTransmissionFrame(char* data, int length, uint16_t destination,
return frame; return frame;
} }
/**
* Get frame length
*
* \param frame pointer on frame header
* \return length of incoming frame
*/
uint16_t XBEE_GetFrameLength(uint8_t *frame) {
return (((uint16_t)frame[1])<<8) + (uint16_t)frame[2];
}
/** /**
* Get a complete frame, check if frame is correct and extract raw data * Get a complete frame, check if frame is correct and extract raw data
* *
* \param frame pointer on complete frame * \param raw_frame pointer on complete frame
* \param data pointer to raw data, with escape char removed * \param incomingFrame pointer to processed frame, with escape char removed
* \param sender address of the sender * \return status of decoding: XBEE_OK if decoding is successful, XBEE_INVALID_FRAME otherwise
* \return status of decoding: XBEE_OK if decoding is successfull, XBEE_INVALID_FRAME otherwise
*/ */
XBEE_Status XBEE_DecodeFrame(char* frame, char** data, uint16_t *sender) { XBEE_Status XBEE_DecodeFrame(char* rawFrame, XBEE_INCOMING_FRAME** incomingFrame) {
uint8_t frame_type = (uint8_t)frame[3]; uint8_t frame_type = (uint8_t)rawFrame[3];
uint16_t frame_length; uint16_t rawFrameLength;
uint8_t checksum; uint8_t checksum;
XBEE_Status status = XBEE_OK;
int incomingDataLength = 0;
int i; int i;
frame_length = (((uint16_t)frame[1])<<8) + (uint16_t)frame[2]; if (rawFrame[0] == '~') {
rawFrameLength = (((uint16_t)rawFrame[1])<<8) + (uint16_t)rawFrame[2];
/* verification du checksum */ /* verification du checksum */
checksum =0; checksum =0;
for (i=3; i<3+frame_length+1; i++) { for (i=3; i<3+rawFrameLength+1; i++) {
checksum += (uint8_t)frame[i]; checksum += (uint8_t)rawFrame[i];
} }
if (checksum != 0xFF) if (checksum != 0xFF)
return XBEE_INVALID_FRAME; return XBEE_INVALID_FRAME;
*incomingFrame = (XBEE_INCOMING_FRAME*) malloc(sizeof(XBEE_INCOMING_FRAME)); /* Allocate a generic frame struct */
(*incomingFrame)->type = frame_type;
switch (frame_type) { switch (frame_type) {
case XBEE_RX_PACKET_TYPE: case XBEE_RX_16BIT_PACKET_TYPE:
*data = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_RX_PACKET_FRAME)+(frame_length-12)+1); // +1 for 0 ending in data frame /* Get source address */
memset((void*)*data, 0, sizeof(XBEE_RX_PACKET_FRAME)+(frame_length-12)+1); (*incomingFrame)->source_addr = (((uint16_t)rawFrame[4])<<8) + (uint16_t)rawFrame[5];
((XBEE_RX_PACKET_FRAME*)(*data))->type = frame_type; (*incomingFrame)->data = XBEE_DecodeWithoutEscapeChar(&rawFrame[8], rawFrameLength-6, &incomingDataLength);
((XBEE_RX_PACKET_FRAME*)(*data))->data_length = frame_length-12; (*incomingFrame)->ack = 0;
((XBEE_RX_PACKET_FRAME*)(*data))->options = frame[14];
((XBEE_RX_PACKET_FRAME*)(*data))->source_addr =0;
for (i=0; i<8; i++) {
((XBEE_RX_PACKET_FRAME*)(*data))->source_addr = ((XBEE_RX_PACKET_FRAME*)(*data))->source_addr<<8;
((XBEE_RX_PACKET_FRAME*)(*data))->source_addr +=(uint64_t)frame[4+i];
}
for (i=0; i<((XBEE_RX_PACKET_FRAME*)(*data))->data_length; i++) {
((XBEE_RX_PACKET_FRAME*)(*data))->data[i] =(char)frame[15+i];
}
((XBEE_RX_PACKET_FRAME*)(*data))->data[((XBEE_RX_PACKET_FRAME*)(*data))->data_length]=0x0; // 0 ending frame
break; break;
case XBEE_MODEM_STATUS_TYPE: case XBEE_MODEM_STATUS_TYPE:
*data = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_MODEM_STATUS_FRAME)); (*incomingFrame)->modem_status = rawFrame[4];
((XBEE_MODEM_STATUS_FRAME*)(*data))->type = frame_type; (*incomingFrame)->data=0x0;
((XBEE_MODEM_STATUS_FRAME*)(*data))->status = frame[4];
break; break;
case XBEE_TX_STATUS_TYPE: case XBEE_TX_STATUS_TYPE:
(*incomingFrame)->ack = rawFrame[5];
(*incomingFrame)->data=0x0;
break;
case XBEE_EXTENDED_TX_STATUS_TYPE: case XBEE_EXTENDED_TX_STATUS_TYPE:
*data = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_TX_STATUS_FRAME)); (*incomingFrame)->ack = rawFrame[8];
((XBEE_TX_STATUS_FRAME*)(*data))->type = frame_type; (*incomingFrame)->data=0x0;
((XBEE_TX_STATUS_FRAME*)(*data))->frame_id = frame[4];
if (frame_type == XBEE_TX_STATUS_TYPE) {
((XBEE_TX_STATUS_FRAME*)(*data))->status = frame[5];
((XBEE_TX_STATUS_FRAME*)(*data))->retry_count = 0;
} else {
((XBEE_TX_STATUS_FRAME*)(*data))->status = frame[8];
((XBEE_TX_STATUS_FRAME*)(*data))->retry_count = frame[7];
}
break; break;
case XBEE_AT_CMD_RESPONSE_TYPE:
*data = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_AT_CMD_RESPONSE_FRAME)+(frame_length-5));
((XBEE_AT_CMD_RESPONSE_FRAME*)(*data))->type = frame_type;
((XBEE_AT_CMD_RESPONSE_FRAME*)(*data))->data_length = frame_length-5;
((XBEE_AT_CMD_RESPONSE_FRAME*)(*data))->status = frame[7];
for (i=0; i<((XBEE_AT_CMD_RESPONSE_FRAME*)(*data))->data_length; i++) {
((XBEE_AT_CMD_RESPONSE_FRAME*)(*data))->data[i] =(uint8_t)frame[8+i];
}
break;
default: default:
*data = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_GENERIC_FRAME)); free (*incomingFrame);
((XBEE_GENERIC_FRAME*)(*data))->type = frame_type;
return XBEE_INVALID_FRAME; return XBEE_INVALID_FRAME;
}; };
} else status = XBEE_INVALID_FRAME;
return XBEE_OK; return status;
} }
/**** TX Part *****/ /**** TX Part *****/
/**
* Send data. Create a transmission frame, add escape char to data and send it over UART
*
* \param data raw data to send
* \param length length of data to send
* \return status of decoding: XBEE_OK if decoding is successful,
* XBEE_TX_ERROR in case of sending error,
* XBEE_TX_ACK_ERROR in case frame was not acknowledge by detination part
*/
int XBEE_SendData(char* data, int length) { int XBEE_SendData(char* data, int length) {
int data_length; int data_length;
BaseType_t state; BaseType_t state;
XBEE_INCOMING_FRAME* incomingFrame;
// Prevents successive calls to overlap // Prevents successive calls to overlap
state = xSemaphoreTake(xHandleSemaphoreTX, pdMS_TO_TICKS(XBEE_TX_SEMAPHORE_WAIT)); // wait max 500 ms (to avoid interlocking) state = xSemaphoreTake(xHandleSemaphoreTX, pdMS_TO_TICKS(XBEE_TX_SEMAPHORE_WAIT)); // wait max 500 ms (to avoid interlocking)
@ -283,23 +282,43 @@ int XBEE_SendData(char* data, int length) {
We should probably reset something in "else" branch */ We should probably reset something in "else" branch */
/* TODO: stuff to do here for converting data into API frame */ /* TODO: stuff to do here for converting data into API frame */
data_length = length; txBuffer = (uint8_t*)XBEE_EncodeWithEscapeChar(data, length, &data_length);
if ((txBuffer = (uint8_t*)malloc(length))!=NULL) {
memcpy((void*)txBuffer, (void*) data, length);
if(HAL_UART_Transmit_IT(&hlpuart1, txBuffer, data_length)!= HAL_OK) if (txBuffer!=NULL) {
return -3; if (HAL_UART_Transmit_DMA(&hlpuart1, txBuffer, data_length)!= HAL_OK)
} else return -2; return XBEE_TX_ERROR;
} else return -1; else {
rxWaitForACK = 1; /* wait for TX ack */
// Wait for ACK frame after TX
state = xSemaphoreTake(xHandleSemaphoreTX_ACK, pdMS_TO_TICKS(XBEE_TX_SEMAPHORE_WAIT)); // wait max 500 ms (to avoid interlocking)
if (XBEE_DecodeFrame((char*) rxBuffer, &incomingFrame)!=XBEE_OK)
return XBEE_TX_ACK_ERROR;
else {
if (incomingFrame == 0x0)
return XBEE_TX_ACK_ERROR;
else if ((incomingFrame->type != XBEE_TX_STATUS_TYPE) || (incomingFrame->ack != XBEE_TX_STATUS_SUCCESS)) {
free ((XBEE_INCOMING_FRAME*) incomingFrame);
return XBEE_TX_ACK_ERROR;
}
}
}
} else return XBEE_TX_ERROR;
} else return XBEE_TX_ERROR;
return length; return length;
} }
/**
* DMA Interrupt request for transmission. Call when transmission is finished
*
* \param UartHandle not used
*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) { void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Do stuff here */ /* Free transmit buffer */
free (txBuffer); free (txBuffer);
if (rxWaitForACK != 1) /* we are waiting for an acknowledge frame, so do not give semaphore yet */
xSemaphoreGiveFromISR( xHandleSemaphoreTX, &xHigherPriorityTaskWoken ); xSemaphoreGiveFromISR( xHandleSemaphoreTX, &xHigherPriorityTaskWoken );
/* If xHigherPriorityTaskWoken was set to true you /* If xHigherPriorityTaskWoken was set to true you
@ -309,30 +328,60 @@ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) {
} }
/***** Rx Part *****/ /***** Rx Part *****/
/**
* Reception thread. Wait for incoming frame, process it and send message to application
*
* \param params not used
*/
void XBEE_RxThread(void* params) { void XBEE_RxThread(void* params) {
BaseType_t state;
XBEE_INCOMING_FRAME* incomingFrame;
rxPhase= XBEE_RX_PHASE_HEADER;
while (HAL_UART_Receive_DMA(&hlpuart1, rxBuffer, 3)== HAL_OK); // start reception of frame
// endless task // endless task
while (1) { while (1) {
while ((state = xSemaphoreTake(xHandleSemaphoreRX, portMAX_DELAY))==pdTRUE); // wait forever
/* Process frame */
if (XBEE_DecodeFrame((char*) rxBuffer, &incomingFrame)==XBEE_OK) // frame is valid
if (incomingFrame != 0x0) // frame is valid
MESSAGE_SendMailbox(APPLICATION_Mailbox, MSG_ID_XBEE_CMD, (QueueHandle_t)0x0, (void*)incomingFrame);
} }
} }
/**
* DMA IRQ handler for reception. Receive a complete frame send send event to sending frame in case of acknowledge frame or to receive task otherwise
*
* \param UartHandle not used
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) { void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint16_t frameLength;
if (rxBuffer[rxBufferIndex] == '\r') { if (rxPhase == XBEE_RX_PHASE_HEADER) { // we just received header part
rxBuffer[rxBufferIndex+1]=0; // add end of string frameLength=XBEE_GetFrameLength(rxBuffer); /* Compute body part of the frame + checksum */
MESSAGE_SendMailboxFromISR(APPLICATION_Mailbox, MSG_ID_XBEE_CMD, (QueueHandle_t)0x0, (void*)rxBuffer, &xHigherPriorityTaskWoken);
rxBuffer = malloc(XBEE_RX_BUFFER_MAX_LENGTH); if (HAL_UART_Receive_DMA(&hlpuart1, rxBuffer+3, frameLength+1)== HAL_OK) {
rxBufferIndex=0; /* Reception of body part started successfully */
} else if (rxBufferIndex>=XBEE_RX_BUFFER_MAX_LENGTH-2) // prevent buffer overflow rxPhase = XBEE_RX_PHASE_BODY;
rxBufferIndex=0; } else {
else /* Failed to start reception of body
rxBufferIndex++; * Restart reception of header */
while (HAL_UART_Receive_DMA(&hlpuart1, rxBuffer, 3)!= HAL_OK); // try to receive header
}
} else { // we just received body part. Frame is complete
if (rxWaitForACK) {
xSemaphoreGiveFromISR( xHandleSemaphoreTX_ACK, &xHigherPriorityTaskWoken); /* Send event to sending function */
xSemaphoreGiveFromISR( xHandleSemaphoreTX, &xHigherPriorityTaskWoken ); /* Allow new sending data */
} else {
xSemaphoreGiveFromISR( xHandleSemaphoreRX, &xHigherPriorityTaskWoken ); /* send event to receive task to process received task */
}
if(HAL_UART_Receive_IT(&hlpuart1, &rxBuffer[rxBufferIndex], 1)!= HAL_OK) { rxPhase = XBEE_RX_PHASE_HEADER;
while(1); while (HAL_UART_Receive_DMA(&hlpuart1, rxBuffer, 3)!= HAL_OK); // try to receive header
} }
if (xHigherPriorityTaskWoken) { if (xHigherPriorityTaskWoken) {

View file

@ -12,12 +12,12 @@
typedef enum { typedef enum {
XBEE_OK=0, XBEE_OK=0,
XBEE_CONFIG_ERROR, XBEE_CONFIG_ERROR=-1,
XBEE_AT_CMD_ERROR, XBEE_TX_ACK_ERROR=-2,
XBEE_RX_TIMEOUT, XBEE_RX_TIMEOUT=-3,
XBEE_RX_ERROR, XBEE_RX_ERROR=-4,
XBEE_TX_ERROR, XBEE_TX_ERROR=-5,
XBEE_INVALID_FRAME XBEE_INVALID_FRAME=-6
} XBEE_Status; } XBEE_Status;
#define XBEE_RX_PACKET_TYPE 0x90 #define XBEE_RX_PACKET_TYPE 0x90
@ -51,36 +51,11 @@ typedef enum {
typedef struct { typedef struct {
uint8_t type; uint8_t type;
} XBEE_GENERIC_FRAME; uint16_t source_addr;
char* data;
typedef struct { char ack;
uint8_t type; char modem_status;
uint64_t source_addr; } XBEE_INCOMING_FRAME;
uint8_t options;
uint8_t data_length;
char data[];
} XBEE_RX_PACKET_FRAME;
typedef struct {
uint8_t type;
uint8_t frame_id;
uint16_t at_cmd;
uint8_t status;
uint8_t data_length;
char data[];
} XBEE_AT_CMD_RESPONSE_FRAME;
typedef struct {
uint8_t type;
uint8_t frame_id;
uint8_t status;
uint8_t retry_count;
} XBEE_TX_STATUS_FRAME;
typedef struct {
uint8_t type;
uint8_t status;
} XBEE_MODEM_STATUS_FRAME;
void XBEE_Init(void); void XBEE_Init(void);
int XBEE_SendData(char* data, int length); int XBEE_SendData(char* data, int length);