STM32 using callbacks to retrive data from USB CDC VCP - arm

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.

Related

Doxygen does not parse __attribute__ correctly

I have some functions defined the following way:
* #brief Obtains the current time tick of the OS.
* This is a weak function and is intended to be overridden.
* #return In the weak version always 0. Otherwise should return the current
* OS time tick.
*/
__attribute__((__weak__)) osalUint_t osal_tickGetCurrent(void)
{
return 0;
}
They are defined as "weak". When I generate the doxygen output for a c file with such a definition, the function is not parsed correctly.
Is there a way to make the Doxygen be __attribute__ aware when it comes to functions (and other objects too, such as structs)?
I used as source code:
/// \file
/**
* #brief Obtains the current time tick of the OS.
* This is a weak function and is intended to be overridden.
* #return In the weak version always 0. Otherwise should return the current
* OS time tick.
*/
__attribute__((__weak__)) osalUint_t osal_tickGetCurrent(void)
{
return 0;
}
And as doxygen settings file (Doxyfile):
QUIET = YES
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
PREDEFINED = __attribute__(x)=
and the result is:

Change name of Application in Pipewire/Pulseaudio

I am currently trying to build a very simple Audio-Tool, which needs to change its name in pavucontrol and qjackctl on runtime. When an Application produces Audio, its name is shown in pavucontrol. E.g. if I use firefox it is shown as "Firefox". I tried the most commonly suggested solutions: Editing argv and using prctl both did not succeed.
I also searched the pipewire documentation but I didn't find anything useful (but maybe I am just blind).
Is it even possible? From where does pipewire get the name of the Application?
Here is a little test-script in C with SDL2:
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <SDL2/SDL.h>
Uint8* audio_buffer = NULL;
Uint32 audio_length = 0;
void audio_callback(void* userdata, Uint8* stream, int n) {
memset(stream, 0, n);
}
int main(int argc, char** argv) {
SDL_Event evt;
SDL_AudioSpec desired;
SDL_Init(SDL_INIT_AUDIO|SDL_INIT_EVENTS);
SDL_LoadWAV("suil.wav", &desired, &audio_buffer, &audio_length);
desired.callback = audio_callback;
SDL_OpenAudio(&desired, NULL);
SDL_PauseAudio(0);
while (1) {
while (SDL_PollEvent(&evt)) {
switch (evt.type) {
case SDL_QUIT:
exit(EXIT_SUCCESS);
}
}
}
}
And a picture of what I would like to have changed on runtime:
(Note: The "test" would be the name in question.)
Disclaimer:
I'm not sure if this would maybe sdl-2 specific, so I added the SDL tag.
SDL's Pipewire backend grabs the application name in this block:
/* Get the hints for the application name, stream name and role */
app_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
if (!app_name || *app_name == '\0') {
app_name = SDL_GetHint(SDL_HINT_APP_NAME);
if (!app_name || *app_name == '\0') {
app_name = "SDL Application";
}
}
...via the hint system:
SDL_HINT_APP_NAME:
/**
* \brief Specify an application name.
*
* This hint lets you specify the application name sent to the OS when
* required. For example, this will often appear in volume control applets for
* audio streams, and in lists of applications which are inhibiting the
* screensaver. You should use a string that describes your program ("My Game
* 2: The Revenge")
*
* Setting this to "" or leaving it unset will have SDL use a reasonable
* default: probably the application's name or "SDL Application" if SDL
* doesn't have any better information.
*
* Note that, for audio streams, this can be overridden with
* SDL_HINT_AUDIO_DEVICE_APP_NAME.
*
* On targets where this is not supported, this hint does nothing.
*/
#define SDL_HINT_APP_NAME "SDL_APP_NAME"
SDL_HINT_AUDIO_DEVICE_APP_NAME:
/**
* \brief Specify an application name for an audio device.
*
* Some audio backends (such as PulseAudio) allow you to describe your audio
* stream. Among other things, this description might show up in a system
* control panel that lets the user adjust the volume on specific audio
* streams instead of using one giant master volume slider.
*
* This hints lets you transmit that information to the OS. The contents of
* this hint are used while opening an audio device. You should use a string
* that describes your program ("My Game 2: The Revenge")
*
* Setting this to "" or leaving it unset will have SDL use a reasonable
* default: this will be the name set with SDL_HINT_APP_NAME, if that hint is
* set. Otherwise, it'll probably the application's name or "SDL Application"
* if SDL doesn't have any better information.
*
* On targets where this is not supported, this hint does nothing.
*/
#define SDL_HINT_AUDIO_DEVICE_APP_NAME "SDL_AUDIO_DEVICE_APP_NAME"
...and then passes the app name into Pipewire using PW_KEY_APP_NAME, here:
PIPEWIRE_pw_properties_set(props, PW_KEY_APP_NAME, app_name);
...where SDL's PIPEWIRE_pw_properties_set() is just a pointer to Pipewire's pw_properties_set().

gstreamer: multiple RTSP clients connecting at the same time makes the video stream crash

Quick summary
video stream crashes if multiple clients connect at the same time due to the clients (all but 1) that skip the media-configure callback trying to change the bitrate by accessing a not yet configured pipeline. I'm asking how to wait with calling change_bitrate as long as the configure-media callback hasn't yet finished.
Detailed overview
I'm developing a door phone application that shows video footage of a user (that just rang the door) over the RTSP protocol on one or multiple screens (called clients from now on) in e.g. an appartment building.
When the application is running, it will not create a pipeline before the first client has connected. A new client callback is created in the following way:
/* Configure Callbacks */
/* Create new client handler (Called on new client connect) */
LOG_debug("Creating 'client-connected' signal handler");
g_signal_connect(info.server, "client-connected", G_CALLBACK(new_client_handler), &info);
Which calls this function as soon as a client has connected:
/**
* new_client_handler
* Called by rtsp server on a new client connection
*/
static void new_client_handler(GstRTSPServer *server, GstRTSPClient *client, struct stream_info *si)
{
DEBUG_ENTER;
/* Used to initiate the media-configure callback */
static gboolean first_run = TRUE;
GstRTSPConnection *connection = gst_rtsp_client_get_connection(client);
if (connection == NULL)
{
LOG_err("Could not get RTSP connection");
DEBUG_EXIT;
return;
}
GstRTSPUrl *url = gst_rtsp_connection_get_url(connection);
if (url == NULL)
{
LOG_err("Could not get RTSP connection URL");
DEBUG_EXIT;
return;
}
si->num_cli++;
gchar* uri = gst_rtsp_url_get_request_uri(url);
LOG_info("[%d]A new client %s has connected", si->num_cli, uri);
g_free(uri);
si->connected = TRUE;
/* Create media-configure handler */
/*relevant part for question*/
if (si->num_cli == 1)
{ /* Initial Setup */
/**
* Stream info is required, which is only
* available on the first connection. Stream info is created
* upon the first connection and is never destroyed after that.
*/
if (first_run == TRUE)
{
LOG_debug("Creating 'media-configure' signal handler");
g_signal_connect(si->factory, "media-configure", G_CALLBACK(media_configure_handler),
si);
}
}
else
{
change_bitrate(si); //This makes video stream crash if 'media_configure_handler' isn't yet finished
}
/* Create new client_close_handler */
LOG_debug("Creating 'closed' signal handler");
g_signal_connect(client, "closed", G_CALLBACK(client_close_handler), si);
first_run = FALSE;
DEBUG_EXIT;
}
When a client is the first one to connect, it sets up the media-configure callback to initialize the pipeline. The configuration code looks like this:
**
* media_configure_handler
* Setup pipeline when the stream is first configured
*/
static void media_configure_handler(GstRTSPMediaFactory *factory, GstRTSPMedia *media,
struct stream_info *si)
{
DEBUG_ENTER;
si->media = media;
LOG_info("[%d]Configuring pipeline...", si->num_cli);
si->pipeline = GST_BIN(gst_rtsp_media_get_element(media)); //Pipeline gets configured here
setup_elements(si);
if (si->num_cli == 1)
{
/* Create Msg Event Handler */
LOG_debug("Creating 'periodic message' handler");
g_timeout_add(si->msg_rate * 1000, (GSourceFunc) periodic_msg_handler, si);
}
DEBUG_EXIT;
}
A second (or nth) client that connects skips the media configuration step and instead goes to change_bitrate. Here the bitrate is adjusted based on the amount of connected clients.
/**
* change_bitrate
* handle changing of bitrates
*/
static void change_bitrate(struct stream_info *si)
{
DEBUG_ENTER;
int c = si->curr_bitrate;
int step = (si->max_bitrate - si->min_bitrate) / si->steps;
GstElement *elem = search_pipeline(si->pipeline, "enc"); //crashes due to an unitialized pipeline
const gchar *name = g_ascii_strdown(G_OBJECT_TYPE_NAME(elem), -1);
GstStructure *extra_controls;
...
}
This all works fine if a single client connects first. Later, the connection can handle multiple clients and adjusts the bitrate accordingly.
The problem arises if the first connection is by multiple clients:
In this case, both clients enter an instance of new_client_handler, in which the first one will set up the media_configure_handler. The second connection tries to change the bitrate, but fails because the pipeline is not yet configured by the callback.
How can i make the second (and nth) connection wait until the media configure callback has finished and thus a pipeline is available?
Solved this in the end with the following code (in function new_client_handler)
/* Create media-configure handler */
if (si->num_cli == 1)
{ /* Initial Setup */
/**
* Stream info is required, which is only
* available on the first connection. Stream info is created
* upon the first connection and is never destroyed after that.
*/
if (first_run == TRUE)
{
LOG_debug("Creating 'media-constructor' signal handler");
g_signal_connect(si->factory, "media-constructed", G_CALLBACK(media_configure_handler),
si);
}
}
else if(si->pipeline != 0)
{
change_bitrate(si);
}
else
{
g_signal_connect(si->factory, "media-configure", G_CALLBACK(media_constructed_handler),
si);
}
Pipeline object's construction is now hooked to the media-constructed event, which runs before the media-configure event.
A second client will only change bitrate if pipeline is initialized. If not, the client hooks in the media-configure callback and changes bitrate there. This callback is guaranteed to run after the media-constructed callback.

Doxygen: group data structures on file level

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.

Calling mod_timer from inside timer callback function

I'm writing a kernel module for linux, and I want my timer to re-set itself. To this end, I thought to call mod_timer from inside the timer's callback function, as shown:
static void sched_send(unsigned long data)
{
send_now();
mod_timer(&test_timer, jiffies+(get_interval()*HZ));
}
static void timer_start(void)
{
set_log_msg("Meep meep!");
test_timer.function = sched_send;
test_timer.expires = jiffies + HZ*get_interval();
}
However, I've read mod_timer deletes the timer and re-adds it. Will it cause problems? If so, is there a better way to create a repeating timer for kernel modules?
It is safe to execute mod_timer from the timer callback.
From the kernel source (kernel/timer.c):
/* mod_timer(timer, expires) is equivalent to:
*
* del_timer(timer); timer->expires = expires; add_timer(timer);
* ...
*/
As for del_timer,
/*
* del_timer - deactive a timer.
* #timer: the timer to be deactivated
*
* del_timer() deactivates a timer - this works on both active and inactive
* timers.
* ...
*/
As noted by Peter, you need to invoke add_timer anytime you want to start/restart the timer.
Your function timer_start() will have to call add_timer() after it sets up the function and the expiration time. Once the timer function triggers, your timer is no longer active, so all you have to do is reset the .expires field to your new value and call add_timer() again. Be sure you provide a clean way to stop rescheduling the timer, for example on module unload.
send_now();
if(!terminate_timer) {
test_timer.expires = jiffies + HZ*get_interval();
add_timer(&test_timer);
}

Resources