Complete Example for Passing Array by Reference to C for Processing

I am having issues getting Matlab Coder to allow me to pass an array into a CRC calculator .m file, then pass that array down to C and have C do the processing.
function crc = crccalculate10(in1) %#codegen
assert(isa(in1,'uint8'));
assert(all(size(in1) <= [inf]));
crc = 0;
% generate an include in the C code
coder.cinclude('crccalculate10.h');
% evaluate the C function
crc = coder.ceval('crccalculate10', coder.rref(in1), uint8(numel(in1)));
end
As far as I can tell, the issue isn't in the code, it's in the codegen params, especially the -args <> argument, where you would normally specify what variables can be passed in. But I cannot find any examples of passing, what I understand needs to be a variable length array. It is documented in several places, for example here, which lacks the codegen command itself to specify the length. And here provides some examples of fixed size matrices being passed in, but no variable sized. And if you read the coder.varsize documentation, every example shows varsize operating on the output variable, never the input variable. This guy seems to have similar questions on the use of coder.varsize and coder.typeof.
My best guess on use use of typeof basically involves building a coder.Type variable and passing that. The procedure would be basically,
x = [uint8(1) uint8(1) uint8(1)]
coder.varsize('x', [1, Inf])
t = coder.typeof(x)
codegen crccalculate10 -args {t} crccalculate10.c
I checked the type and it looks correct to me. But also, I tried using coder.varsize(t, [1 Inf]). Both cases lead to a compiler error, on a line in my .c that doesn't exist (?!),
Error crccalculate10.c: 19 type error in argument 2 to `crccalculate10'; found 'int' expected 'pointer to unsigned char'
Unfortunately I don't have a line 19 in either my C source or my M file, so that compiler output is very incorrect. But, if I had to guess, the value of coder.rref(in1) is not "t" specified above.
At this point I have exhausted basically everything I can think of to make this work. I might just have to try to reimplement it in Matlab, it might have been faster. Any assistance would be appreciated. That said, I think this use case, being incredibly common in C code, deserves a clear and concise example in the documentation.

 Accepted Answer

Thanks for the recommendation!
We're working on improving our documentation and this is valuable feedback.
Let's see if I can help clarify:
  1. "coder.varsize" is meant to be used within the MATLAB function for which you're generating code
  2. "coder.typeof" is meant to be used to create a type to pass to "codegen"
For your example, it sounds like you want the codegen argument (in args):
coder.typeof(uint8(42),[1 Inf],[0 1])
(This can be saved in a variable "t" like in your code.)
The [1 Inf] specify the maximum size in each dimension, and [0 1] indicate that the second dimension (and not the first) are variable-sized.
Based on the error (which comes from the C compiler), it seems like expects an unsigned character pointer as its second argument. However, it is being passed an int, and based on the MATLAB code, it should be passed a uint8.
crccalculate10.c is one of the C files generated by codegen, which is where the C compiler error occurs. Add "-report" (without quotes) as another argument to codegen, which displays the generated files and other information.

3 Comments

Thank you for the quick response,
There seems to be some confusion as to the nature of the C code I am compiling, as I mentioned I am not using the C code generator, I am trying to wrap a handcoded C file with a Matlab function to allow access without rewriting everything. But also, because there are several functions that I need to do this for, and so figuring out how to access them directly and also maintaining common code is better in the long term. Only mentioning because it looks pertinent in this case.
Also noting the version of MATLAB is R2017a in case it matters. The coder documentation doesn't provided a version.
When I use the typeof provided and with -report, after inspecting the source code, it looks like codegen is not using the header from coder.cinclude('crccalculate10.h'); it is instead generating a new header. The definition of crccalculate10.h is not correct in this header, being
extern uint16_T crccalculate10(const emlrtStack *sp, const emxArray_uint8_T *in1);
This is what is giving the error during compilation, because it looks like coder.ceval is calling the generated function rather than the funciton I provided. So when I pass the 2nd argument as the uint8(numel(in1)) then it doesn't match the definition (despite matching both the provided .h file, and the c file).
With the information you provided on typeof I also went back to the PBR example here and found that I also cannot get this to compile. The example also uses arrays passed by reference (just with double instead of uint8). The example omits the codegen command, but I have tried the following to specify two variable sized double arrays of the same type.
cAddType = coder.typeof(double(42.0),[1 Inf],[0 1]);
codegen cAdd -args {cAddType, cAddType} cAdd.c cAdd.h -report
I get the same error in the example code as my own :( The compilation fails due to a mismatch between, for example, the cAdd.h provided via cinclude, and the cAdd generated by codegen. The signature of the cAdd definition is
extern void cAdd(const emlrtStack *sp, const emxArray_real_T *in1, constemxArray_real_T *in2, emxArray_real_T *out);
What I would expect is maybe the method cAdd above would delegate to the example cAdd.c, but, it seems like it's skipping any sort of delegation and trying to call it directly.
I guess the question for me now is, is it possible to do what I am trying to do, and call into a C file? Is there a way to reconcile what Matlab is trying to do in generating the code, with what I have provided in source? That seems to be where the mismatch is. Based on the codegen examples, I thought this was possible, but if the examples don't work as written, then I feel like I am missing some important distinction here.
Edit; My apologies, I thought I saw codegen in the pass by reference example and didn't see it when I went back to try. But it is there, unfortunately, the codegen command as provided also doesn't work
A = rand(2,2)+1;
B = rand(2,2)+10;
codegen cAdd -args {A, B} cAdd.c cAdd.h -report
[ compiler output redacted due to folder names ]
Warning cAdd.c: 23 assignment of pointer to double to pointer to struct emlrtStack
Error cAdd.c: 23 type error in argument 4 to `cAdd'; found 'int' expected 'pointer to double'
Edit; Changed names to match example name
Ah, my apologies for not noticing the root cause earlier. Yes, calling into a C file is supported. The root of the issue is:
The C function and the M function have the same name, which leads to a naming conflict (causing the error). This is because the generated C function name is the same as the M function name, causing a conflict in C.
While your end goal is not generating C code, in order to interface MATLAB with the C function, we generate C code in order to compile it into a MEX, which can be called directly in MATLAB.
In general, specific names can be excluded from appearing in the generated code via the config parameter ReservedNameArray, briefly mentioned on this page:
It can be used as follows:
cfg = coder.config;
cfg.ReservedNameArray = 'name1;name2';
codegen -config cfg ...
This will prevent "name1" and "name2" from appearing as identifiers in the generated code.
However, this is not honored for entry-point functions (the M function name you pass to "codegen") as the expectation is that the C function should have the same name as the M function.
Thus, in this case, the solution is to rename either the M function or the C function from "crccalculate10" so they have different names.
This worked! That was the issue.
If anyone finds this and is looking for a concise example, see
  1. The Pass by Reference example here
  2. The typeof example provided in David's response here, with typeof docs here.
  3. Ensure that the ceval, prototype and definition of functions are all named the same.
  4. Ensure the matlab function is named something else.
With those considerations it should compile.
Thanks!

Sign in to comment.

More Answers (0)

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!