PCI-E Altera transmit-change-receive trouble - linux-device-driver

help to solve the problem.
I have a board Altera db4kgh15. It has built-in support pci-e interface. I have a Linux kernel module, which is controlled by the fee. with the function below I scan the base registers dogs and try to write in the register data.
The board should adopt a 32-bit word and send it back by adding to it 2.
However, the output we get the same number. The project on the FPGA to the main circuit module attached ksis own design.
Screenshot scheme and code module is presented below.
What am I doing wrong?
static int scan_bars(struct pci_dev *dev) {
int i;
int end = 0x3f;
ulong j;
for (i = 0; i < ALTPCIE_BAR_NUM; i++) {
unsigned long bar_start = pci_resource_start(dev, i);
if (bar_start) {
unsigned long bar_end = pci_resource_end(dev, i);
unsigned long bar_flags = pci_resource_flags(dev, i);
printk(KERN_INFO "##pci_m.ko# BAR%d 0x%08lx-0x%08lx flags 0x%08lx\n",
i, bar_start, bar_end, bar_flags);
virt_bar0 = (ulong) bus_to_virt(bar_start);
bar0 = bar_start;
printk(KERN_INFO "##pci_m.ko# Virt bar0 ADDR = 0x%08lx\n", virt_bar0);
if(bar0 == virt_bar0) {
printk(KERN_INFO "##pci_m.ko# bars equals!");
}
outl_p(number, bar0);
printk(KERN_INFO "##pci_m.ko# (bus) outl_p 0x%08lx\n", number);
/*for(j = bar0; j <= bar0 + end + 5; j++) {
printk(KERN_INFO "##pci_m.ko# (bus) inb_p[0x%08lx + %d] 0x%08lx\n", bar0, j - bar0, inb_p(j));
}*/
for(j = bar0; j <= bar0 + end + 5; j += 4) {
printk(KERN_INFO "##pci_m.ko# (bus) inl_p[0x%08lx + %d] 0x%08lx\n", bar0, j - bar0, inl_p(j));
}
outl_p(number, virt_bar0);
printk(KERN_INFO "##pci_m.ko# (virtual) outl_p 0x%08lx\n", number);
/*for(j = virt_bar0; j <= virt_bar0 + end + 5; j++) {
printk(KERN_INFO "##pci_m.ko# (virtual) inb_p[0x%08lx + %d] 0x%08lx\n", virt_bar0, j - virt_bar0, inb_p(j));
}*/
for(j = virt_bar0; j <= virt_bar0 + end + 5; j += 4) {
printk(KERN_INFO "##pci_m.ko# (virtual) inb_p[0x%08lx + %d] 0x%08lx\n", virt_bar0, j - virt_bar0, inl_p(j));
}
} else {
printk(KERN_INFO "##pci_m.ko# Could not correct read BAR #%d\n", i);
break;
}
}
return 0;
}
// bvs_pci_server1bar.v
`timescale 1 ps / 1 ps
module bvs_pci_server1bar #(
parameter AUTO_CLOCK_SINK_CLOCK_RATE = "-1"
) (
input wire [31:0] serv_bar1_0_addr, // avalon_slave.address
input wire serv_bar1_0_read, // .read
output wire serv_bar1_0_waitreq, // .waitrequest
input wire serv_bar1_0_write, // .write
output wire [63:0] serv_bar1_0_readd, // .readdata
input wire [63:0] serv_bar1_0_writed, // .writedata
input wire [6:0] serv_bar1_0_burstcnt, // .burstcount
input wire [8:0] serv_bar1_0_byteen, // .byteenable
output wire serv_bar1_0_readdatavalid, // .readdatavalid
output wire [19:0] serv_txs_addr, // avalon_master.address
output wire [7:0] serv_txs_byteen, // .byteenable
input wire [63:0] serv_txs_readd, // .readdata
output wire serv_txs_read, // .read
output wire serv_txs_write, // .write
input wire serv_txs_readdatavalid, // .readdatavalid
input wire serv_txs_waitreq, // .waitrequest
output wire serv_txs_chipsel, // .chipselect
output wire [6:0] serv_txs_burstcnt, // .burstcount
output wire [63:0] serv_txs_writed, // .writedata
input wire serv_rst, // reset_sink.reset
input wire serv_clk, // clock_sink.clk
output wire serv_irq // interrupt_sender.irq
);
// TODO: Auto-generated HDL template
assign serv_bar1_0_waitreq = 1'b0;
assign serv_bar1_0_readd = 64'b0000000000000000000000000000000000000000000000000000000000000000;
assign serv_bar1_0_readdatavalid = 1'b0;
assign serv_txs_burstcnt = 7'b0000000;
//assign serv_txs_writed = 64'b0000000000000000000000000000000000000000000000000000000000000000;
assign serv_txs_addr = 20'b00000000000000000000;
assign serv_txs_chipsel = 1'b0;
assign serv_txs_write = 1'b0;
assign serv_txs_read = 1'b0;
assign serv_txs_byteen = 8'b00000000;
//assign serv_irq = 1'b0;
reg[63:0] _value = 64'b0000000000000000000000000000000000000000000000000000000000000000;
reg _irq = 1'b0;
reg _txs_writed = 64'b0000000000000000000000000000000000000000000000000000000000000000;
always #(posedge serv_clk)
begin
if(serv_bar1_0_readd != _value)
begin
_value <= serv_bar1_0_readd;
_txs_writed <= serv_bar1_0_readd | 64'b0100000000000000000000000000000000000000000000000000000000000010;
_irq <= 1'b1;
end
else
_irq <= 1'b0;
end
assign serv_value = _value;
assign serv_irq = _irq;
assign serv_txs_writed = _txs_writed;
endmodule

plx_pci_io_base = pci_resource_start(dev, 0);
iolength = pci_resource_len(dev, 0);
if (!request_mem_region(plx_pci_io_base, iolength, "PGDR IO Base")) {
DEBUG(KERN_ERR "request region #1\n");
return -EBUSY;
}
iobase = ioremap_nocache(plx_pci_io_base, iolength);
if (!iobase) {
DEBUG(KERN_ERR "ioremap #1\n");
ret_status = -ENOMEM;
goto cleanup1;
}

You can try the following:
Use writel and readl instead of outl_p and inl_p
Check if the BAR register into which you are writing/reading and the BAR register used by RTL are same
Use Signal Tap to check if the RD/WR reach you RTL logic

Related

Time clock using built in RTC of STM32 bluebill

I am new in STM32 development and trying to built RTC clock that display's time on oled display.
But on screen some random unidentified symbols are displaying by the below code.
while(1){
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
uint8_t *a = sTime.Hours;
char* buffer2;
int i;
buffer2 = malloc(9);
if (!buffer2)
break;
buffer2[8] = 0;
for (i = 0; i <= 7; i++)
buffer2[7 - i] = (((*a) >> i) & (0x01)) + '0';
puts(buffer2);
// sprintf(date,"Date: %02d.%02d.%02d\t",sDate.Date,sDate.Month,sDate.Year);
// sprintf(time,"Time: %02d.%02d.%02d\r\n",sTime.Hours,sTime.Minutes,sTime.Seconds);
SSD1306_GotoXY (0,0);
SSD1306_Puts (buffer2, &Font_11x18, 1);
SSD1306_GotoXY (0, 30);
SSD1306_Puts ("CLOCK", &Font_11x18, 1);
SSD1306_UpdateScreen();
HAL_Delay (1000);
}
Here is my clock configuration

SystemVerilog X propagation issue

I'm having an issue with my SV code. I'm attempting to simulate a carry look ahead adder. However, when I look at my timing results
they show result has having an x propagated, as well as SUM.
Here is my SystemVerilog code
module fulladder (input logic i_bit1, i_bit2, i_carry,
output logic o_sum, o_carry);
assign o_sum = i_bit1 ^ i_bit2 ^ i_carry;
assign o_carry = (i_bit1 & i_bit2) | (i_carry & (i_bit1 ^ i_bit2));
endmodule
module carry_lookahead_adder
#(parameter WIDTH)
(input logic [WIDTH-1:0] i_add1,
input logic [WIDTH-1:0] i_add2,
output logic [WIDTH:0] o_result
);
logic [WIDTH:0] w_C;
logic [WIDTH-1:0] w_G, w_P, w_SUM;
//Generate full adders
genvar i;
generate for (i= 1; i<WIDTH; i++)
begin : f_loop
fulladder fi (
.i_bit1(i_add1[i]),
.i_bit2(i_add2[i]),
.i_carry(w_C[i]),
.o_sum(w_SUM[i]),
.o_carry()
);
end
endgenerate
genvar jj;
generate
for (jj=0; jj<WIDTH; jj++)
begin
assign w_G[jj] = i_add1[jj] & i_add2[jj];
assign w_P[jj] = i_add1[jj] | i_add2[jj];
assign w_C[jj+1] = w_G[jj] | (w_P[jj] & w_C[jj]);
end
endgenerate
assign w_C[0] = 1'b0; //No carry input
assign o_result = {w_C[WIDTH], w_SUM};
endmodule
and the testbench
module carry_lookahead_adder_tb (w_RESULT);
parameter WIDTH = 32;
logic [WIDTH-1:0] r_ADD_1 = 0;
logic [WIDTH-1:0] r_ADD_2 = 0;
output logic [WIDTH:0] w_RESULT;
carry_lookahead_adder #(.WIDTH(WIDTH)) carry_lookahead_inst
(
.i_add1(r_ADD_1),
.i_add2(r_ADD_2),
.o_result(w_RESULT)
);
initial
begin
$dumpfile("dump.vcd");
$dumpvars;
#10;
r_ADD_1 = 32'b00000000000000000000000000000000;
r_ADD_2 = 32'b00000000000000000000000000000001;
#10;
r_ADD_1 = 32'b00000000000000000000000000000010;
r_ADD_2 = 32'b00000000000000000000000000000010;
#10;
r_ADD_1 = 32'b00000000000000000000000000000101;
r_ADD_2 = 32'b00000000000000000000000000000110;
#10;
r_ADD_1 = 32'b00000000100000000000000000000101;
r_ADD_2 = 32'b00000000100000000000000000000110;
#10;
r_ADD_1 = 32'b11111111111111111111111111111111;
r_ADD_2 = 32'b11111111111111111111111111111111;
#10;
r_ADD_1 = 32'b00000000000000000000000000000000;
r_ADD_2 = 32'b00000000000000000000000000000001;
#10;
end
endmodule // carry_lookahead_adder_tb
Can anyone clue me into what may be causing this x? Sorry to post my full code; I'm just lost as to where the problem may be coming from.
Bit [0] of w_SUM is unknown because you are not driving it. Change the generate for loop so that the count starts from 0, not 1. Change:
generate for (i= 1; i<WIDTH; i++)
to:
generate for (i= 0; i<WIDTH; i++)
After this change, the x goes away.
The problem was that the for loop was not generating the right number of fulladder instances: you need 32, but you only got 31. There was no fulladder instance for you to connect w_SUM[0], i_add1[0], etc., to.

uppercase and lowercase in c

I have tried to figure out why the program doesn't work. It turns lowercase to uppercase, let's say I type "k", it returns K. Then I continue typint "A", it doesn't return "a", but exits. But why? Here's the code:
#include <stdio.h>
#include <stdlib.h>
int main(){
char UPPER,LOWER;
printf("Enter UPPERCASE\n");
UPPER = getchar();
if (UPPER >= 65 && UPPER <= 90)
{
UPPER = UPPER + 32;
printf("The UPPERCASE now is %c\n", UPPER);
}
printf("Enter lowercase\n");
LOWER = getchar();
if (LOWER >= 97 && LOWER <= 122)
{
LOWER = LOWER - 32;
printf("The lowercase now is %c\n", LOWER);
}
getchar();
getchar();
}
If you compile and run this code:
void main(void)
{
char c = getchar();
printf("c = %d %c\n", c, c);
c = getchar();
printf("c = %d %c\n", c, c);
}
You will see this output:
user#host ~/work/tmp $ ./test
a
c = 97 a
c = 10
/* new line there*/
This code is not the same, but works:
#include <stdlib.h>
#include <stdio.h>
#define BUFSIZE 4
int main(void)
{
char UPPER[BUFSIZE] = {0}, LOWER[BUFSIZE] = {0};
int i;
printf("Enter UPPERCASE\n");
fgets(UPPER, BUFSIZE, stdin);
for(i = 0; i < BUFSIZE; i++)
{
if (UPPER[i] >= 65 && UPPER[i] <= 90)
{
UPPER[i] = UPPER[i] + 32;
}
}
printf("The UPPERCASE now is %s", UPPER);
printf("Enter LOWERCASE\n");
fgets(LOWER, BUFSIZE, stdin);
for(i = 0; i < BUFSIZE; i++)
{
if (LOWER[i] >= 97 && LOWER[i] <= 122)
{
LOWER[i] = LOWER[i] - 32;
}
}
printf("The LOWERCASE now is %s", LOWER);
return 0;
}
You should separately add getchar();, after printf("The UPPERCASE now is %c\n", UPPER);
and again after printf("The lowercase now is %c\n", LOWER);.
Most of the program is ending with getch(),and so we think that getch() is used to display the output...but it is wrong.It is used to get a single character from the console.
your correct code should be like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char UPPER, LOWER;
printf("Enter UPPERCASE\n");
UPPER = getchar();
if (UPPER >= 65 && UPPER <= 90)
{
UPPER = UPPER + 32;
printf("The UPPERCASE now is %c\n", UPPER);
}
getchar();
printf("Enter lowercase\n");
LOWER = getchar();
if (LOWER >= 97 && LOWER <= 122)
{
LOWER = LOWER - 32;
printf("The lowercase now is %c\n", LOWER);
}
getchar();
}

Behavioral verilog bcd up down counter with enable and reset

I recently need to make a BCD up down counter with enable and reset. I have three always blocks but i dont know how to connect them together.
I have my code from code segments given by my teacher.
I wrote a structural verilog doing the same function before and I have no idea how to convert it to a behavioral type.
Here is my code:
module BCDcountmod(Clock, Clear, E, segment_a, segment_b, segment_c,
segment_d, segment_e, segment_f, segment_g, updown);
input Clock, Clear, E, updown;
output segment_a, segment_b, segment_c, segment_d, segment_e, segment_f, segment_g;
reg [6:0] segment_data;
reg [3:0] BCD1, BCD0;
always #(posedge Clock)
begin
if (Clear)
begin
BCD1 <= 0;
BCD0 <= 0;
end
else if (E)
if (updown)
if (BCD0 == 4′b1001)
begin
BCD0 <= 0;
if (BCD1 == 4′b0101)
BCD1 <= 0;
else
BCD1 <= BCD1 + 1;
end
else
BCD0 <= BCD0 + 1;
end
else
if (BCD0 == 4'b0000)
begin
BCD0 <= 4'b1001;
if (BCD1 == 4'b0000)
BCD1 <= 4'b0101;
else
BCD1 <= BCD1 - 1;
end
else
BCD0 <= BCD0 - 1;
end
always #(BCD0)
case (BCD0)
4'b0000: segment_data = 7'b1111110;
4'b0001: segment_data = 7'b0110000;
4'b0010: segment_data = 7'b1101101;
4'b0011: segment_data = 7'b1111001;
4'b0100: segment_data = 7'b0110011;
4'b0101: segment_data = 7'b1011011;
4'b0110: segment_data = 7'b1011111;
4'b0111: segment_data = 7'b1110000;
4'b1000: segment_data = 7'b1111111;
4'b1001: segment_data = 7'b1111011;
endcase
wire segment_a = ~segment_data[6];
wire segment_b = ~segment_data[5];
wire segment_c = ~segment_data[4];
wire segment_d = ~segment_data[3];
wire segment_e = ~segment_data[2];
wire segment_f = ~segment_data[1];
wire segment_g = ~segment_data[0];
always #(BCD1)
case (BCD1)
4'b0000: segment_data = 7'b1111110;
4'b0001: segment_data = 7'b0110000;
4'b0010: segment_data = 7'b1101101;
4'b0011: segment_data = 7'b1111001;
4'b0100: segment_data = 7'b0110011;
4'b0101: segment_data = 7'b1011011;
endcase
wire segment_a = ~segment_data[6];
wire segment_b = ~segment_data[5];
wire segment_c = ~segment_data[4];
wire segment_d = ~segment_data[3];
wire segment_e = ~segment_data[2];
wire segment_f = ~segment_data[1];
wire segment_g = ~segment_data[0];
endmodule
With the current setup both digits are being driven to the same 7-segment display. To make matters worse, segment_data has competing drivers. For code reuse, create a new module for bcd to 7-segment conversion. For example:
module segment7dec (output reg [6:0] display, input [3:0] bcd);
always #* begin
case(bcd)
4'b0000: display = 7'b1111110;
4'b0001: display = 7'b0110000;
4'b0010: display = 7'b1101101;
4'b0011: display = 7'b1111001;
4'b0100: display = 7'b0110011;
4'b0101: display = 7'b1011011;
4'b0110: display = 7'b1011111;
4'b0111: display = 7'b1110000;
4'b1000: display = 7'b1111111;
4'b1001: display = 7'b1111011;
default: display = 7'b0000000; //IMPORTANT, otherwise latches are inferred
endcase
display = ~display; // invert
end
endmodule
Now connect the new module into BCDcountmod. Remember to remove the old segment_* code.
module BCDcountmod(
input Clock, Clear, E, updown,
output [6:0] display1, display0 );
reg [3:0] BCD1, BCD0;
always #(posedge Clock) begin
/* Your logic for BCD1,BCD0
*
*/
end
segment7dec disp1( .display(display1), .bcd(BCD1) );
segment7dec disp0( .display(display0), .bcd(BCD0) );
endmodule
Example : http://www.edaplayground.com/s/6/398

Bluetooth low energy, how to parse R-R Interval value?

My application is receiving information from smart heart device. Now i can see pulse value. Could you please help me to parse R-R Interval value? How can i check device support R-R Interval value or Not ?
Any advise from you
Thanks
Have you checked the Bluetooth spec? The sample code below is in C#, but I think it shows the way to parse the data in each heart rate packet.
//first byte of heart rate record denotes flags
byte flags = heartRateRecord[0];
ushort offset = 1;
bool HRC2 = (flags & 1) == 1;
if (HRC2) //this means the BPM is un uint16
{
short hr = BitConverter.ToInt16(heartRateRecord, offset);
offset += 2;
}
else //BPM is uint8
{
byte hr = heartRateRecord[offset];
offset += 1;
}
//see if EE is available
//if so, pull 2 bytes
bool ee = (flags & (1 << 3)) != 0;
if (ee)
offset += 2;
//see if RR is present
//if so, the number of RR values is total bytes left / 2 (size of uint16)
bool rr = (flags & (1 << 4)) != 0;
if (rr)
{
int count = (heartRateRecord.Length - offset)/2;
for (int i = 0; i < count; i++)
{
//each existence of these values means an R-Wave was already detected
//the ushort means the time (1/1024 seconds) since last r-wave
ushort value = BitConverter.ToUInt16(heartRateRecord, offset);
double intervalLengthInSeconds = value/1024.0;
offset += 2;
}
}
This post is a little old but a full answer has not been given.
As I run into this post and it did help me at the end, I would like to share my final code. Hopefully it will help others.
The code provided by Daniel Judge is actually right, but as he already wrote, it is C#. HIs code is a bit better compared to what Simon M came up with at the end as the code of Daniel Judge takes into account there can be more than two RR-values within one message.
Here is the actual spec of the Heart_rate_measurement characteristic
I have translated Daniel Judge his code to Objective-C:
// Instance method to get the heart rate BPM information
- (void) getHeartBPMData:(CBCharacteristic *)characteristic error:(NSError *)error
{
// Get the BPM //
// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml //
// Convert the contents of the characteristic value to a data-object //
NSData *data = [characteristic value];
// Get the byte sequence of the data-object //
const uint8_t *reportData = [data bytes];
// Initialise the offset variable //
NSUInteger offset = 1;
// Initialise the bpm variable //
uint16_t bpm = 0;
// Next, obtain the first byte at index 0 in the array as defined by reportData[0] and mask out all but the 1st bit //
// The result returned will either be 0, which means that the 2nd bit is not set, or 1 if it is set //
// If the 2nd bit is not set, retrieve the BPM value at the second byte location at index 1 in the array //
if ((reportData[0] & 0x01) == 0) {
// Retrieve the BPM value for the Heart Rate Monitor
bpm = reportData[1];
offset = offset + 1; // Plus 1 byte //
}
else {
// If the second bit is set, retrieve the BPM value at second byte location at index 1 in the array and //
// convert this to a 16-bit value based on the host’s native byte order //
bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[1]));
offset = offset + 2; // Plus 2 bytes //
}
NSLog(#"bpm: %i", bpm);
// Determine if EE data is present //
// If the 3rd bit of the first byte is 1 this means there is EE data //
// If so, increase offset with 2 bytes //
if ((reportData[0] & 0x03) == 1) {
offset = offset + 2; // Plus 2 bytes //
}
// Determine if RR-interval data is present //
// If the 4th bit of the first byte is 1 this means there is RR data //
if ((reportData[0] & 0x04) == 0)
{
NSLog(#"%#", #"Data are not present");
}
else
{
// The number of RR-interval values is total bytes left / 2 (size of uint16) //
NSUInteger length = [data length];
NSUInteger count = (length - offset)/2;
NSLog(#"RR count: %lu", (unsigned long)count);
for (int i = 0; i < count; i++) {
// The unit for RR interval is 1/1024 seconds //
uint16_t value = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[offset]));
value = ((double)value / 1024.0 ) * 1000.0;
offset = offset + 2; // Plus 2 bytes //
NSLog(#"RR value %lu: %u", (unsigned long)i, value);
}
}
}
EDIT:
this work for me, i get the correct rr values:
In some cases you can find two values at the same time for rr.
- (void) updateWithHRMData:(NSData *)datas {
const uint8_t *reportData = [datas bytes];
uint16_t bpm = 0;
uint16_t bpm2 = 0;
if ((reportData[0] & 0x04) == 0)
{
NSLog(#"%#", #"Data are not present");
}
else
{
bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[2]));
bpm2 = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[4]));
if (bpm != 0 || bpm2 != 0) {
NSLog(#"%u", bpm);
if (bpm2 != 0) {
NSLog(#"%u", bpm2);
}
}
}
}
in #Brabbeldas solution i had to use a different flag to get rri values. but might depend on device used.
if ((reportData[0] & 0x10) == 0)
instead of
if ((reportData[0] & 0x04) == 0)
Parse heart rate parameters in "C"
I uploaded the sample application to GitHub Heart-Rate-Bluegiga
void ble_evt_attclient_attribute_value(const struct ble_msg_attclient_attribute_value_evt_t *msg)
{
if (msg->value.len < 2) {
printf("Not enough fields in Heart Rate Measurement value");
change_state(state_finish);
}
// Heart Rate Profile defined flags
const unsigned char HEART_RATE_VALUE_FORMAT = 0x01;
const unsigned char ENERGY_EXPENDED_STATUS = 0x08;
const unsigned char RR_INTERVAL = 0x10;
unsigned char current_offset = 0;
unsigned char flags = msg->value.data[current_offset];
int is_heart_rate_value_size_long = ((flags & HEART_RATE_VALUE_FORMAT) != 0);
int has_expended_energy = ((flags & ENERGY_EXPENDED_STATUS) != 0);
int has_rr_intervals = ((flags & RR_INTERVAL) != 0);
current_offset++;
uint16 heart_rate_measurement_value = 0;
if (is_heart_rate_value_size_long)
{
heart_rate_measurement_value = (uint16)((msg->value.data[current_offset + 1] << 8) +
msg->value.data[current_offset]);
current_offset += 2;
}
else
{
heart_rate_measurement_value = msg->value.data[current_offset];
current_offset++;
}
printf("Heart rate measurment value: %d ", heart_rate_measurement_value);
uint16 expended_energy_value = 0;
if (has_expended_energy)
{
expended_energy_value = (uint16)((msg->value.data[current_offset + 1] << 8) +
msg->value.data[current_offset]);
current_offset += 2;
printf(" Expended energy value: %d ", expended_energy_value);
}
uint16 rr_intervals[10] = {0};
if (has_rr_intervals)
{
printf(" Rr intervals: ");
int rr_intervals_count = (msg->value.len - current_offset) / 2;
for (int i = 0; i < rr_intervals_count; i++)
{
int raw_rr_interval = (uint16)((msg->value.data[current_offset + 1] << 8) +
msg->value.data[current_offset]);
rr_intervals[i] = ((double)raw_rr_interval / 1024) * 1000;
current_offset += 2;
printf("%d ", rr_intervals[i]);
}
printf("\n");
}
}