Friday, November 3, 2023

Simulink signal

After generating code from a Simulink model, if you want to read the value of a parameter inside the model which is not an output port, you can use signals. In Matlab R2022b, signal definition is different from R2019a. The following R2022b method (assuming you have Embedded Coder) is only valid if you generate C code, I have not been able to find a way to generate signal code for C++:
  1. Open Simulink model
  2. Open Configuration Parameter window, go to Code Generation
  3. System target file: ert.tlc (Embedded Coder)
  4. Language: C
  5. In Simulink APPS menu, click on Embedded Coder, A C CODE tabs appears to the right of APPS menu
  6. Find the signal line you want the generate code for and double click on it, give it a name, e.g. "mySignal"
  7. Single click on signal line, a pop up will appear, click on the left-most item, "Add selected signals to code mappings"
  8. Under C CODE tab, click on Code Interface and then click Default Code Mappings
  9. A Code Mappings panel will appear at the bottom of model
  10. Click on right most tab, Signals/States
  11. Under Signals, find mySignal
  12. Click to the right of mySignal (Store Class column), change Auto to Model Default.
  13. Generate code by pressing ctrl + b
  14. If your model name was MyModel, the generated code will have a file called MyModel_ert_rtw/MyModel.h containing the data structure MyModel_B which has mySignal as a field that you can access from your own C/C++ code. 
  15. If your code is C++, dont forget to use include in C wrapper: extern "C" {#include "MyModel_ert_rtw/MyModel.h"}

Friday, October 13, 2023

Sanity checks

If your software component is taking data from other components or sensors, that data should go through at least one sanity check. The world outside of your component is full of surprising errors, most of whom you won't be able to guess beforehand. A correctly working external component might get buggy after an update, don't assume that newer versions don't break existing functionality. Sanity checks prevent the simple ones from crashing your software, protecting you from embarrassment to even loss of life.

Wednesday, August 16, 2023

Compile s-function with C++17

To compile a Simulink s-function file with C++17 (assuming you have Visual Studio 2019 or higher) , use:
        mex COMPFLAGS='$COMPFLAGS /std:c++17' file.cpp

Note that this does NOT work: mex CXXFLAGS='$CXXFLAGS /std:c++17' file.cpp

Thursday, March 16, 2023

Effective usage of locks in multi-threading

In an application with multiple threads and shared resources, make sure that you lock sections that have the minimal time impact, because other threads have to wait for the lock to be released. Let's say you have a function that saves a buffer to a file:

function saveData(newData) {
    addToBuffer(newData)
    saveBufferToFile()
}
To make this function thread safe, you might haphazardly lock at the beginning and unlock at the end of function:
function saveData(newData) {
    lock()
    addToBuffer(newData)
    saveBufferToFile()
    unlock()
}
Since saving buffer to file on disk takes a lot of time, another thread that wants to add to the buffer has to wait for file operation to finish. To decrease wait time of other locks that call saveData function, lock before adding to buffer and unlock before saving to file:
function saveData(newData) {
    lock()
    addToBuffer(newData)
    unlock()
    saveBufferToFile()
}

Thursday, January 12, 2023

C++: Using non-standard data types

When you use non-standard data types like enum, bool, double, long double, it might become a problem if you are sending data to another platform, e.g. sending from x86 to ARM, or even when sending from Windows to Linux. For example, long double is 8 bytes in MSVC but 16 bytes in GCC. These size differences will result in errors when casting the received bytes to data. Always know non-standard data type lengths of the platform that you are communicating with.

Wednesday, January 11, 2023

C++: Simple serialization

Simple serialization demo by converting struct to char (byte) array:

Monday, January 9, 2023

C: char pointer vs array

In C, the difference between a char pointer and char array becomes clear when you want to do assignment:

  #include<stdio.h>
  #include<string.h> //for strcpy
  int main() {
      char s[][10] = {"aaa", "bbb", "ccc"};
      //char* s[] = {"aaa", "bbb", "ccc"}; //same as above
      char* t1 = s[1];
      char t2[10]; strcpy(t2, s[1]);
      //t2 = s[1];// error: assignment to expression with array type
      printf("s[1] = %s\n", s[1]);
      printf("t1 = %s\n", t1);
      printf("t2 = %s\n", t2);
      return 0;
  }

s[1] is a char pointer. You can assign a char pointer to another char pointer but you cannot assign a char array to char pointer, you have to use strcpy. 

Another interesting difference:

    char a[] = "string1"; 
    char *p1  = a;
    char *p2  = "string2";
    a[0] = 'z';
    printf("a[0] = %c\n", a[0]);
    p1[0] = 'k'; //works fine, changes a[0]
    printf("a[0] = %c\n", a[0]);
    p2[0] = 'm'; //results in segmentation fault
    printf("p2[0] = %c\n", p2[0]);