Why is the xTimerPeriodInTicks affecting the code's runtime? - c++

So for a report I'm trying to time the number of cycles it takes to execute a couple seperate functions in a program running on an ESP32, using freeRTOS. The code looks something like this with init_input_generator() being the first function called, here i'm timing onesecwindow.fifo_iir_filter_datapoint():
float geninputarray[SAMPLING_RATE]; //stores the values of an artificial signal we can use to test the algorithm
fifo_buffer onesecwindow = fifo_buffer(SAMPLING_RATE);
esp_err_t init_input_generator() {
dsps_tone_gen_f32(geninputarray, SAMPLING_RATE, 4, 0.04, 0); //10Hz
TimerHandle_t input_signal_timer =
xTimerCreate("input_timer", pdMS_TO_TICKS(10), pdTRUE, (void *)0, input_generator_callback);
xTimerStart(input_signal_timer, 0);
return ESP_OK;
}
void input_generator_callback(TimerHandle_t xTimer)
{
xTaskCreatePinnedToCore(
input_counter,
"input_generator",
4096,
NULL,
tskIDLE_PRIORITY + 11,
NULL,
PRO_CPU_NUM);
}
void input_counter(TimerHandle_t xTimer)
{
stepcounter = (stepcounter + 1) % SAMPLING_RATE;
insert_new_data(geninputarray[stepcounter]);
vTaskDelete(nullptr); // to gracefully end the task as returning is not allowed
}
esp_err_t insert_new_data(float datapoint)
{
onesecwindow.fifo_write(datapoint); // writes the new datapoint into the onesec window
unsigned int start_time = dsp_get_cpu_cycle_count();
onesecwindow.fifo_iir_filter_datapoint();
unsigned int end_time = dsp_get_cpu_cycle_count();
printf("%i\n", (end_time-start_time));
}
The thing that i'm noticing is that whenever I change the xTimerPeriodInTicks to a larger number, I get significantly longer time results, which just really confuses me and get's in the way of proper timing. Although the function doesn't scale with the SAMPLING_RATE and thus should give quite consistent results for each loop, output in cycles with a 10ms timer period looks something like this (every 5 or 6 "loops" for some reason it's longer):
1567, 630, 607, 624, 591, 619, 649, 1606, 607
with a 40ms timer period I get this as a typical output:
1904, 600, 1894, 616, 1928, 1928, 607, 1897, 628
As such I'm confused by the output, as they use the same freeRTOS taskcreate to run with the same priority on the same core, I don't see why there would be any difference. Perhaps I'm misunderstanding something basic/fundamental here so any help would be greatly appreciated.
Update
So based on the comments by #Tarmo i have restructured to approach to having a recurring task, unfortunately the output still seems to suffer from the same problem. The code now looks like this:
#include <esp_dsp.h> //Official ESP-DSP library
float geninputarray[SAMPLING_RATE]; //stores the values of an artificial signal we can use to test the algorithm
fifo_buffer onesecwindow = fifo_buffer(SAMPLING_RATE);
esp_err_t init_input_generator() {
dsps_tone_gen_f32(geninputarray, SAMPLING_RATE, 4, 0.04, 0); //10Hz
xTaskCreatePinnedToCore(
input_counter, // the actual function to be called
"input_generator",
4096,
NULL,
tskIDLE_PRIORITY + 5,
NULL,
APP_CPU_NUM);
return ESP_OK;
}
void input_counter(TimerHandle_t xTimer)
{
while (true)
{
stepcounter = (stepcounter + 1) % SAMPLING_RATE;
insert_new_data(geninputarray[stepcounter]);
vTaskDelay(4);
}
}
esp_err_t insert_new_data(float datapoint)
{
onesecwindow.fifo_write(datapoint); // writes the new datapoint into the onesec window
unsigned int start_time = dsp_get_cpu_cycle_count();
onesecwindow.fifo_iir_filter_datapoint();
unsigned int end_time = dsp_get_cpu_cycle_count();
printf("%i\n", (end_time-start_time));
}

Related

FreeRTOS Shared pointer parameter set to 0

I am trying to share data between 2 FreeRTOS tasks. My approach for this is to create a struct for the tasks' pvParameters that contains a std::shared_pointer.
My task creation looks like this:
auto shared_value = std::make_shared<int8_t>(-1);
auto paramsA = SharedValParams(shared_value);
xTaskCreate(taskA,
"Task A",
4000,
(void *)&paramsA ,
1,
NULL);
auto paramsB = SharedValParams(shared_value);
xTaskCreate(taskB,
"Task B",
4000,
(void *)&paramsB,
1,
NULL);
I'm currently trying to modify this value
void taskA(void *params)
{
for (;;)
{
*((SharedValParams*)params)->shared_val= 5;
Serial.printf("Shared val is now %d\n",
*(*(SharedValParams*)params).shared_val.get());
vTaskDelay(1000/ portTICK_PERIOD_MS);
}
}
The first couple executions of taskA, shared_val is printed as 5. Great! However, after this shared_val is set to 0, or at least that's what is being printed. I've yet to implement this in taskB, so nothing else accesses or modifies shared_val. I'm unsure as to why this is happening, especially when the default value of shared_val is -1.
In the future once I resolve this issue, I will surround shared_val in a mutex, but for now, I cannot reliably set the value. The motivation behind passing this as a param, is to keep the value scoped between relevant tasks.

Building a Timeline from Lossy Time Stamps

I'm working with a product from Velodyne called the VLP-16 (the manual is available from their website with details) and I'm trying to build a timeline of the data it sends. The data it sends comes through a UDP transmission (UDP packets may appear out of order) and each packet is time-stamped with a 32-bit microsecond value. The microsecond value is synced with UTC time. This means that the timestamp will wrap around back to zero after each hour in UTC time. Since UDP packets may technically appear out of order, it is difficult to know what hour a packet may belong to.
Here's a snippet of code that generally describes the problem at hand:
struct LidarPacket
{
uint32_t microsecond;
/* other data */
};
struct LidarTimelineEntry
{
uint32_t hour;
LidarPacket packet;
};
using LidarTimeline = std::vector<LidarTimelineEntry>;
void InsertAndSort(LidarTimeline& timeline, uint32_t hour, const LidarPacket&);
void OnLidarPacket(LidarTimeline &timeline, LidarPacket& newestPacket)
{
/* Where to insert 'newestPacket'? */
}
The simplest approach would be to assume that the packets come in order.
void OnLidarPacket(LidarTimeline &timeline, LidarPacket& newestPacket)
{
if (timeline.empty()) {
timeline.emplace_back(LidarTimelineEntry{0, newestPacket});
return;
}
auto &lastEntry = timeline.back();
if (newestPacket.microsecond < lastEntry.packet.microsecond) {
InsertAndSort(timeline, lastEntry.hour + 1, newestPacket);
} else {
InsertAndSort(timeline, lastEntry.hour, newestPacket);
}
}
This approach will fail if even one packet is out of order though. A slightly more robust way is to also check to see if the wrap occurs near the end of the hour.
bool NearEndOfHour(const LidarPacket& lidarPacket)
{
const uint32_t packetDuration = 1344; // <- approximate duration of one packet.
const uint32_t oneHour = 3600000000; // <- one hour in microseconds
return (lidarPacket.microsecond < packetDuration) || (lidarPacket.microsecond > (oneHour - packetDuration));
}
void OnLidarPacket(LidarTimeline &timeline, LidarPacket& newestPacket)
{
if (timeline.empty()) {
timeline.emplace_back(LidarTimelineEntry{0, newestPacket});
return;
}
auto &lastEntry = timeline.back();
if ((newestPacket.microsecond < lastEntry.packet.microsecond) && NearEndOfHour(lastEntry.packet)) {
InsertAndSort(timeline, lastEntry.hour + 1, newestPacket);
} else {
InsertAndSort(timeline, lastEntry.hour, newestPacket);
}
}
But it's difficult to tell if this is really going to cut it. What is the best way to build a multi-hour timeline from microsecond-stamped data coming from a UDP stream?
Doesn't have to be answered in C++
The approach I ended up going with is the following:
If the timeline is empty, add the time point to the timeline with hour=0
Otherwise, create three possible time points. One using the hour of the last time point, one with an hour before the hour of the last time point, and the last an hour after the last time point.
Compute the absolute differences of all these time points with the last time point (using a 64-bit integer).
Select the hour which yields the smallest absolute difference with the last time point.
This approach passed the following tests:
uint32_t inputTimes[] = { 0, 750, 250 };
// gets sorted to:
uint32_t outputTimes[] = { 0, 250, 750 };
int32_t outputHours[] = { 0, 0, 0 };
uint32_t inputTimes[] = { 1500, oneHour - 500, 250 };
// gets sorted to:
uint32_t outputTimes[] = { oneHour - 500, 250, 1500 };
int32_t outputHours[] = { -1, 0, 0 };
uint32_t inputTimes[] = { oneHour - 500, 1500, 250 };
// gets sorted to:
uint32_t outputTimes[] = { oneHour - 500, 250, 1500 };
int32_t outputHours[] = { 0, 1, 1 };

Passing variables by reference to avoid global variables and extern

I have had written my program but it was relying solely on the use of global variables and extern. I have decided to work on fixing my code and make it as simple as possible. However, It seems to be going in the wrong direction. I have 3 structures that are used pretty much everywhere in my code:
item_inside_struct
device_info
encoder_struct.
I have written a wrapper for the tft display. The tft display must know all the states of the 3 structs since it is displaying everything on the screen. So I pass these structs to my tft functions as a reference. But since the tft functions are being called elsewhere in the code ( it could be main.c or even invoked in other source files), the structures must be passed to other functions that invoke tft methods as well.
For example: I have written sensor.c and sensor.h. It contains all the sensor functions. After the sensor is read, based on the sensor result, it may need to do update tft display hence I must pass all the structure data to the function that performs reading the sensor even though the function itself does not care about these 3 structures apart from the ftf update function. My sensor.c :
void Read_sensor_no_delay(item_inside_struct* item_inside, device_info* device, encoder_struct* encoder){
if(sensor_disable == 0){
if(strncmp(item_inside->state, "PILDYMAS", 8) != 0)
{
sensor = digitalRead(SENSOR);
if(sensor==LOW && sensor_prev_state==HIGH)// SENSOR ON
{
sensor_prev_state=LOW; // set the previous state to LOW
if (strncmp(item_inside->state,"ACTIVE",6)!=0){ // IF NUMBER TO PICK ITEMS IS 0, SET RED LIGHT TO SHOW OPERATOR WRONG BOX
handle_wrong_box(item_inside,device,encoder);
}
}
else if(sensor==HIGH && sensor_prev_state==LOW) //SENSOR DEACTIVATED
{
if(item_inside->num_to_pick > 0 && (strncmp(item_inside->state,"ACTIVE",6)==0) )// if number_to_pick >0, and device is activated, take items
{
handle_active_device(item_inside,device,encoder);
sensor_disable = 1;
lastMsg2 = millis();
}
else if(strncmp(item_inside->state,"ACTIVE",6)!=0)
{
handle_not_active_device(item_inside,device,encoder);
}
sensor_prev_state = HIGH;
}
}
}
else{
if (now - lastMsg2 > 4000)
{
//Serial.println("5 seconds passed");
sensor_disable=0;
}
}
}
void handle_wrong_box(item_inside_struct* item_inside, device_info* device, encoder_struct* encoder){
turn_ON_timer();
LED_strip_ON(red,PixelCount);
update_screen_colour(ST77XX_RED,item_inside,device,encoder);
}
void handle_active_device(item_inside_struct* item_inside, device_info* device, encoder_struct* encoder){
sensor_prev_state = HIGH;
item_inside->num_to_pick--;
item_inside->quantity--;
mb.Hreg(MAIN_REG, 12); //PUT 55 IN REG1
mb.Hreg(NUMBER_TO_PICK_REG, item_inside->quantity); // register 24
update_screen_colour(ST77XX_BLACK,item_inside,device,encoder);
strcpy(item_inside->state,"DONE");
turn_ON_timer2();
if(item_inside->quantity <=10)
{
}
return;
}
void handle_not_active_device(item_inside_struct* item_inside, device_info* device, encoder_struct* encoder){
turn_OFF_timer();
LED_strip_ON(black,PixelCount);
update_screen_colour(ST77XX_BLACK,item_inside,device,encoder);
sensor_prev_state = HIGH;
}
Notice the read_sensor_no_delay() function only needs to know about item_inside_struct, but does not care about device_info or encoder_struct, but I still must pass those to the function. Further down in read_sensor_no_delay() function the other function is calledhandle_wrong_box(). This function will redraw the display and display the new data therefore it must know all 3 structures.
My tft.c:
#include "tft_custom.h"
int screen_colour = ST77XX_BLACK ;
int local_quantity = 0;
int local_number_to_pick = 0;
char local_eeprom_serial[10]="NONE";
char local_current_status[20] = "NONE";
int local_displaycounter = 0;
char local_device_id[10] = "NONE";
char local_device_version[10] = "NONE";
char local_mqtt_server[20] = "NONE";
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
void TFT_setup(){
tft.initR(INITR_BLACKTAB);
tft.setRotation(3);
tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
tft.fillScreen(ST77XX_BLACK);
}
void TFT_display_update(item_inside_struct* item_inside,device_info* device, encoder_struct* encoder){
tft.setTextSize(4);
if(local_quantity != item_inside->quantity)
{
tft.setCursor(0, 0);
tft.fillRect(0,0, 80, 32, screen_colour);
local_quantity = item_inside->quantity;
tft.print(local_quantity); //quantity inside
}
if(local_number_to_pick != item_inside->num_to_pick)
{
tft.setCursor(0,32);
tft.fillRect(0,32, 40, 32, screen_colour);
local_number_to_pick = item_inside->num_to_pick;
tft.print(local_number_to_pick); // number2 means number to_pick
}
tft.setTextSize(1);
if(strcmp(local_device_version,device->device_version)!= 0)
{
tft.setCursor(120,0);
tft.fillRect(120,0, 10, 10, screen_colour);
strcpy(local_device_version,device->device_version);
tft.print(local_device_version); // number2 means number to_pick
}
if(strcmp(local_mqtt_server,device->mqtt_server)!= 0)
{
tft.setCursor(80,10);
tft.fillRect(80,10, 40, 5, screen_colour);
strcpy(local_mqtt_server,device->mqtt_server);
tft.print(local_mqtt_server); // number2 means number to_pick
}
tft.setTextSize(2);
if(strcmp(local_device_id,device->DEVICE_ID)!= 0){
tft.setCursor(40,60);
tft.fillRect(40,60, 50, 16, screen_colour);
strcpy(local_device_id,device->DEVICE_ID);
tft.print(local_device_id);
}
if(strcmp(local_current_status,item_inside->state)!= 0){
tft.setCursor(40,32);
tft.fillRect(40,32, 120, 16, screen_colour);
strcpy(local_current_status,item_inside->state);
tft.print(local_current_status);
}
if(strcmp(local_eeprom_serial,item_inside->serial) !=0)
{
tft.setCursor(40,76);
tft.fillRect(40,76, 120, 16, screen_colour);
strcpy(local_eeprom_serial, item_inside->serial);
tft.print(local_eeprom_serial); //print SERIAL id
}
if(local_displaycounter != encoder->displaycounter)
{
tft.setCursor(40,94);
tft.fillRect(40,94, 60, 16, screen_colour);
local_displaycounter = encoder->displaycounter;
tft.print(local_displaycounter/10); //print SERIAL id
}
}
void TFT_display(item_inside_struct* item_inside,device_info* device, encoder_struct* encoder){
//tft.fillRect(0,0, 160, 80, ST77XX_BLACK);
tft.setTextSize(4);
tft.setCursor(0, 0);
tft.print(item_inside->quantity); //quantity inside
tft.setCursor(0,32);
tft.print(item_inside->num_to_pick); // number2 means number to_pick
tft.setTextSize(1);
tft.setCursor(120,0);
tft.print(device->device_version);
tft.setCursor(80,10);
tft.print(device->mqtt_server); // number2 means number to_pick
tft.setTextSize(2);
tft.setCursor(64,32);
tft.print(item_inside->state);
tft.setCursor(40,60);
tft.print(device->DEVICE_ID);
tft.setCursor(40,76);
tft.print(item_inside->serial); //print SERIAL id
tft.setCursor(40,94);
tft.print(encoder->displaycounter/10); //print SERIAL id
}
void update_screen_colour(int background_colour,item_inside_struct* item_inside, device_info* device, encoder_struct* encoder)
{
screen_colour=background_colour;
tft.setTextColor(ST77XX_WHITE, background_colour);
tft.fillScreen(background_colour);
TFT_display(item_inside,device,encoder);
}
Now I pretty much pass these 3 structs to every single function in my code because at some point tft update method will be called. Could someone point me in the right direction how this ugly code could be improved?
Trying to write tft class
I have rewritten my tft.c and tft.h and learned quite a bit in the process.
My tft.c :
include "tft_custom.h"
//class constructor, pass the 3 structures here
TFT::TFT(item_inside_struct &item_inside, device_info &device, encoder_struct &encoder){
Serial.println("calling tft class constructor");
screen_colour = ST77XX_BLACK ;
local_quantity = 0;
local_number_to_pick = 0;
local_displaycounter = 0;
strcpy(local_eeprom_serial,"NONE");
strcpy(local_current_status,"NONE");
strcpy(local_device_id,"NONE");
strcpy(local_device_version,"NONE");
strcpy(local_mqtt_server,"NONE");
class_item_inside = &item_inside;
class_device = &device;
class_encoder = &encoder;
}
void TFT::begin(){
tft.initR(INITR_BLACKTAB);
tft.setRotation(3);
tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
tft.fillScreen(ST77XX_BLACK);
}
void TFT::update_display_once(){
tft.setTextSize(4);
tft.setCursor(0, 0);
tft.print(class_item_inside->quantity); //quantity inside
tft.setCursor(0,32);
tft.print(class_item_inside->num_to_pick); // number2 means number to_pick
tft.setTextSize(1);
tft.setCursor(120,0);
tft.print(class_device->device_version);
tft.setCursor(80,10);
tft.print(class_device->mqtt_server); // number2 means number to_pick
tft.setTextSize(2);
tft.setCursor(64,32);
tft.print(class_item_inside->state);
tft.setCursor(40,60);
tft.print(class_device->DEVICE_ID);
tft.setCursor(40,76);
tft.print(class_item_inside->serial); //print SERIAL id
tft.setCursor(40,94);
tft.print(class_encoder->displaycounter/10); //print SERIAL id
}
void TFT::TFT_display_update(){
tft.setTextSize(4);
if(local_quantity != class_item_inside->quantity)
{
tft.setCursor(0, 0);
tft.fillRect(0,0, 80, 32, screen_colour);
local_quantity = class_item_inside->quantity;
tft.print(local_quantity); //quantity inside
}
if(local_number_to_pick != class_item_inside->num_to_pick)
{
tft.setCursor(0,32);
tft.fillRect(0,32, 40, 32, screen_colour);
local_number_to_pick = class_item_inside->num_to_pick;
tft.print(local_number_to_pick); // number2 means number to_pick
}
tft.setTextSize(1);
if(strcmp(local_device_version,class_device->device_version)!= 0)
{
tft.setCursor(120,0);
tft.fillRect(120,0, 10, 10, screen_colour);
strcpy(local_device_version,class_device->device_version);
tft.print(local_device_version); // number2 means number to_pick
}
if(strcmp(local_mqtt_server,class_device->mqtt_server)!= 0)
{
tft.setCursor(80,10);
tft.fillRect(80,10, 40, 5, screen_colour);
strcpy(local_mqtt_server,class_device->mqtt_server);
tft.print(local_mqtt_server); // number2 means number to_pick
}
tft.setTextSize(2);
if(strcmp(local_device_id,class_device->DEVICE_ID)!= 0){
tft.setCursor(40,60);
tft.fillRect(40,60, 50, 16, screen_colour);
strcpy(local_device_id,class_device->DEVICE_ID);
tft.print(local_device_id);
}
if(strcmp(local_current_status,class_item_inside->state)!= 0){
tft.setCursor(40,32);
tft.fillRect(40,32, 120, 16, screen_colour);
strcpy(local_current_status,class_item_inside->state);
tft.print(local_current_status);
}
if(strcmp(local_eeprom_serial,class_item_inside->serial) !=0)
{
tft.setCursor(40,76);
tft.fillRect(40,76, 120, 16, screen_colour);
strcpy(local_eeprom_serial, class_item_inside->serial);
tft.print(local_eeprom_serial); //print SERIAL id
}
if(local_displaycounter != class_encoder->displaycounter)
{
tft.setCursor(40,94);
tft.fillRect(40,94, 60, 16, screen_colour);
local_displaycounter = class_encoder->displaycounter;
tft.print(local_displaycounter/10); //print SERIAL id
}
}
void TFT::update_screen_colour(int background_colour)
{
screen_colour=background_colour;
tft.setTextColor(ST77XX_WHITE, background_colour);
tft.fillScreen(background_colour);
update_display_once();
}
and tft.h:
#ifndef TFT_CUSTOM_H
#define TFT_CUSTOM_H
#include "Adafruit_ST7735.h" // Hardware-specific library for ST7735
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "definitions.h"
#define TFT_CS 5 // Hallowing display control pins: chip select
#define TFT_RST 4 // Display reset
#define TFT_DC 2 // Display data/command select
#define TFT_MOSI 19 // Data out
#define TFT_SCLK 18 // Clock out
class TFT
{
private:
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
//create 3 pointers to the struct
item_inside_struct *class_item_inside;
device_info *class_device;
encoder_struct *class_encoder;
int screen_colour;
int local_quantity;
int local_number_to_pick;
char local_eeprom_serial[10];
char local_current_status[20];
int local_displaycounter;
char local_device_id[10] ;
char local_device_version[10];
char local_mqtt_server[20];
public:
TFT(item_inside_struct &item_inside, device_info &device, encoder_struct &encoder);
void begin();
void update_display_once();
void TFT_display_update();
void update_screen_colour(int background_colour);
};
#endif
In my main.c I create a class constructor and pass the 3 structures. Inside a class constructor, I create a pointers for all 3 structures and I use these 3 pointers throughout the whole class
my main.c:
TFT tft_object(item_inside, device, encoder);
void setup() {
Serial.begin(115200);
pinMode(SENSOR, INPUT); // sets the digital pin 13 as output
Expander_SETUP();
setup_leds();
tft_object.begin();
tft_object.update_display_once();
}
void loop() {
if(strncmp(item_inside.state, "PILDYMAS", 8) != 0)
{
Read_sensor_no_delay(tft_object);
}
Notice in my read_sensor_no_delay function, I pass this the tft object.
And inside the read_sensor function I want to be able to read and write to the class object structures as shown below:
void Read_sensor_no_delay(TFT &tft_object ){
sensor = digitalRead(SENSOR);
if(sensor==LOW && sensor_prev_state==HIGH)// SENSOR ON
{
if (strncmp(tft_object.class_item_inside->state,"ACTIVE",6)!=0){ // IF NUMBER TO PICK ITEMS IS 0, SET RED LIGHT TO SHOW OPERATOR WRONG BOX
handle_activation(tft_object);
}
else if(sensor==HIGH && sensor_prev_state==LOW) //SENSOR DEACTIVATED
{
handle_deactivation(tft_object);
}
}
Notice if (strncmp(tft_object.class_item_inside->state,"ACTIVE",6)!=0) inside read sensor function. However, I am getting an issue due to all the variables in my tft class declared as private. Is the only way to solve this issue declare the 3 pointers to the structure public?
There is no right answer of course. If you try to come up with one, a bunch of people will hop on and tell you why its wrong :-)
But, a few choices:
It's actually ok to have global variables. It makes it harder for people to understand the code and where values are coming from, etc, but it's technically not "wrong" (ie, it compiles so the compiler thinks its ok right?). You can also use goto statements as well, and that's considered "bad" by many as well.
Some code encapsulates local copies of variables they need to know about within static variables in a file. Then you can create an init_sensors() function that takes those three pointers and remembers them.
Another common mechanism, probably preferred by most in raw-C code, is to create a single pointer that encapsulates the three other structures and to pass that pointer around instead as the first argument to pretty much every function. This also future-proofs your code a bit in case you ever need to add a fourth. Something like:
struct foo_context {
item_inside_struct* item_inside;
device_info* device;
encoder_struct* encoder;
}
You're using C++ but much of the code feels more "C" like. Getting a better handle on the object oriented nature might be helpful as well and trying to encapsulate more of the functionality into the objects. IE, if the TFT* functions were wrapped inside a new TFT object, then you could create that object once, pass the pointers in during its constructor and have it memorize them while the class' instance is alive.
This is certainly not a complete answer, just a pointer towards separating responsibilities, which others mentioned already.
Let's see this part:
After the sensor is read, based on the sensor result, it may need to do update tft display hence I must pass all the structure data to the function
This smells bad. The code reading a sensor needs not know about the tft display. There may be multiple objects which would need to give some feedback or other reaction on the sensor's state change – displaying something, blinking some LED, beeping an acoustic signal, logging the event in some file, etc, etc. You just can't know all possible future objects which will need to be updated. And your code must not depend on classes representing those objects.
A solution can be a message broker – an object who knows different participants and transfers messages between them (see Message broker at Wikipedia). This can be simply an object of a main application class: the item_inside_struct can contain a pointer to an App object and that would be responsible for proper handling (i.e. dispatching) events to other devices.
Another approach may be an observer (see Observer pattern at Wikipedia) – all objects of different classes in your application, which may utilize changes of the sensor's state somehow, would register in the sensor class object (i.e. by appending themselves to the list) and will be notified whenever a change is recognized. Then each of them will produce appropriate response without being known in details to the sensor's class.

MFC. Quickly highlight all matches in RichEditCtrl

I have a very large text (>50mb).
FindText, SetSel and SetSelectionCharFormat is too slow for me.
I tried to formulate the text and then display but it was even slower.
Can I work with RichEditCtrl in memory and then just display?
Or can I speed up the first option or you can solve my problem in another way?
My measurements of improvement are different than yours.
Here is my code:
void CRichEditAppView::OnEditHighlight()
{
FINDTEXTEX ft = {};
ft.chrg = { 0, -1 };
ft.lpstrText = L"Lorem ipsum";
DWORD dwFlags(FR_DOWN);
CHARFORMAT2 cf = {};
cf.cbSize = sizeof cf;
cf.dwMask = CFM_BACKCOLOR;
cf.crBackColor = RGB(255, 255, 0);
CRichEditCtrl& ctrl = GetRichEditCtrl();
ctrl.HideSelection(TRUE, FALSE);
ctrl.SetRedraw(FALSE);
int count(0);
while (ctrl.FindTextW(dwFlags, &ft) >= 0)
{
ctrl.SetSel(ft.chrgText);
ctrl.SetSelectionCharFormat(cf);
ft.chrg.cpMin = ft.chrgText.cpMax + 1;
count++;
}
ctrl.HideSelection(FALSE, FALSE);
ctrl.SetRedraw(TRUE);
ctrl.Invalidate();
}
I have tested it on a file with 3,000 copies of "Lorem ipsum" text (file size 1,379 KB).
The "naive" implementation (without calls to HideSelection() and SetRedraw()) took 11 seconds.
Calling HideSelection() reduced the time to 9 seconds, adding SetRedraw() - to 1.2 seconds. So I expect to see a 10-times improvement.
Just to compare, if I remove a call to SetSelectionCharFormat(), I'm only saving 0.4 seconds.

Why is my CFRunLoopTimer not firing?

I have a CFRunLoopTimer created within a C++ class as shown below:
#import <CoreFoundation/CoreFoundation.h>
void cClass::StartTimer()
{
if(!mActiveSenseTimer)
{
CFTimeInterval TIMER_INTERVAL = 5;
CFRunLoopTimerContext TimerContext = {0, this, NULL, NULL, NULL};
CFAbsoluteTime FireTime = CFAbsoluteTimeGetCurrent() + TIMER_INTERVAL;
mTimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
FireTime,
0, 0, 0,
ActiveSenseTimerCallback,
&TimerContext);
NSLog(#"RunLoop:0x%x, TimerIsValid:%d, TimeIsNow:%f, TimerWillFireAt:%f",
CFRunLoopGetCurrent(),
CFRunLoopTimerIsValid(mActiveSenseTimer),
CFAbsoluteTimeGetCurrent(),
FireTime);
}
}
void ActiveSenseTimerCallback(CFRunLoopTimerRef timer, void *info)
{
NSLog(#"Timeout");
CFRunLoopTimerContext TimerContext;
TimerContext.version = 0;
CFRunLoopTimerGetContext(timer, &TimerContext);
((cClass *)TimerContext.info)->Timeout();
}
Calling cClass::StartTimer() results in the following log output:
RunLoop:0x7655d60, TimerIsValid:1, TimeIsNow:389196910.537962, TimerWillFireAt:389196915.537956
However, my timer never fires. Any ideas why?
Quote from the docs
A timer needs to be added to a run loop mode before it will fire. To add the timer to a run loop, use CFRunLoopAddTimer. A timer can be registered to only one run loop at a time, although it can be in multiple modes within that run loop.
Also make sure your run loop doesn't die before the timer fires.