Micro-Ros for Arduino-rpi pico multiple publishers issue - arduino

I'm unable to publish more than 2 topics per node on RPi-Pico with micro-Ros.
When I try to publish only 2 topics its works fine , but otherwise the agent is not recieving any data but can see the topic in ros2 topic list , when trying to "echo" the topics it has no data or freezes.
So my question is where did my code went wrong and how to publish multiple publishers in micro-ros?
Thanks ahead to all.
Here is the code
#include <micro_ros_arduino.h>
#include "pinout.h"
#include "motor.h"
#include <math.h>
#include <stdio.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <geometry_msgs/msg/twist.h>
#include <std_msgs/msg/float32.h>
#include <std_msgs/msg/int16.h>
#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}}
void error_loop(){
while(1){
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(100);
}
}
// declare motors
Motor Motor_LF(motor_lf, dir_lf1, dir_lf2, true, LF_ENCODER_P, LF_ENCODER_N);
Motor Motor_LB(motor_lb, dir_lb1, dir_lb2, true, LB_ENCODER_P, LB_ENCODER_N);
Motor Motor_RF(motor_rf, dir_rf1, dir_rf2, true, RF_ENCODER_P, RF_ENCODER_N);
Motor Motor_RB(motor_rb, dir_rb1, dir_rb2, true, RB_ENCODER_P, RB_ENCODER_N);
//uROS declarations
rcl_node_t node;
rclc_support_t support;
rcl_allocator_t allocator;
//Declare uROS Pub/Sub
// Pub
rcl_publisher_t encLF_pub;
rcl_publisher_t encLB_pub;
rcl_publisher_t encRF_pub;
rcl_publisher_t encRB_pub;
std_msgs__msg__Int16 rpm_lf;
std_msgs__msg__Int16 rpm_lb;
std_msgs__msg__Int16 rpm_rf;
std_msgs__msg__Int16 rpm_rb;
rclc_executor_t executor_pub;
rclc_executor_t executor_pub2;
rcl_timer_t timer;
// Hardware interrupt handler functions
void cntEnc0() {
// cntEnc is activated if DigitalPin is going from LOW to HIGH
// Check pin to determine direction
if(digitalRead(LF_ENCODER_N)==LOW)
Motor_LF.encoder.encoderCount++;
else
Motor_LF.encoder.encoderCount--;
}
void cntEnc1() {
// cntEnc is activated if DigitalPin is going from LOW to HIGH
// Check pin to determine the direction
if(digitalRead(LF_ENCODER_P)==LOW)
Motor_LF.encoder.encoderCount--;
else
Motor_LF.encoder.encoderCount++;
}
void cntEnc2() {
if(digitalRead(LB_ENCODER_N)==LOW)
Motor_LB.encoder.encoderCount++;
else
Motor_LB.encoder.encoderCount--;
}
void cntEnc3() {
if(digitalRead(LB_ENCODER_P)==LOW)
Motor_LB.encoder.encoderCount--;
else
Motor_LB.encoder.encoderCount++;
}
void cntEnc4() {
if(digitalRead(RF_ENCODER_N)==LOW)
Motor_RF.encoder.encoderCount++;
else
Motor_RF.encoder.encoderCount--;
}
void cntEnc5() {
if(digitalRead(RF_ENCODER_P)==LOW)
Motor_RF.encoder.encoderCount--;
else
Motor_RF.encoder.encoderCount++;
}
void cntEnc6() {
if(digitalRead(RB_ENCODER_N)==LOW)
Motor_RB.encoder.encoderCount++;
else
Motor_RB.encoder.encoderCount--;
}
void cntEnc7() {
if(digitalRead(RB_ENCODER_P)==LOW)
Motor_RB.encoder.encoderCount--;
else
Motor_RB.encoder.encoderCount++;
}
// motion directions
float power_y = 0, power_x = 0, power_z = 0, alpha = 0;
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
RCLC_UNUSED(last_call_time);
if (timer != NULL) {
RCSOFTCHECK(rcl_publish(&encLF_pub, &rpm_lf, NULL));
RCSOFTCHECK(rcl_publish(&encLB_pub, &rpm_lb, NULL));
RCSOFTCHECK(rcl_publish(&encRF_pub, &rpm_rf, NULL));
RCSOFTCHECK(rcl_publish(&encRB_pub, &rpm_rb, NULL));
}
}
void linear_y(float power){
Motor_RF.drive(power);
Motor_LF.drive(power);
Motor_RB.drive(power);
Motor_LB.drive(power);
}
void linear_x(float power){
Motor_RF.drive(power);
Motor_LF.drive(-power);
Motor_RB.drive(-power);
Motor_LB.drive(power);
}
void angular_z(float power){ //clockwise
Motor_RF.drive(-power);
Motor_LF.drive(power);
Motor_RB.drive(-power);
Motor_LB.drive(power);
}
//ROS functions
// Init hardware function
void setup() {
// Start serial output
Serial.begin(115200);
set_microros_transports();
delay(2000);
allocator = rcl_get_default_allocator();
// Setup hardware interrupt pins for encoder sensors
attachInterrupt(digitalPinToInterrupt(LF_ENCODER_P), cntEnc0, RISING); //Hardware interrupt pin 1 for encoder
attachInterrupt(digitalPinToInterrupt(LF_ENCODER_N), cntEnc1, RISING); //Hardware interrupt pin 2 for encoder
attachInterrupt(digitalPinToInterrupt(LB_ENCODER_P), cntEnc2, RISING);
attachInterrupt(digitalPinToInterrupt(LB_ENCODER_N), cntEnc3, RISING);
attachInterrupt(digitalPinToInterrupt(RF_ENCODER_P), cntEnc4, RISING);
attachInterrupt(digitalPinToInterrupt(RF_ENCODER_N), cntEnc5, RISING);
attachInterrupt(digitalPinToInterrupt(RB_ENCODER_P), cntEnc6, RISING);
attachInterrupt(digitalPinToInterrupt(RB_ENCODER_N), cntEnc7, RISING);
//create init_options
RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));
// create node
RCCHECK(rclc_node_init_default(&node, "skateNode", "", &support));
// create publishers
RCCHECK(rclc_publisher_init_default(
&encLF_pub,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int16),
"rpm_lf_pub"));
RCCHECK(rclc_publisher_init_default(
&encLB_pub,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int16),
"rpm_lb_pub"));
RCCHECK(rclc_publisher_init_default(
&encRF_pub,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int16),
"rpm_rf_pub"));
RCCHECK(rclc_publisher_init_default(
&encRB_pub,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int16),
"rpm_rb_pub"));
// // create executor
const unsigned int timer_timeout = 100;
RCCHECK(rclc_timer_init_default(
&timer,
&support,
RCL_MS_TO_NS(timer_timeout),
timer_callback));
RCCHECK(rclc_executor_init(&executor_pub, &support.context, 1, &allocator));
RCCHECK(rclc_executor_add_timer(&executor_pub, &timer));
rpm_lf.data = Motor_LF.encoder.rpm;
rpm_lb.data = Motor_LB.encoder.rpm;
rpm_rf.data = Motor_RF.encoder.rpm;
rpm_rb.data = Motor_RB.encoder.rpm;
}
// Do stuff here
void loop() {
// Driving functions
if(power_x == 0 && power_z == 0 ){
linear_y(power_y);
}
else if(power_y == 0 && power_z == 0){
linear_x(power_x);
}
else if(power_y == 0 && power_x == 0){
angular_z(power_z);
}
else {
mixed_motion_xy(power_y , power_x);
}
RCSOFTCHECK(rclc_executor_spin_some(&executor_pub, RCL_MS_TO_NS(100)));
// RCSOFTCHECK(rclc_executor_spin_some(&executor_pub2, RCL_MS_TO_NS(100)));
delay(50);
}

My was a bit different - do not see more than 2 topics at all.
from my arduino rp2040 I was trying to create 3 pubs and 1 sub.
but 'ros2 topic list' shows me two pubs created only.
investigating the problem, I found that arduino is defined as verylowmem profile while compiling micro-ros library, hence the settings are:
"rmw_microxrcedds": {
"cmake-args": [
"-DRMW_UXRCE_MAX_NODES=1",
"-DRMW_UXRCE_MAX_PUBLISHERS=2",
"-DRMW_UXRCE_MAX_SUBSCRIPTIONS=1",
"-DRMW_UXRCE_MAX_SERVICES=0",
"-DRMW_UXRCE_MAX_CLIENTS=1",
"-DRMW_UXRCE_MAX_HISTORY=1",
"-DRMW_UXRCE_TRANSPORT=custom"
]
}
the default settings are defined in extras/library_generation/colcon_verylowmem.meta
you can find more about configuration for memory constrained devices here
https://micro.ros.org/docs/tutorials/advanced/microxrcedds_rmw_configuration/
UPDATE: I recompiled the library using lowmem settings for cortex_m0 and now it allows to create up to 10 pubs. So far, I don't see any issues with my setup of 3 pubs and 1 sub.
If you want to play around with the settings - you may need to re-compile the library too. here is the instruction:
https://github.com/micro-ROS/micro_ros_arduino/tree/main#how-to-build-the-precompiled-library
more details on library recompilation (mostly follow the process described on the micro-ros-arduino project):
okay. let me put some more details.
clone the microro repo
git clone https://github.com/micro-ROS/micro_ros_arduino.git
and cd to the cloned folder, make sure that git branch is 'humble'
pull the builder docker image
docker pull microros/micro_ros_static_library_builder:humble
humble is is the latest up-to-date release of ROS2
modify the following line in the lib generation script:
diff --git a/extras/library_generation/library_generation.sh b/extras/library_generation/library_generation.sh
index 29c8ead..ef7e71a 100755
--- a/extras/library_generation/library_generation.sh
+++ b/extras/library_generation/library_generation.sh
## -76,7 +76,7 ## if [[ " ${PLATFORMS[#]} " =~ " cortex_m0 " ]]; then
rm -rf firmware/build
export TOOLCHAIN_PREFIX=/uros_ws/gcc-arm-none-eabi-7-2017-q4-major/bin/arm-none-eabi-
- ros2 run micro_ros_setup build_firmware.sh /project/extras/library_generation/cortex_m0_toolchain.cmake /project/extras/library_generation/colcon_verylowmem.meta
+ ros2 run micro_ros_setup build_firmware.sh /project/extras/library_generation/cortex_m0_toolchain.cmake /project/extras/library_generation/colcon_lowmem.meta
find firmware/build/include/ -name "*.c" -delete
cp -R firmware/build/include/* /project/src/```
I believe there is a better way to tell library to compile with lowmem profile for context_m0, but I directly modified the build script.
start building the library using the pulled docker image
docker run -it --rm -v $(pwd):/project --env MICROROS_LIBRARY_FOLDER=extras microros/micro_ros_static_library_builder:humble
this step will take a while, relax and wait.
After the build is done, you may have up to 10 pubs on your rp2040

Related

ESP32 FreeRTOS pin interrupt ISR handler core 0 panic (C++)

Currently I am trying to attach a pin interrupt whose ISR is to call xTaskResumeFromISR or xQueueSendFromISR. The ISR gets called correctly, but the code to execute results in a core 0 panic.
Here are the implementation details.
PlatformIO: platform = espressif32 # 6.0.1, framework = arduino, board = esp32dev
Header file (Worker.h)
#pragma once
#include <Arduino.h>
class Worker {
public:
Worker(uint8_t pinExtInterrupt);
bool startTask(void);
protected:
// static wrapper for task creation
static void staticRun(void *arg) {
reinterpret_cast<Worker *>(arg)->run();
}
// actual task's logic
void run(void);
// static interrupt handler
static void staticIsrHandler(void* arg);
// actual interrupt handler
void isrHandler();
TaskHandle_t _taskHandle = nullptr;
uint8_t _pinExtInterrupt;
};
Source file (Worker.cpp)
#include "Worker.h"
Worker::Worker(uint8_t pinExtInterrupt) {
_pinExtInterrupt = pinExtInterrupt;
pinMode(pinExtInterrupt, INPUT);
}
bool Worker::startTask(void) {
BaseType_t xReturned = xTaskCreate(staticRun, "Worker", 2048, this, 5, &_taskHandle);
gpio_set_intr_type(static_cast<gpio_num_t>(_pinExtInterrupt), GPIO_INTR_NEGEDGE);
gpio_install_isr_service(0);
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, NULL);
return true;
}
void Worker::run(void) {
for (;;) {
vTaskSuspend(NULL);
// LOGIC
}
}
void IRAM_ATTR Worker::staticIsrHandler(void* arg) {
reinterpret_cast<Worker*>(arg)->isrHandler();
}
void IRAM_ATTR Worker::isrHandler() {
xTaskResumeFromISR(_taskHandle); // ###### THIS LINE THROWS THE EXCEPTION ######
}
Error
Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
0x400d1d00:0x3ffbeaac in Worker::isrHandler() at ...
But what works is if you replace xTaskResumeFromISR e.g. with digitalWrite(..).
Need to fix the problem above.
Your call here:
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, NULL);
assigns a null pointer for the ISR handler's context data. As a result, when your static ISR is called:
void IRAM_ATTR Worker::staticIsrHandler(void* arg) {
reinterpret_cast<Worker*>(arg)->isrHandler();
}
arg is a null pointer, causing the access to _taskHandle to fail here:
void IRAM_ATTR Worker::isrHandler() {
xTaskResumeFromISR(_taskHandle);
}
If you replace your gpio_isr_handler_add call with the following:
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, this);
everything should work.

What is rosidl_runtime_c__double__Sequence type?

I'm trying to use a teensy 4.1 as an interface between an encoder and ROS thanks to micro-ros (arduino version).
I would like to publish position of a wheel to the /jointState topic with the teensy but there is no example on the micro-ros arduino Github repo.
I've tried to inspect the sensormsgs/msg/jointState message struct but everything is a bit fuzzy and I don't understand how to make it works. I can't understand what is rosidl_runtime_c__double__Sequence type.
I've tried several things but I always get an error about operand types
no match for 'operator=' (operand types are 'rosidl_runtime_c__String' and 'const char [18]')
msg.name.data[0] = "drivewhl_1g_joint";
Here is my arduino code
#include <micro_ros_arduino.h>
#include <stdio.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <sensor_msgs/msg/joint_state.h>
rcl_publisher_t publisher;
sensor_msgs__msg__JointState msg;
rclc_executor_t executor;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
rcl_timer_t timer;
#define LED_PIN 13
#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}}
void error_loop(){
while(1){
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(100);
}
}
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
RCLC_UNUSED(last_call_time);
if (timer != NULL) {
RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
//
//Do not work
//msg.name=["drivewhl_1g_joint","drivewhl_1d_joint","drivewhl_2g_joint","drivewhl_2d_joint"];
//msg.position=["1.3","0.2", "0","0"];
msg.name.size = 1;
msg.name.data[0] = "drivewhl_1g_joint";
msg.position.size = 1;
msg.position.data[0] = 1.85;
}
}
void setup() {
set_microros_transports();
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
delay(2000);
allocator = rcl_get_default_allocator();
//create init_options
RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));
// create node
RCCHECK(rclc_node_init_default(&node, "micro_ros_arduino_node", "", &support));
// create publisher
RCCHECK(rclc_publisher_init_default(
&publisher,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(sensor_msgs, msg, JointState),
"JointState"));
// create timer,
const unsigned int timer_timeout = 1000;
RCCHECK(rclc_timer_init_default(
&timer,
&support,
RCL_MS_TO_NS(timer_timeout),
timer_callback));
// create executor
RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
RCCHECK(rclc_executor_add_timer(&executor, &timer));
}
void loop() {
delay(100);
RCSOFTCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100)));
}
I'm a beginner with Ros and C, it may be a very dumb question but I don't know how to solve it. Thanks for your help !
rosidl_runtime_c__String__Sequence is a structure used to old string data that is to be transmitted. Specifically it is a sequence of rosidl_runtime_c__String data. You're running into an error because rosidl_runtime_c__String is also a struct itself with no custom operators defined. Thus, your assignment fails since the types are not directly convertible. What you need to do instead is use the rosidl_runtime_c__String.data field. You can see slightly more info here
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
RCLC_UNUSED(last_call_time);
if (timer != NULL) {
//msg.name=["drivewhl_1g_joint","drivewhl_1d_joint","drivewhl_2g_joint","drivewhl_2d_joint"];
//msg.position=["1.3","0.2", "0","0"];
msg.name.size = 1;
msg.name.data[0].data = "drivewhl_1g_joint";
msg.name.data[0].size = 17; //Size in bytes excluding null terminator
msg.position.size = 1;
msg.position.data[0] = 1.85;
RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
}
}
I also spent quite some time trying to get publishing JointState message from my esp32 running microros, and also couldn't find working example. Finally, i was successful, maybe it will help someone.
In simple words:
.capacity contains max number of elements
.size contains actual number of elements (strlen in case of string)
.data should be allocated as using malloc as .capacity * sizeof()
each string within sequence should be allocated separately
This is my code that allocates memory for 12 joints, named j0-j11. Good luck!
...
// Declarations
rcl_publisher_t pub_joint;
sensor_msgs__msg__JointState joint_state_msg;
...
// Create publisher
RCCHECK(rclc_publisher_init_default(&pub_joint, &node,
ROSIDL_GET_MSG_TYPE_SUPPORT(sensor_msgs, msg, JointState),
"/hexapod/joint_state"));
//Allocate memory
joint_state_msg.name.capacity = 12;
joint_state_msg.name.size = 12;
joint_state_msg.name.data = (std_msgs__msg__String*) malloc(joint_state_msg.name.capacity*sizeof(std_msgs__msg__String));
for(int i=0;i<12;i++) {
joint_state_msg.name.data[i].data = malloc(5);
joint_state_msg.name.data[i].capacity = 5;
sprintf(joint_state_msg.name.data[i].data,"j%d",i);
joint_state_msg.name.data[i].size = strlen(joint_state_msg.name.data[i].data);
}
joint_state_msg.position.size=12;
joint_state_msg.position.capacity=12;
joint_state_msg.position.data = malloc(joint_state_msg.position.capacity*sizeof(double));
joint_state_msg.velocity.size=12;
joint_state_msg.velocity.capacity=12;
joint_state_msg.velocity.data = malloc(joint_state_msg.velocity.capacity*sizeof(double));
joint_state_msg.effort.size=12;
joint_state_msg.effort.capacity=12;
joint_state_msg.effort.data = malloc(joint_state_msg.effort.capacity*sizeof(double));
for(int i=0;i<12;i++) {
joint_state_msg.position.data[i]=0.0;
joint_state_msg.velocity.data[i]=0.0;
joint_state_msg.effort.data[i]=0.0;
}
....
//Publish
RCSOFTCHECK(rcl_publish(&pub_joint, &joint_state_msg, NULL));

Repeatedly Play Audio on Sony Spresense

I'm trying to repeatedly play an audio file on the Sony Spresense. I have tested the example sketches provided by Sony and they work fine for playing an audio file. But if I want to replay the file, I get errors. Unfortunately, all sketches only play their file once...
To keep it simple, I have shrunk the source code.
#include <Audio.h>
#include <SDHCI.h>
static void audioErrorCallback(const ErrorAttentionParam *atprm);
bool initializeSound();
SDClass theSD;
AudioClass *theAudio;
File soundFile;
bool soundFinished;
void setup() {
Serial.begin(115200);
while (!Serial);
initializeSound();
soundFinished = true;
}
void loop() {
if (!soundFinished) {
int err = theAudio->writeFrames(AudioClass::Player0, soundFile);
if (err == AUDIOLIB_ECODE_FILEEND) {
soundFinished = true;
stopPlay();
}
} else {
Serial.println("Sleep");
delay(3000);
soundFinished = false;
startPlay();
}
usleep(40000);
}
static void audioErrorCallback(const ErrorAttentionParam *atprm) {
if (atprm->error_code >= AS_ATTENTION_CODE_WARNING)
{
Serial.println("Error!");
}
}
bool initializeSound() {
theAudio = AudioClass::getInstance();
theAudio->begin(audioErrorCallback);
theAudio->setRenderingClockMode(AS_CLKMODE_NORMAL);
theAudio->setPlayerMode(AS_SETPLAYER_OUTPUTDEVICE_SPHP, AS_SP_DRV_MODE_LINEOUT);
theAudio->initPlayer(AudioClass::Player0, AS_CODECTYPE_MP3, "/mnt/sd0/BIN", AS_SAMPLINGRATE_AUTO, AS_CHANNEL_STEREO);
soundFile = theSD.open("audioFile.mp3");
theAudio->setVolume(-160);
return true;
}
void startPlay() {
theAudio->writeFrames(AudioClass::Player0, soundFile);
theAudio->startPlayer(AudioClass::Player0);
}
void stopPlay() {
theAudio->stopPlayer(AudioClass::Player0);
// soundFile.close();
}
The audio file is played without problems for the first time. Afterwards, I receive the following error, always:
Attention: module[5] attention id[2]/code[6] (objects/media_player/player_input_device_handler.cpp L220)
Error!
ERROR: Command (0x22) fails. Result code(0xf1) Module id(0x5) Error code(0x2f) Error subcode(0x0)
ERROR: Command (0x23) fails. Result code(0xf1) Module id(0x5) Error code(0x1)
What's missing? Any ideas?
I had a similar issue, and I was able to fix it by closing the File at the end, and creating a new File at the the start of the loop() instead of in the setup() function.

Using semaphore in FreeRTOS

I am trying to use a semaphore of the arduino core for ESP32. My code is a follows:
#include <Arduino.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#define configUSE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
void vTaskExample(void *pvParameters);
void accessSharedResource{}
volatile SemaphoreHandle_t xResourceSemaphore = NULL;
void setup()
{
xTaskCreatePinnedToCore(&vTaskExample, "example task", 1024, NULL, 2, NULL, 1);
}
void loop()
{
// Do nothing
}
void vTaskExample(void *pvParameters)
{
vSemaphoreCreateBinary(xResourceSemaphore);
while (true)
{
if (xSemaphoreAltTake(xResourceSemaphore, (TickType_t)0))
{
accessSharedResource();
xSemaphoreAltGive(xResourceSemaphore);
}
}
}
Unfortunately, during compilation (in the linking phase to be exact), I get the following error message:
main.cpp:(.text._Z12vTaskExamplePv+0x37): undefined reference to `xQueueAltGenericReceive'
main.cpp:(.text._Z12vTaskExamplePv+0x4b): undefined reference to `xQueueAltGenericSend'
I have looked up the freeRTOS documentation, and it indicates that the two functions are located in the queue.h; thus, should be available. Also, I have set the necessary freeRTOS configuration by setting configUSE_MUTEXES and configUSE_COUNTING_SEMAPHORES flags
Any suggestions why this does not compile?
Only prototypes are provided in queue.h - nothing executable. If you look at the FreeRTOS documentation you will note that the alternative API has been deprecated for a long time, and is only included in the build if configUSE_ALTERNATIVE_API is set to 1.

File changes handle, QSocketNotifier disables due to invalid socket

I am developing for a touch screen and need to detect touch events to turn the screen back on. I am using Qt and sockets and have run into an interesting issue.
Whenever my QSocketNotifier detects the event it sends me infinite notices about it. Therefore I need to close and open the event file to cycle the notifier (inputNotifier in the below code). The problem usually arises several minutes after the device has been running and the file (inputDevice) suddenly changes it's handle from 24 to something else (usually 17).
I am not sure what to do, because the initial connect statement is linked to the initial Notifier pointer. If I create a new Notifier using the new handle, the connect is invalid. As far as I can tell there is no option to set a new socket value on a running QSocketNotifier. Suggestions? The relevant code is below:
#include "backlightcontroller.h"
#include <QTimer>
#include <QFile>
#include <syslog.h>
#include <QDebug>
#include <QSocketNotifier>
BacklightController::BacklightController(QObject *parent) :
QObject(parent)
{
backlightActive = true;
// setup timer
trigger = new QTimer;
trigger->setSingleShot(false);
connect(trigger, SIGNAL(timeout()), SLOT(deactivateBacklight()));
idleTimer = new QTimer;
idleTimer->setInterval(IDLE_TIME * 1000);
idleTimer->setSingleShot(false);
connect(idleTimer, SIGNAL(timeout()), SIGNAL(idled()));
idleTimer->start();
// setup socket notifier
inputDevice = new QFile(USERINPUT_DEVICE);
if (!inputDevice->open(QIODevice::ReadOnly))
{
syslog (LOG_ERR, "Input file for Backlight controller could not been opened.");
}
else
{
inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
inputNotifier->setEnabled(true);
connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));
}
qDebug()<<"backlight socket: "<<inputNotifier->socket();
// read out settings-file
QString intensity = Global::system_settings->getValue("BelatronUS_backlight_intensity");
if (intensity.length() == 0) intensity = "100";
QString duration = Global::system_settings->getValue("BelatronUS_backlight_duration");
if (duration.length() == 0) duration = "180";
QString always_on = Global::system_settings->getValue("BelatronUS_backlight_always_on");
if (always_on.length() == 0) always_on = "0";
setIntensity(intensity.toInt());
setDuration(duration.toInt());
if (always_on == "0")
setAlwaysOn(false);
else
setAlwaysOn(true);
}
BacklightController::~BacklightController()
{
trigger->stop();
inputNotifier->setEnabled(false);
inputDevice->close();
delete trigger;
delete inputDevice;
delete inputNotifier;
}
void BacklightController::setCurrentIntensity(int intensity)
{
// adapt backlight intensity
QFile backlightFile("/sys/class/backlight/atmel-pwm-bl/brightness");
if (!backlightFile.open(QIODevice::WriteOnly))
{
syslog (LOG_ERR, "Backlight intensity file could not been opened.");
}
else
{
QString intensityString = QString::number(TO_BRIGHTNESS(intensity));
if (backlightFile.write(
qPrintable(intensityString), intensityString.length()
) < intensityString.length())
{
syslog (LOG_ERR, "Backlight intensity could not been changed.");
}
backlightFile.close();
}
}
void BacklightController::resetNotifier()
{
inputDevice->close();
if (!inputDevice->open(QIODevice::ReadOnly))
{
syslog (LOG_ERR, "BacklightController::%s: Input file could not been opened.", __FUNCTION__);
}
qDebug()<<"reset, handle: "<<inputDevice->handle();
//inputNotifier=QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
// restart timer after user input
idleTimer->start();
}
void BacklightController::activateBacklight()
{
// only activate backlight, if it's off (avoid to useless fileaccess)
if (!backlightActive)
{
setCurrentIntensity(_intensity);
backlightActive = true;
emit backlightActivated();
}
// restart backlight timeout, but only if we don't want the backlight to shine all the time
if (!_alwaysOn)
trigger->start();
// reset notifier to be able to catch the next userinput
resetNotifier();
}
void BacklightController::deactivateBacklight()
{
// don't turn it off, if it's forced on
if (!_alwaysOn)
{
if (backlightActive)
{
// only deactivate backlight, if it's on (avoid to useless fileaccess)
setCurrentIntensity(BACKLIGHT_INTENSITY_OFF);
backlightActive = false;
emit backlightDeactivated();
}
}
qDebug()<<"trigger stopping";
trigger->stop();
}
void BacklightController::setIntensity(int intensity)
{
if (intensity > 100)
intensity = 100;
else if (intensity < 0)
intensity = 0;
_intensity = intensity;
// write new intensity to file if it's active at the moment
if (backlightActive)
{
setCurrentIntensity(_intensity);
trigger->start();
}
}
void BacklightController::setDuration(int duration)
{
if (duration < 1)
duration = 1;
_duration = duration;
trigger->setInterval(_duration * MS_IN_SEC);
// reset trigger after changing duration
if (backlightActive)
{
trigger->start();
}
}
void BacklightController::setAlwaysOn(bool always_on)
{
_alwaysOn = always_on;
// tell the timer what to to now
if (_alwaysOn)
{
this->activateBacklight();
trigger->stop();
}
else
{
trigger->start();
}
}
I seem to have found a working solution for now. It's not the greatest so if there are better solutions I would be interested to hear them. The reason I did not think of this before is because I thought if I had a new connect statement in a function it would have limited scope as the function ended.
The solution was to simply check for an occurrence of the handle change in the file and then create a new pointer for the notifier using that handle. Then re-enable the notifier because it has likely been disabled by now and then create a new connect statement for the pointer. This is the code I used, added just below the closing and reopening of the event file:
if(inputDevice->handle()!=inputNotifier->socket()){
inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
inputNotifier->setEnabled(true);
connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));
}

Resources