How to make a single function from repetitive code? - c

I'm writing some code for my embedded system. As I'm adding more different channels of the same periphery, I'm getting code that's really repetitive. For example:
void pos1_write_read(int *pwriteData)
{
// Reset rx buffer and transfer done flag
memset(m_rx_buf0, 0, m_length0);
spi0_xfer_done = false;
nrfx_spi_xfer_desc_t m_pos1_write;
m_pos1_write.p_tx_buffer = pwriteData;
m_pos1_write.tx_length = m_length0;
m_pos1_write.p_rx_buffer = m_rx_buf0;
m_pos1_write.rx_length = m_length0;
nrf_gpio_pin_clear(SPI0_CS0_PIN); //Set CS0 to 0 (on)
APP_ERROR_CHECK(nrfx_spi_xfer(&spi0, &spi0_transfer, NULL));
while (!spi0_xfer_done){} //Wait until the tranfser is done
nrf_gpio_pin_set(SPI0_CS0_PIN); //Set CS0 to 1 (off)
}
void pos2_write_read(int *pwriteData)
{
// Reset rx buffer and transfer done flag
memset(m_rx_buf0, 0, m_length0);
spi0_xfer_done = false;
nrfx_spi_xfer_desc_t m_pos2_write;
m_pos2_write.p_tx_buffer = pwriteData;
m_pos2_write.tx_length = m_length0;
m_pos2_write.p_rx_buffer = m_rx_buf0;
m_pos2_write.rx_length = m_length0;
nrf_gpio_pin_clear(SPI0_CS1_PIN); //Set CS1 to 0 (on)
APP_ERROR_CHECK(nrfx_spi_xfer(&spi0, &spi0_transfer, NULL));
while (!spi0_xfer_done){} //Wait until the tranfser is done
nrf_gpio_pin_set(SPI0_CS1_PIN); //Set CS1 to 1 (off)
}
How would I write a single function that could be used in both examples? Is there any general good practice to avoid repeating the same code?

Finding the right design depends on how it's intended to be used, how generic you feel is appropriate, etc. There is no single correct way to do this. But the naive solution based only on your code snippet is something like:
void write_read(int *pwriteData, int pin)
{
// Reset rx buffer and transfer done flag
memset(m_rx_buf0, 0, m_length0);
spi0_xfer_done = false;
nrfx_spi_xfer_desc_t m_pos1_write;
m_pos1_write.p_tx_buffer = pwriteData;
m_pos1_write.tx_length = m_length0;
m_pos1_write.p_rx_buffer = m_rx_buf0;
m_pos1_write.rx_length = m_length0;
nrf_gpio_pin_clear(pin); //Set CS0 to 0 (on)
APP_ERROR_CHECK(nrfx_spi_xfer(&spi0, &spi0_transfer, NULL));
while (!spi0_xfer_done){} //Wait until the tranfser is done
nrf_gpio_pin_set(pin); //Set CS0 to 1 (off)
}
void pos1_write_read(int *pwriteData)
{
write_read(pwriteData, SPI0_CS0_PIN);
}
void pos2_write_read(int *pwriteData)
{
write_read(pwriteData, SPI0_CS1_PIN);
}
The idea is to just take the common code, and parameterize anything that's different between them.

The only real difference is the SC pin, which you can pass as an argument:
void pos_write_read(int *pwriteData, uint32_t pin)
{
// Reset rx buffer and transfer done flag
memset(m_rx_buf0, 0, m_length0);
spi0_xfer_done = false;
nrfx_spi_xfer_desc_t m_pos_write;
m_pos_write.p_tx_buffer = pwriteData;
m_pos_write.tx_length = m_length0;
m_pos_write.p_rx_buffer = m_rx_buf0;
m_pos_write.rx_length = m_length0;
nrf_gpio_pin_clear(pin); //Set CS to 0 (on)
APP_ERROR_CHECK(nrfx_spi_xfer(&spi0, &spi0_transfer, NULL));
while (!spi0_xfer_done){} //Wait until the tranfser is done
nrf_gpio_pin_set(pin); //Set CS to 1 (off)
}
/* This allows you to do the following: */
void pos1_write_read(int *pwriteData)
{
pos_write_read(pwriteData, SPI0_CS0_PIN);
}
void pos2_write_read(int *pwriteData)
{
pos_write_read(pwriteData, SPI0_CS1_PIN);
}

Related

Is there a way to calculate -time interval- using Esp32 timers?

I want to calculate time interval with timers. I'm using arduino ide. Also i can not decide which library to useful.
I just tried something following code.
I'm using this library
#include <ESP32Time.h>
int a;
int b;
int ldrValue;
#define LDR 0
/* create a hardware timer */
hw_timer_t * timer = NULL;
int timeThatPast;
/* motor pin */
int motor = 14;
/* motor state */
volatile byte state = LOW;
void IRAM_ATTR onTimer(){
state = !state;
digitalWrite(motor, state);
}
void setup() {
Serial.begin(115200);
pinMode(motor, OUTPUT);
/* Use 1st timer of 4 */
/* 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */
timer = timerBegin(0, 80, false);
/* Attach onTimer function to our timer */
timerAttachInterrupt(timer, &onTimer, true);
//********************ALARM*******************
/* Set alarm to call onTimer function every second 1 tick is 1us
=> 1 second is 1000000us */
/* Repeat the alarm (third parameter) */
timerAlarmWrite(timer, 7000000, false);
//********************************************
/* Start an alarm */
timerAlarmEnable(timer);
Serial.println("start timer");
}
void loop() {
int ldrValue = analogRead(LDR);
ldrValue = map(ldrValue, 0, 4095, 0, 10000);
if(ldrValue > 8500){
a = timerRead(timer);
digitalWrite(motor,HIGH);
while(1){
int ldrValue = analogRead(LDR);
ldrValue = map(ldrValue, 0, 4095, 0, 10000);
if(ldrValue < 8500){
b = timerRead(timer);
digitalWrite(motor,LOW);
Serial.print("Entering Loop");
Serial.println(a);
Serial.println("**********");
Serial.println("**********");
Serial.print("Exiting loop");
Serial.println(b);
int difference = b - a;
Serial.println("Difference");
Serial.println(difference);
break;
}
}
}
}
Use millis or micros if you need more precise timing.
Here is an example sketch:
long lastDoTime = 0;
void setup(){
Serial.begin(115200);
delay(1000);
Serial.println("Hello! We will do something at every ms");
}
void doThisAtEvery(int ms){
if( millis() - lastDoTime >= ms ){
// Must save the lastDoTime
lastDoTime = millis();
// Do some stuff at every ms
}
}
void loop(){
// It will do the thing in every 100 ms.
doThisAtEvery(100);
}
If you want to toggle a pin let's say every 100 microsec
long lastToggleTime = 0;
int motorPin = 14;
boolean lastPinState = LOW;
void setup(){
Serial.begin(115200);
}
void togglePinEvery(int micros){
if( micros() - lastToggleTime >= micros ){
lastToggleTime = micros();
digitalWrite(motorPin,!lastPinState);
lastPinState = !lastPinState;
}
}
void loop(){
togglePinEvery(100);
}
EDIT Since you wanted timers only.
Here is a detailed explanation about timers: https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
Code example:
volatile int interruptCounter;
int totalInterruptCounter;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000000, true);
timerAlarmEnable(timer);
}
void loop() {
if (interruptCounter > 0) {
portENTER_CRITICAL(&timerMux);
interruptCounter--;
portEXIT_CRITICAL(&timerMux);
totalInterruptCounter++;
Serial.print("An interrupt as occurred. Total number: ");
Serial.println(totalInterruptCounter);
}
}

time between two edges pic 18f4550

I would like to calculate the time interval between two rising edges of two different signals using the two CCP modules from pic 18f4550.
The idea of ​​calculation is illustrated in the following figures.
The simulation works fine, but my electrical circuit is not. I don't know if there is something wrong with my code. If anyone has an answer or a clue to fix this, I will be grateful! And if you have any questions, please feel free to ask.
#pragma config FOSC = INTOSC_EC
#define _XTAL_FREQ 8000000
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "LCD_8bit_file.h"
#include <string.h>
unsigned long comtage, capt0, x;
char DEPHASAGE[20];
char pulse[20];
float period, dephTempo, deph, phi;
void main()
{
IRCF0 = 1; /* set internal clock to 8MHz */
IRCF1 = 1;
IRCF2 = 1;
LCD_Init();
LCD_String_xy(0, 1, "Dephasage[rad]");
T3CONbits.RD16 = 1;
T3CKPS0 = 0;
T3CKPS1 = 0;
TMR3CS = 0;
TMR3IF = 0;
while (1)
{
CCP2CON = 0b00000101;
CCP1CON = 0b00000101;
PIR2bits.CCP2IF = 0;
PIR1bits.CCP1IF = 0;
TMR3ON = 0;
TMR3 = 0;
if (PIR1bits.CCP1IF == 1) {
TMR3ON = 1;
while (!PIR2bits.CCP2IF);
comtage = TMR3;
dephTempo = (((float)comtage / 30.518) / 65536);
sprintf(pulse,"%.3f ", dephTempo);
LCD_String_xy(0, 0, "Dephasage : ");
LCD_String_xy(2, 9, pulse);
}
}
}
When you test a schematic using a real circuit, other issues will appear, like capacitive and resistive parasitics and that will after the timings. Also, can have jitter noise. If you a have an oscilloscope, try to figure out if there is too much noise. Try do add a pull-down/pull-up on those lines, make sure you have good ground connection. But after looking for your code, you should take an approach similar to CTC: You make fast samples of your input signal and then you check your sampled array, if there is more one than zeros, you caught an edge trigger.
I have a better scenario for your application to implement. But first let's talk about the bad practices in your code.
In your main while loop you setup the CCP modules:
CCP2CON = 0b00000101;
CCP1CON = 0b00000101;
PIR2bits.CCP2IF = 0;
PIR1bits.CCP1IF = 0;
TMR3ON = 0;
TMR3 = 0;
You better do this before the program enters to the infinite while loop.
You handle the timer reads directly while the CCP module captures its value in which the edge you configured it to capture.
comtage = TMR3;
I don't see that you configure the CCP pins as inputs. You have to configure them as inputs by setting the corresponding TRIS bits in order to have them working properly.
So the structure of my recommended scenario would be something like this:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "LCD_8bit_file.h"
#include <string.h>
unsigned long comtage, capt0, x;
char DEPHASAGE[20];
char pulse[20];
float period, dephTempo, deph, phi;
/******************** Utility funcs ********************/
void setupSysClock() {
IRCF0 = 1; /* set internal clock to 8MHz */
IRCF1 = 1;
IRCF2 = 1;
}
void setupCCP1withTMR1() {
CCP1CON = 0b00000101;
PIR1bits.CCP1IF = 0;
TRISCbits.TRISC2 = 1; // set CCP1 pin as input
}
void setupCCP2withTMR3() {
CCP2CON = 0b00000101;
PIR2bits.CCP2IF = 0;
// T3 goes for CCP2 and CCP1, PS 1:1, internal CS
T3CON = (1 << T3CCP2) | (0 << T3CKPS1) | (0 << T3CKPS0) | (1 << T3CCP1) | (0 << TMR3CS);
TMR3 = 0;
// In config bits you must choose RC1 pin for the CCP2 if necessary although it so by default
TRISCbits.TRISC1 = 1 // set CCP2 pin as input
}
void rearm() {
CCP1CON = 0x5
CCP2CON = 0x5
PIR1bits.CCP1IF = 0;
PIR2bits.CCP2IF = 0;
TMR3 = 0;
TMR3ON = 1;
}
void suspend() {
CCP1CON = 0;
CCP2CON = 0;
}
void main()
{
setupSysClock(); // setu internal clock
setupCCP1withTMR1(); // setup CCP1 for capture mode
setupCCP2withTMR3(); // setup CCP1 for capture mode with TMR3
LCD_Init();
LCD_String_xy(0, 1, "Dephasage[rad]");
while (1)
{
while(!CCP2IF); // Wait for the second rising edge
// Event has occured process, first make sure that the CCP1 rised first
if(!CCP1F) {
// An invalid sequence occured ignore and rearm. Note that the sequence of signals is important.
rearm();
continue;
}
/* The sequence is correct let's process the event. Here you will have
two captured value in CCPR1 and CCPR2 registers. First one is the captured value of the T3 when the first rising event occured. Second one is the captured value of the T3 when the second rising event occured. You have to get the delta of the two captured values first. This delta value is the elapsed ticks between the two discrete rising input signals. This is what the capture hardware is made for ;)
Now first we shuld suspend the CCP modules to avoid unwanted captures
while we process the previous value. Because if another capture occures
before we process the previous value, the new capture value will be
overwritten over the old value that we need for computation.
*/
suspend(); // suspend the CCP modules while processing
uint16_t timeDelta = CCPR2 - CCPR1; // Calculate the difference
dephTempo = (((float)timeDelta / 30.518) / 65536);
sprintf(pulse,"%.3f ", dephTempo);
LCD_String_xy(0, 0, "Dephasage : ");
LCD_String_xy(2, 9, pulse);
// Now that we finished processing we can rearm the CCP for new captures
rearm();
}
}
I wrote this code in an editor and haven't compiled in MPLAB. So you must compile and test the code. You can give me a feedback for me to help further.
One important thing to note: If the amount of time between two signals is large, you must either increment the prescaler of Timer3 or you must use a complementary variable for TMR3 register in case it overflows.

Stream sine wave to XAudio2

I am trying to write a very simple sine wave generator that plays out through XAudio2.
Currently there is sound playing, and if I call Win32XAudioInit() and then Win32PlayTone() a tone will play, and the tone will change on subsequent calls to Win32PlayTone(), however there is a noticeable click almost every time the tone changes.
I know there are a few reasons that could cause this:
I am not keeping track of the phase-offset, which means new waves would be misaligned.
I am simply updating the Memory that the buffer is pointing to without regard to what is playing.
Regarding #2, I am not sure if XAudio wants me to create a new XAUDIO2_BUFFER and resubmit that every time I change the tone, or if I am supposed to somehow keep track of where the 'playhead' is (for lack of a better term) and only update bytes that have already been played.
I know if #2 is a problem, I won't be able to hear if I fixed it I am still plagued by problem #1.
I have read through XAudio2 - Play generated sine, when changing frequency clicking sound and I think I could figure out the sin wave problem if I knew XAudio2 was set up correctly.
Any thoughts would be helpful, thanks!
struct win32_audio_buffer
{
real32 Memory[44100 * 1]; // samples per buffer (44100) * channels 1
int BytesPerBuffer;
XAUDIO2_BUFFER XBuffer;
IXAudio2 *XEngine;
IXAudio2SourceVoice *SourceVoice;
WAVEFORMATEX WaveFormat;
};
// NOTE XAUDIO2
internal HRESULT
Win32XAudioInit(win32_audio_buffer *AudioBuffer)
{
// Initialize a COM:
HRESULT HRes;
HRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(FAILED(HRes)) { return(HRes); }
// Init XAUDIO Engine
AudioBuffer->XEngine = {};
if (FAILED(HRes = XAudio2Create(&AudioBuffer->XEngine, 0, XAUDIO2_DEFAULT_PROCESSOR)))
{ return HRes; }
// MASTER VOICE
IXAudio2MasteringVoice* XAudioMasterVoice = nullptr;
if (FAILED(HRes = AudioBuffer->XEngine->CreateMasteringVoice(&XAudioMasterVoice)))
{ return HRes; }
AudioBuffer->WaveFormat = {};
//int32 SamplesPerBuffer = 4410;
int SampleHz = 44100;
WORD Channels = 1;
WORD BitsPerChannel = 32; // 4 byte samples
int32 BufferSize = Channels * BitsPerChannel * SampleHz;
AudioBuffer->BytesPerBuffer = SampleHz * Channels;
AudioBuffer->WaveFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; // or could use WAVE_FORMAT_PCM WAVE_FORMAT_IEEE_FLOAT
AudioBuffer->WaveFormat.nChannels = Channels;
AudioBuffer->WaveFormat.nSamplesPerSec = SampleHz;
AudioBuffer->WaveFormat.wBitsPerSample = BitsPerChannel; // 32
AudioBuffer->WaveFormat.nBlockAlign = (Channels * BitsPerChannel) / 8;
AudioBuffer->WaveFormat.nAvgBytesPerSec = SampleHz * Channels * BitsPerChannel / 8;
AudioBuffer->WaveFormat.cbSize = 0; // set to zero for PCM or IEEE float
AudioBuffer->XBuffer.Flags = 0;
AudioBuffer->XBuffer.AudioBytes = SampleHz * Channels * BitsPerChannel / 8;
AudioBuffer->XBuffer.PlayBegin = 0;
AudioBuffer->XBuffer.PlayLength = 0;
AudioBuffer->XBuffer.LoopBegin = 0;
AudioBuffer->XBuffer.LoopLength = 0;
AudioBuffer->XBuffer.LoopCount = XAUDIO2_LOOP_INFINITE;
AudioBuffer->XBuffer.pContext = NULL;
AudioBuffer->XBuffer.pAudioData = (BYTE *)&AudioBuffer->Memory;
if(FAILED(HRes = AudioBuffer->XEngine->CreateSourceVoice(&AudioBuffer->SourceVoice, (WAVEFORMATEX*)&AudioBuffer->WaveFormat)))
{ return HRes; }
if(FAILED(HRes = AudioBuffer->SourceVoice->Start(0)))
{ return HRes; }
if(FAILED(HRes = AudioBuffer->SourceVoice->SubmitSourceBuffer(&AudioBuffer->XBuffer)))
{ return HRes; }
return(S_OK);
}
internal HRESULT
Win32PlayTone(win32_audio_buffer *Buffer, int32 Hz)
{
real32 PI2 = (real32)6.28318; //530718;
for(int i = 0;
i < Buffer->BytesPerBuffer;
i++)
{
real32 CurrentSample = sinf(i * PI2 / 44100 * Hz);
Buffer->Memory[i] = CurrentSample;
}
return(S_OK);
}
XAudio2 is entirely asynchronous, so you should not change the memory pointed to by a playing packet until the packet is completed or you will get clicks as you describe.
Also, when the current packet completes, you want to have another one already queued up if you want the sound to be continuous.
See these resources for learning how to program XAudio2:
https://github.com/walbourn/directx-sdk-samples/tree/master/XAudio2
https://github.com/microsoft/Xbox-ATG-Samples/tree/master/UWPSamples/Audio
DirectX Tool Kit for Audio

CAN bus receiver don't receive

I am working with a PIC32MX795F512L. With below code I can transmit but cannot receive. How can it be possible I can transmit but I cannot receive? Any suggestions will be appreciated.
Here is the init code:
void CAN1Init(void) {
CAN_BIT_CONFIG canBitConfig;
UINT baudPrescalar;
PORTSetPinsDigitalIn(IOPORT_F, BIT_0);
PORTSetPinsDigitalOut(IOPORT_F, BIT_1);
// ODCFSET = BIT_1;
// change the CAN1 RX register from anlog to digital
// PORTSetPinsDigitalIn(IOPORT_F, BIT_0);
// PORTSetPinsDigitalOut(IOPORT_F, BIT_1);
CANEnableModule(CAN1, TRUE);
// Set the CAN_en pin to low, which is at RC3
mPORTCClearBits(BIT_3);
PORTSetPinsDigitalOut(IOPORT_C, BIT_3);
CANSetOperatingMode(CAN1, CAN_CONFIGURATION);
while (CANGetOperatingMode(CAN1) != CAN_CONFIGURATION);
canBitConfig.phaseSeg2Tq = CAN_BIT_3TQ;
canBitConfig.phaseSeg1Tq = CAN_BIT_3TQ;
canBitConfig.propagationSegTq = CAN_BIT_3TQ;
canBitConfig.phaseSeg2TimeSelect = TRUE;
canBitConfig.sample3Time = TRUE;
canBitConfig.syncJumpWidth = CAN_BIT_2TQ;
// baudPrescalar = CANCalcBitClockPrescalar(&canBitConfig,80000000,250000);
CANSetSpeed(CAN1, & canBitConfig, SYS_FREQ, CAN_BUS_SPEED);
/* Step 3: Assign the buffer area to the
* CAN module.
*/
CANAssignMemoryBuffer(CAN1, CAN1MessageFifoArea, (2 * 8 * 16));
CANConfigureChannelForTx(CAN1, CAN_CHANNEL0, 8, CAN_TX_RTR_DISABLED, CAN_LOW_MEDIUM_PRIORITY);
CANConfigureChannelForRx(CAN1, CAN_CHANNEL1, 8, CAN_RX_FULL_RECEIVE);
//CANConfigureFilter (CAN1, CAN_FILTER0, 0x000, CAN_SID);
//CANConfigureFilterMask (CAN1, CAN_FILTER_MASK0, 0x7FF, CAN_SID, CAN_FILTER_MASK_IDE_TYPE);
// CANLinkFilterToChannel (CAN1, CAN_FILTER0, CAN_FILTER_MASK0, CAN_CHANNEL1);
// CANEnableFilter (CAN1, CAN_FILTER0, TRUE);
CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, TRUE);
CANEnableModuleEvent(CAN1, CAN_RX_EVENT, TRUE);
INTSetVectorPriority(INT_CAN_1_VECTOR, INT_PRIORITY_LEVEL_4);
INTSetVectorSubPriority(INT_CAN_1_VECTOR, INT_SUB_PRIORITY_LEVEL_0);
INTEnable(INT_CAN1, INT_ENABLED);
/* Step 7: Switch the CAN mode
* to normal mode. */
CANSetOperatingMode(CAN1, CAN_NORMAL_OPERATION);
mPORTEToggleBits(BIT_6 | BIT_7);
while (CANGetOperatingMode(CAN1) != CAN_NORMAL_OPERATION);
CANSetTimeStampValue(CAN1, 0x00);
printf("CAN BUS is working\n");
}
Edit: main part of the code:
void RxMsgProcess(void)
{
if(isCAN1MsgReceived == FALSE) // This flag to make sure there is an interrupt from receiving a new message, if it's true then there are new packet
{
return;
}
isCAN1MsgReceived = FALSE;
CANRxMessageBuffer * message2;
message2 = CANGetRxMessage(CAN1,CAN_CHANNEL1);
printf(" received\n");
CANUpdateChannel(CAN1, CAN_CHANNEL1);
CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, TRUE);
}
void __attribute__((vector(46), interrupt(ipl4), nomips16)) CAN1InterruptHandler(void)
{
/* Check if the source of the interrupt is
* RX_EVENT. This is redundant since only this
* event is enabled in this example but
* this shows one scheme for handling events. */
if((CANGetModuleEvent(CAN1) & CAN_RX_EVENT) != 0)
{
/* Within this, you can check which channel caused the
* event by using the CANGetModuleEvent() function
* which returns a code representing the highest priority
* pending event. */
if(CANGetPendingEventCode(CAN1) == CAN_CHANNEL1_EVENT)
{
CANEnableChannelEvent(CAN1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY, FALSE);
isCAN1MsgReceived = TRUE;
}
}
INTClearFlag(INT_CAN1);
}

Pass RR in BLE Protocol [Heart Rate] for Arduino

code:
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
byte flags = 0b00011110;
byte bpm;
byte rr;
byte heart[8] = { 0b00011110, 60, 60, 60, 60 , 60, 60, 60};
byte hrmPos[1] = {2};
bool _BLEClientConnected = false;
#define heartRateService BLEUUID((uint16_t)0x180D)
BLECharacteristic heartRateMeasurementCharacteristics(BLEUUID((uint16_t)0x2A37), BLECharacteristic::PROPERTY_NOTIFY);
BLECharacteristic sensorPositionCharacteristic(BLEUUID((uint16_t)0x2A38), BLECharacteristic::PROPERTY_READ);
BLEDescriptor heartRateDescriptor(BLEUUID((uint16_t)0x2901));
BLEDescriptor sensorPositionDescriptor(BLEUUID((uint16_t)0x2901));
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
_BLEClientConnected = true;
};
void onDisconnect(BLEServer* pServer) {
_BLEClientConnected = false;
}
};
void InitBLE() {
BLEDevice::init("Sensor X");
// Create the BLE Server
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pHeart = pServer->createService(heartRateService);
pHeart->addCharacteristic(&heartRateMeasurementCharacteristics);
heartRateMeasurementCharacteristics.addDescriptor(&heartRateDescriptor);
heartRateMeasurementCharacteristics.addDescriptor(new BLE2902());
pHeart->addCharacteristic(&sensorPositionCharacteristic);
sensorPositionCharacteristic.addDescriptor(&sensorPositionDescriptor);
pServer->getAdvertising()->addServiceUUID(heartRateService);
pHeart->start();
// Start advertising
pServer->getAdvertising()->start();
}
void setup() {
Serial.begin(115200);
Serial.println("Start");
InitBLE();
bpm = 1;
rr = 800;
}
void loop() {
// put your main code here, to run repeatedly:
heart[1] = (byte)bpm;
int energyUsed = 3000;
heart[3] = energyUsed / 256;
heart[6] = (byte)bpm;
heart[2] = energyUsed - (heart[2] * 256);
Serial.println(bpm);
Serial.println(rr);
heartRateMeasurementCharacteristics.setValue(heart, 8);
heartRateMeasurementCharacteristics.notify();
sensorPositionCharacteristic.setValue(hrmPos, 1);
rr++;
bpm++;
delay(2000);
}
I have the above code - and I have been looking at this here but I can't figure out how do I pass the RR data over BLE. I set the flags according to the BLE spec shown here. But whenever I use an app to see the data "HRV Logger", it says that I am not transmitted RR data. I thought all I had to do was pass heart[6] data and that would show up as RR. I have dummy information being passed since I'm not connected to any sensors. Help would be helpful, determining how to pass the RR data across, thanks! (for future reference I am using the Sparkfun ESP32, but this shouldn't affect solving the issue since it has to do with protocols)

Resources