mirror of
https://github.com/yoboujon/dumber.git
synced 2025-06-08 13:50:49 +02:00
remaniement des drivers xbee et commands
This commit is contained in:
parent
85bf7179df
commit
f319857e0d
10 changed files with 279 additions and 1454 deletions
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
|
@ -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;
|
||||
//}
|
||||
|
|
@ -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_ */
|
|
@ -63,21 +63,23 @@ typedef struct {
|
|||
char powerOffRequired;
|
||||
} APPLICATION_Infos;
|
||||
|
||||
APPLICATION_Infos systemInfos = {0};
|
||||
APPLICATION_Infos systemInfos = {0};
|
||||
|
||||
void APPLICATION_Init(void) {
|
||||
/* Init des messages box */
|
||||
MESSAGE_Init();
|
||||
MESSAGE_Init();
|
||||
|
||||
LEDS_Init();
|
||||
//LEDS_Tests();
|
||||
/* Init de l'afficheur */
|
||||
LEDS_Init();
|
||||
//LEDS_Tests();
|
||||
|
||||
//XBEE_Init();
|
||||
//BATTERIE_Init();
|
||||
//MOTEURS_Init();
|
||||
//SEQUENCEUR_Init();
|
||||
/* Init de la partie RF / reception des messages */
|
||||
XBEE_Init();
|
||||
//BATTERIE_Init();
|
||||
//MOTEURS_Init();
|
||||
//SEQUENCEUR_Init();
|
||||
|
||||
/*MOTEURS_Init();
|
||||
/*MOTEURS_Init();
|
||||
MOTEURS_Test();*/
|
||||
|
||||
/* Create the task without using any dynamic memory allocation. */
|
||||
|
@ -91,8 +93,7 @@ void APPLICATION_Init(void) {
|
|||
&xTaskApplicationMain); /* Variable to hold the task's data structure. */
|
||||
vTaskResume(xHandleApplicationMain);
|
||||
|
||||
/* Create the task without using any dynamic memory allocation. */
|
||||
|
||||
/* Create a periodic task without using any dynamic memory allocation. */
|
||||
xHandleTimerTimeout = xTimerCreateStatic(
|
||||
"Seq Timer",
|
||||
//pdMS_TO_TICKS(100),
|
||||
|
@ -103,8 +104,8 @@ void APPLICATION_Init(void) {
|
|||
&xBufferTimerTimeout);
|
||||
xTimerStart(xHandleTimerTimeout,0 );
|
||||
|
||||
APPLICATION_CntTimeout =0;
|
||||
APPLICATION_CntPowerOff=0;
|
||||
APPLICATION_CntTimeout =0;
|
||||
APPLICATION_CntPowerOff=0;
|
||||
}
|
||||
|
||||
void APPLICATION_MainThread(void* params) {
|
||||
|
|
|
@ -12,139 +12,81 @@
|
|||
|
||||
/* 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* decodedCmd;
|
||||
|
||||
if (cmdVerifyChecksum(cmd) != okANS)
|
||||
return CMD_DECODE_INVALID;
|
||||
else if (cmd[0] == moveCMD) {
|
||||
int32_t laps;
|
||||
uint16_t testReception = sscanf(cmd, "M=%li", &laps);
|
||||
switch (cmd[0])
|
||||
{
|
||||
case CMD_MOVE:
|
||||
decodedCmd = (CMD_Generic*)malloc(sizeof(CMD_Move));
|
||||
((CMD_Move*)decodedCmd)->distance = ((uint16_t)cmd[1]<<8) + (uint16_t)cmd[2];
|
||||
break;
|
||||
|
||||
if (testReception!=1) return CMD_DECODE_INVALID;
|
||||
else {
|
||||
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", °ree);
|
||||
case CMD_TURN:
|
||||
decodedCmd = (CMD_Generic*)malloc(sizeof(CMD_Turn));
|
||||
|
||||
if (testReception != 1) return CMD_DECODE_INVALID;
|
||||
else {
|
||||
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);
|
||||
((CMD_Turn*)decodedCmd)->turns = ((uint16_t)cmd[1]<<8) + (uint16_t)cmd[2];
|
||||
((CMD_Turn*)decodedCmd)->turns = ((CMD_Turn*)decodedCmd)->turns * 1.4;
|
||||
|
||||
if (testReception != 1) return CMD_DECODE_INVALID;
|
||||
else {
|
||||
decodedCmd=(CMD_Generic*)malloc(sizeof(CMD_SetMotor));
|
||||
((CMD_SetMotor*)decodedCmd)->type = moveCMD;
|
||||
((CMD_SetMotor*)decodedCmd)->motor_left= moteurG;
|
||||
((CMD_SetMotor*)decodedCmd)->motor_right= moteurD;
|
||||
}
|
||||
} else if ((cmd[0] == pingCMD) || (cmd[0] == resetCMD) || (cmd[0] == startWWatchDogCMD) || (cmd[0] == resetWatchdogCMD) ||
|
||||
(cmd[0] == getBatteryVoltageCMD) || (cmd[0] == getVersionCMD) || (cmd[0] == startWithoutWatchCMD) || (cmd[0] == busyStateCMD) ||
|
||||
(cmd[0] == testCMD) || (cmd[0] == debugCMD) || (cmd[0] == powerOffCMD)) {
|
||||
decodedCmd=(CMD_Generic*)malloc(sizeof(CMD_Generic));
|
||||
break;
|
||||
|
||||
case CMD_PING:
|
||||
case CMD_RESET:
|
||||
case CMD_START_WITHOUT_WATCHDOG:
|
||||
case CMD_START_WITH_WATCHDOG:
|
||||
case CMD_RESET_WATCHDOG:
|
||||
case CMD_GET_BATTERY:
|
||||
case CMD_GET_BUSY_STATE:
|
||||
case CMD_GET_VERSION:
|
||||
case CMD_TEST:
|
||||
case CMD_DEBUG:
|
||||
case CMD_POWER_OFF:
|
||||
decodedCmd = (CMD_Generic*)malloc(sizeof(CMD_Generic));
|
||||
decodedCmd->type = cmd[0];
|
||||
} else return CMD_DECODE_UNKNOWN;
|
||||
|
||||
default:
|
||||
decodedCmd = CMD_DECODE_UNKNOWN;
|
||||
}
|
||||
|
||||
return decodedCmd;
|
||||
}
|
||||
|
||||
void cmdSendAnswer(ANS_Type ans) {
|
||||
char cmdStr[4];
|
||||
cmdStr[0] = (char)ans;
|
||||
cmdStr[1] = (char)ans;
|
||||
cmdStr[2] = END_OF_CMD;
|
||||
cmdStr[3] = 0; // end of string
|
||||
XBEE_SendData(cmdStr, 3);
|
||||
void cmdSendAnswer(uint8_t ans) {
|
||||
ANS_Generic answer;
|
||||
|
||||
answer.ans = ans;
|
||||
XBEE_SendData((char*)&answer, sizeof (answer));
|
||||
}
|
||||
|
||||
void cmdSendBatteryLevel(char level) {
|
||||
char cmdStr[4];
|
||||
ANS_Battery answer;
|
||||
char localLevel=level;
|
||||
|
||||
if (localLevel<0) localLevel=0;
|
||||
else if (localLevel>2) localLevel=2;
|
||||
|
||||
cmdStr[0] = localLevel+'0';
|
||||
cmdStr[1] = localLevel+'0';
|
||||
cmdStr[2] = END_OF_CMD;
|
||||
cmdStr[3] = 0; // end of string
|
||||
XBEE_SendData(cmdStr, 3);
|
||||
answer.ans = ANS_OK;
|
||||
answer.bat_level = localLevel;
|
||||
|
||||
XBEE_SendData((char*)&answer, sizeof (answer));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -10,61 +10,71 @@
|
|||
|
||||
#include "application.h"
|
||||
|
||||
typedef enum {
|
||||
pingCMD = 'p',
|
||||
resetCMD = 'r',
|
||||
setMotorCMD = 'm',
|
||||
startWWatchDogCMD = 'W',
|
||||
resetWatchdogCMD = 'w',
|
||||
getBatteryVoltageCMD = 'v',
|
||||
getVersionCMD = 'V',
|
||||
startWithoutWatchCMD = 'u',
|
||||
moveCMD = 'M',
|
||||
turnCMD = 'T',
|
||||
busyStateCMD = 'b',
|
||||
testCMD = 't',
|
||||
debugCMD = 'a',
|
||||
powerOffCMD = 'z'
|
||||
} CMD_Type;
|
||||
#define CMD_PING 0x1
|
||||
#define CMD_RESET 0x2
|
||||
#define CMD_START_WITH_WATCHDOG 0x3
|
||||
#define CMD_RESET_WATCHDOG 0x4
|
||||
#define CMD_GET_BATTERY 0x5
|
||||
#define CMD_GET_VERSION 0x6
|
||||
#define CMD_START_WITHOUT_WATCHDOG 0x7
|
||||
#define CMD_MOVE 0x8
|
||||
#define CMD_TURN 0x9
|
||||
#define CMD_GET_BUSY_STATE 0xA
|
||||
#define CMD_TEST 0xB
|
||||
#define CMD_DEBUG 0xC
|
||||
#define CMD_POWER_OFF 0xD
|
||||
|
||||
typedef enum {
|
||||
okANS = 'O',
|
||||
errANS = 'E',
|
||||
unknownANS = 'C',
|
||||
batOK = '2',
|
||||
batLOW = '1',
|
||||
batEMPTY = '0'
|
||||
} ANS_Type;
|
||||
#define ANS_OK 0x80
|
||||
#define ANS_ERR 0x81
|
||||
#define ANS_UNKNOWN 0x82
|
||||
|
||||
#define END_OF_CMD '\r'
|
||||
#define ANS_BAT_OK 0x2
|
||||
#define ANS_BAT_LOW 0x1
|
||||
#define ANS_BAT_EMPTY 0x0
|
||||
|
||||
typedef struct {
|
||||
CMD_Type type;
|
||||
#define ANS_STATE_NOT_BUSY 0x0
|
||||
#define ANS_STATE_BUSY 0x1
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type;
|
||||
} CMD_Generic;
|
||||
|
||||
typedef struct {
|
||||
CMD_Type type;
|
||||
int32_t motor_left;
|
||||
int32_t motor_right;
|
||||
} CMD_SetMotor;
|
||||
|
||||
typedef struct {
|
||||
CMD_Type type;
|
||||
int32_t distance;
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type;
|
||||
int16_t distance;
|
||||
} CMD_Move;
|
||||
|
||||
typedef struct {
|
||||
CMD_Type type;
|
||||
int32_t turns;
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t type;
|
||||
int16_t turns;
|
||||
} 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_UNKNOWN ((CMD_Generic*)UINT32_MAX)
|
||||
|
||||
ANS_Type cmdIsValid(char* cmd);
|
||||
CMD_Generic* cmdDecode(char* cmd);
|
||||
void cmdSendAnswer(ANS_Type ans);
|
||||
void cmdSendAnswer(uint8_t ans);
|
||||
void cmdSendBatteryLevel(char level);
|
||||
void cmdSendVersion();
|
||||
void cmdBusyState(uint8_t state);
|
||||
|
||||
#endif /* INC_CMD_H_ */
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "cmsis_os.h"
|
||||
|
||||
#define SYSTEM_VERSION_STR "version 2.0\r"
|
||||
#define SYSTEM_VERSION 0x20
|
||||
|
||||
#define STACK_SIZE 0x100
|
||||
|
||||
|
|
|
@ -34,7 +34,11 @@ SemaphoreHandle_t xHandleSemaphoreRX = NULL;
|
|||
StaticSemaphore_t xSemaphoreRx;
|
||||
|
||||
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 ******/
|
||||
SemaphoreHandle_t xHandleSemaphoreTX = NULL;
|
||||
|
@ -50,11 +54,7 @@ void XBEE_Init(void) {
|
|||
xSemaphoreGive(xHandleSemaphoreTX);
|
||||
|
||||
rxBuffer=(uint8_t*)malloc(XBEE_RX_BUFFER_MAX_LENGTH);
|
||||
rxBufferIndex=0;
|
||||
|
||||
if(HAL_UART_Receive_IT(&hlpuart1, rxBuffer, 1)!= HAL_OK) {
|
||||
while(1);
|
||||
}
|
||||
rxWaitForACK = 0;
|
||||
}
|
||||
|
||||
/**** Support functions ****/
|
||||
|
@ -98,7 +98,7 @@ char* XBEE_EncodeWithEscapeChar(char* data, int length, int *encodedLength) {
|
|||
|
||||
for (char* p=encodedData; p< (encodedData + *encodedLength); p++) {
|
||||
if ((*data == (char)XBEE_API_ESCAPE_CHAR) || (*data == (char)XBEE_API_START_OF_FRAME) ||
|
||||
(*data == (char)XBEE_API_XOFF) ||(*data == (char)XBEE_API_XON)) {
|
||||
(*data == (char)XBEE_API_XOFF) ||(*data == (char)XBEE_API_XON)) {
|
||||
*p = (char) XBEE_API_ESCAPE_CHAR;
|
||||
p++;
|
||||
}
|
||||
|
@ -119,10 +119,10 @@ char* XBEE_EncodeWithEscapeChar(char* data, int length, int *encodedLength) {
|
|||
* \return new buffer allocated without escaped char
|
||||
*/
|
||||
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,
|
||||
// au cas où aucun caractere d'echappement ne serait present
|
||||
*length = encodedLength; // par defaut, on considére que les données brutes ont la même taille que
|
||||
// celles avec caractéres 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 caractère d'echappement ne serait present
|
||||
*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.
|
||||
|
||||
for (char* p=data; p< (data + encodedLength); p++) {
|
||||
if (*encodedData == (char)XBEE_API_ESCAPE_CHAR) {
|
||||
|
@ -185,95 +185,94 @@ char* XBEE_EncodeTransmissionFrame(char* data, int length, uint16_t destination,
|
|||
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
|
||||
*
|
||||
* \param frame pointer on complete frame
|
||||
* \param data pointer to raw data, with escape char removed
|
||||
* \param sender address of the sender
|
||||
* \return status of decoding: XBEE_OK if decoding is successfull, XBEE_INVALID_FRAME otherwise
|
||||
* \param raw_frame pointer on complete frame
|
||||
* \param incomingFrame pointer to processed frame, with escape char removed
|
||||
* \return status of decoding: XBEE_OK if decoding is successful, XBEE_INVALID_FRAME otherwise
|
||||
*/
|
||||
XBEE_Status XBEE_DecodeFrame(char* frame, char** data, uint16_t *sender) {
|
||||
uint8_t frame_type = (uint8_t)frame[3];
|
||||
uint16_t frame_length;
|
||||
XBEE_Status XBEE_DecodeFrame(char* rawFrame, XBEE_INCOMING_FRAME** incomingFrame) {
|
||||
uint8_t frame_type = (uint8_t)rawFrame[3];
|
||||
uint16_t rawFrameLength;
|
||||
uint8_t checksum;
|
||||
XBEE_Status status = XBEE_OK;
|
||||
int incomingDataLength = 0;
|
||||
|
||||
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 */
|
||||
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:
|
||||
*data = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_RX_PACKET_FRAME)+(frame_length-12)+1); // +1 for 0 ending in data frame
|
||||
memset((void*)*data, 0, sizeof(XBEE_RX_PACKET_FRAME)+(frame_length-12)+1);
|
||||
((XBEE_RX_PACKET_FRAME*)(*data))->type = frame_type;
|
||||
((XBEE_RX_PACKET_FRAME*)(*data))->data_length = frame_length-12;
|
||||
((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];
|
||||
/* verification du checksum */
|
||||
checksum =0;
|
||||
for (i=3; i<3+rawFrameLength+1; i++) {
|
||||
checksum += (uint8_t)rawFrame[i];
|
||||
}
|
||||
|
||||
for (i=0; i<((XBEE_RX_PACKET_FRAME*)(*data))->data_length; i++) {
|
||||
((XBEE_RX_PACKET_FRAME*)(*data))->data[i] =(char)frame[15+i];
|
||||
}
|
||||
if (checksum != 0xFF)
|
||||
return XBEE_INVALID_FRAME;
|
||||
|
||||
((XBEE_RX_PACKET_FRAME*)(*data))->data[((XBEE_RX_PACKET_FRAME*)(*data))->data_length]=0x0; // 0 ending frame
|
||||
*incomingFrame = (XBEE_INCOMING_FRAME*) malloc(sizeof(XBEE_INCOMING_FRAME)); /* Allocate a generic frame struct */
|
||||
(*incomingFrame)->type = frame_type;
|
||||
|
||||
break;
|
||||
case XBEE_MODEM_STATUS_TYPE:
|
||||
*data = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_MODEM_STATUS_FRAME));
|
||||
((XBEE_MODEM_STATUS_FRAME*)(*data))->type = frame_type;
|
||||
((XBEE_MODEM_STATUS_FRAME*)(*data))->status = frame[4];
|
||||
switch (frame_type) {
|
||||
case XBEE_RX_16BIT_PACKET_TYPE:
|
||||
/* Get source address */
|
||||
(*incomingFrame)->source_addr = (((uint16_t)rawFrame[4])<<8) + (uint16_t)rawFrame[5];
|
||||
(*incomingFrame)->data = XBEE_DecodeWithoutEscapeChar(&rawFrame[8], rawFrameLength-6, &incomingDataLength);
|
||||
(*incomingFrame)->ack = 0;
|
||||
break;
|
||||
|
||||
break;
|
||||
case XBEE_TX_STATUS_TYPE:
|
||||
case XBEE_EXTENDED_TX_STATUS_TYPE:
|
||||
*data = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_TX_STATUS_FRAME));
|
||||
((XBEE_TX_STATUS_FRAME*)(*data))->type = frame_type;
|
||||
((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];
|
||||
}
|
||||
case XBEE_MODEM_STATUS_TYPE:
|
||||
(*incomingFrame)->modem_status = rawFrame[4];
|
||||
(*incomingFrame)->data=0x0;
|
||||
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];
|
||||
case XBEE_TX_STATUS_TYPE:
|
||||
(*incomingFrame)->ack = rawFrame[5];
|
||||
(*incomingFrame)->data=0x0;
|
||||
break;
|
||||
|
||||
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:
|
||||
*data = (XBEE_GENERIC_FRAME*)malloc(sizeof(XBEE_GENERIC_FRAME));
|
||||
((XBEE_GENERIC_FRAME*)(*data))->type = frame_type;
|
||||
return XBEE_INVALID_FRAME;
|
||||
};
|
||||
case XBEE_EXTENDED_TX_STATUS_TYPE:
|
||||
(*incomingFrame)->ack = rawFrame[8];
|
||||
(*incomingFrame)->data=0x0;
|
||||
break;
|
||||
|
||||
return XBEE_OK;
|
||||
default:
|
||||
free (*incomingFrame);
|
||||
return XBEE_INVALID_FRAME;
|
||||
};
|
||||
} else status = XBEE_INVALID_FRAME;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**** 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 data_length;
|
||||
BaseType_t state;
|
||||
XBEE_INCOMING_FRAME* incomingFrame;
|
||||
|
||||
// Prevents successive calls to overlap
|
||||
state = xSemaphoreTake(xHandleSemaphoreTX, pdMS_TO_TICKS(XBEE_TX_SEMAPHORE_WAIT)); // wait max 500 ms (to avoid interlocking)
|
||||
|
@ -283,24 +282,44 @@ int XBEE_SendData(char* data, int length) {
|
|||
We should probably reset something in "else" branch */
|
||||
|
||||
/* TODO: stuff to do here for converting data into API frame */
|
||||
data_length = length;
|
||||
if ((txBuffer = (uint8_t*)malloc(length))!=NULL) {
|
||||
memcpy((void*)txBuffer, (void*) data, length);
|
||||
txBuffer = (uint8_t*)XBEE_EncodeWithEscapeChar(data, length, &data_length);
|
||||
|
||||
if(HAL_UART_Transmit_IT(&hlpuart1, txBuffer, data_length)!= HAL_OK)
|
||||
return -3;
|
||||
} else return -2;
|
||||
} else return -1;
|
||||
if (txBuffer!=NULL) {
|
||||
if (HAL_UART_Transmit_DMA(&hlpuart1, txBuffer, data_length)!= HAL_OK)
|
||||
return XBEE_TX_ERROR;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* DMA Interrupt request for transmission. Call when transmission is finished
|
||||
*
|
||||
* \param UartHandle not used
|
||||
*/
|
||||
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
/* Do stuff here */
|
||||
/* Free transmit buffer */
|
||||
free (txBuffer);
|
||||
|
||||
xSemaphoreGiveFromISR( xHandleSemaphoreTX, &xHigherPriorityTaskWoken );
|
||||
if (rxWaitForACK != 1) /* we are waiting for an acknowledge frame, so do not give semaphore yet */
|
||||
xSemaphoreGiveFromISR( xHandleSemaphoreTX, &xHigherPriorityTaskWoken );
|
||||
|
||||
/* If xHigherPriorityTaskWoken was set to true you
|
||||
we should yield. The actual macro used here is
|
||||
|
@ -309,30 +328,60 @@ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) {
|
|||
}
|
||||
|
||||
/***** Rx Part *****/
|
||||
|
||||
/**
|
||||
* Reception thread. Wait for incoming frame, process it and send message to application
|
||||
*
|
||||
* \param params not used
|
||||
*/
|
||||
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
|
||||
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) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
uint16_t frameLength;
|
||||
|
||||
if (rxBuffer[rxBufferIndex] == '\r') {
|
||||
rxBuffer[rxBufferIndex+1]=0; // add end of string
|
||||
MESSAGE_SendMailboxFromISR(APPLICATION_Mailbox, MSG_ID_XBEE_CMD, (QueueHandle_t)0x0, (void*)rxBuffer, &xHigherPriorityTaskWoken);
|
||||
if (rxPhase == XBEE_RX_PHASE_HEADER) { // we just received header part
|
||||
frameLength=XBEE_GetFrameLength(rxBuffer); /* Compute body part of the frame + checksum */
|
||||
|
||||
rxBuffer = malloc(XBEE_RX_BUFFER_MAX_LENGTH);
|
||||
rxBufferIndex=0;
|
||||
} else if (rxBufferIndex>=XBEE_RX_BUFFER_MAX_LENGTH-2) // prevent buffer overflow
|
||||
rxBufferIndex=0;
|
||||
else
|
||||
rxBufferIndex++;
|
||||
if (HAL_UART_Receive_DMA(&hlpuart1, rxBuffer+3, frameLength+1)== HAL_OK) {
|
||||
/* Reception of body part started successfully */
|
||||
rxPhase = XBEE_RX_PHASE_BODY;
|
||||
} else {
|
||||
/* Failed to start reception of body
|
||||
* 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) {
|
||||
while(1);
|
||||
rxPhase = XBEE_RX_PHASE_HEADER;
|
||||
while (HAL_UART_Receive_DMA(&hlpuart1, rxBuffer, 3)!= HAL_OK); // try to receive header
|
||||
}
|
||||
|
||||
if (xHigherPriorityTaskWoken) {
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
|
||||
typedef enum {
|
||||
XBEE_OK=0,
|
||||
XBEE_CONFIG_ERROR,
|
||||
XBEE_AT_CMD_ERROR,
|
||||
XBEE_RX_TIMEOUT,
|
||||
XBEE_RX_ERROR,
|
||||
XBEE_TX_ERROR,
|
||||
XBEE_INVALID_FRAME
|
||||
XBEE_CONFIG_ERROR=-1,
|
||||
XBEE_TX_ACK_ERROR=-2,
|
||||
XBEE_RX_TIMEOUT=-3,
|
||||
XBEE_RX_ERROR=-4,
|
||||
XBEE_TX_ERROR=-5,
|
||||
XBEE_INVALID_FRAME=-6
|
||||
} XBEE_Status;
|
||||
|
||||
#define XBEE_RX_PACKET_TYPE 0x90
|
||||
|
@ -50,37 +50,12 @@ typedef enum {
|
|||
#define XBEE_RX_OPTIONS_PAN_BROADCASTED 0x04
|
||||
|
||||
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;
|
||||
uint8_t type;
|
||||
uint16_t source_addr;
|
||||
char* data;
|
||||
char ack;
|
||||
char modem_status;
|
||||
} XBEE_INCOMING_FRAME;
|
||||
|
||||
void XBEE_Init(void);
|
||||
int XBEE_SendData(char* data, int length);
|
||||
|
|
Loading…
Add table
Reference in a new issue