I am writing a C++ code and I am struggling with something rather simple:
I have declared an array
uint8_t *received_data as global variable in my code.
Then I allocate its memory inside a function:
void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
if(params->type == 3){
for(int i = 0; i < params->advertisingDataLen; i++){
if(params->advertisingData[i] == 0x16){
if(params->advertisingData[i+1] == 0x34 && params->advertisingData[i+2] == 0x23){
received_data_size = params->advertisingDataLen - (i + 3);
received_data = new uint8_t[received_data_size];
for(int index = i+3; index < params->advertisingDataLen; index++){
received_data[index] = params->advertisingData[index];
//printf("%02x ", received_data[index]);//params->advertisingData[index]);
//printf("\r\n");
}
}
}
}
}
}
Note that the commented printf's are printing the data I receive correctly.
But then in my main when I try the same printf I receive garbage most of the times and some times I receive the last three elements of the array in the first three places and then garbage.
My main is:
int main(void)
{
BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
ble.init(bleInitComplete);
bool state = true;
while(true){
ble.waitForEvent();
measurement[2]++;
printf("In the loop \n");
for(int i = 0; i < received_data_size; i++){
printf("%02x ", received_data[i]);//params->advertisingData[index]);
printf("\r\n");
}
delete[] received_data;
}
}
The whole code as of now is:
#include "mbed.h"
#include "ble/BLE.h"
/* Optional: Device Name, add for human read-ability */
const static char DEVICE_NAME[] = "G4";
uint16_t uuid16_list[] = {0x2334};
/* You have up to 26 bytes of advertising data to use. */
const static uint8_t AdvData[] = {0x01,0x02,0x03,0x04,0x05}; /* Example of hex data */
uint8_t meas = 0;
uint8_t received_data_size;
static uint8_t *received_data;
uint8_t measurement[] = {0x34,0x23, meas};
/* Optional: Restart advertising when peer disconnects */
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
BLE::Instance().gap().startAdvertising();
}
/**
* This function is called when the ble initialization process has failed
*/
void onBleInitError(BLE &ble, ble_error_t error)
{
/* Avoid compiler warnings */
(void) ble;
(void) error;
/* Initialization error handling should go here */
}
void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
if(params->type == 3){
for(int i = 0; i < params->advertisingDataLen; i++){
if(params->advertisingData[i] == 0x16){
if(params->advertisingData[i+1] == 0x34 && params->advertisingData[i+2] == 0x23){
received_data_size = params->advertisingDataLen - (i + 3);
received_data = new uint8_t[received_data_size];
for(int index = i+3; index < params->advertisingDataLen; index++){
received_data[index] = params->advertisingData[index];
//printf("%02x ", received_data[index]);//params->advertisingData[index]);
//printf("\r\n");
}
}
}
}
}
}
/**
* Callback triggered when the ble initialization process has finished
*/
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
BLE& ble = params->ble;
ble_error_t error = params->error;
if (error != BLE_ERROR_NONE) {
/* In case of error, forward the error handling to onBleInitError */
onBleInitError(ble, error);
return;
}
/* Ensure that it is the default instance of BLE */
if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
return;
}
/* Set device name characteristic data */
ble.gap().setDeviceName((const uint8_t *) DEVICE_NAME);
/* Optional: add callback for disconnection */
ble.gap().onDisconnection(disconnectionCallback);
/* Sacrifice 3B of 31B to Advertising Flags */
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE );
ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
/* Sacrifice 2B of 31B to AdvType overhead, rest goes to AdvData array you define */
//ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, AdvData, sizeof(AdvData));
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, measurement, sizeof(measurement));
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
/* Optional: Add name to device */
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
/* Set advertising interval. Longer interval == longer battery life */
ble.gap().setAdvertisingInterval(500); /* 100ms */
/* Start advertising */
//ble.gap().startAdvertising();
/*Start Scanning*/
ble.gap().setScanParams(500 /* scan interval */, 200 /* scan window */);
ble.gap().startScan(advertisementCallback);
}
int main(void)
{
BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
ble.init(bleInitComplete);
bool state = true;
while(true){
ble.waitForEvent();
measurement[2]++;
printf("In the loop \n");
for(int i = 0; i < received_data_size; i++){
printf("%02x ", received_data[i]);//params->advertisingData[index]);
printf("\r\n");
}
delete[] received_data;
}
}
BLE stands for bluetooth low energy. The code is based on examples found at mbed.org
I guess I am missing something, but I am not sure what exactly. Thank you very much for your help.
First of all, without taking a further look at the rest of the code, the first three bytes of your global received_data will never be written. Take a look into this particular part of your advertisementCallback():
for(int index = i+3; index < params->advertisingDataLen; index++){
received_data[index] = params->advertisingData[index];
So the index used for writing to received_data always starts at an offset of 3 - never less - , while it should start at 0. Add a dedicated index variable for this purpose. In your main(), you created a loop starting at 0:
for(int i = 0; i < received_data_size; i++){
printf("%02x ", received_data[i]);
Therefore the first three bytes of your debug output will always contain random data.
Related
I am using stm32f4 and I am trying to write some data on dual bank flash.
I am calling the below function in my code after the clean flash.
uint32_t totalBlockNumber;
uint32_t blockNumber;
uint8_t blockData[512];
uint32_t frameDataCount;
(frameDataCount always > 8)
Flash_Write_Start(totalBlockNumber,blockNumber,(frameDataCount - 8), blockData);
Than this is the Flash_Write_Start function:
void Flash_Write_Start( uint32_t totalBlockNumber, uint32_t blockNumber, uint32_t packet_length, uint8_t * blockData)
{
HAL_StatusTypeDef errorCheck = 1;
uint32_t bankActive;
if(fwFrameCounter == blockNumber)
{
errorCheck = FLASH_If_Write(Flash_Write_Address, blockData, packet_length);
}
if(errorCheck != FLASHIF_OK)
{
SerialPrint("FLASH ERROR\n");
}
Not every time but I have a hardfault, when code comes in FLASH_If_Write(Flash_Write_Address, blockData, packet_length); function. What is the reason for ?
FLASHIF_StatusTypeDef FLASH_If_Write(uint32_t destination, uint32_t *p_source, uint32_t length)
{
FLASHIF_StatusTypeDef status ;
HAL_StatusTypeDef halErrorFlag;
/* Unlock the Flash to enable the flash control register access *************/
if (HAL_FLASH_Unlock() != HAL_OK)
{
return FLASHIF_CRCKO;
}
uint32_t i ;
status = FLASHIF_OK;
/* DataLength must be a multiple of 32 bit */
for ( i = 0U; (i < (length >> 2U)) && (destination <= (USER_FLASH_END_ADDRESS - 4U)); i++) //
{
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
be done by word */
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (destination + (i * 4U)), *(uint32_t *)(p_source + i)) == HAL_OK)
{
/* Check the written value */
if (*(__IO uint32_t *)(destination + (i * 4U)) != *(uint32_t *)(p_source + i))
{
status = FLASHIF_WRITINGCTRL_ERROR;
}
/* Increment FLASH destination address */
// destination += 4;
}
else
{
/* Error occurred while writing data in Flash memory */
status = FLASHIF_WRITING_ERROR;
break;
}
// SerialPrint(" 4 \n");
if (status != FLASHIF_OK)
{
break;
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
halErrorFlag = HAL_FLASH_Lock();
if( halErrorFlag != HAL_OK)
{
}
return status;
}
I've trying to work out why someone would write the following section of code in a Arduino loop. To me, it doesnt make sense, why have a return in a if statement? Does it just return to the start of the loop and not carry on with the rest of the loop. Here's the snippet of interest:
if (!modem.available()) {
Serial.println("No downlink message received at this time.");
return;
}
Here's the full code
/*
Lora Send And Receive
This sketch demonstrates how to send and receive data with the MKR WAN 1300/1310 LoRa module.
This example code is in the public domain.
*/
#include <MKRWAN.h>
LoRaModem modem;
// Uncomment if using the Murata chip as a module
// LoRaModem modem(Serial1);
#include "arduino_secrets.h"
// Please enter your sensitive data in the Secret tab or arduino_secrets.h
String appEui = SECRET_APP_EUI;
String appKey = SECRET_APP_KEY;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial);
// change this to your regional band (eg. US915, AS923, ...)
if (!modem.begin(EU868)) {
Serial.println("Failed to start module");
while (1) {}
};
Serial.print("Your module version is: ");
Serial.println(modem.version());
Serial.print("Your device EUI is: ");
Serial.println(modem.deviceEUI());
int connected = modem.joinOTAA(appEui, appKey);
if (!connected) {
Serial.println("Something went wrong; are you indoor? Move near a window and retry");
while (1) {}
}
// Set poll interval to 60 secs.
modem.minPollInterval(60);
// NOTE: independent of this setting, the modem will
// not allow sending more than one message every 2 minutes,
// this is enforced by firmware and can not be changed.
}
void loop() {
Serial.println();
Serial.println("Enter a message to send to network");
Serial.println("(make sure that end-of-line 'NL' is enabled)");
while (!Serial.available());
String msg = Serial.readStringUntil('\n');
Serial.println();
Serial.print("Sending: " + msg + " - ");
for (unsigned int i = 0; i < msg.length(); i++) {
Serial.print(msg[i] >> 4, HEX);
Serial.print(msg[i] & 0xF, HEX);
Serial.print(" ");
}
Serial.println();
int err;
modem.beginPacket();
modem.print(msg);
err = modem.endPacket(true);
if (err > 0) {
Serial.println("Message sent correctly!");
} else {
Serial.println("Error sending message :(");
Serial.println("(you may send a limited amount of messages per minute, depending on the signal strength");
Serial.println("it may vary from 1 message every couple of seconds to 1 message every minute)");
}
delay(1000);
if (!modem.available()) {
Serial.println("No downlink message received at this time.");
return;
}
char rcv[64];
int i = 0;
while (modem.available()) {
rcv[i++] = (char)modem.read();
}
Serial.print("Received: ");
for (unsigned int j = 0; j < i; j++) {
Serial.print(rcv[j] >> 4, HEX);
Serial.print(rcv[j] & 0xF, HEX);
Serial.print(" ");
}
Serial.println();
}
Being able to return from functions early is one major reason to use functions. Arduino perculiarities aside, a very common case is for example to break out of nested loops. Suppose you have
for (int i = 0; i < imax; ++i) {
for (int j = 0; j < jmax; ++j) {
do_something(i,j);
if (some_condition(i,j)) {
// now I want to break out of both loops...
}
}
}
break only breaks the inner most loop. If you want to break out of more than one nested loop you can introduce bool flags and make them part of the loop conditions, though this ends in a mess rather fast. Usually the much cleaner way is to place the loops in a function and simply return from the function:
void my_nested_loops() {
for (int i = 0; i < imax; ++i) {
for (int j = 0; j < jmax; ++j) {
do_something(i,j);
if (some_condition(i,j)) {
return; // breaks out of both loops
}
}
}
}
In some sense your code is an inside out variant of this. The loop function is called for you in a loop and because the loop is not in your control, you cannot use continue to continue with the next loop iteration, but you can call return.
After return <value>; or just return; (for void functions) the program exits from the loop and also from function. The function returns <value> (for non-void functions). This statement applies when executing function already is not requeris.
simple return; in void function is used to "break" function. When you don't want to execute rest of it program just will return in stack to function what called executing function.
right now, I am currently trying to output the contents of buf.mtext so I can make sure take the correct input before moving on with my program. Everything seems to work fine, except one thing; msgrcv() puts garbage characters into the buffer, and the reciever process outputs garbage characters.
Here is my sender process:
int main (void)
{
int i; // loop counter
int status_01; // result status
int msqid_01; // message queue ID (#1)
key_t msgkey_01; // message-queue key (#1)
unsigned int rand_num;
float temp_rand;
unsigned char eight_bit_num;
unsigned char counter = 0;
unsigned char even_counter = 0;
unsigned char odd_counter = 0;
srand(time(0));
struct message {
long mtype;
char mtext[BUFFER_SIZE];
} buf_01;
msgkey_01 = MSG_key_01; // defined at top of file
msqid_01 = msgget(msgkey_01, 0666 | IPC_CREAT)
if ((msqid_01 <= -1) { exit(1); }
/* wait for a key stroke at the keyboard ---- */
eight_bit_num = getchar();
buf_01.mtype = 1;
/* send one eight-bit number, one at a time ------------ */
for (i = 0; i < NUM_REPEATS; i++)
{
temp_rand = ((float)rand()/(float)RAND_MAX)*255.0;
rand_num = (int)temp_rand;
eight_bit_num = (unsigned char)rand_num;
if ((eight_bit_num % 2) == 0)
{
printf("Even number: %d\n", eight_bit_num);
even_counter = even_counter + eight_bit_num;
}
else
{
printf("Odd number: %d\n", eight_bit_num);
odd_counter = odd_counter + eight_bit_num;
}
/* update the counters ------------------------------ */
counter = counter + eight_bit_num;
if((eight_bit_num % 2) == 0) { even_counter = even_counter + eight_bit_num; }
else { odd_counter = odd_counter + eight_bit_num; }
buf_01.mtext[0] = eight_bit_num; // copy the 8-bit number
buf_01.mtext[1] = '\0'; // null-terminate it
status_01 = msgsnd(msqid_01, (struct msgbuf *)&buf_01, sizeof(buf_01.mtext), 0);
status_01 = msgctl(msqid_01, IPC_RMID, NULL);
}
Here is my receiver process:
int main() {
struct message {
long mtype;
char mtext[BUFFER_SIZE];
} buf;
int msqid;
key_t msgkey;
msgkey = MSG_key_01;
msqid = msgget(msgkey, 0666); // connect to message queue
if (msqid < 0) {
printf("Failed\n");
exit(1);
}
else {
printf("Connected\n");
}
if (msgrcv(msqid, &buf, BUFFER_SIZE, 0, 0) < 0) { // read message into buf
perror("msgrcv");
exit(1);
}
printf("Data received is: %s \n", buf.mtext);
printf("Done receiving messages.\n");
return 0;
}
The output is usually something like as follows:
Data received is: ▒
Done receiving messages.
I have made sure to clear my message queues each time after running the sender and receiver processes, as well, since I have come to find out this can cause issues. Thanks in advance for your help.
Turns out neither of the suggested solutions were the issue, as I suspected; the sender process actually works just fine. The problem was that I was trying to print buf.mtext instead of buf.mtext[0] which isn't an actual integer value. I fixed the issue by just doing this:
int temp_num = buf.mtext[0];
printf("Data recieved is %d \n", temp_num);
I am trying to read data from an Arduino serial port. My current code:
if(Serial.available()>0){
if(Serial.available()==9){...}
When I type 9 characters in the serial monitor it works fine.
So when I add a second if in the
if(Serial.available()>0)
after the
if(Serial.available()==9){}
it recognizes each character as a single reading. For example when i type 4 characters it says Serial.available()=1 4 times.
real code:
if(Serial.available() > 0){
if(Serial.available()==9){
for(int i =0;i<9;i++){
RGB[i]=Serial.read() - '0';
}
//get the data from the integer array
R= RGB[0]*100+RGB[1]*10+RGB[2];
G= RGB[3]*100+RGB[4]*10+RGB[5];
B= RGB[6]*100+RGB[7]*10+RGB[8];
for(int q=0; q<=255; q++){
if(R>Rp){
Rp+=1;
analogWrite(8, Rp);
}else if(R<Rp){
Rp-=1;
analogWrite(8, Rp);
}
if(G>Gp){
Gp+=1;
analogWrite(9, Gp);
}else if(G<Gp){
Gp-=1;
analogWrite(9, Gp);
}
if(B>Bp){
Bp+=1;
analogWrite(10, Bp);
}else if(B<Bp){
Bp-=1;
analogWrite(10, Bp);
}
delay(10);
}
}
// if(Serial.read()=='r'){
// if(readinglstate==0){
// analogWrite(readinglight, 5);
// readinglstate=1;
// }else if(readinglstate==1){
// analogWrite(readinglight, 70);
// readinglstate=2;
// }else if(readinglstate==2){
// analogWrite(readinglight, 255);
// readinglstate=3;
// }else if(readinglstate==3){
// analogWrite(readinglight, 0);
// readinglstate=0;
// }
// }
}
The commented code is the one that changes the things...
The
Serial.read()=='r'
is popping the byte off the receive buffer. Think of it more like...
input = Serial.read(); // pop the next byte off, regardless of its value.
if (input == 'r') {
hence all your bytes in the buffer are read off the buffer. until "Serial.available() == 0"
I recommend the peek function.
if(Serial.peek()=='r'){
Serial.read(); // already know it, so pop it.
if(readinglstate==0){
...
Input data can arrive in several chunks, so you need to slightly rework approach to read data, please check the following code for reference:
int bytesToRead = 0;
int currBytePtr = 0;
int RGB[9];
while (9 > currBytePtr) { // we need 9 bytes of data
if (0 < (bytesToRead = Serial.available())) { // have something to read
for (int i = 0; i < bytesToRead; ++i ) {
RGB[currBytePtr++] = Serial.read();
if (9 == currBytePtr) { // we have enough data
break;
}
}
} else {
delay(1000); // sleep a bit
}
} // while
// process data received
...
why not just read the data till you have 9 bytes then process.
char buffer[10];
int index=0;
while (Serial.available()){
buffer[index++]=Serial.read();
if (index>8) {
ProcessData(buffer);
index=0;
}
}
I am working on firmware of an ATMEL sensor board (accelerometer and gyro)and trying to read the data in a platform in Ubuntu.
Currently the firmware is like this:
Ubuntu sends a character "D" and the firmware in response sends back 20 bytes of data that ends in "\n" then ubuntu uses serialport_read_until(fd, buff, '\n') and assumes that buff[0] is byte zero and so on.The frequency of acquisition is 200hz.
BUT using this method sometimes I receive corrupted values and it is not working well. Also there are many "Unable to write on serial port" error in ubuntu.
I have found an example code from ATMEL for the firmware and there the data is sent in different packages and continuously (without waiting for the computer to ask for it) the structure is like this:
void adv_data_send_3(uint8_t stream_num, uint32_t timestamp,
int32_t value0, int32_t value1, int32_t value2)
{
/* Define packet format with 3 data fields */
struct {
adv_data_start_t start; /* Starting fields of packet */
adv_data_field_t field [3]; /* 3 data fields */
adv_data_end_t end; /* Ending fields of packet */
} packet;
/* Construct packet */
packet.start.header1 = ADV_PKT_HEADER_1;
packet.start.header2 = ADV_PKT_HEADER_2;
packet.start.length = cpu_to_le16(sizeof(packet));
packet.start.type = ADV_PKT_DATA;
packet.start.stream_num = stream_num;
packet.start.time_stamp = cpu_to_le32(timestamp);
packet.field[0].value = cpu_to_le32(value0);
packet.field[1].value = cpu_to_le32(value1);
packet.field[2].value = cpu_to_le32(value2);
packet.end.crc = 0x00; /* Not used */
packet.end.mark = ADV_PKT_END;
/* Write packet */
adv_write_buf((uint8_t *)&packet, sizeof(packet));
}
but I don't know how I can continuously read the data that is sent in a structure like above.
Sorry if it is a trivial question. I am not a programmer but I need to solve this and I could not find a solution (that I can understand!) after searching for a couple of days.
The reading function I use in linux:
int serialport_read_until(int fd, unsigned char* buf, char until){
char b[1];
int i=0;
do {
int n = read(fd, b, 1); // read a char at a time
if( n==-1) return -1; // couldn't read
if( n==0 ) {
usleep( 1 * 1000 ); // wait 1 msec try again
continue;
}
buf[i] = b[0]; i++;
} while( b[0] != until );
buf[i] = 0; // null terminate the string
return 0;}
The new Reading Func:
// Read the header part
adv_data_start_t start;
serial_read_buf(fd, reinterpret_cast<uint8_t*>(&start), sizeof(start));
// Create a buffer for the data and the end marker
std::vector<uint8_t> data_and_end(start.length - sizeof(start));
// Read the data and end marker
serial_read_buf(fd, data_and_end.data(), data_and_end.size());
// Iterate over the data
size_t num_data_fields = (data_and_end.size() - sizeof(adv_data_end_t)) / sizeof(adv_data_field_t);
adv_data_field_t* fields = reinterpret_cast<adv_data_field_t*>(data_and_end.data());
for (size_t i = 0; i < num_data_fields; i++)
std::cout << "Field #" << (i + 1) << " = " << fields[i].value << '\n';
The data packets that are sent from the firmware:
typedef struct {
uint8_t header1; // header bytes - always 0xFF5A
uint8_t header2; // header bytes - always 0xFF5A
uint16_t length; // packet length (bytes)
uint32_t time_stamp; // time stamp (tick count)
} adv_data_start_t;
typedef struct {
int32_t value; // data field value (3 VALUES)
} adv_data_field_t;
typedef struct {
uint8_t crc; // 8-bit checksum
uint8_t mark; // 1-byte end-of-packet marker
uint16_t mark2; // 2-byte end-of-packet marker (Added to avoid data structure alignment problem)
} adv_data_end_t;
Well you have the length of the packet in the packet "header", so read the header fields (the start structure) in one read, and in a second read you read the data and the end.
If the start and end parts are the same for all packets (which I guess they are), you can easily figure out the amount of data fields after the second read.
Something like this:
// Read the header part
adv_data_start_t start;
adv_read_buf(reinterpret_cast<uint8_t*>(&start), sizeof(start));
// Create a buffer for the data and the end marker
std::vector<uint8_t> data_and_end(start.length - sizeof(start));
// Read the data and end marker
adv_read_buf(data_and_end.data(), data_and_end.size());
// Iterate over the data
size_t num_data_fields = (data_and_end.size() - sizeof(adv_data_end_t)) / sizeof(adv_data_field_t);
adv_data_end_t* fields = reinterpret_cast<adv_data_end_t*>(data_and_end.data());
for (size_t i = 0; i < num_data_fields; i++)
std::cout << "Field #" << (i + 1) << " = " << fields[i] << '\n';
Possible read_buf implementation:
// Read `bufsize` bytes into `buffer` from a file descriptor
// Will block until `bufsize` bytes has been read
// Returns -1 on error, or `bufsize` on success
int serial_read_buf(int fd, uint8_t* buffer, const size_t bufsize)
{
uint8_t* current = buffer;
size_t remaining = bufsize
while (remaining > 0)
{
ssize_t ret = read(fd, current, remaining);
if (ret == -1)
return -1; // Error
else if (ret == 0)
{
// Note: For some descriptors, this means end-of-file or
// connection closed.
usleep(1000);
}
else
{
current += ret; // Advance read-point in buffer
remaining -= ret; // Less data remaining to read
}
}
return bufsize;
}