Bluetooth - some first steps
응답
15. 7. 27 오후 12:02
As indeed there are several threads and requests about bluetooth, I'll give a short overview about my first steps and pitfalls.

My starting point was the Workbench Built-In Example ADT_bleAccelData.
Important in this demo:
- The XDK stops sending data periodically when not connected - and after starting, the device is not yet connected. So a manual override function was implemented (s. below)
- The READ-characteristic (here 5303) sends only data after initializing the device: send "0x00100001" to the WRITE characteristic (here 5302), both of service 5301 (here)
- I tested all this with a third-party bluetooth Android app. "BLE Tool" (from "Action+") did work for me, as it also allows writing to characteristics.

The demo has some interaction with the XDK via console input. I (crudely, I know) added this in the function "ADT_interruptHandling" 's switch set:

    case 'a':
        adtBleAccelDataTransmit;
        printf("Send accel data once"\r\n");
        break;

This calls the function to read out accel data and send it over bluetooth once, after typing the single letter 'a' to the console. I later changed this to using the XDK button1, based on the intructions from the "simple compass" thread, and added LED confirmation of the acceleration's dominant axis, but this is not part of this post.

In order to restart the timer after manual triggering the function, I added this to the end of "adtBleAccelDataTransmit":

    else
    {
        /* re-set the flag */
        bleTransmitStatus = ADT_NUMBER_ONE;
        /* Start the Accel data transmission timer */
        timerReturnVal = OS_timerStart(ADT_bleTransmitTimerHandle,
            ADT_NUMBER_ONE);
        /* BLE timer start fail case */
        if (OS_ERR_NOT_ENOUGH_MEMORY == timerReturnVal)
        {
            DBG_FAIL(
                "This software timer was not started, Due to Insufficient heap memory");
        }
    }

Now at least I can initialize the connection with a WRITE of "0x00100001" to the WRITE characteristic, trigger the first accel readout and data transmission by entering "a" into the console and have a periodic transmission afterwards to the connected device (in my case BLE tool =)

Next steps (optimistic approach ;):
  • Eliminate the need to initialize the connection via the WRITE characteristic
  • Define my own characteristics
Any comments and help appreciated =)

 
0 (0 투표)
Bluetooth - some first steps
응답
15. 7. 29 오전 7:25 as a reply to T. Pirk.
Hi tpirk,

this looks like a helpful example. 

While code sharing functionalities are currently not availble in the current state of the forum, I'd like to encourage you to share your example on here as soon as we have such functionalities in here!

Great work! Keep on posting.

- Florian
0 (0 투표)
Bluetooth - some first steps
응답
15. 7. 29 오전 9:27 as a reply to Florian Harr.
Hi tpirk,

Thank you for the effort.
please keep updating your findings. it will be very helpful for us here!

- Arash
0 (0 투표)
Bluetooth - some first steps
응답
15. 7. 30 오전 9:11 as a reply to Arash Eftekhar.
Hi tpirk,

thank you for your interessting example. I tried to build it up like you but reaches to some problems. Can you please have a look through:
I understood, that there are 5301, 5302, 5302 services.
Your wrote:
"The READ-characteristic (here 5303) sends only data after initializing the device: send "0x00100001" to the WRITE characteristic (here 5302), both of service 5301 (here)"
I would like to trigger the XDK with an input to send data. I dont't mind if its an 'a' or the button because it's the same way.
I didn't unterstand how you are doing this. How can I reach the switch/case function where the 'a' is captured? I understood your code:
case 'a':
        adtBleAccelDataTransmit;              //calls the function for send accel-data once
        printf("Send accel data once"\r\n"); //output on console
        break;


n Kornau
0 (0 투표)
Bluetooth - some first steps
응답
15. 7. 30 오전 10:57 as a reply to Nils Kornau.
Hi,

I used the function under case 'a' with giving a useless pointer.

Then the acc-data was send and once I got it inside the BLE Tool under the service read (5303) with "start notify".
But after that it doesn't work again. Any idea?


How did you include your button?

- kornau
0 (0 투표)
Bluetooth - some first steps
응답
15. 7. 30 오후 12:35 as a reply to Nils Kornau.
Hi Kornau,
here's my full disclosure ;)
I hope this helps, as I'll be off on holidays for ~3 weeks from now.

Additional header files:

#include "led.h"    // 21.7.15 Pk for LED / Button-Support
#include "button.h"    // 21.7.15 Pk for LED / Button-Support
#include "xdk_board.h"    // 21.7.15 Pk for LED / Button-Support

Local variables:

static LED_handle_tp HMI_redLedHandle = (LED_handle_tp) NULL; /**< variable to store red led handle */
static LED_handle_tp HMI_yellowLedHandle = (LED_handle_tp) NULL; /**< variable to store yellow led handle */
static LED_handle_tp HMI_orangeLedHandle = (LED_handle_tp) NULL; /**< variable to store orange led handle */
static BUTTON_handle_tp HMI_Button1Handle = (BUTTON_handle_tp) NULL; /**< variable to store button 1 handle */
static BUTTON_handle_tp HMI_Button2Handle = (BUTTON_handle_tp) NULL; /**< variable to store button 2 handle */

! Please add the declaration for the following function also in ADT_bleAccelData_ch.h

/** The function to handle the status of ButtonII (switch normal - yellow alert - red alert - normal)
 *
 * @brief Sets static global variable about alert status
 *
 * @param[in] pvParameters Rtos task should be defined with the type void *(as argument)
 */
static void adtHandleButtonStatus(void *handle, uint32_t userParameter)
{
    switch (userParameter)
    {
    /*  Button 1 press/release  */
    case HMI_CALLBACK_PARAMETER_PB1:
        if (BUTTON_isPressed(handle))
        {
            uint8_t returnValue = HMI_ZERO_VALUE;
            returnValue += LED_setState(HMI_redLedHandle, LED_SET_ON);
            returnValue += LED_setState(HMI_orangeLedHandle, LED_SET_OFF);
            returnValue += LED_setState(HMI_yellowLedHandle, LED_SET_OFF);
            if (returnValue == HMI_ZERO_VALUE)
            {
                printf("PB1 pressed\n\r");
            }
            else
            {
                printf("PB1 pressed (LED FAIL)\n\r");
            }
            // Call data transmit
            adtBleAccelDataTransmit((uint32_t) 0);
        }
        break;

        /* Button 2 press/release */
    case HMI_CALLBACK_PARAMETER_PB2:
        if (BUTTON_isPressed(handle))
        {
            uint8_t returnValue = HMI_ZERO_VALUE;
            returnValue += LED_setState(HMI_redLedHandle, LED_SET_OFF);
            returnValue += LED_setState(HMI_orangeLedHandle, LED_SET_ON);
            returnValue += LED_setState(HMI_yellowLedHandle, LED_SET_OFF);
            if (returnValue == HMI_ZERO_VALUE)
            {
                printf("PB2 pressed\n\r");
            }
            else
            {
                printf("PB2 pressed (LED FAIL)\n\r");
            }
//            adtBleAccelDataTransmit((uint32_t) 0); // Disabled to allow visual LED control of button status
        }
        break;
    default:
        printf("Button not available \n\r");
        break;
    }

}

Visual indication of maximum acceleration axis (and generate random value from accel for other functionality): Full adtBleAccelDataTransmit function

 static void adtBleAccelDataTransmit(void *pvParameters)
{
    UNUSED_PARAMETER(pvParameters);

    /* return value for BLE SendData */
    BleStatus bleSendReturn;

    sensor_errorType_t advancedApiRetValue = SENSOR_ERROR;

    /* Return value for software timer */
    int8_t timerReturnVal;

    /* buffer for accel data receive function */
    uint8_t accelDataRec[ADT_ACCEL_RECEIVELENGTH] = { 0 };

    /** structure variable to hold the accel raw data*/
    accelerometer_xyzData_t getaccelData =
            { INT32_C(0), INT32_C(0), INT32_C(0) };

/* Max buffer for acceleration values */
    int32_t MaxAcc = 0;

    /* Random value from acceleration */
    uint32_t m_w;
    uint32_t m_z;
    uint32_t AccRnd;

    /*get accel data*/
    advancedApiRetValue = accelerometerReadXyzLsbValue(
            xdkAccelerometers_BMA280_Handle, &getaccelData);

    if (advancedApiRetValue == SENSOR_SUCCESS)
    {
        // Get max absolute accel data and set MaxAcc: x=1, y=2, z=3
        MaxAcc = labs(getaccelData.xAxisData) > labs(getaccelData.yAxisData) ? labs(getaccelData.xAxisData) : -labs(getaccelData.yAxisData);
        MaxAcc = labs(getaccelData.zAxisData) > labs(MaxAcc) ? 3 : MaxAcc >= 0 ? 1 : 2;
        printf("MaxAcc: %ld\n\r", (long int) MaxAcc);

        // Get Random # from Acceleration Readout (from Wikipedia: https://en.wikipedia.org/wiki/Random_number_generation)
        m_w = labs(getaccelData.xAxisData * getaccelData.zAxisData) + labs(getaccelData.yAxisData);
        m_z = labs(getaccelData.yAxisData * getaccelData.zAxisData) + labs(getaccelData.xAxisData);
        m_z = 36969 * (m_z & 65535) + (m_z >> 16);
        m_w = 18000 * (m_w & 65535) + (m_w >> 16);
        AccRnd = (m_z << 16) + m_w;  /* 32-bit result */
        AccRnd = (uint32_t) ((double)AccRnd/4294967295 * 200);
        printf("Accelerometer Random: %lu\n\r", (long int) AccRnd);

        // switch LED on according to max accel: x=RED, y=ORANGE, z=YELLOW.
        // MaxAcc <1 or >3 --> all LED on
        switch (MaxAcc)
        {
        case 1:
            LED_setState(HMI_redLedHandle, LED_SET_ON);
            LED_setState(HMI_orangeLedHandle, LED_SET_OFF);
            LED_setState(HMI_yellowLedHandle, LED_SET_OFF);
            break;
        case 2:
            LED_setState(HMI_redLedHandle, LED_SET_OFF);
            LED_setState(HMI_orangeLedHandle, LED_SET_ON);
            LED_setState(HMI_yellowLedHandle, LED_SET_OFF);
            break;
        case 3:
            LED_setState(HMI_redLedHandle, LED_SET_OFF);
            LED_setState(HMI_orangeLedHandle, LED_SET_OFF);
            LED_setState(HMI_yellowLedHandle, LED_SET_ON);
            break;
        default: LED_setState(HMI_redLedHandle, LED_SET_ON);
            LED_setState(HMI_orangeLedHandle, LED_SET_ON);
            LED_setState(HMI_yellowLedHandle, LED_SET_ON);
            break;
        }
        printf("BMA280 Accel Raw Data : (x =%ld, y =%ld, z =%ld)\n\r",
                (long int) getaccelData.xAxisData, (long int) getaccelData.yAxisData, (long int) getaccelData.zAxisData);
    }
    else
    {
        printf("BMA280 XYZ Data read FAILED\n\r");
    }
    /*Transmitting the Accel value into target device via Alpwise DataExchange service */
    bleSendReturn = BLEALPWDATAEXCHANGE_SERVER_SendData(ADT_BleConnectionHandle,
        (uint8_t*) accelDataRec, ADT_BLETRANSMITLENGTH);

    /*Device Disconnect and data are discarded by Alphwise DataExchange Service */
    if (bleSendReturn == BLESTATUS_FAILED)
    {

        printf("BLE send FAIL\n\r");

// 29-7-15 Pk: Disabled transmission stop to avoid manual interaction after connection loss
        /* clearing the flag */
//        bleTransmitStatus = ADT_NUMBER_ZERO;

        /* Terminating the Accel data transmission timer */
//        timerReturnVal = OS_timerStop(ADT_bleTransmitTimerHandle, ADT_NUMBER_ZERO);

        /* BLE timer stop fail case */
/*        if (OS_ERR_NOT_ENOUGH_MEMORY == timerReturnVal)
        {
            DBG_FAIL(
                "This software timer was not stopped, Due to Insufficient heap memory");
        }
*/
    }
    else
    {

        /* re-set the flag */
        bleTransmitStatus = ADT_NUMBER_ONE;
        ID++;

        /* Start the Accel data transmission timer */
        timerReturnVal = OS_timerStart(ADT_bleTransmitTimerHandle,
            ADT_NUMBER_ONE);

        /* BLE timer start fail case */
        if (OS_ERR_NOT_ENOUGH_MEMORY == timerReturnVal)
        {
            DBG_FAIL(
                "This software timer was not started, Due to Insufficient heap memory");
        }
    }

ADT_init first lines:

extern void ADT_init(void)
{

    /* return value for BLE stack configuration */
    BleStatus appInitReturn = BLESTATUS_FAILED;

    BLE_notification_t configParams;

    BLE_returnStatus_t returnBLEValue;

    BUTTON_errorTypes_t returnSetButtonCallback;

    /* return value for BLE task create */
    int8_t appTaskInitReturn = OS_ERR_NOT_ENOUGH_MEMORY;
    int8_t appTimerInitReturn;

    sensor_errorType_t advancedApiRetValue = SENSOR_ERROR;
    BUTTON_errorTypes_t buttonReturn = BUTTON_ERROR_INVALID_PARAMETER;

    /* register LEDs and BUTTONs */
    HMI_redLedHandle = LED_create(gpioRedLed_Handle, GPIO_STATE_OFF);
    HMI_orangeLedHandle = LED_create(gpioOrangeLed_Handle, GPIO_STATE_OFF);
    HMI_yellowLedHandle = LED_create(gpioYellowLed_Handle, GPIO_STATE_OFF);

    HMI_Button1Handle = BUTTON_create(gpioButton1_Handle,     GPIO_STATE_OFF);
    if (HMI_Button1Handle != NULL)
    {
        HMI_Button2Handle = BUTTON_create(gpioButton2_Handle,     GPIO_STATE_OFF);
    }
    if (HMI_Button2Handle != NULL)
    {
        printf("Button creation SUCCESS\n\r");
    }

    buttonReturn = BUTTON_enable(HMI_Button1Handle);
    if (buttonReturn == BUTTON_ERROR_OK)
    {
        buttonReturn = BUTTON_enable(HMI_Button2Handle);
    }
    if (buttonReturn == BUTTON_ERROR_OK)
    {
        printf("Button enable SUCCESS\n\r");
    }

    /* Set callback = adtBleAccelDataTransmit */
    printf("Button Callback ...\n\r");
    returnSetButtonCallback = BUTTON_setCallback(HMI_Button1Handle, (void *) adtHandleButtonStatus, HMI_CALLBACK_PARAMETER_PB1);
    if (returnSetButtonCallback == BUTTON_ERROR_OK)
    {
        returnSetButtonCallback = BUTTON_setCallback(HMI_Button2Handle, (void *) adtHandleButtonStatus, HMI_CALLBACK_PARAMETER_PB2);;
    }
    if (returnSetButtonCallback == BUTTON_ERROR_OK)
    {
        printf("Button Callback creation SUCCESS\n\r");
    }
    else
    {
        printf("Button Callback creation FAILED\n\r");
    }

... USB ISR registration, etc. ...
... and end of my ADT_init function

       /* create timer task to get and transmit accel data via BLE for every one second automatically*/
        printf("Timer creation...\n\r");
        ADT_bleTransmitTimerHandle = OS_timerCreate((const int8_t *) "bleAccelDataTransmit", 10000, OS_AUTORELOAD_ON, NULL, adtBleAccelDataTransmit);
        if (ADT_bleTransmitTimerHandle != NULL)
        {
            printf("Timer creation SUCCESS\n\r");
            appTimerInitReturn = OS_timerStart(ADT_bleTransmitTimerHandle, 100);
            if (appTimerInitReturn == OS_ERR_NO_ERROR)
            {
                printf("Timer started SUCCESS\n\r");
            }
            else
            {
                printf("Timer started FAIL\n\r");
            }
        }
        else
        {
            printf("Timer creation FAILED\n\r");
        }
    }
}





 
0 (0 투표)
Bluetooth - some first steps
응답
15. 7. 30 오후 12:43 as a reply to T. Pirk.
Hi Kornau,
... I guess the one time BLE shot you mention in your post is due to the standard timer disabling when no ble connection is detected. Also, after every new connection, you have to re-send 0x00100001 (acceleration sensor selection) to WRITE characteristic 5302, at least in my experience =) If you figure out how to avoid that, I'd be glad =)
Best,
Tjalf
 
0 (0 투표)
Bluetooth - some first steps
응답
15. 8. 3 오전 11:16 as a reply to T. Pirk.
Hi tpirk,

concerning to the 5302-characteristic:

My college next to me is developing an application. After I send data from the XDK with BLE he wrote an App to connect and receive the data. The connection doesn't neet any sending from 0x00100001 to be able to listen. Maybe it's one of the differences between iOS and Android (the connection I described is running on iOS whether I am using BLE Tool on Android).

Regards,
-nils
 
0 (0 투표)
Bluetooth - some first steps
응답
15. 10. 21 오후 5:28 as a reply to Nils Kornau.
Hello everyone,

             I wanted to give more input on bluetooth + android support. I got this demo to work really well by setting 5303's descriptor of 0x2902 to ENABLE_NOTIFICATION_VALUE (after succesfull connection of course). After this I had the XDK start sending data and it would give a constant refresh. 

I only have to write to the write characteristic on the first boot of the XDK. After I write to it once I can disconnect and reconnect and skip that step. 

I hope this information helped. 


Travis Hunt

 
0 (0 투표)
Bluetooth - some first steps
응답
15. 10. 27 오후 1:02 as a reply to Travis Hunt.
Travis,

this sounds great. 

Could you provide us with the code you've been using?

- Florian
0 (0 투표)
Bluetooth - some first steps
응답
15. 10. 27 오후 1:20 as a reply to Florian Harr.
Okay I can start with the changes I did to the above comments. 

first is In  notificationCallback:

When the phone writes to the device force the timer to start sending 

(with a connection 'boolean' and calling the transmit)

 switch (connectionDetails.connectionStatus)
    {
    case BLE_CONNECTED_TO_DEVICE:
        printf("Device connected  : \r\n");
        bleIsConnected = 1; // manually set the data send loop
        ADTBleDataTransmit(1); // manually start when the device connects
        break;
    case BLE_DISCONNECTED_FROM_DEVICE:
        printf("Device Disconnected   : \r\n");
        bleIsConnected = 0;
        break;
    default:
        DBG_FAIL("invalid status of Bluetooth Device");
        break;
    }

Next I changed tpirk's else block to 

If (bleIsConnected){
...

So far this works pretty good. once the device connects it writes right away. I also striped away all the accel code and added my own packet which is straight forward. 

If you want to see my phone bluetooth code it might take a little more than this post. BLE android is well documented online anyhow. 


If there is a logic flaw let me know, because I have only been working with this for a few weeks now.

Thanks!


Travis Hunt 



 
0 (0 투표)
Bluetooth - some first steps
응답
15. 12. 16 오후 9:41 as a reply to Travis Hunt.
tpirk/Florian,

I was able to get the first example tpirk described working.  I had a few questions for a better understanding of the operation of BLE with the XDK.  How did you know to write 0x00100001 to the write characteristic, where is this documented? 

Why don't we (and how do we) send the 'start' command the bleAlpwDataExchangeService function is looking for?  I would like to be able to have this demo send data to a Raspberry Pi but have run into some issues with figuring out what commands are necessary to be sent to the XDK for this to operate correctly.

Thank you for your help,

Chris
0 (0 투표)
Bluetooth - some first steps
응답
15. 12. 26 오후 3:22 as a reply to Christopher Koch.
Hi Chris,

I can't tell you how tpirk found out about the 0x00100001, but according to his post in another thread, it selects the accelerometer:

The default state of the Alpwise bluetooth stack is the setup of a service (5301) and two characteristics (5302 and 5303). I would like to define my own characteristics and get rid of the need to write 0x00100001 (=select accelerometer sensor) to characteristic 5302 prior to get out any data from 5303.

I hope he will answer this question himself.

The Bluetooth profile that is used to transmit the accelerometer data, called "ALPWISE Data Exchange Service", is documented in this PDF (but some of the information seems to be wrong)

[your-workbench-folder]\SDK\lib\BLEStack\Alpwise\Documentation\BLESW-ALPWDataExchange_Service_specification.pdf

If you work with the unmodified ADT_bleAccelData demo, you can start the data transmission by connecting your device to the XDK and sending the string 'start' to the characteristic 0x00005302-0000-0041-4C50-574953450000 in the service 00005301-0000-0041-4C50-574953450000. This worked for me without any additional initialization.

Please let me know if this helps you solve your issues.

Kind regards,
Manuel
0 (0 투표)