« hrt_call_every » don't work above 1ms

Hi guys,

First I wanted to implement a timer to wake up perdiodicly a function but I saw that it was more precise and easy to implement so I tryed. The problem is that it only works if I put the delay and interval <= 1ms

int debug_main(int argc, char *argv[])
{
  struct hrt_call call;
  struct timespec ts;

  ts.tv_sec = 0;
  ts.tv_nsec = 1000000; //1 msec

  while(1){
  hrt_call_every(&call,
                ts_to_abstime(&ts),
                ts_to_abstime(&ts),
                (hrt_callout)todo,
                 NULL);
                
}
                
return 1;
}

int todo(int argc, char *argv[]){

 PX4_INFO("Was done !");
 return 1;
}

If I put for example
ts.tv_sec = 1;
ts.tv_nsec = 0;
I does not work anymore. Do you have an explanation ?

Why are you doing it in a loop? Did you look at other examples?

If I dont put while(1) I doen’t do anything because the app is returning 1 and get out of the main :confused:

And I thought in a the task code we always put the code into a while loop;

I try to create its own thread but It’s still does nothing

__EXPORT int debug_main(int argc, char *argv[]);
int debug_thread_main(int argc, char *argv[]);
int todo(int argc, char *argv[]);


int debug_main(int argc, char *argv[])
{	
	px4_task_spawn_cmd("debug",
						 SCHED_DEFAULT,
						 SCHED_PRIORITY_DEFAULT,
						 2000,
						 debug_thread_main,
						 (char * const *)&argv[0]);
			
	return 1;
}
int debug_thread_main(int argc, char *argv[]){
	
	struct hrt_call call;
	struct timespec ts;
	
	ts.tv_sec = 0;
	ts.tv_nsec = 1000000; //1msec
	
	hrt_call_every(	&call,
					ts_to_abstime(&ts),
					ts_to_abstime(&ts),
					(hrt_callout)todo,
					NULL);
					
	return 1;
}
int todo(int argc, char *argv[]){
	
	PX4_INFO("Was done !");
	return 1;
}

And this also doesn’t work:

static bool thread_should_exit = false;		/**< daemon exit flag */
static bool thread_running = false;		/**< daemon status flag */
static int daemon_task;				/**< Handle of daemon task / thread */

__EXPORT int debug_main(int argc, char *argv[]);
int debug_thread_main(int argc, char *argv[]);
int todo(int argc, char *argv[]);
static void usage(const char *reason);

void
usage(const char *reason)
{
	if (reason) {
		warnx("%s\n", reason);
	}

	warnx("usage: daemon {start|stop|status} [-p <additional params>]\n\n");
}
int debug_main(int argc, char *argv[])
{	
		if (argc < 2) {
		usage("missing command");
		return 1;
	}

	if (!strcmp(argv[1], "start")) {

		if (thread_running) {
			warnx("daemon already running\n");
			/* this is not an error */
			return 0;
		}

		thread_should_exit = false;
		daemon_task = px4_task_spawn_cmd("debug",
						 SCHED_DEFAULT,
						 SCHED_PRIORITY_DEFAULT,
						 2000,
						 debug_thread_main,
						 (argv) ? (char *const *)&argv[2] : (char *const *)NULL);
		return 0;
	}

	if (!strcmp(argv[1], "stop")) {
		thread_should_exit = true;
		return 0;
	}

	if (!strcmp(argv[1], "status")) {
		if (thread_running) {
			warnx("\trunning\n");

		} else {
			warnx("\tnot started\n");
		}

		return 0;
	}

	usage("unrecognized command");
	return 1;
}
int debug_thread_main(int argc, char *argv[]){
	
	struct hrt_call call;
	struct timespec ts;
	
	thread_running = true;
	
	ts.tv_sec = 0;
	ts.tv_nsec = 1000000; //1msec
	
	while (!thread_should_exit) {
		
	hrt_call_every(	&call,
				ts_to_abstime(&ts),
				ts_to_abstime(&ts),
				(hrt_callout)todo,
				NULL);
	}		warnx("[daemon] exiting.\n");
	
	thread_running = false;		
	return 0;
}
int todo(int argc, char *argv[]){
	
	PX4_INFO("Was done !");
	return 1;
}

Ok this way it works I dont know why really, I just try some stuff, the while(1); is after the hrt_call_every

int debug_thread_main(int argc, char *argv[]){
	
	struct hrt_call call;
	struct timespec ts;

	ts.tv_sec = 0;
	ts.tv_nsec = 100000000; //100msec
		
	hrt_call_every(	&call,
					ts_to_abstime(&ts),
					ts_to_abstime(&ts),
					(hrt_callout)todo,
					NULL);
	while(1);
	return 1;
}
void todo(int argc, char *argv[]){
	
	PX4_INFO("Was done !");
}

Hi @Darkus3, I wouldn’t use hrt for this.

Look at running in the high or low priority work queue. The pattern is you setup the call (scheduled), it runs your code, and at the bottom it schedules the next call.

The land detector is a good example.
Start - https://github.com/PX4/Firmware/blob/master/src/modules/land_detector/LandDetector.cpp#L77

Then note at the bottom of cycle it schedules the next call, or exits. https://github.com/PX4/Firmware/blob/master/src/modules/land_detector/LandDetector.cpp#L157

Ok I will try that, I didn’t know it was posible to do it manually like this. thank you !

One more question; I know that it is a basic C question and it’s not the right place to ask but:

How I pass multiple argument to the called function in the work_queue argument here:

work_queue(HPWORK, &_work,(worker_t)debug_thread_main,????,0);
I want to pass pointer int *uart, char *str, char *c, px4_pollfd_struct_t * fds

Here is my code:

    int debug_main(int argc, char *argv[]){
    	char str[100]={0};
    	char c;
	
	int uart = uart_initt("/dev/ttyS6");
	if(false == uart)return -1;
	if(false == set_uart_baudratee(uart,115200)){
		printf("[YCM]set_uart_baudrate is failed\n");
		return -1;
	}

	int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
	
	px4_pollfd_struct_t fds[] = {
	{ .fd = sensor_sub_fd,   .events = POLLIN },
	};
	
	return work_queue(HPWORK, &_work,(worker_t)debug_thread_main,?????,0);
}
int debug_thread_main(int *uart, char *str, char *c, px4_pollfd_struct_t * fds){
	int poll_ret = px4_poll(fds, 1,1000);
		if(poll_ret > 0){
			if (fds[0].revents & POLLIN) {
				/* obtained data for the first file descriptor */
				struct sensor_combined_s raw;
				/* copy sensors raw data into local buffer */
				orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
				sprintf(str,"S %8.4f %8.4f %8.4f %8.4f %8.4f %8.4f E\r\n",
				(double)raw.accelerometer_m_s2[0],
				(double)raw.accelerometer_m_s2[1],
				(double)raw.accelerometer_m_s2[2],
				(double)raw.gyro_rad[0],
				(double)raw.gyro_rad[1],
				(double)raw.gyro_rad[2]);
				
				for(int j=0;j<sizeof(str);j++){
					c = str[j];
					write(uart, &c, 1);
				}
			}
		}		
	work_queue(HPWORK, &_work,(worker_t)debug_thread_main,?????,USEC2TICK(100000)); //Delay of x usec
	return 0;
}

I’d again look at an example like the land detector or an i2c driver. Instead of trying to pass everything in the call you can allocate an object and access what you need from it.

I see but right now I don’t program in cpp only basic c :confused: will find something tank you