How to change a label at runtime from ble char array

Description

I want to change the string of a label at runtime when a new string is written from ble.

What MCU/Processor/Board and compiler are you using?

nRF52 with ST7789

What LVGL version are you using?

8.3.5

What do you want to achieve?

I want to change the text which is displayed on my screen after the text is changed.

What have you tried so far?

I get a new char array from ble and can see it in the serial monitor.

Code to reproduce

The code block(s) should be formatted like:


String message = "Hello World";

void display_screen() {
  
  lv_obj_set_style_bg_color(lv_scr_act(), lv_color_black(), LV_PART_MAIN);

  //Create a white label, set its text and align it to the center
  lv_obj_t * label = lv_label_create(lv_scr_act());
  lv_label_set_text(label,message.c_str());
  //lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
  lv_obj_set_style_text_color(lv_scr_act(), lv_color_white(), LV_PART_MAIN);
  lv_obj_set_style_text_font(label,&lv_font_montserrat_24,0);
  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);

}

void ble_written(BLECentral& central, BLECharacteristic& characteristic) {
  char remoteCharArray[22];
  tempLen1 = characteristic.valueLength();
  memcpy(remoteCharArray, characteristic.value(), tempLen1);
  Serial.println(remoteCharArray);
}

The simplest would be to make your label global, so you can access (change) the label from anywhere.
You also have a potential problematic code in ble_written function:
When the string from characteristic is for ever reason longer than your buffer (the remoteCharArray), it might result in a crash.

The code would look like the following:

String message = "Hello World";

lv_obj_t*   gtLabel = NULL;      // make the label object global

void display_screen () 
{
  lv_obj_set_style_bg_color (lv_scr_act (), lv_color_black (), LV_PART_MAIN);

  // Create a white label, set its text and align it to the center
  gtLabel = lv_label_create (lv_scr_act ());
  lv_label_set_text (gtLabel, message.c_str ());

  //lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
  lv_obj_set_style_text_color (lv_scr_act (), lv_color_white (), LV_PART_MAIN);
  lv_obj_set_style_text_font (gtLabel, &lv_font_montserrat_24, 0);
  lv_obj_align (gtLabel, LV_ALIGN_CENTER, 0, 0);
}

#define MAX_REMOTE_CHAR  22

void ble_written (BLECentral& central, BLECharacteristic& characteristic) 
{
  char remoteCharArray[MAX_REMOTE_CHAR];

  remoteCharArray[0] = '\0';                                        
  strncat (remoteCharArray, characteristic.value (), MAX_REMOTE_CHAR - 1);

  if (gtLabel) {
    lv_label_set_text (gtLabel, remoteCharArray);
  }

  Serial.println (remoteCharArray);
}

I got this error:

error: invalid conversion from 'const unsigned char*' to 'const char*' [-fpermissive]
strncat(remoteCharArray, characteristic.value(), MAX_REMOTE_CHAR - 1);

and I’m not sure how to make the gtLabel global as the display_screen function is in one .cpp file and the ble_written is in another.

I didn’t find any description of BLECharacteristic.value (), so I didn’t know about the return value…
The fix would be (we need a cast):

strncat (remoteCharArray, (const char*) characteristic.value (), MAX_REMOTE_CHAR - 1);

Just a quick fix: within the file where your ble_written is (e.g. after all the includes, before your functions) write:
(The better way would be a proper include file, with all the extern and prototypes for the specific implementation file)

extern lv_obj_t*   gtLabel;

So now the compiler nows the type (how to handle the variable gtLabel).

1 Like

This is great, @robekras! Thank you. I am using Arduino, so I need to figure out the extern part, but will try to follow what you recommend by creating a globals.h or something similar. It’s giving me a ‘undefined reference’ error now but that’s probably an Arduino loading thing.

I could also create a function which is in my display.ccp and call it from the ble_written function in the ble.cpp, but this well off the intent of the original post, which you solved. Thank you again.

I’m getting something through, but need to deal with shorter strings, because I’m getting some junk on the screen.

Ok. Now I am getting both text layered on top of one another. @robekras, it’s not getting rid of the text before.

I don’t know if this is the best answer but it seems to work, despite a quick flash of the previous screen text:

void screen_message(char* blemessage)
{

  lv_obj_t * scr1 = lv_obj_create(NULL);
  lv_obj_set_style_bg_color(scr1, lv_color_black(), LV_PART_MAIN);

  lv_obj_t* gtLabel = lv_label_create(scr1);
  
  lv_label_set_text(gtLabel,blemessage);
  lv_obj_set_style_text_color(scr1, lv_color_white(), LV_PART_MAIN);
  lv_obj_set_style_text_font(gtLabel,&lv_font_montserrat_24,0);
  lv_obj_align(gtLabel, LV_ALIGN_CENTER, 0, 0);

  lv_scr_load(scr1);
}

Well that works the first time but not the 2nd.

@robekras got the solution. My code was wrong. I was calling a 2nd function in the loop causing this behavior.