Simple guide to understand the Simulink-hackrf source code

A simple guide to understand the S-func in simulink, mask and source code of simulink hackrf

After trying the simulink-hackrf, I get very interested in how it is realized. I found it is using the S-func block in Simulink to call those functions in hackrf.c and control the HackRF board. So I think this is a good opportunity to learn something about the S-func in Matlab and also the hackrf.c. However, the true understanding of the simulink-hackrf source code is based on the full understanding of those functions in hackrf.c. We will remain this part for later. You could regard this blog as an entrance for studying the source code of simulink-hackrf and hackrf.c

The main contents of this blog include:

  1. An introduction to the source code of simulink-hackrf and how it is realized

  2. An introduction to the S-func block in Simulink, based on one model (hackrf_source) in simulink-hackrf

  3. Change the mask of the hackrf_source in Simulink for a new GUI

  4. Change the code in hackrf_source to achieve more functions

The key of simulink-hackrf is using the S-func to call functions in the hackrf.c. It has three important source codes which are hackrf_find_devices.c, hackrf_source.c and hackrf_sink.c. They are in the path simulink-hackrf/src/. They are all written in C and executed as mex (MATLAB Executable).

Finally, these files are complied using simulink-hackrf/make.m and generate corresponding .mexw64 file. Then they are called by S-func in Simulink. The hackrf_find_devices.c is used to connect the HackRF device, hackrf_source.c is used for receiving and hackrf_sink.c is used for transmitting.

S-func is a very important tool in Simulink. It allows the user to create self-defined function in C, C# and etc. There are lots of blogs introducing the S-func. Here I will introduce the S-func based on hackrf_source.c. If you are interested, you could also refer to https://blog.smileland.me/2020/02/12/%E4%BD%BF%E7%94%A8C%E8%AF%AD%E8%A8%80%E5%86%99%E7%AE%80%E5%8D%95S-Function/ to write a simple S-func by yourself. This will help you understand the S-func more thoroughly.

Using hackrf_source.c as an example, a S-func is constructed as shown in the figure below: You could also refer to this manual https://ww2.mathworks.cn/help/simulink/sfg/how-the-simulink-engine-interacts-with-c-s-functions.html> to know more about the workflow of Simulink Engine.

mdlInitializeSizes

mdlInitializeSizes is used at the beginning of the S-func. It is used for setting input and output port, sampling time, port type and etc. You could refer to https://ww2.mathworks.cn/help/simulink/sfg/mdlinitializesizes.html for more information.

mdlStarts

mdlStart is executed after mdlInitializeSizes. It will call startHackRF function to turn on the recevier of HackRF. You could refer to https://ww2.mathworks.cn/help/simulink/sfg/mdlstart.html for more information.

mdlOutputs

mdlOutput is executed after each step. It will calculate the output of the S-func in current time step. The detailed output format is defined in mdlInitializeSizes. And you could refer to https://ww2.mathworks.cn/help/simulink/sfg/mdloutputs.html for more information.

mdlSimStatusChange

mdlSimStatusChange will be called when Pause or Continue button is pressed. It will execute stopHackRF when Pause is pressed, and execute startHackRF when Continue is pressed. You could refer to https://ww2.mathworks.cn/help/simulink/sfg/mdlsimstatuschange.html for more information.

mdlTerminate

mdlTerminate is called when simulation is stop. It will execute the stopHackRF. You could refer to https://ww2.mathworks.cn/help/simulink/sfg/mdlterminate.html for more information

mdlCheckParameters & mdlProcessParameters

mdlCheckParameters will be called when input parameter is changed. The change of parameter will happen at the begining or each time step of the simulation. mdlCheckParameters will chekc whether or not each input parameter is satisfied the requirement. mdlProcessParameters will be executed after mdlCheckParameters verify the input parameters. It is used for processing the new input parameter. In hackrf_source.c, it is mainly call Hackrf_Set_Param function to write the new parameter into the HackRF. You could refer to https://ww2.mathworks.cn/help/simulink/sfg/mdlcheckparameters.html and https://ww2.mathworks.cn/help/simulink/sfg/mdlprocessparameters.html for more information.

This is the all for introducing the S-func of hacrf_source.c. Acutally if you look at the S-func construcntion figure, it will be quite straightfoward. The whole code is not difficult to understand except those relats to pthread_mutex in mdlOutputs block. But we don’t need to care too much about these codes, just know that they are used for generating a reliable output.

After we realize the S-func using C languages, we could add a mask to make a simple UI. This UI can be used for accepting input and processing the changes in the input. There are two mask files for hackrf_source.c and hackrf_sink.c in blockset/hackrf_library.slx, and it will copy this .slx file to build/ folder in simulink-hackrf/make.m So lets have a look at how the mask in blockset/hackrf_library.slx corresponds to the hackrf_source.c

Double click to open the HackRF_Source block in hackrf_library.slx, it is shown as below:

​image​

You could see that there are several settings including center frequency, sample rate, bandwidth, output frame length, output data type, gain, lna and vga. These are actually the same as the parameters mentioned in hackrf_source.c -> mdlCheckParameters. We could try to add more input/output ports to realize more self-defined functions. What we have seen now is known as the mask, it will transform the input port in .c file into GUI. After we select the block, right click to Mask -> Edit Mask to open the Mask editor, as shown below:

​image​

Lets see an example of changing the GUI of the input parameter center frequency. Open the tab for Parameters & Dialog and select the Center Frequency. Now you could change the type of this parameter from editor to slider, ans set the max and min value for it, as shown below. Now we reopen the Hackrf_Source block and we can find the GUI of center frequency has changed to the slider. Moreover, we could set more features of this Center Frequency in Parameters & Dialog, for example like Tunable, layout and etc. To summarize, the Mask editor us very user friendly.

​image​

We could have a deeper look at the tab Initialization, as shown below. NOTICE: The parameters here are the one links to the parameters in mask and hackrf_source.c. If you look closely, you could find that the name of parameters in hackrf_source.c is different from the name in Mask -> Parameters&Dialog. For example, the parameter about center frequency setting in hackrf_source.c mdlCheckParameters function is FREQUENCY, but in mask it is called center frequency. So how are the connected ?

​image​

Actually, the first step of mex complie from hackrf_source.c to S func is through the Block Parameters tab, as shown below

​image​

We could use right click to open this Block Parameters tab (Or we will automatically start from this tab if we create a new S-func). The S-func name corresponds to the name of hackrf_source.c file. And parameters in S-func are corresponds to the input parameters in mdlCheckParameters func. For example, the second item hackrf_frequency_rounded is corresponding to the second item FREQUENCY in mdlCheckParameters.

The second step is to relate the variable in S-func parameters with the variable in Mask. For example, we could see there we use:

​>​ hackrf_frequency_rounded = round(hackrf_frequency); 

This is to take the rounded value from hackrf_frequency in Mask and give it to hackrf_frequency_rounded, which is FREQUENCY in hackrf_source.c. In this way, we create the link between parameters in MASK and .c file. The benefits of doing this is significant. For example, the required center frequency is uint64t in hackrf.c, but in MASK UI we could type in any frequency in float type. This will make no mistake.

Finally, lets try add some new input/output in hackrf_source.c to realize some new features. The original purpose is to add a software switch to turn on the biasTee in hackrf. But I find I always measure a 2.7V voltage at the antenna port whenever I turn on the biasTee or not. I also try to use software like SDRange or Airspy to turn on this function, but the result is the same. So maybe the biasTee function on my board is damaged. So I can only add a non relative feature in the hacrf_source.c code, just for the purpose to introduce the method. If you are interested, you could add some new features which are really related to the hackrf.

My new feature is very boring. It is just read a input, and when this value is higher than 10, the output will be 1, otherwise it will be 0.

Step 1.

Firstly, we need to add a input, which is named ANT_PORT. We add following code in mdlInitializeSizes. Here the SS_PRM_SIM_ONLY_TUNABLE setting indicates that this input is allowed to change during running.

​>​ ssSetSFcnParamTunable(S, ANT_PORT,  SS_PRM_SIM_ONLY_TUNABLE);

Secondly, we add code to check the type of the input to make sure it is num.

​ Assert_is_numeric(S, ANT_PORT);

Step 2.

Lets add a output. We make the following changes in mdlInitializeSizes: the code ssSetNumOutputPorts(S,2) sets the number of output ports to 2.

​ if (!ssSetNumInputPorts(S, 0)     !ssSetNumOutputPorts(S, 2)) return;

Then we set the bit width to 1:

​ ssSetOutputPortWidth(S, 1, 1);

###​ ​Step 3.

Finally add the functions in mdlOutputs to achieve what we want: The function ssGetOutputPortSignal get the value of Output Port and we could manipulate on it.

real_T *y2 = ssGetOutputPortSignal(S,1);

if(GetParam(ANT_PORT)>10){

y2[0] = GetParam(ANT_PORT)+1;

}

else{

y2[0] = 0;

}

###​ ​Step 4.

Finally we save our new code to Mine_hackrf_source.c and mex complie it. After it is successfully complied, we get Mine_hackrf_source.mexw64.

Then we create a new S-func in simulink. In Block Parameters -> S-function name we fill in hackrf_source_v2. And we fill in the name of the nine input parameters in Block Parameters -> S-function parameters. Then we can find the symbol of this S-func changes from one input and output to two outputs, as shown in the figure below. Then we could define the corresponding Mask for it.

​image​

NOTICE, becuase we define the type of all parameters should be numeric in mdlCheckParameters, and we also define the frame_size should pow of 2. So we need to follow these rules here to fill in the Block Parameters -> S-function parameters, for example, we could fill in 1,2,3,4,5,6,8,7,9. Then it can successfully link the S-func to hackrf_source_v2. After we create the link, we can chenge the Block Parameters -> S-function parameters to a more easy understand name. And we could define these parameters in mask_editor.

The final output is shown as below. We see that the hackrf is receiving and another output port is changing according to the value of ANT_PORT.

​mask4-R2019a​