Using gr::fec::code::cc_encoder class in a hierarchical block - c++

I have implemented a very basic C++ CCSDS convolutional encoder (k = 7,r = 1/2) and it works fine. However, it is very basic and it lacks options such as operational mode (CC_STREAMING, CC_TERMINATED, CC_TAILBITING, CC_TRUNCATED) etc ..etc.
Therefore, I have decided to use the default gnuradio gr::fec::code::cc_encoder class. My coding superclass will include puncturing and other blocks and therefore everything will be in a hierarchical block. So far I'm putting the blocks one by one in the hierarchical block starting with gr::fec::code::cc_encoder. Below is my .cc implementation file.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "debug_conv_encoder_impl.h"
namespace gr {
namespace baseband {
debug_conv_encoder::sptr
debug_conv_encoder::make(int frame_size, std::vector<int> polys, int mode, int pad)
{
return gnuradio::get_initial_sptr
(new debug_conv_encoder_impl(frame_size, polys, mode, pad));
}
/*
* The private constructor
*/
debug_conv_encoder_impl::debug_conv_encoder_impl(int frame_size, std::vector<int> polys, int mode, int pad)
: gr::hier_block2("debug_conv_encoder",
gr::io_signature::make(1, 1, sizeof(unsigned char)),
gr::io_signature::make(1, 1, sizeof(unsigned char)))
{
//Creating convolutional encoder
int k = 7;
int rate = 2;
bool d_pad = (pad == 1) ? true : false;
cc_mode_t d_mode = get_mode(mode);
gr::fec::code::cc_encoder::sptr encoder(gr::fec::code::cc_encoder::make(frame_size,k,rate,polys,0,d_mode,d_pad));
//connect(self(),0,self(),0); -- Works fine
connect(self() , 0 , encoder , 0); // --gives an error
connect(encoder , 0 , self() , 0); // --gives an error
//connect(encoder);
}
cc_mode_t debug_conv_encoder_impl::get_mode(int mode)
{
switch(mode)
{
case 0:
return CC_STREAMING;
case 1:
return CC_TERMINATED;
case 2:
return CC_TRUNCATED;
case 3:
return CC_TAILBITING;
default:
return CC_STREAMING;
}
}
/*
* Our virtual destructor.
*/
debug_conv_encoder_impl::~debug_conv_encoder_impl()
{
}
} /* namespace baseband */
} /* namespace gr */
And here is the header file
#ifndef INCLUDED_BASEBAND_DEBUG_CONV_ENCODER_IMPL_H
#define INCLUDED_BASEBAND_DEBUG_CONV_ENCODER_IMPL_H
#include <baseband/debug_conv_encoder.h>
#include <gnuradio/fec/cc_encoder.h>
namespace gr {
namespace baseband {
class debug_conv_encoder_impl : public debug_conv_encoder
{
private:
cc_mode_t get_mode(int mode);
public:
debug_conv_encoder_impl(int frame_size, std::vector<int> polys, int mode, int pad);
~debug_conv_encoder_impl();
// Where all the action really happens
};
} // namespace baseband
} // namespace gr
#endif /* INCLUDED_BASEBAND_DEBUG_CONV_ENCODER_IMPL_H */
Unfortunately, compiling and linking the file (cmake .. && make) give this error:
xxx/GRC/baseband/gr-baseband/lib/debug_conv_encoder_impl.cc:53:39: error: no matching function for call to ‘gr::baseband::debug_conv_encoder_impl::connect(gr::hier_block2::opaque_self, int, gr::fec::generic_encoder::sptr&, int)’
connect(self() , 0 , encoder , 0);
/usr/local/include/gnuradio/hier_block2.h:105:10: note: no known conversion for argument 3 from ‘gr::fec::generic_encoder::sptr {aka boost::shared_ptr<gr::fec::generic_encoder>}’ to ‘gr::basic_block_sptr {aka boost::shared_ptr<gr::basic_block>}’
Basically, the line "gr::fec::generic_encoder::sptr {aka boost::shared_ptr<gr::fec::generic_encoder>}’ to ‘gr::basic_block_sptr {aka boost::shared_ptr<gr::basic_block>}’" implies that the shared pointer gr::fec::generic_encoder can't be converted to gr::basic_block as required by hier_block2.connect (basic_block_sptr src, int src_port, basic_block_sptr dst, int dst_port).
I have created many hierarchical blocks this way but never encountered this error. I'm pretty sure there is something big I'm missing. Any help will be highly appreciated. And by the way, please let me know if more information is needed.
Cheers.

I was finally able to fix the issue. Turns out the Gnu radio FECAPI provides coder variables to define the FEC property (classes derived from the gr::fec::generic_encoder class eg. cc_encoder, ldpc_encoder etc) and deployment variables ( which interact with the scheduler and the coder variable in the GNU radio flowgraph. The deployment variable "gr::fec::encoder" can be used with a number of coder variables such as the cc_encoder or LDPC encoder. The work function now looks as shown below. The OOT now compiles and works as it should.
debug_conv_encoder_impl::debug_conv_encoder_impl(int frame_size, std::vector<int> polys, int mode, int pad)
: gr::hier_block2("debug_conv_encoder",
gr::io_signature::make(1, 1, sizeof(unsigned char)),
gr::io_signature::make(1, 1, sizeof(unsigned char)))
{
//Creating a coder variable
int k = 7;
int rate = 2;
bool d_pad = (pad == 1) ? true : false;
cc_mode_t d_mode = get_mode(mode);
gr::fec::code::cc_encoder::sptr coder_variable(gr::fec::code::cc_encoder::make(frame_size,k,rate,polys,0,d_mode,d_pad));
//Creating a deployment variable
gr::fec::encoder::sptr coder_deployment(gr::fec::encoder::make(coder_variable,sizeof(unsigned char),sizeof(unsigned char)));
connect(self() , 0 , coder_deployment , 0);
connect(coder_deployment , 0 , self() , 0);
//connect(encoder);
}

cc_encoder is not a block, hence you can't connect it in a flow graph like a block.
In fact, you shouldn't be able to instantiate it, even, as it's an abstract base class only:
https://gnuradio.org/doc/doxygen/classgr_1_1fec_1_1code_1_1cc__encoder.html
I'm not quite sure what an encoder you need, but in any case, this class isn't the way to go.

Related

GStreamer error: gst_element_register: assertion 'g_type_is_a (type, GST_TYPE_ELEMENT)' failed

I'm trying to write a basic plugin for gstreamer in C++. I am working from another person's examples and have followed the structure of the code (I believe) exactly. However, I've been trying to compile the code and I am seeing an error saying
unresolved external symbol gst_adder_get_type referenced in function "int __cdecl plugin_init(struct _GstPlugin *)" (?plugin_init##YAHPEAU_GstPlugin###Z)
I have declared but not implemented gst_adder_get_type. I did that because the examples I have seen have not had any implementation of the function either, they just have the declaration in the header file and somehow that works.
I have tried implementing the function myself anyway, but other errors pop up instead.
Adder.h:
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
G_BEGIN_DECLS
#define GST_TYPE_ADDER (gst_adder_get_type())
#define GST_ADDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ADDER,Gstadder))
#define GST_ADDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ADDER,GstadderClass))
#define GST_IS_ADDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ADDER))
#define GST_IS_ADDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ADDER))
struct _Gstadder
{
GstElement element;
//pads
GstPad* srcpadadder; //publish data
// property values
gint _num_one;
gint _num_two;
gint _sum;
};
struct _GstadderClass
{
GstElementClass parent_class;
};
GType gst_adder_get_type(void);
typedef struct _Gstadder Gstadder;
typedef struct _GstadderClass GstadderClass;
GST_ELEMENT_REGISTER_DECLARE(adder);
G_END_DECLS
Adder.cpp:
// Adder.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"
#include "pch.h"
#include <gst/gst.h>
#include "Adder.h"
#include <gstreamer-1.0/gst/base/gstbasesrc.h>
#include <gstreamer-1.0/gst/base/gstpushsrc.h>
GST_DEBUG_CATEGORY(gst_adder_debug);
// This defines the properties owned by this class.
enum
{
PROP_NUMONE,
PROP_NUMTWO,
PROP_SUM
};
// Definitions of functions later in this file so that we can access them now.
static void gst_adder_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec);
static void gst_adder_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec);
static gboolean gst_adder_start(GstBaseSrc* basesrc);
static gboolean gst_adder_stop(GstBaseSrc* basesrc);
static GstCaps* gst_adder_get_caps(GstBaseSrc* bsrc, GstCaps* caps);
static GstFlowReturn gst_adder_fill(GstPushSrc* src, GstBuffer* buf);
static void gst_adder_finalize(GObject* object);
/*
* "CAPS" are literally capabilities. They seem only to be descriptions, not functions.
* I think this means that when I run an inspect on the DLL, this gets called to write out
* what the capabilities of the function actually are and what kinds of pads exist.
*/
static GstStaticPadTemplate src_det_factory = GST_STATIC_PAD_TEMPLATE(
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS("Integer"));
static void gst_adder_class_init(GstadderClass * klass) {
/*
Class starting initiation. Different from the object instantiation.
*/
GObjectClass* gobject_class;
gobject_class = G_OBJECT_CLASS(klass);
GstElementClass* element_class;
element_class = GST_ELEMENT_CLASS(klass);
GstBaseSrcClass* gstbasesrc_class;
gstbasesrc_class = (GstBaseSrcClass*)klass;
GstPushSrcClass* gstpushsrc_class;
gstpushsrc_class = (GstPushSrcClass*)klass;
// Metadata. Not sure if this is redundant or not. Assuming not.
const gchar* m_a = "AdditionMan";
gst_element_class_set_static_metadata(
element_class,
m_a,
"MY_ADDER",
"Add two numbers, return the sum",
"John Garst <john.garst#parsons.com>");
// Initialize pad for the source
gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&src_det_factory));
// This appears to be where we are linking the callback functions for the adder.
gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_adder_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_adder_get_property);
gstbasesrc_class->start = GST_DEBUG_FUNCPTR(gst_adder_start);
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR(gst_adder_stop);
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR(gst_adder_get_caps);
gstpushsrc_class->fill = GST_DEBUG_FUNCPTR(gst_adder_fill);
gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_adder_finalize);
// Property Definitions. This is linked to an enum at the top of this file,
// and will be used more in the adder instantiation and getters/setters.
g_object_class_install_property(
gobject_class,
PROP_NUMONE,
g_param_spec_string(
"NumOne",
"NumOne",
"The first number to add.",
0,
G_PARAM_READWRITE
)
);
g_object_class_install_property(
gobject_class,
PROP_NUMTWO,
g_param_spec_string(
"NumTwo",
"NumTwo",
"The second number to add.",
0,
G_PARAM_READWRITE
)
);
g_object_class_install_property(
gobject_class,
PROP_SUM,
g_param_spec_string(
"Sum",
"Sum",
"The sum of NumOne and NumTwo.",
0,
G_PARAM_READWRITE
)
);
}
static void gst_adder_init(Gstadder* filter) {
/*
instantiate the element. This happens after class initiation.
*/
//initialize pads
filter->srcpadadder = gst_pad_new_from_static_template(&src_det_factory, "src");
//initialize values
filter->_num_one = 0;
filter->_num_two = 0;
filter->_sum = 0;
//configure
gst_base_src_set_format(GST_BASE_SRC(filter), GST_FORMAT_TIME);
gst_base_src_set_live(GST_BASE_SRC(filter), true);
gst_base_src_set_do_timestamp(GST_BASE_SRC(filter), true);
}
static gint gst_adder_add_two_numbers(Gstadder* filter) {
/*
This function takes two numbers and adds them together, returning the sum of those numbers.
*/
filter->_sum = filter->_num_one + filter->_num_two;
return filter->_sum;
}
void gst_adder_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) {
/*
Set properties in the adder.
We can set the two numbers to add, but not the sum.
*/
Gstadder* that = GST_ADDER(object);
switch (prop_id)
{
case PROP_NUMONE:
that->_num_one = g_value_get_int(value);
break;
case PROP_NUMTWO:
that->_num_two = g_value_get_int(value);
break;
}
}
void gst_adder_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) {
/*
Set properties in the adder.
We can get any property, including the sum.
*/
Gstadder* that = GST_ADDER(object);
switch (prop_id)
{
case PROP_NUMONE:
g_value_set_int(value, that->_num_one);
break;
case PROP_NUMTWO:
g_value_set_int(value, that->_num_two);
break;
case PROP_SUM:
g_value_set_int(value, that->_sum);
break;
}
}
gboolean gst_adder_start(GstBaseSrc* basesrc) {
/*
Start the adder. There is nothing else necessary to initialize, so we won't do anything here.
*/
return gboolean();
}
gboolean gst_adder_stop(GstBaseSrc* basesrc) {
/*
Stop the adder. There is nothing to clean, so we won't do anything here.
*/
return gboolean();
}
GstFlowReturn gst_adder_fill(GstPushSrc* src, GstBuffer* buf) {
/*
Fill the adder from buffer. This seems to be where the magic actually happens.
*/
Gstadder* filter = GST_ADDER(src);
gst_adder_add_two_numbers(filter);
return GstFlowReturn();
}
GstCaps* gst_adder_get_caps(GstBaseSrc* bsrc, GstCaps* caps) {
/*
Return Adder capabilities
*/
#ifdef __linux__
return gst_caps_new_simple(0, NULL, NULL);
#else
return gst_caps_new_simple(0, nullptr);
#endif
}
void gst_adder_finalize(GObject* object) {
/*
Release memory and clean up the workspace.
*/
}
GType gst_adder_get_type(void)
{
static GType gst_adder_get_type = 0;
if (!gst_adder_get_type) {
static const GTypeInfo gst_adder_get_type_info = {
sizeof(GstadderClass),
NULL,
NULL,
NULL,
NULL,
NULL,
0,
0,
NULL,
};
gst_adder_get_type = g_type_register_static(G_TYPE_INTERFACE,
"GstVideoOverlay", &gst_adder_get_type_info, G_TYPE_FLAG_ABSTRACT);
}
return gst_adder_get_type;
}
gst_Plugin_Test.h
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the VIDEOSTRETCH_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// VIDEOSTRETCH_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef GST_PLUGIN_TEST_EXPORTS
#define GST_PLUGIN_TEST_API __declspec(dllexport)
#else
#define GST_PLUGIN_TEST_API __declspec(dllimport)
#endif
gst_Plugin_Test.cpp
// GST_Plugin_Test.cpp : Seems to initialize only the other classes that are involved. Doesn't seem
// like this can do it's own processing, which is a little odd to me. I don't know if that's correct.
//Includes. stdafx is required for some reason, as is pch.
#include "stdafx.h"
#include "pch.h"
#include "Adder.h"
#include <gst/gst.h>
#include "gst_Plugin_Test.h"
GST_DEBUG_CATEGORY(gst_gst_plugin_test_debug);
static gboolean plugin_init(GstPlugin* plugin)
{
/*
One of (?) the initialization functions. Seems like the main entry point.
*/
gboolean ret = TRUE;
GST_DEBUG_CATEGORY_INIT(gst_gst_plugin_test_debug, "gst_plugin_test", 0, "Test Stuff");
// The adder class is where things actually happen. We register it here.
ret = gst_element_register(plugin, "MY_ADDER", GST_RANK_NONE, GST_TYPE_ADDER);
return ret;
}
#define PACKAGE "GST_Plugin_Test"
// This is where the plugin metadata is defined. Shown on a gst-inspect-1.0
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
GST_VERSION_MINOR,
GST_Plugin_Test,
"Just Testing Things",
plugin_init, "1.0", "LGPL",
"TEST", "http://www.polarisalpha.com");
UPDATE:
I did find a place that has another example where the get_type function is declared in the header and implemented in the C file, which makes a lot more sense. I've done it myself, again following the structure as best I can, and now can compile the DLL and put it into my plugins folder. However, I can't successfully inspect the plugin. It give me the error:
gst_element_register: assertion 'g_type_is_a (type, GST_TYPE_ELEMENT)' failed
which seems odd. I've updated the Adder file to include the implementation of the get_type function.

Convert errno to exit codes

I'm working on lib which uses a lot of file system functions.
What I want is that my function returns various of error codes (not just -1 as error) depending on errno in case file system function fails.
Although I could use errno values directly but I want to create some abstraction layer between my functions error codes and system errno (e.g. my error values begins on -1000 and are negative whereas errno values are positive).
My question what is the best way to implement it.
For now I see two possible solution:
use an enum with error codes and switch case function to translate, e.g.:
typedef enum {
MY_ERROR_EPERM = -1104, /* Operation not permitted */
MY_ERROR_ENOENT = -1105, /* No such file or directory */
// ...
} MyReturnCodes_t;
int ErrnoToErrCode(unsigned int sysErrno) {
int error = ENOSYS;
switch(sysErrno) {
case EPERM: error = MY_ERROR_EPERM; break;
case ENOENT: error = MY_ERROR_ENOENT; break;
// ...
}
return error;
}
use translation directly in enum:
#define ERR_OFFSET -1000
typedef enum {
MY_ERROR_EPERM = ERR_OFFSET - EPERM, /* Operation not permitted */
MY_ERROR_ENOENT = ERR_OFFSET - ENOENT, /* No such file or directory */
MY_ERROR_ESRCH = ERR_OFFSET - ESRCH, /* No such process */
// ...
} MyReturnCodes_t;
Which way is more constant?
One more point: This library should be used both on QNX and Linux OS, what is the proper way to align errno codes (which different in some cases)?
I´d go for a std::map in a dedicated function. You don't have to care about gaps or anything as long as you use the provided error macros:
#include <iostream>
#include <errno.h>
#include <map>
namespace MyError
{
enum MyReturnCode: int
{
MY_INVALID_VAL = 0 , /* Invalid Mapping */
MY_ERROR_EPERM = -1104, /* Operation not permitted */
MY_ERROR_ENOENT = -1105, /* No such file or directory */
};
MyReturnCode fromErrno(int e)
{
static const std::map<int, MyReturnCode> mapping {
{ EPERM, MY_ERROR_EPERM},
{ ENOENT, MY_ERROR_ENOENT}
};
if(mapping.count(e))
return mapping.at(e);
else
return MY_INVALID_VAL;
}
}
int main()
{
std::cout << MyError::fromErrno(ENOENT) << std::endl;
std::cout << MyError::fromErrno(42) << std::endl;
return 0;
}
http://coliru.stacked-crooked.com/a/1da9fd44d88fb097

LLVM ERROR: MCJIT::runFunction does not support full-featured argument passing

I have got an example from here and I faced with a run error
LLVM ERROR: Target does not support MC emission!
which I fixed it by this.
nevertheless, I still observe runtime problem:
./example 3 5
LLVM ERROR: MCJIT::runFunction does not support full-featured argument passing. Please use ExecutionEngine::getFunctionAddress and cast the result to the desired function pointer type.
main.cpp
/**
* LLVM equivalent of:
*
* int sum(int a, int b) {
* return a + b;
* }
*/
#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/Target.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/BitWriter.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
LLVMModuleRef mod = LLVMModuleCreateWithName("my_module");
LLVMTypeRef param_types[] = { LLVMInt32Type(), LLVMInt32Type() };
LLVMTypeRef ret_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, 0);
LLVMValueRef sum = LLVMAddFunction(mod, "sum", ret_type);
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(sum, "entry");
LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, entry);
LLVMValueRef tmp = LLVMBuildAdd(builder, LLVMGetParam(sum, 0), LLVMGetParam(sum, 1), "tmp");
LLVMBuildRet(builder, tmp);
char *error = NULL;
LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error);
LLVMExecutionEngineRef engine;
error = NULL;
LLVMLinkInMCJIT();
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter(); // added
LLVMInitializeNativeAsmParser(); // added
if (LLVMCreateExecutionEngineForModule(&engine, mod, &error) != 0)
{
fprintf(stderr, "failed to create execution engine\n");
abort();
}
if (error)
{
fprintf(stderr, "error: %s\n", error);
LLVMDisposeMessage(error);
exit(EXIT_FAILURE);
}
if (argc < 3)
{
fprintf(stderr, "usage: %s x y\n", argv[0]);
exit(EXIT_FAILURE);
}
long long x = strtoll(argv[1], NULL, 10);
long long y = strtoll(argv[2], NULL, 10);
LLVMGenericValueRef args[] = {
LLVMCreateGenericValueOfInt(LLVMInt32Type(), x, 0),
LLVMCreateGenericValueOfInt(LLVMInt32Type(), y, 0)
};
LLVMGenericValueRef res = LLVMRunFunction(engine, sum, 2, args);
printf("%d\n", (int)LLVMGenericValueToInt(res, 0));
// Write out bitcode to file
if (LLVMWriteBitcodeToFile(mod, "sum.bc") != 0) {
fprintf(stderr, "error writing bitcode to file, skipping\n");
}
LLVMDisposeBuilder(builder);
LLVMDisposeExecutionEngine(engine);
}
Though the meessage is clear for the view point of the code author, for me as a user it is so cryptic. How can I solve this?
From the documentation of MCJIT::runFunction:
For MCJIT execution engines, clients are encouraged to use the "GetFunctionAddress" method (rather than runFunction) and cast the returned uint64_t to the desired function pointer type. However, for backwards compatibility MCJIT's implementation can execute 'main-like' function (i.e. those returning void or int, and taking either no arguments or (int, char*[])).
So you can't call MCJIT::runFunction (and by extension the C API's LLVMRunFunction when used with an MCJIT engine) unless the arguments array is either empty or consists of only an i32 and an i8* (in that order). Your array contains two i32s, so it does not meet those restrictions.
As stated in the documentation (and the exception message), you should instead use ExecutionEngine::getFunctionAddress (or its C wrapper LLVMGetFunctionAddress), cast the result to int (*)(int, int) and then call it as f(0, 0);.

Problems compiling simple OpenCL example code under Xcode 6.1.1 with C++

I have a simple hello world OpenCL program. For some reason the compiler gives an error when I try to reference the kernel name from within the code.
In kernel.cl I have
kernel void square_kernel(global float *input, global float * output, const unsigned int count)
{
size_t i = get_global_id(0);
if(i<count)
output[i] = input[i] * input[i];
}
In main.cpp I have:
...
#include "kernel.cl.h"
...
int main()
{
...
dispatch_sync(queue, ^{
size_t wgs;
gcl_get_kernel_block_workgroup_info(square_kernel, CL_KERNEL_WORK_GROUP_SIZE, sizeof(wgs), &wgs, NULL);
cl_ndrange range = {
1, // number of dims
{0, 0, 0}, // offset in each dim
{DATA_SIZE, 0, 0}, // global range (total)
{wgs, 0, 0} // local size of each work group #work_groups = DATA_SIZE / wgs
};
// call kernel
square_kernel(&range, (cl_float *)mem_in, (cl_float *)mem_out, DATA_SIZE);
// copy the output
gcl_memcpy(results, mem_out, sizeof(cl_float) * DATA_SIZE);
});
...
}
I get "use of undeclared identifier square_kernel" where it is referenced. The cl file must be building because it generates the byte code files.
Now its just occurred to me that it might be because I am referencing it from a c++ file. However I am not sure how to fix that problem, if that is what causes it. I don't want to use C if I can help it. Any ideas?
It's worth checking the auto-generated kernel.cl.h header to double-check the definition of the function you are trying to call in this situation. I've just created a new Xcode project and built your OpenCL kernel with it, and the resulting function definition looks like this:
extern void (^square_kernel_kernel)(const cl_ndrange *ndrange, cl_float* input, cl_float* output, cl_uint count);
Note the extra _kernel in the function name.

Attempting to use a Template instead of an Overloaded Function in Arduino: TYPE not declared in this Scope

I'm trying to write a function that can Shift out data to 74HC595 shift registers which can shift out 8, 16, and 32 bit values.
Using an overloaded function, I have this:
/**********************************************************************************
* Software SPI Pin Settings
*********************************************************************************/
#define SPIPINPORT PORTB //The Port that the Pins are on.
#define LatchPin 2 //_RCLK Shift register clock pin
#define DataPin 3 //SER DS Serial data input
#define ClockPin 5
/**********************************************************************************
* Preproccesor PIN to PIN Mask
*********************************************************************************/
#define LATCHMASK (1 << LatchPin)
#define MOSIMASK (1 << DataPin)
#define CLOCKMASK (1 << ClockPin)
/**********************************************************************************
* Macros
*********************************************************************************/
#define tggl(port,bit) (port)^=(1<<(bit))
#define LATCH (SPIPINPORT &=~ LATCHMASK)
#define unLATCH (SPIPINPORT |= LATCHMASK)
#define PULSE { tggl(SPIPINPORT,ClockPin); tggl(SPIPINPORT,ClockPin); }
void zShiftClass::ShiftOut(uint8_t value)
{
LATCH;
for (uint8_t i = 0; i <= 7; i++)
{
if( !!(value&(1<<i)) == true) //If value is not a 1, turn off MOSIMASK
{ SPIPINPORT |= MOSIMASK; }
else
{ SPIPINPORT &= ~MOSIMASK; }
PULSE; //Pulse the Clock
}
unLATCH;
}
void zShiftClass::ShiftOut(uint16_t value)
{
LATCH;
for (uint8_t i = 0; i <= 15; i++)
{
if( !!(value&(1<<i)) == true) //If value is not a 1, turn off MOSIMASK
{ SPIPINPORT |= MOSIMASK; }
else
{ SPIPINPORT &= ~MOSIMASK; }
PULSE; //Pulse the Clock
}
unLATCH;
}
void zShiftClass::ShiftOut(uint32_t value)
{
LATCH;
for (uint8_t i = 0; i <= 31; i++)
{
if( !!(value&(1<<i)) == true) //If value is not a 1, turn off MOSIMASK
{ SPIPINPORT |= MOSIMASK; }
else
{ SPIPINPORT &= ~MOSIMASK; }
PULSE; //Pulse the Clock
}
unLATCH;
}
And I want to use this template to replace these functions:
template<typename TYPE>void Shift(TYPE value)
{
uint8_t loops = (( 8 * sizeof(value) ) - 1 );
LATCH;
for (uint8_t i = 0; i <= loops; i++)
{
if( !!(value&(1<<i)) == true) //If value is not a 1, turn off MOSIMASK
{ SPIPINPORT |= MOSIMASK; }
else
{ SPIPINPORT &= ~MOSIMASK; }
PULSE; //Pulse the Clock
}
unLATCH;
}
When I compile, I get the following errors:
Compiling 'zLEDArray' for 'Arduino Uno'
zLEDArray.ino : variable or field 'Shift' declared void
zLEDArray.ino : 'TYPE' was not declared in this scope
Error compiling
What am I doing wrong?
Okay, this falls in the category of "beware of dev tools bearing gifts". The Arduino sketch tool is your problem. If you turn on verbose compiler output on the preferences menu, you will get some insight into what happens. With your code, I can duplicate your error. When compiling a test project called template1, the same error is reported, but now can see the compiler command line:
D:\arduino-dev\arduino-1.0.3\hardware\tools\avr\bin\avr-g++ -c ...yada yada
more yada... e:\Temp\build3528223623599856131.tmp\template1.cpp ...
template1:14: error: variable or field 'Shift' declared void
template1:14: error: 'TYPE' was not declared in this scope
The key point is that .CPP file. That is a file that the dev environment constructs from your .INO and is what is the actual input to the compiler. If you go grab that file, you will see all your code with some bonus lines included:
#include "Arduino.h"
void Shift(TYPE value);
void setup();
void loop();
The build tool added for you, 4 lines:
the Arduino header (because nobody remembers this)
3 forward declarations for functions that it figured out by parsing code
The attempt at producing a forward declaration from the function template is incorrect, and produces the code that results in the compiler error.
The solution is to move the template out from the .INO file.
Create a library folder, say T1.
Create a .H file in that folder with the template code, say tspi.h.
Import the library to your project.
Make sure the #include line is after the first line of code in your .INO (more weirdness - the tool will insert a #include "Arduino.h" after all the comments but before first line of code. If you leave your include at the top of the .INO file, it will be processed before the Arduino header)
You can get rid of the error by adding the correct forward declaration in your ino file. The inuntuitive thing is that you must also do this if you define the function before you use it:
template <typename TYPE> void Shift(TYPE value);
// you may use the function here or you can have the declaration
// immediately before the definition
template<typename TYPE>void Shift(TYPE value)
{
// your implementation
}
The explanation why this is the case is in jdr5ca's answer. Thanks for clarifying, I found this out by trial and error.