Hi,
We are using USB-KW40 with IAR, and able to do "WIreless UART" code which is communicating with "Kinetis BLE Toolbox", But what should we do to send "Hello Word \n" from USB-KW40 to our cell phone bluetooth? We can see the device name on our cell phone but not able to pair with bluetooth.
Solved! Go to Solution.
Hello Syed,
I will try to explain how wireless_uart is structured. In function BleApp_StateMachineHandler function, different event states are handled, at the begining, mAppIdle_c state is handled, in this function a software timer is started:
TMR_StartLowPowerTimer(mUartStreamFlushTimerId,
gTmrLowPowerIntervalMillisTimer_c,
15,
UartStreamFlushTimerCallback, NULL);
This timer is configured to call UartStreamFlushTimerCallback callback every 15 milliseconds (and this callback is used to read from console and send it back to cellphone). Once timer is running, application continues with its logic (Find art stream characteristics and store service handles) until it is in mAppRunning_c state.
As callback is called every 15 millisenconds, UartStreamFlushTimerCAllback will be polling for data in serial port just after application is in mAppRunning_c state. So this UartStreamFlushTimerCallback is called periodically.
If you want to send data to Wireless Uart application only once you have to consider:
I added a short workaround that prints a message in th terminal:
#if WORKAROUND_TO_SEND_DATA_ONCE
static uint8_t message_was_sent = FALSE;
uint8_t data_buffer[] = {"This is my test\r"};
#endif
static void UartStreamFlushTimerCallback(void *pData)
{
uint16_t bytesRead = 0;
uint16_t byteCount = 0;
if (mPeerInformation.appState != mAppRunning_c)
{
return;
}
#if WORKAROUND_TO_SEND_DATA_ONCE
if (!message_was_sent) {
message_was_sent = TRUE;
/* Send data to app, buffer size is decreased by one in order to eliminate NULL character at the buffer's end and last byte could be 0x0D*/
BleApp_SendUartStream(mPeerInformation.deviceId, &data_buffer[0], sizeof(data_buffer) - 1);
} else {
#endif
if ( Serial_Read( gAppSerMgrIf, recvStream, mAppUartBufferSize_c, &bytesRead) == gSerial_Success_c )
{
while (byteCount < bytesRead)
{
BleApp_SendUartStream(mPeerInformation.deviceId, &recvStream[byteCount], MIN(mUartStreamMaxSize_c, bytesRead - byteCount));
byteCount += MIN(mUartStreamMaxSize_c, bytesRead - byteCount);
}
}
#if WORKAROUND_TO_SEND_DATA_ONCE
}
#endif
}
In this workaround, message will be printed only once due message_was_sent boolean variable, so, although this UartStreamFlushTimerCallback function is called periodically, it will only send data_buffer the first time.
Another possible solution could be to start an One shot timer and use the callback to send this data to application, this way you do not need to use a boolean variable to control if message has been sent. This solution would look like:
static tmrTimerID_t mOneShotTimerId;
In BleApp_Config function, add the last line:
/* Allocate application timer */
mAppTimerId = TMR_AllocateTimer();
mUartStreamFlushTimerId = TMR_AllocateTimer();
mBatteryMeasurementTimerId = TMR_AllocateTimer();
mOneShotTimerId = TMR_AllocateTimer();
And start this timer just before application reaches mAppRunning_c state:
case mAppCharServiceDisc_c:
{
if (event == mAppEvt_GattProcComplete_c)
{
/* Moving to Running State*/
mPeerInformation.appState = mAppRunning_c;
mpServiceDiscoveryBuffer->aCharacteristics = mpCharDiscoveryBuffer;
BleApp_StoreServiceHandles(mpServiceDiscoveryBuffer);
BleApp_ServiceDiscoveryReset();
TMR_StartLowPowerTimer(mOneShotTimerId,
gTmrLowPowerSingleShotMillisTimer_c,
500,
myCallbackToSendDataOnce, NULL);
}
So 500 milliseconds after mAppRunning_c state is reached, myCallbackToSendDataOnce function will be called and in this callback you can send data to cellphone, just remember to end this buffer by using 0x0D.
Does it make sense to you?
Hope this helps,
Regards,
Isaac
Where are you calling BleApp_SendUartStream()? did you check that you are not calling this periodically? Inside of a timer callback or event?
It should be sending the write command once.
yes it is called in timer callback function.
UartStreamFlushTimerCallback(void *pData)
then where should it be called to print "hello world" only one time?
Hello Syed,
I will try to explain how wireless_uart is structured. In function BleApp_StateMachineHandler function, different event states are handled, at the begining, mAppIdle_c state is handled, in this function a software timer is started:
TMR_StartLowPowerTimer(mUartStreamFlushTimerId,
gTmrLowPowerIntervalMillisTimer_c,
15,
UartStreamFlushTimerCallback, NULL);
This timer is configured to call UartStreamFlushTimerCallback callback every 15 milliseconds (and this callback is used to read from console and send it back to cellphone). Once timer is running, application continues with its logic (Find art stream characteristics and store service handles) until it is in mAppRunning_c state.
As callback is called every 15 millisenconds, UartStreamFlushTimerCAllback will be polling for data in serial port just after application is in mAppRunning_c state. So this UartStreamFlushTimerCallback is called periodically.
If you want to send data to Wireless Uart application only once you have to consider:
I added a short workaround that prints a message in th terminal:
#if WORKAROUND_TO_SEND_DATA_ONCE
static uint8_t message_was_sent = FALSE;
uint8_t data_buffer[] = {"This is my test\r"};
#endif
static void UartStreamFlushTimerCallback(void *pData)
{
uint16_t bytesRead = 0;
uint16_t byteCount = 0;
if (mPeerInformation.appState != mAppRunning_c)
{
return;
}
#if WORKAROUND_TO_SEND_DATA_ONCE
if (!message_was_sent) {
message_was_sent = TRUE;
/* Send data to app, buffer size is decreased by one in order to eliminate NULL character at the buffer's end and last byte could be 0x0D*/
BleApp_SendUartStream(mPeerInformation.deviceId, &data_buffer[0], sizeof(data_buffer) - 1);
} else {
#endif
if ( Serial_Read( gAppSerMgrIf, recvStream, mAppUartBufferSize_c, &bytesRead) == gSerial_Success_c )
{
while (byteCount < bytesRead)
{
BleApp_SendUartStream(mPeerInformation.deviceId, &recvStream[byteCount], MIN(mUartStreamMaxSize_c, bytesRead - byteCount));
byteCount += MIN(mUartStreamMaxSize_c, bytesRead - byteCount);
}
}
#if WORKAROUND_TO_SEND_DATA_ONCE
}
#endif
}
In this workaround, message will be printed only once due message_was_sent boolean variable, so, although this UartStreamFlushTimerCallback function is called periodically, it will only send data_buffer the first time.
Another possible solution could be to start an One shot timer and use the callback to send this data to application, this way you do not need to use a boolean variable to control if message has been sent. This solution would look like:
static tmrTimerID_t mOneShotTimerId;
In BleApp_Config function, add the last line:
/* Allocate application timer */
mAppTimerId = TMR_AllocateTimer();
mUartStreamFlushTimerId = TMR_AllocateTimer();
mBatteryMeasurementTimerId = TMR_AllocateTimer();
mOneShotTimerId = TMR_AllocateTimer();
And start this timer just before application reaches mAppRunning_c state:
case mAppCharServiceDisc_c:
{
if (event == mAppEvt_GattProcComplete_c)
{
/* Moving to Running State*/
mPeerInformation.appState = mAppRunning_c;
mpServiceDiscoveryBuffer->aCharacteristics = mpCharDiscoveryBuffer;
BleApp_StoreServiceHandles(mpServiceDiscoveryBuffer);
BleApp_ServiceDiscoveryReset();
TMR_StartLowPowerTimer(mOneShotTimerId,
gTmrLowPowerSingleShotMillisTimer_c,
500,
myCallbackToSendDataOnce, NULL);
}
So 500 milliseconds after mAppRunning_c state is reached, myCallbackToSendDataOnce function will be called and in this callback you can send data to cellphone, just remember to end this buffer by using 0x0D.
Does it make sense to you?
Hope this helps,
Regards,
Isaac
Hi Isaac,
Do you know how KW41 to achive the same function? That is send data to MobilePhone through UART.
Hello Wenxue,
I've not checked KW41's BLE stack because it is still not available, but I assume that this UART application should work same as KW40's does.
Sorry for this inconvenience,
Regards,
Isaac
Wireless UART requires a PC serial terminal. Once you open a terminal using the COM enumerated by the USB-KW40Z, you can type message in the terminal, then type "Enter" and the message will be sent to the phone and it will be displayed in the Wireless UART application which is part of the Kinetis BLE Toolbox.
We already did this and its working good.
But
1- instead of using "Kinetis BLE toolbox" can't we use any other bluetooth terminal on our cellphones?
2- And instead of writing on PC serial terminal we want to write "Hello \n" in the code only, means as we pair with the bluetooth application it should display "Hello" on cellphone without typing in PC serial monitor.
What should we do?
Syed,
You need to create a mobile application that supports BLE communication to discover Wireless UART devices, then discover the service Wireless UART to start playing with it.
At the end, Wireless UART application has only one service which supports UART stream characteristic which is the one sent to the peer device. So, you need to fill the uart stream characteristic with the information you want.
So, in the wireless UART application you have a timer that is flushing the buffer which is passed to the uart stream attribute in the application. Please, take a look to the function BleApp_SendUartStream. It is the one that send the information to the peer device, please debug and see when this function is called. Actually this function would be called whenever you type a something into the serial terminal. If you want to send the "hello" message from the beginning, you need to change the logic of the application to send the word by the trigger event you wish. By default, this application waits to receive a serial input to trigger a message over the air.
Yeh..
Just made string 'hello' in array new[] and changed the BleApp_SendUartStream as below
BleApp_SendUartStream(mPeerInformation.deviceId, &new[0] ,7);
and successfully getting 'hello' on wireless UART of kinetis BLE toolbox, it has to come only once but it is coming continuously even if the the while loop is commented.
Why so?
And we still need to create BLE suppoerted android app for getting wireless UART data on mobile.