What is the return type here

Hello,

Im busy with learning freertos and a YT course.
But im stuck here :

pvPortMalloc(idx * sizeof(char));
        // Place the message on the heap  
        memcpy()

How can I know what the return type of pvPortMalloc is and what to add as first argument of memcpy ?

The FreeRTOS coding style follows a naming convention to indicate the return type. You can read more about this here. You can also inspect the code freely on Github to verify any functions you like - for example pvPortMalloc. In this case the pv prefix signifies a void pointer is returned.

For memcpy I suggest online documentation for the standard library functions, for example this site.

Thanks

It feels wierd to use a void pointer to a string,
it is then not better to cast it to a char pointer ?

A pointer to void is a special “code” in C that it is a pointer that might point to anything, which could be a string. C will freely convert any other type of pointer to object to a pointer to void, or a pointer to void to any other type of pointer to object.

oke,

So im at a good path now to write a string to the heap ?

Look at your code. You first set idx to zero, then allocate space for idx characters, then copy idx characters.

What does that do?

I presume you will later do something with that buffer, so the fact that it is just leaked here isn’t a problem.

oke

So idx and the pointer schould be global variables ??

or schould the code be like this ?

// make room on the heap for the message  
        void * ptr = pvPortMalloc(idx * sizeof(char));
        // Place the message on the heap  
        memcpy(ptr, buff, idx); 
        // set the flag 
        messageFlag = true;
        idx = 0 ; 
        memset(buff, 0, 20); 

It is not required to ptr to be global or something special. But it should be able to be passed to next code which will use a string from a heap and, finally, will free a heap when data are processed or are transferred.
For example, you may pass ptr as an argument for a function which will use the data you’ve placed in a heap. Or you may make ptr global to use it as is. Also for next string processing, you may cast ptr to a string of chars (char*)ptr to be precise and to ensure your data are handled as a string.
Most important part here: don’t forget to free() the space you got from a heap. Else way a memory leak will occur.

Thanks

I can cast the ptr to a char* and to free the memory is exactly what this challenge is trying to learn me.

To declare memory and think of freeing memory

The problem with the code you shared previously is that you set idx to zero and use it to calculate the number of bytes (idx * sizeof(char)) that need to be allocated via pvPortMalloc, which is zero.

Calling pvPortMalloc, to allocate zero bytes results in implementation-defined behavior; it can either return NULL or undefined behavior depending upon the implementation.

Thanks

So this is the good way :

// my solution to lesson 4

// Learned so far
// - writing task
// - task scheduling
// - memory managament

// Challenge

// Write 2 tasks.

// task 1 : get input from serial monitor 
//          after getting a enter , put it into heap memory 
//          signal to task2 that there is something on the heap 

// task2 :  read input from the heap if the task 1 signal that there is a message
//          display it on the serial monitor 
//          free the memory

#if CONFIG_FREERTOS_UNICORE
static const BaseType_t app_cpu = 0 ;
#else
static const BaseType_t app_cpu = 1;
#endif

// Pins
static const int led_pin = 2;
bool messageFlag = false; 
 char * message_ptr; 

// Our task is to read in a message 
void readMessageFromMonitor(void * parameter) {
  char ch;
  char buff[40];
  int idx = 0;
 
  memset(buff, 0, 20);
  while (1) {
    if (Serial.available() > 0) {
      ch = Serial.read();
       

      if (ch == '\n') {
      
        // clear buffer
       
        
        // make room on the heap for the message  
        message_ptr = (char *) pvPortMalloc(idx * sizeof(char));
        // Place the message on the heap  
        memcpy(message_ptr, buff, idx); 
        // set the flag 
        messageFlag = true;
        idx = 0 ; 
        memset(buff, 0, 20); 

      } else {
        if (idx < 39) {
           
          buff[idx] = ch;

                 
          idx++;
        }
      }
    }
  }
}



void setup() {
  pinMode(led_pin, OUTPUT);
  Serial.begin(9600);
  Serial.println("RW");

  // Task to run forever
  xTaskCreatePinnedToCore(
    readMessageFromMonitor,    // Function to be called
    "Read Message",  // name of the function
    1024,         // stack size
    NULL,         // parameter to pass to the function
    1,            // priority
    NULL,         // task handle
    app_cpu
  );
}

void loop() {
  
}

I can spot the following issues:

  1. The size of buff is 40 but the parameter to memset call is 20.
  2. You want to add a check when \n is the first character (and therefore, idx is zero):
    if ( (ch == '\n') && ( idx != 0 ) ) {
    
  3. As others have pointed out, you are not freeing the memory you are allocating. You are probably yet to implement the second task described in comments:
    // task2 :  read input from the heap if the task 1 signal that there is a message
    //          display it on the serial monitor 
    //          free the memory
    

Thanks for the feedback.

And it is correct that I did not write the second task.
I want to be sure that the first task is good before moving on.

But do i not have to change the \n to a \0 to make a proper string when store it on the heap and/or display it

And if so, how do I do that ?

and here I have to return it or do something else ?

Here is the code:

/* Allocate one extra space for null terminator. */
message_ptr = (char *) pvPortMalloc( ( idx + 1 ) * sizeof(char));
.
.
.
message_ptr [ idx ] = '\0';

That depends on what you want to do with the empty strings. Doing nothing is an option too:

      if (ch == '\n') {
      
        if(idx != 0 )
        {  // clear buffer
        
          
          // make room on the heap for the message  
          message_ptr = (char *) pvPortMalloc(idx * sizeof(char));
          // Place the message on the heap  
          memcpy(message_ptr, buff, idx); 
          // set the flag 
          messageFlag = true;
          idx = 0 ; 
          memset(buff, 0, 20); 
        }
        else
        {
          /* Ignore the empty buffer.  */
        }
      } else {
        if (idx < 39) {
           
          buff[idx] = ch;

                 
          idx++;
        }
      }

oke

Could this be a good solution to the challenge

// my solution to lesson 4

// Learned so far
// - writing task
// - task scheduling
// - memory managament

// Challenge

// Write 2 tasks.

// task 1 : get input from serial monitor 
//          after getting a enter , put it into heap memory 
//          signal to task2 that there is something on the heap 

// task2 :  read input from the heap if the task 1 signal that there is a message
//          display it on the serial monitor 
//          free the memory

#if CONFIG_FREERTOS_UNICORE
static const BaseType_t app_cpu = 0 ;
#else
static const BaseType_t app_cpu = 1;
#endif

// Pins
static const int led_pin = 2;
bool messageFlag = false; 
char * message_ptr; 


// Our task is to read in a message 
void readMessageFromMonitor(void * parameter) {
  char ch;
  char buff[40];
  int idx = 0;
  
  memset(buff, 0, 20);
  while (1) {
    if (Serial.available() > 0) {
      ch = Serial.read();
       

      if (ch == '\n') {
      
        if(idx != 0 )
        {  // clear buffer
        
          
          // make room on the heap for the message  
          message_ptr = (char *) pvPortMalloc(idx * sizeof(char));
          // Place the message on the heap  
          memcpy(message_ptr, buff, idx); 
          // set the flag 
          messageFlag = true;
          idx = 0 ; 
          memset(buff, 0, 20); 
        }
        else
        {
          /* Ignore the empty buffer.  */
        }
      } else {
        if (idx < 39) {
           
          buff[idx] = ch;

                 
          idx++;
        }
      }
    }
  }
}

void displayMessage() { 

  if (messageFlag) {
    Serial.print("Task2 reads :")
    Serial.println(message_ptr);
    vPortFree(message_ptr); 
    messageFlag = false ;  
  }
}


void setup() {
  pinMode(led_pin, OUTPUT);
  Serial.begin(9600);
  Serial.println("RW");

  // Task to run forever
  xTaskCreatePinnedToCore(
    readMessageFromMonitor,    // Function to be called
    "Read Message",  // name of the function
    1024,         // stack size
    NULL,         // parameter to pass to the function
    1,            // priority
    NULL,         // task handle
    app_cpu
  );

  xTaskCreatePinnedToCore(
    displayMessage,    // Function to be called
    "Display Message",  // name of the function
    1024,         // stack size
    NULL,         // parameter to pass to the function
    1,            // priority
    NULL,         // task handle
    app_cpu
  );
}

void loop() {
  
}

I cannot test it because I use wokike and that is one the whole day very very busy

Nope , it chrashing

RW

Task2 reads :Dit is een testxV­º?

E (1678) FreeRTOS: FreeRTOS Task "Display Message" should not return, Aborting now!

Guru Me

tbortn Errorcalled a0 PC 0x400 (c6f on core 1nel
exception). 
0x40

22fc:0x3fe: 440 0891088219f0x6ffb 46-CORR0PTEc

:0x3ffb
B80 tra0e: 06f00x32f99503
`` `

can anyone help me figure out why ?

The error message tells you exactly why. FreeRTOS tasks cannot return and your displayMessage function returns. The signature of displayMessage is also wrong. I’d recommend first doing these tutorials to learn basics of FreeRTOS: GitHub - FreeRTOS/Lab-Project-FreeRTOS-Tutorials: Tutorials to learn FreeRTOS Kernel..

One further observation - Task readMessageFromMonitor does not yield properly. This will result in task displayMessage never executing. The simplest (but not optimal) way to switch switch between the tasks would be to add a simple taskYIELD call to both tasks. This would look like the following:


// Our task is to read in a message 
void readMessageFromMonitor(void * parameter) {
  char ch;
  char buff[40];
  int idx = 0;
  
  memset(buff, 0, 20);
  while (1) {
    if (Serial.available() > 0) {
      ch = Serial.read();
       

      if (ch == '\n') {
      
        if(idx != 0 )
        {  // clear buffer
        
          buff[idx] = '\0';   
          // make room on the heap for the message  
          message_ptr = (char *) pvPortMalloc(idx * sizeof(char));
          // Place the message on the heap  
          memcpy(message_ptr, buff, idx); 
          // set the flag 
          messageFlag = true;
          idx = 0 ; 
          memset(buff, 0, 20); 
          taskYIELD(); // Yield so that the message can be displayed by the other task
        }
        else
        {
          /* Ignore the empty buffer.  */
        }
      } else {
        if (idx < 39) {
           
          buff[idx] = ch;

                 
          idx++;
        }
      }
    }
  }
}

void displayMessage(void * parameter) { 
  while(1) {
  if (messageFlag) {
    Serial.print("Task2 reads :");
    Serial.println(message_ptr);
    vPortFree(message_ptr); 
    messageFlag = false ; 
    taskYIELD(); //Yield now that the message has been displayed
    
  }}
}