I have below code in a C header file:
/** \brief Forward declaration for instance object. */
typedef struct CbData_t CbData;
/**
* \brief Callback function prototype.
*
* \param cbData [OUT] Callback Data. Refer #CbData
* \return None.
*/
typedef void (*cbFxn)(CbData cbData);
/**
* \brief Structure containing callback data.
*/
struct CbData_t
{
uint32_t id;
/**< Id for which interrupt has occurred */
};
When I try to create doxygen (version 1.8.13), I get the below error:
warning: explicit link request to 'CbData' could not be resolved
How can I resolve this error?
Related
I would like to use the Doxygen grouping mechanism for data structures. I'm already using it for functions and it works well so far. What I've experienced so far fits to the documentation regarding member groups of a single type (e.g. function only) or mixed type (e.g. typedefs and functions).
Now I tried to extend these member groups with data structures, and this fails exceptionally. Data structures are always a top section on its own. My tries so far:
Put a data structures definition inside an existing mixed type member group. -> Data structure is still documented in a separate top level section.
/**
* \file doxytest.h
*/
/**
* \name Iteration API
* \brief Some documentation. Group will be on top level.
*/
/// #{
/**
* \brief For no reason this is not part of the member group.
*/
typedef struct {
/**
* \brief Some mask
*/
uint32_t mask;
} filter_t;
/**
* \brief Some variable
*/
extern const uint32_t MODE_FILTER_MASK;
/**
* \brief Curiously this IS part of the member group.
*/
typedef bool (*for_each_cb)(const void *obj, void *opaque);
/**
* \brief Some function
*/
uint32_t filter_id_filter_set(size_t ids_num, ...);
/// #}
Side by Side of final Doxygen output and desired Doxygen output (Photoshopped)
Creating a group solely consisting of data structures. -> Data structures are documented in a separate top level section and the documentation block for this group vanishes completely.
/**
* \file doxytest2.h
*/
/**
* \name Structures
* \brief This documentation block will not show up
* in the final file documentation. It is completely lost.
*/
/// #{
/**
* \brief Won't show up in group/section "Structures"
*/
typedef struct {
/**
* \brief Some mask
*/
uint32_t mask;
} filterA_t;
/**
* \brief Won't show up as well
*/
typedef struct {
/**
* \brief Some mask
*/
uint32_t mask;
} filterB_t;
/// #}
/// Some struct that should not show up in group "Structures"
typedef struct {
int bar;
} someStruct;
Side by Side of final Doxygen output and desired Doxygen output (Photoshopped)
Use a module and add the data structures mit \ingroup. -> Data structure pops up in the module, but the file documentation still looks the same as above
Using \nosubgrouping command on file level documentation. -> No changes at all to file documentation page.
/**
* \file doxytest.h
* \nosubgrouping
*/
I would like that the documentation for file doxytest.h/doxytest2.h displays data structures in the group they were defined in.
The programming language is C, but I'm very limited in terms of changing the code to fit documentation needs. Doxygen version is 1.8.16. The configuration file is almost default. (I left out stuff like project name and input settings)
OPTIMIZE_OUTPUT_FOR_C = YES
EXTRACT_ALL = YES
EXTRACT_STATIC = YES
SORT_MEMBER_DOCS = NO
DISABLE_INDEX = NO
Any help appreciated.
It took me several months to find, but the answer was deceptively simple.
You just need to enable INLINE_SIMPLE_STRUCTS:
# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
# with only public data fields or simple typedef fields will be shown inline in
# the documentation of the scope in which they are defined (i.e. file,
# namespace, or group documentation), provided this scope is documented. If set
# to NO, structs, classes, and unions are shown on a separate page (for HTML and
# Man pages) or section (for LaTeX and RTF).
# The default value is: NO.
INLINE_SIMPLE_STRUCTS = YES
The fact that the data structures are "simple" is only a consideration of every member being publicly accessible, not the number of entries.
I'm migrating some lines coded on C to C++/CLI (UI Windows Form based on .NET). One of my problems comes when I try to do this kind of assignation:
myCallbacks.cbf_data_write = this->dataWriteFunc;
In this case, dataWriteFunc is defined as:
PNIO_IOXS dataWriteFunc(PNIO_UINT32, PNIO_DEV_ADDR *, PNIO_UINT32, PNIO_UINT8 *, PNIO_IOXS);
And myCallbacks is declared as
PNIOD_CBF_FUNCTIONS myCallbacks;
with
typedef struct {
PNIO_UINT32 size; /* size of struct = sizeof(PNIO_CBF_FUNCTIONS) */
PNIO_CBF_DATA_WRITE cbf_data_write; /* mandatory */
PNIO_CBF_DATA_READ cbf_data_read; /* mandatory */
PNIOD_CBF_ASYNC_REC_READ cbf_async_rec_read; /* mandatory */
PNIOD_CBF_ASYNC_REC_WRITE cbf_async_rec_write; /* mandatory */
PNIOD_CBF_SYNC_ALARM_DONE cbf_sync_alarm_done; /* mandatory */
PNIOD_CBF_ASYNC_CONNECT_IND cbf_async_connect_ind; /* mandatory */
PNIOD_CBF_ASYNC_OWNERSHIP_IND cbf_async_ownership_ind; /* mandatory */
PNIOD_CBF_ASYNC_INDATA_IND cbf_async_indata_ind; /* mandatory */
PNIOD_CBF_SYNC_DISCONNECT_IND cbf_sync_disconnect_ind; /* mandatory */
PNIOD_CBF_SYNC_DATA_STATUS_IND cbf_sync_data_status_ind; /* mandatory */
PNIOD_CBF_ASYNC_PRM_END_IND cbf_async_prm_end_ind; /* mandatory */
PNIOD_CBF_SYNC_STOPPED cbf_sync_device_stopped; /* mandatory */
PNIOD_CBF_ASYNC_IRT_INIT_INPUTS cbf_async_irt_init_inputs; /* mandatory for IRT top */
PNIOD_CBF_SYNC_CP_STOP_REQ cbf_sync_cp_stop_req; /* optional */
PNIOD_CBF_SYNC_START_LED_FLASH cbf_sync_start_led_flash; /* optional */
PNIOD_CBF_SYNC_STOP_LED_FLASH cbf_sync_stop_led_flash; /* optional */
PNIOD_CBF_RESERVED
} ATTR_PACKED PNIOD_CBF_FUNCTIONS;
Also:
typedef PNIO_IOXS (*PNIO_CBF_DATA_WRITE) /* write data to IO stack (local ==> remote) */
(PNIO_UINT32 DevHndl, /* Handle for Multidevice */
PNIO_DEV_ADDR * pAddr, /* geographical address */
PNIO_UINT32 BufLen, /* length of the submodule input data */
PNIO_UINT8 * pBuffer, /* Ptr to data buffer to write to */
PNIO_IOXS Iocs); /* remote (io controller) consumer status */
So, what exactly I'm doing wrong? VS2012 gives me next error:
Error 4 error C2440: '=' : cannot convert from 'PNIO_IOXS (__thiscall CP1626::* )(PNIO_UINT32,PNIO_DEV_ADDR *,PNIO_UINT32,PNIO_UINT8 *,PNIO_IOXS)' to 'PNIO_CBF_DATA_WRITE' c:\users\hp\documents\visual studio 2012\projects\ui_cp1626\ui_cp1626\Profinet_IDevice.h 513 1 UI_CP1626
What's the correct form to associate callbacks in this case?
Thank you in advance.
You're trying to convert thiscall function (non-static class member function) to ordinary function. The problem is non-static class members take extra implicit argument, the pointer to class object aka this, so dataWriteFunc's implicit signature is:
PNIO_IOXS dataWriteFunc(CP1626 *this, PNIO_UINT32, PNIO_DEV_ADDR *,
PNIO_UINT32, PNIO_UINT8 *, PNIO_IOXS);
, note the 1st argument, it's implicit presence is what gives function "__thiscall" attribute. If you declare this function as
static PNIO_IOXS dataWriteFunc(PNIO_UINT32, PNIO_DEV_ADDR *,
PNIO_UINT32, PNIO_UINT8 *, PNIO_IOXS);
then the error will go away. Note that inside static methods this is not available.
I have generated a project for USB CDC VCP using CubeMX and HAL and now I am trying to figure out how I can implement these two weak functions:
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
These fuctions will be called inside HAL_PCD_IRQHandler. What I want to do is place some code inside them so I can retrive received data from host and also find out about end of transaction.
I have seen that CubeMX has reimplemented these weak functions inside usbd_conf.c like this:
/**
* #brief Data Out stage callback.
* #param hpcd: PCD handle
* #param epnum: Endpoint Number
* #retval None
*/
void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
}
/**
* #brief Data In stage callback..
* #param hpcd: PCD handle
* #param epnum: Endpoint Number
* #retval None
*/
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
{
USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
}
I am wondered to know what do these two functions (USBD_LL_DataOutStage and USBD_LL_DataInStage) do? And how I can edit them to achieve my goal.
I encountered this same issue in STM32Cube_FW_L4_V1.10.0 and after looking at this and some other discussions decided to work around it by replacing the CDC DataIn handler with an alternate implementation that adds a call to CDC_TransmitReady_CB() to wake the transmit task:
// Modified CDC DataIn handler to invoke a callback (CDC_TransmitReady_CB) on TX ready
uint8_t altDataInHandler(USBD_HandleTypeDef *pdev, uint8_t epnum) {
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
if (hcdc == NULL) return USBD_FAIL;
hcdc->TxState = 0;
CDC_TransmitReady_CB();
return USBD_OK;
}
void hackCdcClass() {
USBD_CDC.DataIn = altDataInHandler;
}
Ugly, but it works like a charm.
in glib GObject for example:
typedef struct _MyInstance MyInstance;
struct _MyInstance {
GObject parent;
......//instance variable
......//this place is method function pointer in instance structure.
};
typedef struct _MyInstanceClass MyInstanceClass;
struct _MyInstanceClass {
GObjectClass parent_class;
......//class variable
......//this place is method function pointer in class structure.
};
I don't understand that the method function pointer puts in class or instance structure that it seen to same . what difference are they? I think that class function method pointers each of instance object is used to call same, so puting this functions to class structure. However, How to use instance object's function method pointers about method pointers of its own? because I think the function method pointers of instance object for itself is same, How to understand instance object function method?
below I give that gstreamer Gstpad.h code snippet as example :
struct _GstPad {
GstObject object;
/*< public >*/
gpointer element_private;
GstPadTemplate *padtemplate;
GstPadDirection direction;
/*< public >*/ /* with STREAM_LOCK */
/* streaming rec_lock */
GStaticRecMutex *stream_rec_lock;
GstTask *task;
/*< public >*/ /* with PREROLL_LOCK */
GMutex *preroll_lock;
GCond *preroll_cond;
/*< public >*/ /* with LOCK */
/* block cond, mutex is from the object */
GCond *block_cond;
GstPadBlockCallback block_callback;
gpointer block_data;
/* the pad capabilities */
GstCaps *caps;
GstPadGetCapsFunction getcapsfunc;
GstPadSetCapsFunction setcapsfunc;
GstPadAcceptCapsFunction acceptcapsfunc;
GstPadFixateCapsFunction fixatecapsfunc;
GstPadActivateFunction activatefunc;
GstPadActivateModeFunction activatepushfunc;
GstPadActivateModeFunction activatepullfunc;
/* pad link */
GstPadLinkFunction linkfunc;
GstPadUnlinkFunction unlinkfunc;
GstPad *peer;
gpointer sched_private;
/* data transport functions */
GstPadChainFunction chainfunc;
GstPadCheckGetRangeFunction checkgetrangefunc;
GstPadGetRangeFunction getrangefunc;
GstPadEventFunction eventfunc;
GstActivateMode mode;
/* generic query method */
GstPadQueryTypeFunction querytypefunc;
GstPadQueryFunction queryfunc;
/* internal links */
#ifndef GST_DISABLE_DEPRECATED
GstPadIntLinkFunction intlinkfunc;
#else
#ifndef __GTK_DOC_IGNORE__
gpointer intlinkfunc;
#endif
#endif
GstPadBufferAllocFunction bufferallocfunc;
/* whether to emit signals for have-data. counts number
* of handlers attached. */
gint do_buffer_signals;
gint do_event_signals;
/* ABI added */
/* iterate internal links */
GstPadIterIntLinkFunction iterintlinkfunc;
/* free block_data */
GDestroyNotify block_destroy_data;
/*< private >*/
union {
struct {
gboolean block_callback_called;
GstPadPrivate *priv;
} ABI;
gpointer _gst_reserved[GST_PADDING - 2];
} abidata;
};
struct _GstPadClass {
GstObjectClass parent_class;
/* signal callbacks */
void (*linked) (GstPad *pad, GstPad *peer);
void (*unlinked) (GstPad *pad, GstPad *peer);
void (*request_link) (GstPad *pad);
gboolean (*have_data) (GstPad *pad, GstMiniObject *data);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
you can see function method pointer in instance structure and class structure from giving above code snippet. intance function method pointers are initialized by gst_pad_init function, as below:
static void
gst_pad_init (GstPad * pad)
{
........//other no important code
GST_PAD_CHAINFUNC (pad) = NULL;
GST_PAD_LINKFUNC (pad) = NULL;
GST_PAD_CAPS (pad) = NULL;
GST_PAD_GETCAPSFUNC (pad) = NULL;
GST_PAD_ACTIVATEFUNC (pad) = gst_pad_activate_default;
GST_PAD_EVENTFUNC (pad) = gst_pad_event_default;
GST_PAD_QUERYTYPEFUNC (pad) = gst_pad_get_query_types_default;
GST_PAD_QUERYFUNC (pad) = gst_pad_query_default;
#ifndef GST_REMOVE_DEPRECATED
GST_PAD_INTLINKFUNC (pad) = gst_pad_get_internal_links_default;
#endif
GST_PAD_ITERINTLINKFUNC (pad) = gst_pad_iterate_internal_links_default;
GST_PAD_ACCEPTCAPSFUNC (pad) = gst_pad_acceptcaps_default;
............//other no important code
}
so I confuse this issue,why there are function method pointers in intance structure rather than puting into class class structure?
Method-function pointers belong in the class structure. This is true for any virtual method (one that can be overridden in inheriting classes).
Declaring a function pointer in the instance structure would imply the corresponding method is defined only on objects of this specific class and cannot be overridden (is non-virtual).
However, in this case there is no need to expose a function pointer at all, since there can never be multiple implementations of the method and thus never any ambiguity about which implementation to invoke. Following GObject conventions, you would simply declare in the header file a function that corresponds to the method and then provide an implementation in the source file.
The GObject reference manual illustrates these scenarios, with the "Non-virtual public methods" section showing what is normally done instead of declaring a function pointer in the instance structure.
The GStreamer code you pasted shows one exception to the above. In that code, the function pointers stored in the instance structure are effectively properties of a GstPad object, not methods defined on the object itself. The description of the class states
A GstElement creating a pad will typically use the various gst_pad_set_*_function() calls to register callbacks for events, queries or dataflow on the pads.
So the activatefunc member stores a pointer to a callback function that is invoked when the pad is activated, for instance, and similarly for the remaining function pointers. This makes sense, as a callback function is more something the object has than it is a part of the object's own nature.
That said, it's true a more purely object-oriented implementation might either
Implement the callback methods directly in the class itself, expecting them to be overridden in a subclass unique to each application; or
Implement callbacks by invoking methods on an application-supplied object that implements a specific callback interface.
My guess is the GStreamer designers chose the simpler implementation they did out of a desire to
Allow GStreamer to be used with existing C code that may not itself use the GObject framework, and
Keep latency low (critical in multimedia applications) by minimizing the number of chained function calls required to invoke a callback routine.
I am trying to specify a node id on my server but don't understand the structure that I am supposed to follow. I followed the seemingly simple structure to change the node ID and didn't receive errors or warnings. I was successful in creating the nodes as seen below but not creating a node_id. I thought to add a simple node id I would follow the same structure and add the lines with $$$$ in them;
// opcua_server.c
#include "ua_types.h"
#define HANDLE_PDU1 15
const uint8_t EN_DISPLAYNAME_PDU1[] = "PDU1";
const UA_UTF8_string_t ENGLISH_TEXT[] = {
{0, 0}, {sizeof(EN_DISPLAYNAME_PDU1) - 1, EN_DISPLAYNAME_PDU1}};
void opcua_add_nodes(void) {
UA_Status_t status = 0;
// Add PDU1 Folder
UA_Folder_t PDU1;
UAServer_Init_config_structure_Folder(&PDU1);
PDU1.node_handle = HANDLE_PDU1;
PDU1.display_name_handle = HANDLE_PDU1;
UA_NodeId_Config_t randomHANDLE; // $$$$ Not creating node id
PDU1.node_id = randomHANDLE; // $$$$ Not creating node id
status = UAServer_Create_Folder(&PDU1);
if (status != 0) {
UA_SERVER_PRINTF("UAServer_Create_Folder returned: %d\n",
(uint16_t)status);
}
status = UAServer_Add_to_folder(folder.node_handle, PDU1.node_handle);
if (status != 0) {
UA_SERVER_PRINTF("UAServer_Add_to_objects_folder returned: %d\n",
(uint16_t)status);
}
}
// ua_types.h
typedef struct {
/**
* A mandatory unique identifier that identifies the node in the library.
* The value zero is invalid.
*/
uint32_t node_handle;
/**
* A mandatory unique identifier that allows the host to efficiently look up
* the
* node name text to display in a translate callback. The value zero is
* invalid.
*/
uint32_t display_name_handle;
/**
* An optional unique identifier that allows the host to efficiently look up
* the
* node description text to display in a translate callback. The value zero
* is
* invalid.
*/
uint32_t description_handle;
/**
* An optional visibility mask that restricts the visibility of the node
* depending
* on which user is logged in. The anonymous user is bit 0 and bits 1 - 15
* represent the corresponding users
*/
uint16_t user_visibility;
/**
* Specifies the namespace index for this node. The UA namespace is 0 and
* cannot
* be used. The default server namespace is 1. Other namespaces may be added
* to the configuration data structure.
*/
uint16_t namespace_index;
/**
* An optional parameter set that defines the NodeId for the node as a
* string
* or a GUID. If this parameter is set to default values then the SDK will
* assign
* an opaque node id to the node. Opaque node ids are easily decoded by the
* SDK
* and offer the best performance. Only populate this parameter set if your
* application requires it.
*/
UA_NodeId_Config_t node_id;
} UA_Base_t;
/*****************************************************************************/
/** \brief A configuration structure for Folder address space nodes.
*
*/
typedef UA_Base_t UA_Folder_t;
/*****************************************************************************/
/** \brief A configuration structure for View address space nodes.
*
*/
typedef UA_Folder_t UA_View_t;
/*****************************************************************************/
/** \brief A configuration structure for Method address space nodes.
*
*/
typedef struct {
/**
* Configuration common to all nodes
*/
UA_Base_t base_config;
/**
* The file size in bytes
*/
uint64_t size;
/**
* The file is writable
*/
bool_t writable;
/**
* An optional writable mask that restricts write access of the file
* depending
* on which user is logged in. The anonymous user is bit 0 and bits 1 - 15
* represent the corresponding users
*/
uint16_t user_writable;
} UA_File_t;
When you define PDU1, a node_id is already created and associated with it. You just need to access node_id and assign value for each of its elements.
Replace
UA_NodeId_Config_t randomHANDLE; // $$$$ Not creating node id
PDU1.node_id = randomHANDLE; // $$$$ Not creating node id
with
PDU1.node_id.identifier_type = xxxx; // xxxx, yyyy, zzz is whatever valid value for their type.
PDU1.node_id.string_identifier = yyyy;
PDU1.node_id.guid_identifier = zzzz;
Turns out I needed to specify the identifier type (which I did by looking at the identifier types) and set it equal to opcua_node_encoding_string. The result is a string node id that I set out to create.
//Add PDU1 Folder
UA_Folder_t PDU1;
UAServer_Init_config_structure_Folder(&PDU1);
PDU1.node_handle = HANDLE_PDU1;
PDU1.display_name_handle = HANDLE_PDU1;
PDU1.node_id.identifier_type = opcua_node_encoding_string;
const char TEST_STRING_ID2[] = "PDU1";
PDU1.node_id.string_identifier.length = sizeof(TEST_STRING_ID2) - 1;
PDU1.node_id.string_identifier.data = (uint8_t*)TEST_STRING_ID2;
status = UAServer_Create_Folder(&PDU1);
if (status != 0)
{
UA_SERVER_PRINTF("UAServer_Create_Folder returned: %d\n", (uint16_t)status);
}
status = UAServer_Add_to_folder(folder.node_handle, PDU1.node_handle);
if (status != 0)
{
UA_SERVER_PRINTF("UAServer_Add_to_objects_folder returned: %d\n", (uint16_t)status);
}