AnsweredAssumed Answered

STM32L0 with BM70 bluetooth

Question asked by ENEDIS.ibrahim on Sep 5, 2016
Hello, I wish to communicate with a Bluetooth PICtail BM70 Microchip and ST STM32L031K6 nucleo in UAR.
But I can not seem to communicate and implement the system. I saw an example in explorrer 16.
http://microchip.wikidot.com/ble:bm70-app-example-stopwatch-demo

Is that BM70 and BM70 Configure which normally must change. Thank you for your reply and help.

bm70_configure.c
#include "stm32l0xx.h"                  // Device header
#include <string.h>
#include <..\MDK-ARM\Definition.h>
#include "usart.h"
#include <..\MDK-ARM\TIM_Soft.h>
#include <..\MDK-ARM\bm70.h>
 
//Static functions only for use in this file
static void cfLocalEnterTestMode(void);
static void cfLocalEnterAppMode(void);
static int8_t cfLocalAccessFlash(void);
static int8_t cfLocalEraseFlash(void);
static int8_t cfLocalEndAccess(void);
static int8_t cfLocalVerifyConfiguration(void);
static int8_t cfLocalReadFlash(uint16_t, uint8_t *);
static int8_t cfLocalProgramConfiguration(void);
static int8_t cfLocalWriteFlash(uint16_t, uint8_t *);
static int8_t cfLocalSendCommandAndCheckResponse(uint8_t *, uint8_t, uint8_t *, uint8_t);
int cmp_tab(uint8_t *tab1, uint8_t *tab2, uint8_t length);
 
uint8_t g_flag = 0;
 
static const struct FlashConfigurationLine configFlashTable[] = {
#ifdef USE_BM70
    #include "Ibra_BLE_EEPROM.txt"                                      //Use BM7x EEPROM Table Utility to create this file
#else
    #include "Ibra_BLE_EEPROM.txt"                                       //Use BM7x EEPROM Table Utility to create this file
#endif
};
 
//**********************************************************************************************************************
// Configure the BM70 module
// Read configuration flash, compare with correct settings, erase and write if necessary
 
int8_t cfConfigureModule(void) {
     
    if (sizeof(configFlashTable) != 9728) {                                     //Check that our array of configuration flash values is the correct size
        cfLocalEnterAppMode();                                                  //Reset the module and go into application mode
        return FALSE;                                                           //Failed to access configuration flash
    }
     
    cfLocalEnterTestMode();                                                     //Reset the module and put into test mode to access configuration flash
    //uartFlushRxBuffer();                                                        //Clear any junk out the buffer
    if (cfLocalAccessFlash() == FALSE) {                                        //Send command to access configuration flash and get response
        cfLocalEnterAppMode();                                                  //Reset the module and go into application mode
        return FALSE;                                                           //Failed to access configuration flash
    }
 
    if(cfLocalVerifyConfiguration() == TRUE) {                                  //See if configuration of the module is correct
        cfLocalEnterAppMode();                                                  //Reset the module and go into application mode
        return TRUE;                                                            //Have correct configuration so return
    }
 
    if (cfLocalEraseFlash() == FALSE) {                                         //Send command to erase configuration flash and get response
        cfLocalEnterAppMode();                                                  //Reset the module and go into application mode
        return FALSE;                                                           //Failed to erase configuration flash
    }
 
    if(cfLocalProgramConfiguration() == FALSE) {                                //Program the configuration flash
        cfLocalEnterAppMode();                                                  //Reset the module and go into application mode
        return TRUE;                                                            //Have correct configuration so return
    }
 
    if(cfLocalVerifyConfiguration() == FALSE) {                                 //See if configuration of the module is correct
        cfLocalEnterAppMode();                                                  //Reset the module and go into application mode
        return FALSE;                                                           //Failed to erase configuration flash
    }
 
    if (cfLocalEndAccess() == FALSE) {                                          //Send command to end access to configuration flash and get response
        cfLocalEnterAppMode();                                                  //Reset the module and go into application mode
        return FALSE;                                                           //Failed to end access
    }
    cfLocalEnterAppMode();                                                      //Reset the module and go into application mode
    return TRUE;
}
 
//**********************************************************************************************************************
// Reset module and put into test mode
 
static void cfLocalEnterTestMode(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7,GPIO_PIN_RESET);                                                     //Reset the module
    Delay(1);                                                           //Hold BM70 reset pin low for at least 1ms
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1,GPIO_PIN_RESET);                                                           //Go into test mode to read or write configuration flash
    Delay(1);                                                           //Hold BM70 reset pin low for at least 1ms
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7,GPIO_PIN_SET);                                                     //Release from reset
    Delay(100);                                                         //Wait at least 46ms for module to enter test mode
}
 
//**********************************************************************************************************************
// Reset module and put into application mode
 
static void cfLocalEnterAppMode(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7,GPIO_PIN_RESET);                                                      //Reset the module
    Delay(1);                                                           //Hold BM70 reset pin low for at least 1ms
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1,GPIO_PIN_SET);                                                           //Go into application mode
    Delay(1);                                                           //Hold BM70 reset pin low for at least 1ms
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7,GPIO_PIN_SET);                                                     //Release from reset
    Delay(200);                                                         //Wait at least 68ms for module to enter application mode
}
 
//**********************************************************************************************************************
// Send command to access configuration flash and check response
 
 
int8_t cfLocalAccessFlash(void)
{
        uint8_t packetOut_copy[17];
        uint8_t packetIn_copy[21];
    uint8_t packetOut[17] = {0x01,0x05,0x04,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //Access command packet
    uint8_t packetIn[21] = {0x04,0x0F,0x04,0x00,0x01,0x05,0x04,0x04,0x03,0x0B,0x00,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00};
        int i = 0, k = 0;
        for(i = 0; i < 17; i++)
        {
            packetOut_copy[i] = packetOut[i];
        }
        for(k = 0; k < 21; k++)
        {
            packetIn_copy[k] = packetIn[k];
        }
    return cfLocalSendCommandAndCheckResponse(packetOut_copy, 17, packetIn_copy, 21);
}
 
//**********************************************************************************************************************
// Send command to erase configuration flash and check response
 
int8_t cfLocalEraseFlash(void)
{
        uint8_t packetOut_copy[19];
        uint8_t packetIn_copy[27];
    uint8_t packetOut[19] = {0x02,0xFF,0x0F,0x0E,0x00,0x12,0x01,0x0A,0x00,0x03,0x00,0x00,0x40,0x03,0x00,0x00,0x20,0x00,0x00}; //Erase command packet
    uint8_t packetIn[27] = {0x04,0x13,0x05,0x01,0xFF,0x0F,0x01,0x00,0x02,0xFF,0x0F,0x0E,0x00,0x12,0x01,0x0A,0x00,0x00,0x00,0x00,0x40,0x03,0x00,0x00,0x20,0x00,0x00};
         
        int i = 0, k = 0;
        for(i = 0; i < 19; i++)
        {
            packetOut_copy[i] = packetOut[i];
        }
        for(k = 0; k < 27; k++)
        {
            packetIn_copy[k] = packetIn[k];
        }
    return cfLocalSendCommandAndCheckResponse(packetOut_copy, 19, packetIn_copy, 27);
}
 
 
//**********************************************************************************************************************
// Send command to end access to configuration flash and check response
 
int8_t cfLocalEndAccess(void)
{
        uint8_t packetOut_copy[7];
        uint8_t packetIn_copy[14];
    uint8_t packetOut[7] = {0x01,0x06,0x04,0x03,0xFF,0x0F,0x00};                //End access command packet
    uint8_t packetIn[14] = {0x04,0x0F,0x04,0x00,0x01,0x06,0x04,0x04,0x05,0x04,0x00,0xFF,0x0F,0x00};
         
        int i = 0, k = 0;
        for(i = 0; i < 7; i++)
        {
            packetOut_copy[i] = packetOut[i];
        }
        for(k = 0; k < 14; k++)
        {
            packetIn_copy[k] = packetIn[k];
        }
    return cfLocalSendCommandAndCheckResponse(packetOut_copy, 7, packetIn_copy, 14);
}
 
//**********************************************************************************************************************
// Read the entire configuration flash and verify against the correct configuration
 
static int8_t cfLocalVerifyConfiguration(void)
{
    uint16_t i, j, k;
    uint16_t address;
    uint8_t dataIn[128], *ptrDataIn;                                            //Packets contain 128 bytes of data (after the 19 byte preamble))
     
    address = 0;
    for(i = 0; i < 512; i += 8) {
        if (cfLocalReadFlash(address, dataIn) == FALSE) {                       //Send command to read configuration flash and get response
            return FALSE;                                                       //Failed to read configuration flash
        }
        ptrDataIn = &dataIn[0];
        for (j = 0; j < 8; j++) {
            for (k = 0; k < 16; k++) {
                if(*ptrDataIn++ != configFlashTable[i+j].data[k]) {
                    return FALSE;
                }
            }
        }
        address += 128;
    }
    return TRUE;
}
 
//**********************************************************************************************************************
// Read 128 bytes of configuration flash
 
uint8_t dataRead[400];
uint8_t dataRead_cpy[128];
extern uint8_t dataRead_save[400];
int8_t cfLocalReadFlash(uint16_t address, uint8_t *data)
{
    uint8_t j = 0, packetOut[19] = {0x02,0xFF,0x0F,0x0E,0x00,0x10,0x01,0x0A,0x00,0x03,0x00,0x00,0x40,0x03,0x00,0x80,0x00,0x00,0x00}; //Read command packet
    uint8_t packetIn[19] = {0x04,0x13,0x05,0x01,0xFF,0x0F,0x01,0x00,0x02,0xFF,0x0F,0x86,0x00,0x10,0x01,0x82,0x00,0x00,0x00};
         
             
    packetOut[11] = (uint8_t)address;                                           //Add lower address byte to base address low byte (0x00) already in packet
    packetOut[12] += (uint8_t)(address >> 8);                                   //Add upper address byte to base address high byte (0x40) already in packet
 
    if (cfLocalSendCommandAndCheckResponse(packetOut, 19, packetIn, 19) == FALSE) {
        return FALSE;                                                           //Did not get correct response
    }
        Delay(20);
            /*for (i = 0; i < 128; i++) {                                                 //Should receive 128 bytes following the preamble
        *data++ = uartReadRxBuffer();                                           //Read the byte and put it in the return buffer
    }*/    
      if(huart2.gState != HAL_UART_STATE_BUSY_RX)
        {
            g_flag = 2;
            HAL_UART_Receive_IT(&huart2,(uint8_t *)dataRead, (uint16_t) 400);
        }
        Delay(2);
        for(j = 0; j < 128; j++)
        {
            data[j] = dataRead_save[j]; 
            dataRead_cpy[j] = dataRead_save[j];         //Read the byte and put it in the return buffer
 
        }
        /*for(i = 0; i < 128; i++)
        {
            dataRead_copy[i] = data[i];
        }*/
        //k = i;
    return TRUE;                                                                //Got all 147 bytes
}
 
//**********************************************************************************************************************
// Write the entire configuration flash
 
int8_t cfLocalProgramConfiguration(void)
{
    uint16_t i, j, k;
    uint16_t address;
    uint8_t dataOut[128], *ptrDataOut;                                          //Packets contain 128 bytes of data (after the 19 byte preamble))
     
    address = 0;
    for(i = 0; i < 512; i += 8) {
        ptrDataOut = &dataOut[0];
        for (j = 0; j < 8; j++) {
            for (k = 0; k < 16; k++) {
                *ptrDataOut++ = configFlashTable[i+j].data[k];                  //Get a byte to program and add it to the data to write
            }
        }
        if (cfLocalWriteFlash(address, dataOut) == FALSE) {                     //Send command to write configuration flash and get response
            return FALSE;                                                       //Failed to read configuration flash
        }
        address += 128;
    }
    return TRUE;
}
 
//**********************************************************************************************************************
// Write 128 bytes of configuration flash
 
int8_t cfLocalWriteFlash(uint16_t address, uint8_t *data)
{
    uint8_t i, packetOut[147] = {0x02,0xFF,0x0F,0x8E,0x00,0x11,0x01,0x8A,0x00,0x03,0x00,0x00,0x40,0x03,0x00,0x80,0x00,0x00,0x00}; //Write command packet
    uint8_t packetIn[19] = {0x04,0x13,0x05,0x01,0xFF,0x0F,0x01,0x00,0x02,0xFF,0x0F,0x06,0x00,0x11,0x01,0x02,0x00,0x00,0x00};
     
    packetOut[11] = (uint8_t)address;                                           //Add lower address byte to base address low byte (0x00) already in packet
    packetOut[12] += (uint8_t)(address >> 8);                                   //Add upper address byte to base address high byte (0x40) already in packet
 
    for (i = 19; i < 147; i++) {                                                //Add data to outgoing packet with write command
        packetOut[i] = *data++;
    }
                     
    if (cfLocalSendCommandAndCheckResponse(packetOut, 147, packetIn, 19) == FALSE) {
        return FALSE;                                                           //Did not get correct response
    }
    return TRUE;
}
 
//**********************************************************************************************************************
// Send command and check response
 
int cmp_tab(uint8_t *tab1, uint8_t *tab2, uint8_t length)
{
    int i = 0;
    for(i = 0; i < length; i++)
    {
        if(tab1[i] != tab2[i])
            return 0;
    }
    return 1;
}
 
 
uint8_t incoming_data_copy1[30];
extern uint8_t input_save_copy[30];
 
uint8_t incoming_data_in[30];
uint8_t incoming_data[1];
uint8_t incomingLength_copy;
 
int8_t cfLocalSendCommandAndCheckResponse(uint8_t *outgoing, uint8_t outgoingLength, uint8_t *incoming, uint8_t incomingLength)
{
            uint8_t i = 0;
     
            incomingLength_copy = incomingLength;
            uint8_t incoming_data_in_copy[incomingLength_copy];
             
     
     
            if(huart2.gState != HAL_UART_STATE_BUSY_TX)
            {
                HAL_UART_Transmit_IT(&huart2,outgoing,outgoingLength);
            }          
            //memset(incoming_data,0,incomingLength);
            if(huart2.gState != HAL_UART_STATE_BUSY_RX)
            {
                g_flag = 1;
                HAL_UART_Receive_IT(&huart2, (uint8_t *)incoming_data_in, incomingLength);
            }
            HAL_Delay(20); 
            for(i = 0; i < incomingLength; i++)
            {
                incoming_data_in_copy[i] = input_save_copy[i];
            }
          if (cmp_tab(incoming,incoming_data_in_copy,incomingLength) == 0)
            {
                return FALSE;
            }
            return TRUE;
}

bm70.c
#include "stm32l0xx.h"                  // Device header
#include <string.h>
#include <stdio.h>
#include <..\MDK-ARM\Definition.h>
#include "usart.h"
#include <..\MDK-ARM\TIM_Soft.h>
#include <..\MDK-ARM\bm70.h>
#include <..\bm70_configure.h>
 
//Static functions only for use in this file
int8_t bmLocalSendCommandAndWaitResponse(enum CommandOpcode, uint8_t, uint8_t *);
static void bmLocalWriteCommandToBuffer(struct MessageOut *);
 
//Static variables  only for use in this file
static struct MessageIn messageInBuffer[SIZE_MSG_IN_BUFFER];                    //Buffer for incoming messages from module
static uint8_t msgInRdIndex, msgInWrIndex;                                      //Indexes to track additions and removals from message buffer
static struct MessageOut messageOutBuffer[SIZE_MSG_OUT_BUFFER];                 //Buffer for outgoing messages to module
static uint8_t msgOutRdIndex, msgOutWrIndex;                                    //Indexes to track additions and removals from message buffer
extern uint8_t g_flag;
//**********************************************************************************************************************
// Set up BM70 module
// Read EEPROM, compare with correct settings, write EEPROM if necessary
 
int8_t bmSetupModule(uint8_t *name, uint8_t *address)
{
    struct MessageIn messageIncoming;                                           //Structure to hold incoming message
    uint8_t i, correctVersionResponse[5] = {0, 1, 6, 1, 1};                     //Expected response to reading the version number
    uint8_t alternateVersionResponse[5] = {0, 1, 4, 1, 1};                      //Expected response to reading the version number
     
    msgInRdIndex = msgInWrIndex = 0;                                            //Initialize the incoming message buffer indices for later use in the bmIncomingTasks() function
    msgOutRdIndex = msgOutWrIndex = 0;                                          //Initialize the outgoing message buffer indices for later use in the bmOutgoingTasks() function
 
    if (cfConfigureModule() == FALSE) {                                         //Check that module is configured correctly and configure if not
        return FALSE;
    }
    //uartFlushRxBuffer();                                                        //Clear any junk out the buffer
    if (bmLocalSendCommandAndWaitResponse(ReadLocalInformation, 0, 0) == FALSE) { //Send command to read firmware version and MAC address
        return FALSE;
    }
    if (bmGetIncomingMessage(&messageIncoming) == TRUE) {                       //See if we have a message from the module
        if (messageIncoming.event == CommandComplete && messageIncoming.command == ReadLocalInformation) { //See if the message is the Command Complete response to the Read Local Information command
            for (i = 0; i < 5; i++) {
                if (messageIncoming.data[i] != correctVersionResponse[i]) {     //See if the module has the correct firmware version
                    if (messageIncoming.data[i] != alternateVersionResponse[i]) { //See if the module has the correct firmware version
                        return FALSE;
                    }
                }
            }
            for (i = 10; i > 4; i--) {                                          //Reverse the order of MAC address bytes
                *address++ = messageIncoming.data[i];                           //Save the MAC address
            }
        } //if (messageIncoming.event == CommandComplete &&
        else {                                                                  //Did not get the correct response to read local information command
            return FALSE;
        }
    } //if (bmGetIncomingMessage(&messageIncoming) == TRUE)
    else {                                                                      //Did not get a response to read local information command
        return FALSE;
    }
    if (bmLocalSendCommandAndWaitResponse(ReadDeviceName, 0, 0) == FALSE) {     //Send command to read the device name
        //uartIsDataAvailable();
        return FALSE;
    }
    if (bmGetIncomingMessage(&messageIncoming) == TRUE) {                       //See if we have a message from the module
        if (messageIncoming.event == CommandComplete &&                         //See if the message is the Command Complete response to the Read Device Name command
                messageIncoming.command == ReadDeviceName && messageIncoming.data[0] == 0) { //and returned Command Succeeded status
            for (i = 0; i < 7; i++) {                                           //Get the first six characters of the device name
                if (messageIncoming.data[i + 1] > 31) {                         //Check that the character is printable
                    name[i] = messageIncoming.data[i + 1];                      //Save the name character
                }
                else {
                    name[i] = 32;                                               //or use space character instead
                }
            }
        } //if (messageIncoming.event == CommandComplete &&
        else {                                                                  //Did not get the correct response to read device name command
            return FALSE;
        }
    } //if (bmGetIncomingMessage(&messageIncoming) == TRUE)
    else {                                                                      //Did not get a response to read device name command
        return FALSE;
    }
 
    return TRUE;                                                                //Successfully updated the settings in the radio
}
 
//**********************************************************************************************************************
//Only for initialization because code is blocking for 20ms. Sends a command and waits for a response to be received
 
int8_t bmLocalSendCommandAndWaitResponse(enum CommandOpcode command, uint8_t parameter, uint8_t *data)
{
     
        uint16_t counter = 0;
    bmSendCommand(command, parameter, data);                                    //Send command to read firmware version and MAC address                             
    while(counter < 50000)        //Get a timer to wait 50ms
    { //Loop for 50ms while sending command and receiving a response
        bmOutgoingTasks();                                                      //Handle outgoing packets
        if (bmIncomingTasks() == TRUE) //Handle incoming packets and see if we have a message from the module
                {                                       
           return TRUE;
                }
    counter++;
    }
    return FALSE;
}
 
//**********************************************************************************************************************
// Receive and parse incoming messages from BM7x module - return TRUE if new message decoded
uint8_t input_save[1];
extern uint8_t input_save_copy[1];
 
int8_t bmIncomingTasks(void)
{
    static enum StateIncomingPacket {FrameError, StartFrame, LengthHigh, LengthLow, EventOpcode, CommandOpcode, DataPayload, Checksum} stateIncomingPacket = StartFrame;
    static struct MessageIn *messageIncoming = &messageInBuffer[0];             //Pointer to the current message being written into the message buffer
    static uint8_t *ptrData = 0;                                                //Pointer to data payload from incoming packet (initialized to avoid compiler warning)
    static uint8_t checksum = 0;                                                //Checksum (initialized to avoid compiler warning)
    static uint16_t length = 0;                                                 //Data length in incoming packet (initialized to avoid compiler warning)
    uint8_t input;                                                              //Byte received from module
         
        //g_flag = 3;
        HAL_UART_Receive_IT(&huart2, (uint8_t *)&input_save[0],(uint16_t) 1);
        input_save_copy[0] = input_save[0];
    if(huart2.gState != HAL_UART_STATE_BUSY_RX){                                                //Check for new byte from BT module
         
            input = input_save_copy[0];                                             //Read the byte
             
        checksum += input;                                                      //Sum new byte for checksum
 
        switch (stateIncomingPacket) {                                          //Check which stage of packet reception we are in
            case FrameError:                                                    //Had a frame error (no start, invalid length, bad checksum)
                stateIncomingPacket = StartFrame;                               //Now look for start of frame
                //TODO should add delay to flush out potential bad data packet that might contain a start byte
                //For now just fall through to look for a new start of frame
                //break;
                 
            case StartFrame:                                                    //Are waiting to receive a start byte (0xaa)
                if (input == 0xaa) {                                            //Look for start byte
                    ptrData = &(messageIncoming->data[0]);                      //Initialize the pointer to the buffer for incoming data in the selected message
                    checksum = 0;                                               //Start new checksum calculation
                    stateIncomingPacket = LengthHigh;                           //Now look for high byte of packet length
                }
                break;
 
            case LengthHigh:                                                    //Receiving high byte of two byte length field
                length = input * 256;                                           //Save high byte of length
                stateIncomingPacket = LengthLow;                                //Now look for low byte of packet length
                break;
 
            case LengthLow:                                                     //Receiving low byte of two byte length field
                length += input;                                                //Save low byte of length
                if (length > 0 && length <= (SIZE_INCOMING_DATA + 1)) {         //Must be at least one byte for opcode but not more than buffer size
                    length--;                                                   //Reduce length by one to get data length without event opcode
                    stateIncomingPacket = EventOpcode;                          //Now look for event opcode
                }
                else {
                 //   SYS_DEBUG_BreakPoint();
                    stateIncomingPacket = FrameError;                           //Error because length is out of range
                }
                break;
 
            case EventOpcode:                                                   //Receiving event opcode
                messageIncoming->event = (enum EventOpcode) input;                                 //Save the event opcode
                if (input == NoEventOpcode) {                                   //See if the event was a response to a command
                }
                if (input == CommandComplete) {                                 //See if the event was a response to a command
                    if (length > 0) {                                           //See if there is another byte for the command opcode
                        length--;                                               //Reduce length by one to get data length without command opcode
                        stateIncomingPacket = CommandOpcode;                    //Now look for command opcode
                    }
                    else {
                        stateIncomingPacket = FrameError;                       //Error because length does not allow for command opcode
                    }
                }
                else {
                    if (length > 0) {                                           //See if there is data following the opcode
                        stateIncomingPacket = DataPayload;                      //Now look for data
                    }
                    else {
                        stateIncomingPacket = Checksum;                         //Now look for checksum because there is no data
                    }
                }
                messageIncoming->length = length;                               //Save data length, not counting byte(s) for opcode(s)
                break;
 
            case CommandOpcode:                                                 //Receiving command opcode
                messageIncoming->command = (enum CommandOpcode) input;                               //In that case save the command
                if (length > 0) {                                               //See if there is data following the opcode
                    stateIncomingPacket = DataPayload;                          //Now look for data
                }
                else {
                    stateIncomingPacket = Checksum;                             //Now look for checksum because there is no data
                }
                break;
 
            case DataPayload:                                                   //Receiving data payload
                *ptrData++ = input;                                             //Save received byte as data
                if (--length == 0) {                                            //Count down the bytes being received and see if done
                    stateIncomingPacket = Checksum;
                }
                break;
 
            case Checksum:                                                      //Receiving checksum
                if (checksum == 0) {                                            //Bytes should sum to multiple of 256
                    msgInWrIndex++;                                             //Fully received a new message, so increment message pointer to next message
                    if (msgInWrIndex >= SIZE_MSG_IN_BUFFER) {                   //Check if end of buffer
                        msgInWrIndex = 0;                                       //Wrap index to beginning
                    }
                    messageIncoming = &messageInBuffer[msgInWrIndex];           //Set pointer for next message
                    stateIncomingPacket = StartFrame;                           //Now wait for next start of frame
                    if (msgInWrIndex == msgInRdIndex) {                         //Check if we have overrun the buffer space
                        return ERROR;                                           //Return error
                    }
                    return TRUE;                                                //Return TRUE because we have received a new message
                }
                else {
                    stateIncomingPacket = FrameError;                           //Error because of incorrect checksum
                }
                break;
 
            default:
                stateIncomingPacket = FrameError;                               //Error because of invalid state
        }
 
    }
    return FALSE;                                                               //Did not get a complete packet
}
     
//**********************************************************************************************************************
// Get a message from the message buffer if available, return FALSE if no message in message buffer
 
int8_t bmGetIncomingMessage(struct MessageIn *message)
{
    if(msgInRdIndex != msgInWrIndex) {                                          //Check if message buffer is not empty
        *message = messageInBuffer[msgInRdIndex++];                             //Copy structure to return by reference and increment index (be careful, not all compilers will copy the content of the structure)
        if (msgInRdIndex >= SIZE_MSG_IN_BUFFER) {                               //Check if at end of buffer
            msgInRdIndex = 0;                                                   //then wrap the index to beginning
        }
        return TRUE;                                                            //Got a message so return TRUE
    }
    return FALSE;                                                               //Buffer empty so return FALSE    
}
 
//**********************************************************************************************************************
// Send a command to the BM7x module
 
int8_t bmSendCommand(enum CommandOpcode command, uint8_t parameter, uint8_t *data)
{
    const struct MessageOut commandReadLocalInfo =              {.length = 1, .command = (enum CommandOpcode)0x01}; //all commands have length h/l, opcode, and optional data
    const struct MessageOut commandReset =                      {.length = 1, .command = (enum CommandOpcode)0x02};
    const struct MessageOut commandReadStatus =                 {.length = 1, .command = (enum CommandOpcode)0x03};
    const struct MessageOut commandReadADC =                    {.length = 2, .command = (enum CommandOpcode)0x04, .data = {0x00}};
    const struct MessageOut commandIntoShutdownMode =           {.length = 1, .command = (enum CommandOpcode)0x05};
    const struct MessageOut commandReadDeviceName =             {.length = 1, .command = (enum CommandOpcode)0x07};
    const struct MessageOut commandEraseAllPaired =             {.length = 1, .command = (enum CommandOpcode)0x09};
    const struct MessageOut commandReadPairingMode =            {.length = 1, .command = (enum CommandOpcode)0x0a};
 
    const struct MessageOut commandLeaveStandbyMode =           {.length = 2, .command = (enum CommandOpcode)0x1c, .data = {0x00}};
    const struct MessageOut commandEnterStandbyMode =           {.length = 2, .command = (enum CommandOpcode)0x1c, .data = {0x01}};
    const struct MessageOut commandEnterStandbyModeTrusted =    {.length = 2, .command = (enum CommandOpcode)0x1c, .data = {0x02}};
    const struct MessageOut commandEnterStandbyModeBeacon =     {.length = 2, .command = (enum CommandOpcode)0x1c, .data = {0x81}};
    const struct MessageOut commandEnterStandbyModeBeaconTrusted =  {.length = 2, .command = (enum CommandOpcode)0x1c, .data = {0x82}};
 
    const struct MessageOut commandReadAllPrimaryService =          {.length = 1, .command = (enum CommandOpcode)0x3b};
    const struct MessageOut commandReadLocalSpecificPrimaryService ={.length = 17, .command = (enum CommandOpcode)0x3c, .data = {0x8e, 0x95, 0x98, 0xac, 0x06, 0x62, 0x11, 0xe6, 0xb5, 0x12, 0x3e, 0x1d, 0x05, 0xde, 0xfe, 0x78}};
 
    struct MessageOut commandPacket;                                            //Structure to hold command packet
    uint8_t *commandDataPtr;                                                    //Pointer to access the data in the packet
     
    switch (command) {                                                          //Check which command is being sent
        case NoCommandOpcode:                                                   //No command selected
            return FALSE;
            break;
             
        //General commands
        case ReadLocalInformation:                                              //Send command to read firmware version and MAC address
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandReadLocalInfo);
            break;
             
        case Reset:                                                             //Send command to reset the module
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandReset);
            break;
             
        case ReadStatus:                                                        //Send command to read module status
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandReadStatus);
            break;
             
        case ReadADCValue:                                                      //Send command to read ADC (TODO add code for ADC channel)
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandReadADC);
            break;
             
        case IntoShutdownMode:                                                  //Send command to enter shutdown mode
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandIntoShutdownMode);
            break;
 
        case DebugCommand:
            break;
 
        case ReadDeviceName:                                                    //Send command to read device name
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandReadDeviceName);
            break;
             
        case WriteDeviceName:
            if (parameter == 0 || parameter > 20) {                             //Limit name from 1 to 20 characters
                return FALSE;                                                   //Invalid length so return fail
            }
            commandPacket.command = (enum CommandOpcode) 0x08;                                       //Load the opcode for WriteDeviceName command
            commandPacket.length = parameter + 2;                               //Length must also include opcode, reserved byte
            commandDataPtr = &commandPacket.data[0];                            //Point to the data
            *commandDataPtr++ = 0;                                              //Copy reserved byte to data payload
            while (parameter-- > 0) {
                *commandDataPtr++ = *data++;                                    //Copy name to data payload
            }
            bmLocalWriteCommandToBuffer(&commandPacket);                        //Send the packet
            break;
             
        case EraseAllPairedDeviceInformation:                                   //Send command to erase all paired device information
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandEraseAllPaired);
            break;
             
        case ReadPairingModeSetting:                                            //Send command to read pairing mode setting
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandReadPairingMode);
            break;
             
        case WritePairingModeSetting:
        case ReadAllPairedDeviceInformation:
        case DeletePairedDevice:
        case DitalIOControl:
        case PWMControl:
        //GAP commands   
        case ReadRSSIValue:
        case WriteAdvertisingData:
        case WriteScanResultData:
        case SetAdvertisingParameter:
        case SetScanParameter:
        case SetScanEnable:
        case LeCreateConnection:
        case LeCreateConnectionCancel:
        case ConnectionParameterUpdateRequest:
        case Disconnect:
            return FALSE;
            break;
 
        case SetAdvertisingEnable:
            switch (parameter) {
                case LeaveStandbyMode:                                          //Leave standby mode
                    bmLocalWriteCommandToBuffer((struct MessageOut *)&commandLeaveStandbyMode); //Send command to leave standby mode
                    break;
                case EnterStandbyMode:                                          //Enter standby mode (starts advertising))
                    bmLocalWriteCommandToBuffer((struct MessageOut *)&commandEnterStandbyMode);
                    break;
                case EnterStandbyModeForTrusted:                                //Enter standby mode only connectable to trusted device
                    bmLocalWriteCommandToBuffer((struct MessageOut *)&commandEnterStandbyModeTrusted);
                    break;
                case EnterStandbyModeWithBeacon:                                //Enter standby mode with beacon enabled
                    bmLocalWriteCommandToBuffer((struct MessageOut *)&commandEnterStandbyModeBeacon);
                    break;
                case EnterStandbyModeWithBeaconForTrusted:                      //Enter standby mode  with beacon enabled and only connectable to trusted device
                    bmLocalWriteCommandToBuffer((struct MessageOut *)&commandEnterStandbyModeBeaconTrusted);
                    break;
                default:                                                        //Invalid setting
                    return ERROR;
            }
            break;
        case ReadRemoteDeviceName:
        //GATT Client commands   
        case DiscoverAllPrimaryServices:
        case DiscoverSpecificPrimaryServiceCharacteristics:
        case ReadCharacteristicValue:
        case ReadUsingCharacteristicUUID:
        case WriteCharacteristicValue:
        case EnableTransparent:
            break;
        //GATT Server commands   
        case SendCharacteristicValue:
            if (parameter == 0 || parameter > 20) {                             //Characteristic value must be 1 to 20 bytes
                return FALSE;                                                   //Invalid length so return fail
            }
            parameter += 4;                                                    
            commandPacket.command = (enum CommandOpcode) 0x38;                                       //Load the opcode for SendCharacteristicValue command
            commandPacket.length = parameter;                                   //Length must also include opcode, connection handle and char value handle
            commandDataPtr = &commandPacket.data[0];                            //Point to the data
            while (parameter-- > 0) {
                *commandDataPtr++ = *data++;                                    //Copy connection handle, char value handle, and char value data
            }
            bmLocalWriteCommandToBuffer(&commandPacket);                        //Send the packet
            break;
             
        case UpdateCharacteristicValue:
        case ReadLocalCharacteristicValue:
        case ReadLocalAllPrimaryService:                                        //Read all local services
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandReadAllPrimaryService);
            break;
        case ReadLocalSpecificPrimaryService:                                   //Read a specific (by UUIID) local service
            bmLocalWriteCommandToBuffer((struct MessageOut *)&commandReadLocalSpecificPrimaryService);
            break;
             
        //Transparent service command
        case SendTransparentData:
        //Pairing commands   
        case PasskeyEntryResponse:
        case UserConfirmResponse:
        case PairingRequest:
        //Configure mode command
        case LeaveConfigureMode:
        default:
            return FALSE;
    }
    return TRUE;
}
 
 
//**********************************************************************************************************************
// Copy a command to the output buffer so it can be sent to the module by bmOutgoingTasks()
 
static void bmLocalWriteCommandToBuffer(struct MessageOut *msg)
{
    messageOutBuffer[msgOutWrIndex++] = *msg;                                   //Copy structure and increment index (be careful, not all compilers will copy the content of the structure)
    if (msgOutWrIndex >= SIZE_MSG_OUT_BUFFER) {                                 //Check if end of buffer
        msgOutWrIndex = 0;                                                      //Wrap index to beginning
    }
    if (msgOutWrIndex == msgOutRdIndex) {                                       //Check if we have overrun the buffer space
        //return ERROR;                                                         //Return error
    }
}
 
 
//**********************************************************************************************************************
// Send any messages queued in the send buffer
 
int8_t bmOutgoingTasks(void)
{
    static enum StateOutgoingPacket {OutgoingIdle, OutgoingRxIndLow, OutgoingTransmit, OutgoingRxIndHigh} stateOutgoingPacket = OutgoingIdle;
    uint16_t length;
    uint8_t *data, temp, checksum = 0;                                          //Initial value of checksum
 
    switch (stateOutgoingPacket) {
        case OutgoingIdle:                                                      //Idle, so keep checking for a new outgoing message
            if(msgOutRdIndex != msgOutWrIndex) {                                //Check if message buffer is not empty
               // BLE_RX_IND_PIN = 0;                                             //Indicate that we are going to transmit so module can come out of power saving
                                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0,GPIO_PIN_RESET);
                stateOutgoingPacket = OutgoingRxIndLow;                         //Now wait for 2ms for module to wake up
            }
            break;
             
        case OutgoingRxIndLow:                                                  //Waiting for time since RX_IND pin went low so keep checking timer
                length = messageOutBuffer[msgOutRdIndex].length;
                if (length > 0 && length < SIZE_OUTGOING_DATA) {                //Check that length is within bounds
                    //uartWriteTxBuffer(0xaa);                                    //Load start byte into the transmit buffer
                                        HAL_UART_Transmit_IT(&huart2,(uint8_t *)0xaa,1);
                    temp = (uint8_t)(length >> 8);                              //Calculate high byte of length
                    //uartWriteTxBuffer(temp);                                    //Load high byte of length into the transmit buffer
                                        HAL_UART_Transmit_IT(&huart2,(uint8_t *)&temp,1);
                    checksum -= temp;                                           //Do running checksum calculation
                    temp = (uint8_t)(length & 0x00ff);                          //Calculate low byte of length
                    //uartWriteTxBuffer(temp);                                    //Load low byte of length into the transmit buffer
                                        HAL_UART_Transmit_IT(&huart2,(uint8_t *)&temp,(uint16_t)1);
                    checksum -= temp;                                           //Do running checksum calculation
                    temp = messageOutBuffer[msgOutRdIndex].command;
                    //uartWriteTxBuffer(temp);                                    //Load opcode into the transmit buffer
                                        HAL_UART_Transmit_IT(&huart2,(uint8_t *)&temp,(uint16_t)1);
                    checksum -= temp;                                           //Do running checksum calculation
                    data = &messageOutBuffer[msgOutRdIndex].data[0];            //Load pointer to data
                    while (--length > 0) {
                        //uartWriteTxBuffer(*data);                               //Load data into the transmit buffer                                         
                                                HAL_UART_Transmit_IT(&huart2,(uint8_t *)&data,1);
                        checksum -= *data++;                                    //Do running checksum calculation
                    }
                    //uartWriteTxBuffer(checksum);                                //Load the checksum
                                        HAL_UART_Transmit_IT(&huart2,(uint8_t *)&checksum,(uint16_t)sizeof(checksum));
                 //   uartStartTransmitData();                                    //Start transmitting the bytes
                }
                if (msgOutRdIndex++ >= SIZE_MSG_OUT_BUFFER) {                   //Increment read index and check if at end of buffer
                    msgOutRdIndex = 0;                                          //then wrap the index to beginning
                }
                stateOutgoingPacket = OutgoingTransmit;
            break;
             
        case OutgoingTransmit:
              //  BLE_RX_IND_PIN = 1;                                             //Indicate done transmitting, module can go into power saving mode
                                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0,GPIO_PIN_SET);
                stateOutgoingPacket = OutgoingIdle;                             //Back to idle state
            break;
             
        default:
            stateOutgoingPacket = OutgoingIdle;                                 //Back to idle state
            break;
    }
     
    return TRUE;
}

 

Outcomes