I'm working on an electronic phone-line emulation for a raspberry pi. For this, I’m in need of a function, which is called each 20 ms (=50Hz, half of the ringing voltage-frequency), checks the electrical current and updates the duty-cycle of a HW PWM. To get there, I set up a signal-handler on an according timer (as I’d hang it into the scheduler in a pure embedded environment) and let it do its work. Note, that the code below is shortened just in order to kfocus on the issue.
This already works pretty well. I was amazed, how accurate the timing is kept (the jitter is below 10µs, measured with an oscilloscope).
However, there’s up to now one flaw: When working like that, the main-loop is actually not required. I cannot return from it, since that would kill the process. When I just let it be an empty loop, all is working fine. But I’m thinking about unnecessarily consumed CPU load.
I tried sleep, wait (both of which should not be used anymore, I know), and sigsuspend. But all of these let to the alarm-handler not being called anymore.
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <sys/time.h>
#include <bcm2835.h>
#define PIN_PWM RPI_V2_GPIO_P1_35
bool b_Alive;
/** Signal-Handlers: ******************************************************************/
void SIG_Alarm (int signum) {
/** Just toggle a pin for now: */
static bool bOn;
if (bOn) {
bOn = 0;
bcm2835_gpio_write(PIN_PWM, LOW);
}else{
bOn = 1;
bcm2835_gpio_write(PIN_PWM, HIGH);
}
}
void SIG_Quit (int signum) {
/** Shutdown the bcm-library: */
bcm2835_close();
/** Close the sys-log handler: */
syslog(LOG_NOTICE + LOG_DAEMON, "Received SigInt and closed.");
closelog();
b_Alive = false;
}
/** Main-Function: ********************************************************************/
int main(void) {
/** Variables: */
struct sigaction sa;
struct itimerval timer;
/** Open syslog instead: */
openlog( "PhoneLined", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_LOCAL0 );
/** Setup pins: */
if (!bcm2835_init()) return 1;
bcm2835_gpio_fsel(PIN_PWM, BCM2835_GPIO_FSEL_OUTP);
/** Setup signal handler for kill: */
memset(&sa, 0, sizeof (sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = &SIG_Quit;
sigaction(SIGINT , &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGKILL, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
/** Setup signal handler for timer: */
memset(&sa, 0, sizeof (sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = &SIG_Alarm;
sigaction(SIGVTALRM, &sa, NULL);
/** Configure the timer of a start- and cycle-time of 20ms (=50Hz): */
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 20000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 20000;
setitimer(ITIMER_VIRTUAL, &timer, NULL);
/** Prepare main-loop: */
b_Alive = true;
syslog(LOG_NOTICE + LOG_DAEMON, "Sucessfully initialized.");
/** ... and do nothing, while the timer works: */
while (b_Alive) {
//pause(), suspend, wait or anything?
}
exit(EXIT_SUCCESS);
}
Are there any hints, how to proceed, when nothing is actually to be done in this loop?