Saturday 30 May 2020
This book is copyrighted by Christophe Delord (cdelord.fr/essays). It is available at lulu.com:
This book has been initially published on lulu.com. It is now fully and freely available on http://cdelord.fr/essays.
You can download and read this tutorial for free. If you like it, please consider making some donation here (http://cdelord.fr/essays) or buying it on lulu.com to support my work.
This book has been written using some free tools and formats:
If you are interested by the source code of the book, please contact me at http://cdelord.fr.
The source code of this book is also a nice example of literate programming with PP: the same source files are used to produce the documentation (in PDF and HTML formats) as well as the source code of the examples that can be compiled for both the Linux simulated platform and the actual Raspberry Pi device.
The aim of this tutorial is simply to learn how to program Raspberry Pi 3 GPIOs in C as well as to show how to write clean and efficient C code for the Raspberry Pi.
The circuit we are going to realize is quite simple. It provides three functions:
The software is based on state machines and written in C. The goal is to provide micro controller low level like software instead of using higher level languages such as Python. C gives better performances and real time characteristics.
The reader is assumed to have some basic knowledge on GNU/Linux, bash, gcc…
The source code available in this tutorial is copyrighted under the GNU General Public License.
Copyright (C) 2016 Christophe Delord
http://cdelord.fr/essays/RaspiTuto
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
This tutorial uses the wiringPi library. The source code of wiringPi can be found here: http://wiringpi.com/.
/*
* wiringPi.h:
* Arduino like Wiring library for the Raspberry Pi.
* Copyright (c) 2012-2016 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* wiringPi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
This demo runs on a Raspberry Pi 3 but I guess it can run on a Raspberry Pi 2 as well.
We will also simulate the hardware to debug and run the software on a regular GNU/Linux PC before running it on a real Raspberry Pi.
This dummy example shows the structure of a classical state machine for embedded softwares.
This implementation has a taste of object oriented programmation but with static allocation only (no dynamic object allocation, no polymorphism or inheritance à la C++).
All (hard) real time applications must have a clean and deterministic time model. In this tutorial we will define a simple model based on cooperative multitasking. Contrary to preemptive multitasking, cooperative tasks run for some period of time and shall give control back to the sequencer deterministically. Tasks are not arbitrarily interrupted by the sequencer. This model makes it easier to distribute time to tasks and control shared global variables.
Each task is a state machine. The state machines are made of a state (a set of values that represent the current state) and a set of functions (or methods) that transform the state. During each time slice, the sequencer calls every state machines once.
First we need some generic definitions and tools.
/******************************************************************/
/* file: demo.h */
/* */
/* Some global definitions for theses tutorials. */
/******************************************************************/
#ifndef __DEMO__
#define __DEMO__
#include <stdio.h>
#include <stdlib.h>
/* wiringPi library used to access Raspberry Pi GPIOs */
#include "wiringPi.h"
/* Time units (all times are internally in µs) */
#define US * 1
#define MS * 1000 US
#define S * 1000 MS
/* The base cycle is the period of the sequencer. */
#define CYCLE (10 MS)
/* Routines to be defined by the application. */
/* init is called once to initialise the state machines */
extern void init();
/* isalive is called periodically to check if the state machines */
/* are still alive */
extern int isalive();
/* run is called periodically to run one step of every state machines */
extern void run();
/* cleanup is called once when the system is not alive */
extern void cleanup();
/* interrupted is called when an interrupt signal is received. */
/* interrupt signals are SIGINT, SIGQUIT, SIGABRT and SIGTERM. */
extern void interrupted();
#endif
/******************************************************************/
/******************************************************************/
/* file: demo.h */
/* */
/* Sequencer for the state machines of theses tutorials. */
/******************************************************************/
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include "demo.h"
/* signal_handler is called when a signal is received. It calls */
/* the `interrupted` function defined by the application (which */
/* in turns calls the "interrupted" functions of the state */
/* machines. */
static void signal_handler(int sig)
{"\nSignal received: %s\n", strsignal(sig));
printf(
interrupted();
}
/* timer_handler is called periodically. The period is CYCLE. */
/* The main loop is driven by a timer which is more accurate than */
/* a simple wait. */
/* timer_handler calls: */
/* - `run` to execute one step of every state machines */
/* - `isalive` to check that the system is still alive */
/* - `cleanup` and exits when the system is not alive anymore */
static void timer_handler(int signum)
{/* run one step */
run();/* check if the program is still alive */
if (!isalive())
{/* stop the program when it is not alive anymore */
cleanup();
exit(EXIT_SUCCESS);
}/* wait for the next cycle */
}
/* The main function initializes the state machines, */
/* starts a periodic timer to run the state machines */
/* and undefinitely waits for the system to exit. */
int main(void)
{/* Initialisation of the wiringPi library to access GPIOs */
wiringPiSetup();
/* Interruption signal handler */
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGABRT, signal_handler);
signal(SIGTERM, signal_handler);
/* Some information about the hardware */
int model, rev, mem, maker, overVolted;
piBoardId(&model, &rev, &mem, &maker, &overVolted);"model = %s\n", piModelNames[model]);
printf("rev = %s\n", piRevisionNames[rev]);
printf("mem = %d Mb\n", mem);
printf("maker = %s\n", piMakerNames[maker]);
printf("over volted = %s\n", overVolted ? "yes" : "no");
printf("\n");
printf(
/* state machine initializations */
init();
/* Install timer_handler as the signal handler for SIGALRM. */
struct sigaction sa;
0, sizeof (sa));
memset (&sa,
sa.sa_handler = &timer_handler;
sigaction(SIGALRM, &sa, NULL);
/* Configure the timer to expire after CYCLE µs... */
struct itimerval itimer;
0;
itimer.it_value.tv_sec =
itimer.it_value.tv_usec = CYCLE;/* ... and every CYCLE µs after that. */
0;
itimer.it_interval.tv_sec =
itimer.it_interval.tv_usec = CYCLE;/* Start the timer. */
setitimer (ITIMER_REAL, &itimer, NULL);
/* Main loop */
while (1)
{/* This loop could be used as a background loop */
1000);
sleep(
}
return EXIT_SUCCESS;
}
/******************************************************************/
WiringPi is a C library that brings the simplicity of Arduino to the powerful world of Raspberry Pi.
To simulate the Raspberry Pi on a GNU/Linux PC, we need to stub this library. I/O functions on a PC will be simulated.
Of course on a Raspberry Pi, the real library will be used.
The source code of the wiringPi stub is in the appendix “wiringPi stub”.
Instead of abusing Linux facilities, we will design software with state machines. This is a clean and deterministic way to describe the behaviour of several tasks (some kind of processes). They are simple and predictable, which is not always the case with general OS. We don’t need here the richness of GNU/Linux.
We are going to use a cooperative multitasking model instead of a preemptive model.
A state machine is a set of functions (methods) that initialize and manage the state of the state machine by interacting with other machines or with the environment.
A state is described by a structured type. Each instance of a state machine has its own state in a global variable.
This example defines a clock that just counts ticks. Each clock can have its own period.
/******************************************************************/
/* file: clock.h */
/* */
/* Clock state machine. Clocks can count execution cycles */
/* and generate rising edges. */
/* A clock is defined by a period and an offset (date of the */
/* first rising edge) in µs. */
/******************************************************************/
#ifndef __CLOCK_STATE_MACHINE__
#define __CLOCK_STATE_MACHINE__
#include "demo.h"
/* Clock state */
typedef struct
{int period_us; /* period of the clock in µs */
int offset_us; /* offset of the clock in µs */
int t; /* time in µs since the start of the period */
int time_us; /* current time in µs */
int ticks; /* number of cycles since the clock started */
} CLOCK_t;
/* Clock initialisation method */
void CLOCK_init(CLOCK_t *c, int period_us, int offset_us);
/* Clock main loop method */
void CLOCK_run(CLOCK_t *c);
double CLOCK_time(CLOCK_t *c); /* current time in seconds */
int CLOCK_time_ms(CLOCK_t *c); /* current time in ms */
int CLOCK_time_us(CLOCK_t *c); /* current time in µs */
int CLOCK_edge(CLOCK_t *c); /* is the current cycle a rising edge */
int CLOCK_ticks(CLOCK_t *c); /* number of cycles since the beginning */
double CLOCK_ratio(CLOCK_t *c); /* position within the current cycle */
#endif
/******************************************************************/
/******************************************************************/
/* file: clock.c */
/* */
/* Clock state machine: implementation (see clock.h) */
/******************************************************************/
#include "clock.h"
void CLOCK_init(CLOCK_t *c, int period_us, int offset_us)
{
c->period_us = period_us;
c->offset_us = offset_us;0 ? period_us - offset_us : 0;
c->t = offset_us > 0;
c->time_us = 0;
c->ticks =
}
void CLOCK_run(CLOCK_t *c)
{
c->ticks++;
c->time_us += CYCLE;
c->t += CYCLE;if (c->t >= c->period_us)
{0;
c->t =
}
}
double CLOCK_time(CLOCK_t *c) { return c->time_us/1e6; }
int CLOCK_time_ms(CLOCK_t *c) { return c->time_us/1000; }
int CLOCK_time_us(CLOCK_t *c) { return c->time_us; }
int CLOCK_edge(CLOCK_t *c) { return c->t == 0; }
int CLOCK_ticks(CLOCK_t *c) { return c->ticks; }
double CLOCK_ratio(CLOCK_t *c) { return ((double)c->t) / c->period_us; }
/******************************************************************/
The program is made of two main functions:
init
initializes all the state machines.run
runs all the state machines in one cycleThe main
function calls init
and starts a timer to periodically call run
.
The function isalive
shall return FALSE
to stop the execution.
In this example, we instantiate two clocks. The first one has a period of 500 ms and the first edge is shifted by 250 ms. The second one has a period of 1 s and no offset.
/******************************************************************/
/* file: ex1-Clock.c */
/* */
/* Clock usage example. */
/******************************************************************/
#include "demo.h"
#include "clock.h"
/* Clocks are statically allocated "objects" */
CLOCK_t c1, c2;
void init()
{/* Initialisation of the state machines */
500 MS, 250 MS);
CLOCK_init(&c1, 1 S, 0 MS);
CLOCK_init(&c2,
}
int isalive()
{/* Let's run for 5 seconds... */
return CLOCK_time(&c1) < 5.0;
}
void run()
{/* Some outputs to see that the clocks are running */
int e1 = CLOCK_edge(&c1);
int e2 = CLOCK_edge(&c2);
if (e1 || e2)
{/* print "CLOCK" in upper case on rising edges */
"[%s 1: %7.3f / %9d] [%s 2: %7.3f / %9d]\n",
printf("CLOCK" : "clock", CLOCK_time(&c1), CLOCK_ticks(&c1),
e1 ? "CLOCK" : "clock", CLOCK_time(&c2), CLOCK_ticks(&c2));
e2 ?
}
/* Execute one step */
CLOCK_run(&c1);
CLOCK_run(&c2);
}
void interrupted()
{
}
void cleanup()
{
}
/******************************************************************/
First we are going to test this dummy example on a regular PC. The program can be compiled on GNU/Linux (maybe on Cygwin as well) with gcc using the stubbed wiringPi library:
gcc -Wall -Werror \
-o ex1-Clock \
ex1-Clock.c demo.c clock.c wiringPi.c
Some quick explanations about this command line:
-Wall
-Werror
-o ex1-Clock
ex1-Clock.c
clock.c
wiringPi.c
demo.c
main
function.
The executable can be run from the command line. ex1-Clock
will run for 5 seconds, printing a line when a rising edge is detected on one of the clocks (c1
or c2
).
$ ./ex1-Clock
model = Stubbed wiringPi
rev = n/a
mem = 0 Mb
maker = cdelord.fr
over volted = no
[clock 1: 0.000 / 0] [CLOCK 2: 0.000 / 0]
[CLOCK 1: 0.250 / 25] [clock 2: 0.250 / 25]
[CLOCK 1: 0.750 / 75] [clock 2: 0.750 / 75]
[clock 1: 1.000 / 100] [CLOCK 2: 1.000 / 100]
[CLOCK 1: 1.250 / 125] [clock 2: 1.250 / 125]
[CLOCK 1: 1.750 / 175] [clock 2: 1.750 / 175]
[clock 1: 2.000 / 200] [CLOCK 2: 2.000 / 200]
[CLOCK 1: 2.250 / 225] [clock 2: 2.250 / 225]
[CLOCK 1: 2.750 / 275] [clock 2: 2.750 / 275]
[clock 1: 3.000 / 300] [CLOCK 2: 3.000 / 300]
[CLOCK 1: 3.250 / 325] [clock 2: 3.250 / 325]
[CLOCK 1: 3.750 / 375] [clock 2: 3.750 / 375]
[clock 1: 4.000 / 400] [CLOCK 2: 4.000 / 400]
[CLOCK 1: 4.250 / 425] [clock 2: 4.250 / 425]
[CLOCK 1: 4.750 / 475] [clock 2: 4.750 / 475]
A similar command line can be used on a Raspberry Pi (I’m using Raspbian).
gcc -Wall -Werror \
-o ex1-Clock \
ex1-Clock.c demo.c clock.c \
-lwiringPi
The main difference is that we use the real wiringPi
library (-lwiringPi
) instead of the stub.
This example is not specific to the Raspberry Pi as it doesn’t uses any Raspberry Pi input/output. Except from the hardware detection, the program should print the same clock timings.
The program uses the real wiringPi
library so it requires root privileges.
$ sudo ./ex1-Clock
model = Model 2
rev = 1.1
mem = 1024 Mb
maker = Sony
over volted = yes
[clock 1: 0.000 / 0] [CLOCK 2: 0.000 / 0]
[CLOCK 1: 0.250 / 25] [clock 2: 0.250 / 25]
[CLOCK 1: 0.750 / 75] [clock 2: 0.750 / 75]
[clock 1: 1.000 / 100] [CLOCK 2: 1.000 / 100]
[CLOCK 1: 1.250 / 125] [clock 2: 1.250 / 125]
[CLOCK 1: 1.750 / 175] [clock 2: 1.750 / 175]
[clock 1: 2.000 / 200] [CLOCK 2: 2.000 / 200]
[CLOCK 1: 2.250 / 225] [clock 2: 2.250 / 225]
[CLOCK 1: 2.750 / 275] [clock 2: 2.750 / 275]
[clock 1: 3.000 / 300] [CLOCK 2: 3.000 / 300]
[CLOCK 1: 3.250 / 325] [clock 2: 3.250 / 325]
[CLOCK 1: 3.750 / 375] [clock 2: 3.750 / 375]
[clock 1: 4.000 / 400] [CLOCK 2: 4.000 / 400]
[CLOCK 1: 4.250 / 425] [clock 2: 4.250 / 425]
[CLOCK 1: 4.750 / 475] [clock 2: 4.750 / 475]
The following chapters will use the same kind of software architecture. Of course we will also see how to use the Inputs/Outputs of the Raspberry Pi to interact with the real world.
Printing messages on a terminal may be some kind of fun… But blinking a LED is way more amusing!
This chapter shows:
The electrical wiring for this project is quite simple.
Here is what you need:
The LED and the resistor are connected to an output GPIO.
For this example we need a state machine that implements a blinking LED. The state machine has two states (the LED can be switched on or off). A clock is embedded to the LED state machine to periodically switch the LED state.
To debug this state machine on a regular PC, we use the STATUS
state machine that prints some information. This state machine will be used in all the examples in this book. Its source code is in the appendix “STATUS state machine”
/******************************************************************/
/* file: blink.h */
/* */
/* Blinking LED state machine. The LED is periodically switched */
/* on and off. */
/******************************************************************/
#ifndef __BLINK_STATE_MACHINE__
#define __BLINK_STATE_MACHINE__
#include "demo.h"
#include "clock.h"
/* Blinking LED state */
typedef struct
{int pin; /* pin on which the LED is connected */
/* internal clock of the blinking LED */
CLOCK_t clock; enum
{
BLINK_LED_OFF,
BLINK_LED_ON,/* current LED state */
} state; int killed; /* kill flag to stop the led */
} BLINK_t;
/* Blinking LED initialisation method */
void BLINK_init(BLINK_t *q, int pin, int period_in_us);
/* The blinking period can be modified */
void BLINK_reschedule(BLINK_t *q, int period_in_us);
/* Blinking LED main loop method */
void BLINK_run(BLINK_t *q);
/* This method is called to kill the state machine. */
void BLINK_kill(BLINK_t *q);
/* The state machine is alive until it is killed. */
int BLINK_isalive(BLINK_t *q);
/* Cleanup function (to leave the LED switched off at the end) */
void BLINK_cleanup(BLINK_t *q);
#endif
/******************************************************************/
/******************************************************************/
/* file: blink.c */
/* */
/* Blinking LED state machine: implementation (see blink.h) */
/******************************************************************/
#include "blink.h"
#include "status.h"
/* Blinking LED initialisation method */
void BLINK_init(BLINK_t *q, int pin, int period_in_us)
{
q->killed = FALSE;
q->pin = pin;0);
CLOCK_init(&q->clock, period_in_us,
q->state = BLINK_LED_OFF;
pinMode(q->pin, OUTPUT);
}
/* The blinking period can be modified */
void BLINK_reschedule(BLINK_t *q, int period_in_us)
{
q->clock.period_us = period_in_us;
}
/* Blinking LED main loop method */
void BLINK_run(BLINK_t *q)
{switch (q->state)
{/* if the LED is off during the first half of the clock */
/* period it must be switched on. */
case BLINK_LED_OFF:
if (CLOCK_ratio(&q->clock) < 0.5)
{
q->state = BLINK_LED_ON;
digitalWrite(q->pin, HIGH);
STATUS_act(HIGH);
}break;
/* if the LED is on during the second half of the clock */
/* period it must be switched off. */
case BLINK_LED_ON:
if (CLOCK_ratio(&q->clock) >= 0.5)
{
q->state = BLINK_LED_OFF;
digitalWrite(q->pin, LOW);
STATUS_act(LOW);
}break;
}/* the clock shall also run. */
CLOCK_run(&q->clock);
}
/* This method is called to kill the state machine. */
void BLINK_kill(BLINK_t *q)
{
q->killed = TRUE;
}
/* The state machine is alive until it is killed. */
int BLINK_isalive(BLINK_t *q)
{return !q->killed;
}
/* Cleanup function (to leave the LED switched off at the end) */
void BLINK_cleanup(BLINK_t *q)
{
digitalWrite(q->pin, LOW);
}
/******************************************************************/
The main program is very similar to the previous example.
/******************************************************************/
/* file: ex2-BlinkingLED.c */
/* */
/* The famous Raspberry Pi "hello world": Blinking LED example. */
/******************************************************************/
#include "demo.h"
#include "status.h"
#include "blink.h"
#define ACTIVITY_LED 7 /* BCM GPIO 4 */
#define ACTIVITY_PERIOD (1 S)
/* The activity LED that eternally blinks to show that the */
/* software is running. */
BLINK_t activity;
void init()
{/* Initialisation of the state machines */
BLINK_init(&activity, ACTIVITY_LED, ACTIVITY_PERIOD);
STATUS_init();
}
int isalive()
{/* Continue while no interruption signal is received. */
return BLINK_isalive(&activity);
}
void run()
{
BLINK_run(&activity);
STATUS_run();
}
void cleanup()
{
BLINK_cleanup(&activity);
STATUS_cleanup();
}
void interrupted()
{/* Interruption signal received => stop the demo */
BLINK_kill(&activity);
}
/******************************************************************/
First we are going to test this demo on a regular PC. The program can be compiled on GNU/Linux with gcc using the stubbed wiringPi library:
gcc -Wall -Werror \
-o ex2-BlinkingLED \
ex2-BlinkingLED.c demo.c clock.c blink.c wiringPi.c
Some quick explanations about this command line:
-Wall
, -Werror
-o ex2-BlinkingLED
ex2-BlinkingLED.c
clock.c
blink.c
blink.c
wiringPi.c
demo.c
main
function.
The executable can be run from the command line. ex2-BlinkingLED
will run until you kill it (with Ctrl-C
for instance).
$ ./ex2-BlinkingLED
model = Stubbed wiringPi
rev = n/a
mem = 0 Mb
maker = cdelord.fr
over volted = no
[ACT: HIGH]
Signal received: Interrupt
A similar command line can be used on a Raspberry Pi (I’m using Raspbian).
gcc -Wall -Werror \
-o ex2-BlinkingLED \
ex2-BlinkingLED.c demo.c clock.c blink.c \
-lwiringPi
The main difference is that we use the real wiringPi
library (-lwiringPi
) instead of the stub.
This example uses a GPIO connected to a LED. While running it you should see the LED blinking once per second.
The program uses the real wiringPi
library so it requires root privileges.
$ sudo ./ex2-BlinkingLED
model = Model 2
rev = 1.1
mem = 1024 Mb
maker = Sony
over volted = yes
[ACT: HIGH]
Signal received: Interrupt
Now we have a blinking LED showing that the system is running… But it still actually does nothing amazing.
The next chapter will add a state machine that composes some nice music (for some definition of nice music). The blinking LED of this chapter will still continue blinking in parallel.
This chapter shows:
The electrical wiring for this project is quite simple. It reuses the blinking LED example.
Here is what you need to add to the previous example:
The LEDs and resistors are connected to output GPIOs.
The speaker is connected to an output PWM GPIO. The potentiometer is used to regulate the volume.
The additional LED will be used to kind of visualize the sounds that are being produced. It’s turned on when the PWM output frequency is rising.
For this example we need a state machine that generates music. The state machine has several states (play, stop, fade in/out transitions, …).
The music is generated by constantly increasing or decreasing the current frequency (f) until a target frequency (f2) is reached. Then a new frequency is randomly chosen between 110 Hz and 880 Hz.
The source code contains some code that will be used in the next chapter to start and stop the music according to a light sensor. This code in not used in this chapter.
The symbol LIGHTSENSOR
must not be defined for the C preprocessor right now.
/******************************************************************/
/* file: music.h */
/* */
/* Music state machine. The music is generated on a PWM output. */
/******************************************************************/
#ifndef __MUSIC_STATE_MACHINE__
#define __MUSIC_STATE_MACHINE__
#include "demo.h"
#ifdef LIGHTSENSOR
#include "light.h"
#endif
/* Music state */
/* Music generation mode */
typedef enum { STOPPED, PLAY, FADEOUT, NIGHT, FADEIN } musicMode_t;
/* Frequency range used by the random generator */
#define FMIN 110 /* Hz */
#define FMAX 880 /* Hz */
/* Full state machine state */
typedef struct
{int ticks; /* number of clock ticks */
int fade_slowdown; /* slowdown in fade out/in mode */
int f; /* current frequency */
int f2; /* target frequency */
/* music generation mode */
musicMode_t mode; int led; /* music LED pin number */
int pwm; /* PWM GPIO pin number */
int killed; /* kill flag to stop the music */
#ifdef LIGHTSENSOR
/* light sensor state machine */
LightSensor_t *sensor; #endif
} MUSIC_t;
/* Initialisation method */
#ifdef LIGHTSENSOR
void MUSIC_init(MUSIC_t *q, int led, int pwm, int fade_slowdown, LightSensor_t *sensor);
#else
void MUSIC_init(MUSIC_t *q, int led, int pwm, int fade_slowdown);
#endif
/* The music generator is alive until it is killed. */
int MUSIC_isalive(MUSIC_t *q);
/* This metod changes the current music generation mode. */
void MUSIC_mode(MUSIC_t *q, musicMode_t mode);
/* This methods kills the music state machine. */
void MUSIC_kill(MUSIC_t *q);
/* Computes and eventually plays a different tone at each cycle. */
void MUSIC_run(MUSIC_t *q);
/* Stops the music. */
void MUSIC_cleanup(MUSIC_t *q);
#endif
/******************************************************************/
/******************************************************************/
/* file: music.c */
/* */
/* Music state machine: implementation (see music.h) */
/******************************************************************/
#include "music.h"
#include "status.h"
/* Initialisation method */
#ifdef LIGHTSENSOR
void MUSIC_init(MUSIC_t *q, int led, int pwm, int fade_slowdown, LightSensor_t *sensor)
#else
void MUSIC_init(MUSIC_t *q, int led, int pwm, int fade_slowdown)
#endif
{0;
q->ticks =
q->fade_slowdown = fade_slowdown;0;
q->f = 0;
q->f2 =
q->mode = PLAY;
q->led = led;
q->pwm = pwm;
q->killed = FALSE;
pinMode(q->led, OUTPUT);
pinMode(q->pwm, PWM_OUTPUT);
pwmSetMode(PWM_MODE_MS);#ifdef LIGHTSENSOR
q->sensor = sensor;#endif
}
/* The music generator is alive until it is killed. */
int MUSIC_isalive(MUSIC_t *q)
{return q->mode != STOPPED;
}
/* This metod changes the current music generation mode. */
void MUSIC_mode(MUSIC_t *q, musicMode_t mode)
{
q->mode = mode;
}
/* This methods kills the music state machine. */
void MUSIC_kill(MUSIC_t *q)
{
MUSIC_mode(q, FADEOUT);
q->killed = TRUE;
digitalWrite(q->led, LOW);
}
/* Computes and eventually plays a different tone at each cycle. */
void MUSIC_run(MUSIC_t *q)
{switch (q->mode)
{
/* Play mode: constantly updates and plays f */
/* until f == f2. */
/* Then choose a new target frequency. */
/* The music may be stopped (Fadeout mode) */
/* when the light is switched off. */
case PLAY:
if (q->f != q->f2)
{/* continue playing towards the same frequency */
if (q->f < q->f2) q->f++;
if (q->f > q->f2) q->f--;
}else
{/* find a new tone */
q->f2 = FMIN + random()%(FMAX-FMIN);
digitalWrite(q->led, q->f2 > q->f ? HIGH : LOW);
}#ifdef LIGHTSENSOR
if (!LIGHTSENSOR_value(q->sensor)) q->mode = FADEOUT;
#endif
break;
/* Fadeout mode: constantly decreases and plays f */
/* until f == 0. */
/* Then stops the music generation. */
/* The music may be restarted in Fadein */
/* mode if the light is switched on. */
case FADEOUT:
if (q->f > 0 && q->ticks%q->fade_slowdown == 0) q->f--;
if (q->f <= 0) q->mode = q->killed ? STOPPED : NIGHT;
digitalWrite(q->led, LOW);#ifdef LIGHTSENSOR
if (!q->killed && LIGHTSENSOR_value(q->sensor)) q->mode = FADEIN;
#endif
break;
/* Fadein mode: constantly increases and plays f */
/* while f < f2. */
/* Then starts normal Play mode. */
/* The music may be stopped in Fadeout */
/* mode if the light is switched off. */
case FADEIN:
if (q->f < q->f2 && q->ticks%q->fade_slowdown == 0) q->f++;
if (q->f >= q->f2) q->mode = PLAY;
digitalWrite(q->led, HIGH);#ifdef LIGHTSENSOR
if (!LIGHTSENSOR_value(q->sensor)) q->mode = FADEOUT;
#endif
break;
/* Night mode: plays nothing */
/* The music may be restarted in Fadein */
/* mode if the light is switched on. */
case NIGHT:
#ifdef LIGHTSENSOR
if (!q->killed && LIGHTSENSOR_value(q->sensor)) q->mode = FADEIN;
#endif
break;
/* Stop mode: plays nothing */
/* and waits for the sequencer to exit. */
case STOPPED:
0;
q->f = break;
}
/* Play the current tone */
pwmToneWrite(q->pwm, q->f);
STATUS_music(q->mode, q->f, q->f2);
q->ticks++;
}
/* Stops the music. */
void MUSIC_cleanup(MUSIC_t *q)
{0);
pwmToneWrite(q->pwm,
digitalWrite(q->led, LOW);
}
/******************************************************************/
The main program is very similar to the previous examples.
/******************************************************************/
/* file: ex3-PWMOutput.c */
/* */
/* Unpleasant random music generator. */
/******************************************************************/
#include "demo.h"
#include "status.h"
#include "blink.h"
#include "music.h"
#define ACTIVITY_LED 7 /* BCM GPIO 4 */
#define MUSIC_LED 0 /* BCM GPIO 0 */
#define MUSIC_PWM 1 /* BCM GPIO 18 */
#define ACTIVITY_PERIOD (1 S)
#define FADE_SLOWDOWN 4
/* The activity LED that eternally blinks to show that the */
/* software is running. */
BLINK_t activity;
/* The music state machine that generates random music according */
/* to its generation mode. */
MUSIC_t music;
void init()
{/* Initialisation of the state machines */
BLINK_init(&activity, ACTIVITY_LED, ACTIVITY_PERIOD);
MUSIC_init(&music, MUSIC_LED, MUSIC_PWM, FADE_SLOWDOWN);
STATUS_init();
}
int isalive()
{return BLINK_isalive(&activity) && MUSIC_isalive(&music);
}
void run()
{
BLINK_run(&activity);
MUSIC_run(&music);
STATUS_run();
}
void cleanup()
{
BLINK_cleanup(&activity);
MUSIC_cleanup(&music);
STATUS_cleanup();
}
void interrupted()
{/* Makes the LED blink faster while the program is stopping. */
4);
BLINK_reschedule(&activity, ACTIVITY_PERIOD//* Also tells the music state machine to stop the music. */
MUSIC_kill(&music);
}
/******************************************************************/
First we are going to test this demo on a regular PC. The program can be compiled on GNU/Linux with gcc using the stubbed wiringPi library:
gcc -Wall -Werror \
-o ex3-PWMOutput \
ex3-PWMOutput.c demo.c clock.c blink.c music.c wiringPi.c
Some quick explanations about this command line:
-Wall
, -Werror
-o ex3-PWMOutput
ex3-PWMOutput.c
clock.c
blink.c
blink.c
music.c
wiringPi.c
demo.c
main
function.
The executable can be run from the command line. ex3-PWMOutput
will run until you kill it (with Ctrl-C
for instance).
$ ./ex3-PWMOutput
model = Stubbed wiringPi
rev = n/a
mem = 0 Mb
maker = cdelord.fr
over volted = no
[ACT: HIGH] [MUSIC: PLAY / 565 / 839]
Of course no sound is played on Linux using the wiringPi stub.
A similar command line can be used on a Raspberry Pi (I’m using Raspbian).
gcc -Wall -Werror \
-o ex3-PWMOutput \
ex3-PWMOutput.c demo.c clock.c blink.c music.c \
-lwiringPi
The main difference is that we use the real wiringPi
library (-lwiringPi
) instead of the stub.
This example uses a GPIO connected to a LED to show if the frequency is rising or falling and another GPIO connected to a speaker. While running it you should see the activity LED blinking once per second, the music LED blinking according to the variation of the frequency and of course hear some unpleasant sound coming from the speaker.
The program uses the real wiringPi
library so it requires root privileges.
$ sudo ./ex3-PWMOutput
model = Model 2
rev = 1.1
mem = 1024 Mb
maker = Sony
over volted = yes
[ACT: HIGH] [MUSIC: PLAY / 565 / 839]
Now we produce some sound… But we have no control.
The next chapter will add a state machine that detects light and stops the music when the light is low.
This chapter shows:
The electrical wiring for this project is quite simple. It reuses the music generator example.
Here is what you need to add to the previous example:
The LEDs and resistors are connected to output GPIOs.
The speaker is connected to an output PWM GPIO. The potentiometer is used to regulate the volume.
The additional LED will be used to kind of visualize the sounds that are being produced. It’s turned on when the PWM output frequency is rising.
The light sensor is connected to an input GPIO. For this demo, the threshold can not be modified.
For this example we need a state machine that reads and filters the light sensor values. It’s important to filter the light sensor values since they can vary a lot when the light level is near to the sensor threshold. The light level must be stable before being used by the software.
A value must be stable for a few cycles before being taken into account.
/******************************************************************/
/* file: light.h */
/* */
/* Light sensor state machine. It reads and filters the light */
/* sensor values. */
/******************************************************************/
#ifndef __LIGHT_STATE_MACHINE__
#define __LIGHT_STATE_MACHINE__
#include "demo.h"
/* Light state */
typedef struct
{int pin; /* GPIO pin number of the sensor */
int confirm; /* number of cycles the input is stable */
int value; /* current value acquired on the GPIO */
int confirmedValue; /* value previously confirmed */
int confirmationPeriod; /* number of confirmation cycles */
} LightSensor_t;
/* Light sensor initialisation */
void LIGHTSENSOR_init(LightSensor_t *q, int pin, int confirmation_in_us);
/* Currently confirmed value */
int LIGHTSENSOR_value(LightSensor_t *q);
/* Reads and filters the light sensor value. */
void LIGHTSENSOR_run(LightSensor_t *q);
/* The light sensor is considered always alive. */
int LIGHTSENSOR_isalive(LightSensor_t *q);
/* Stops the light sensor acquisition. */
void LIGHTSENSOR_cleanup(LightSensor_t *q);
#endif
/******************************************************************/
/******************************************************************/
/* file: light.c */
/* */
/* Light sensor state machine: implementation (see light.h) */
/******************************************************************/
#include "light.h"
#include "status.h"
void LIGHTSENSOR_init(LightSensor_t *q, int pin, int confirmation_in_us)
{
q->pin = pin;0;
q->confirm = 0;
q->value =
q->confirmationPeriod = confirmation_in_us / CYCLE;
pinMode(q->pin, INPUT);
q->confirmedValue = q->value = digitalRead(q->pin);
}
int LIGHTSENSOR_value(LightSensor_t *q)
{return q->confirmedValue;
}
void LIGHTSENSOR_run(LightSensor_t *q)
{int value = digitalRead(q->pin);
if (value == q->value)
{/* same value than the previous cycle */
q->confirm++;if (q->confirm >= q->confirmationPeriod)
{/* same value for `q->confirmationPeriod` cycles */
q->confirmedValue = value;
}
}else
{/* value not stable => start a new confirmation phase */
q->value = value;0;
q->confirm =
}
STATUS_light(q->value, q->confirmedValue);
}
int LIGHTSENSOR_isalive(LightSensor_t *q)
{return TRUE;
}
void LIGHTSENSOR_cleanup(LightSensor_t *q)
{
}
/******************************************************************/
The music state machine described in the previous example is compiled with the LIGHTSENSOR
feature. This adds states and transitions to stop and restart the music when the light gets low or high.
The main program is very similar to the previous examples.
/******************************************************************/
/* file: ex4-LightSensor.c */
/* */
/* Unpleasant random music generator */
/* moderated with a light sensor */
/******************************************************************/
#include "demo.h"
#include "status.h"
#include "blink.h"
#include "music.h"
#include "light.h"
#define ACTIVITY_LED 7 /* BCM GPIO 4 */
#define MUSIC_LED 0 /* BCM GPIO 0 */
#define MUSIC_PWM 1 /* BCM GPIO 18 */
#define LIGHT_INPUT 2 /* BCM GPIO 27 */
#define ACTIVITY_PERIOD (1 S)
#define LIGHT_CONFIRMATION (100 MS)
#define FADE_SLOWDOWN 4
/* The activity LED that eternally blinks to show that */
/* the software is running. */
BLINK_t activity;
/* The music state machine that generates random music according */
/* to its generation mode. */
MUSIC_t music;
/* The light sensor confirmation state machines. */
LightSensor_t light;
void init()
{/* Initialisation of the state machines */
BLINK_init(&activity, ACTIVITY_LED, ACTIVITY_PERIOD);
LIGHTSENSOR_init(&light, LIGHT_INPUT, LIGHT_CONFIRMATION);
MUSIC_init(&music, MUSIC_LED, MUSIC_PWM, FADE_SLOWDOWN, &light);
STATUS_init();
}
int isalive()
{return BLINK_isalive(&activity) && MUSIC_isalive(&music) &&
LIGHTSENSOR_isalive(&light);
}
void run()
{
BLINK_run(&activity);
LIGHTSENSOR_run(&light);
MUSIC_run(&music);
STATUS_run();
}
void cleanup()
{
BLINK_cleanup(&activity);
MUSIC_cleanup(&music);
LIGHTSENSOR_cleanup(&light);
STATUS_cleanup();
}
void interrupted()
{/* Makes the LED blink faster while the program is stopping. */
4);
BLINK_reschedule(&activity, ACTIVITY_PERIOD//* Also tells the music state machine to stop the music. */
MUSIC_kill(&music);
}
/******************************************************************/
First we are going to test this demo on a regular PC. The program can be compiled on GNU/Linux with gcc using the stubbed wiringPi library:
gcc -Wall -Werror \
-DLIGHTSENSOR \
-o ex4-LightSensor \
ex4-LightSensor.c demo.c clock.c blink.c music.c light.c wiringPi.c
Some quick explanations about this command line:
-Wall
, -Werror
-DLIGHTSENSOR
-o ex4-LightSensor
ex4-LightSensor.c
clock.c
blink.c
blink.c
music.c
light.c
wiringPi.c
demo.c
main
function.
The executable can be run from the command line. ex4-LightSensor
will run until you kill it (with Ctrl-C
for instance).
$ ./ex3-PWMOutput
model = Stubbed wiringPi
rev = n/a
mem = 0 Mb
maker = cdelord.fr
over volted = no
[ACT: HIGH] [LIGHT: 1 / DAY ] [MUSIC: PLAY / 565 / 839]
Of course no sound is played on Linux using the wiringPi stub.
A similar command line can be used on a Raspberry Pi (I’m using Raspbian).
gcc -Wall -Werror \
-DLIGHTSENSOR \
-o ex4-LightSensor \
ex4-LightSensor.c demo.c clock.c blink.c music.c light.c \
-lwiringPi
The main difference is that we use the real wiringPi
library (-lwiringPi
) instead of the stub.
This example uses a GPIO connected to a LED to show if the frequency is rising or falling and another GPIO connected to a speaker. The light sensor should detect the light level and the software will stop when the light is switched off. While running it you should see the activity LED blinking once per second, the music LED blinking according to the variation of the frequency and of course hear some unpleasant sound coming from the speaker. Switch the light of the room to stop the music!
The program uses the real wiringPi
library so it requires root privileges.
$ sudo ./ex3-PWMOutput
model = Model 2
rev = 1.1
mem = 1024 Mb
maker = Sony
over volted = yes
[ACT: HIGH] [LIGHT: 1 / DAY ] [MUSIC: PLAY / 565 / 839]
Now we produce some sound with some limited control over it…
The next step is to use an analog input sensor connected to an I2C input to be able to adjust the detection level.
Be patient and wait for the next edition of this tutorial.
/******************************************************************/
/* file: demo.h */
/* */
/* Some global definitions for theses tutorials. */
/******************************************************************/
#ifndef __DEMO__
#define __DEMO__
#include <stdio.h>
#include <stdlib.h>
/* wiringPi library used to access Raspberry Pi GPIOs */
#include "wiringPi.h"
/* Time units (all times are internally in µs) */
#define US * 1
#define MS * 1000 US
#define S * 1000 MS
/* The base cycle is the period of the sequencer. */
#define CYCLE (10 MS)
/* Routines to be defined by the application. */
/* init is called once to initialise the state machines */
extern void init();
/* isalive is called periodically to check if the state machines */
/* are still alive */
extern int isalive();
/* run is called periodically to run one step of every state machines */
extern void run();
/* cleanup is called once when the system is not alive */
extern void cleanup();
/* interrupted is called when an interrupt signal is received. */
/* interrupt signals are SIGINT, SIGQUIT, SIGABRT and SIGTERM. */
extern void interrupted();
#endif
/******************************************************************/
/******************************************************************/
/* file: demo.h */
/* */
/* Sequencer for the state machines of theses tutorials. */
/******************************************************************/
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include "demo.h"
/* signal_handler is called when a signal is received. It calls */
/* the `interrupted` function defined by the application (which */
/* in turns calls the "interrupted" functions of the state */
/* machines. */
static void signal_handler(int sig)
{"\nSignal received: %s\n", strsignal(sig));
printf(
interrupted();
}
/* timer_handler is called periodically. The period is CYCLE. */
/* The main loop is driven by a timer which is more accurate than */
/* a simple wait. */
/* timer_handler calls: */
/* - `run` to execute one step of every state machines */
/* - `isalive` to check that the system is still alive */
/* - `cleanup` and exits when the system is not alive anymore */
static void timer_handler(int signum)
{/* run one step */
run();/* check if the program is still alive */
if (!isalive())
{/* stop the program when it is not alive anymore */
cleanup();
exit(EXIT_SUCCESS);
}/* wait for the next cycle */
}
/* The main function initializes the state machines, */
/* starts a periodic timer to run the state machines */
/* and undefinitely waits for the system to exit. */
int main(void)
{/* Initialisation of the wiringPi library to access GPIOs */
wiringPiSetup();
/* Interruption signal handler */
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGABRT, signal_handler);
signal(SIGTERM, signal_handler);
/* Some information about the hardware */
int model, rev, mem, maker, overVolted;
piBoardId(&model, &rev, &mem, &maker, &overVolted);"model = %s\n", piModelNames[model]);
printf("rev = %s\n", piRevisionNames[rev]);
printf("mem = %d Mb\n", mem);
printf("maker = %s\n", piMakerNames[maker]);
printf("over volted = %s\n", overVolted ? "yes" : "no");
printf("\n");
printf(
/* state machine initializations */
init();
/* Install timer_handler as the signal handler for SIGALRM. */
struct sigaction sa;
0, sizeof (sa));
memset (&sa,
sa.sa_handler = &timer_handler;
sigaction(SIGALRM, &sa, NULL);
/* Configure the timer to expire after CYCLE µs... */
struct itimerval itimer;
0;
itimer.it_value.tv_sec =
itimer.it_value.tv_usec = CYCLE;/* ... and every CYCLE µs after that. */
0;
itimer.it_interval.tv_sec =
itimer.it_interval.tv_usec = CYCLE;/* Start the timer. */
setitimer (ITIMER_REAL, &itimer, NULL);
/* Main loop */
while (1)
{/* This loop could be used as a background loop */
1000);
sleep(
}
return EXIT_SUCCESS;
}
/******************************************************************/
The wiringPi stub is simply the original wiringPi.h
file along with a fake wiringPi.c
implementation that simulates some I/O.
/*
* wiringPi.h:
* Arduino like Wiring library for the Raspberry Pi.
* Copyright (c) 2012-2016 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* wiringPi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#ifndef __WIRING_PI_H__
#define __WIRING_PI_H__
// C doesn't have true/false by default and I can never remember which
// way round they are, so ...
#ifndef TRUE
# define TRUE (1==1)
# define FALSE (!TRUE)
#endif
// Handy defines
// wiringPi modes
#define WPI_MODE_PINS 0
#define WPI_MODE_GPIO 1
#define WPI_MODE_GPIO_SYS 2
#define WPI_MODE_PHYS 3
#define WPI_MODE_PIFACE 4
#define WPI_MODE_UNINITIALISED -1
// Pin modes
#define INPUT 0
#define OUTPUT 1
#define PWM_OUTPUT 2
#define GPIO_CLOCK 3
#define SOFT_PWM_OUTPUT 4
#define SOFT_TONE_OUTPUT 5
#define PWM_TONE_OUTPUT 6
#define LOW 0
#define HIGH 1
// Pull up/down/none
#define PUD_OFF 0
#define PUD_DOWN 1
#define PUD_UP 2
// PWM
#define PWM_MODE_MS 0
#define PWM_MODE_BAL 1
// Interrupt levels
#define INT_EDGE_SETUP 0
#define INT_EDGE_FALLING 1
#define INT_EDGE_RISING 2
#define INT_EDGE_BOTH 3
// Pi model types and version numbers
// Intended for the GPIO program Use at your own risk.
#define PI_MODEL_A 0
#define PI_MODEL_B 1
#define PI_MODEL_AP 2
#define PI_MODEL_BP 3
#define PI_MODEL_2 4
#define PI_ALPHA 5
#define PI_MODEL_CM 6
#define PI_MODEL_07 7
#define PI_MODEL_3 8
#define PI_MODEL_ZERO 9
#define PI_VERSION_1 0
#define PI_VERSION_1_1 1
#define PI_VERSION_1_2 2
#define PI_VERSION_2 3
#define PI_MAKER_SONY 0
#define PI_MAKER_EGOMAN 1
#define PI_MAKER_MBEST 2
#define PI_MAKER_UNKNOWN 3
extern const char *piModelNames [16] ;
extern const char *piRevisionNames [16] ;
extern const char *piMakerNames [16] ;
extern const int piMemorySize [ 8] ;
// Intended for the GPIO program Use at your own risk.
// Threads
#define PI_THREAD(X) void *X (void *dummy)
// Failure modes
#define WPI_FATAL (1==1)
#define WPI_ALMOST (1==2)
// wiringPiNodeStruct:
// This describes additional device nodes in the extended wiringPi
// 2.0 scheme of things.
// It's a simple linked list for now, but will hopefully migrate to
// a binary tree for efficiency reasons - but then again, the chances
// of more than 1 or 2 devices being added are fairly slim, so who
// knows....
struct wiringPiNodeStruct
{int pinBase ;
int pinMax ;
int fd ; // Node specific
unsigned int data0 ; // ditto
unsigned int data1 ; // ditto
unsigned int data2 ; // ditto
unsigned int data3 ; // ditto
void (*pinMode) (struct wiringPiNodeStruct *node, int pin, int mode) ;
void (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ;
int (*digitalRead) (struct wiringPiNodeStruct *node, int pin) ;
void (*digitalWrite) (struct wiringPiNodeStruct *node, int pin, int value) ;
void (*pwmWrite) (struct wiringPiNodeStruct *node, int pin, int value) ;
int (*analogRead) (struct wiringPiNodeStruct *node, int pin) ;
void (*analogWrite) (struct wiringPiNodeStruct *node, int pin, int value) ;
struct wiringPiNodeStruct *next ;
} ;
extern struct wiringPiNodeStruct *wiringPiNodes ;
// Function prototypes
// c++ wrappers thanks to a comment by Nick Lott
// (and others on the Raspberry Pi forums)
#ifdef __cplusplus
extern "C" {
#endif
// Data
// Internal
extern int wiringPiFailure (int fatal, const char *message, ...) ;
// Core wiringPi functions
extern struct wiringPiNodeStruct *wiringPiFindNode (int pin) ;
extern struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) ;
extern int wiringPiSetup (void) ;
extern int wiringPiSetupSys (void) ;
extern int wiringPiSetupGpio (void) ;
extern int wiringPiSetupPhys (void) ;
extern void pinModeAlt (int pin, int mode) ;
extern void pinMode (int pin, int mode) ;
extern void pullUpDnControl (int pin, int pud) ;
extern int digitalRead (int pin) ;
extern void digitalWrite (int pin, int value) ;
extern void pwmWrite (int pin, int value) ;
extern int analogRead (int pin) ;
extern void analogWrite (int pin, int value) ;
// PiFace specifics
// (Deprecated)
extern int wiringPiSetupPiFace (void) ;
extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio program only
// On-Board Raspberry Pi hardware specific stuff
extern int piBoardRev (void) ;
extern void piBoardId (int *model, int *rev, int *mem, int *maker, int *overVolted) ;
extern int wpiPinToGpio (int wpiPin) ;
extern int physPinToGpio (int physPin) ;
extern void setPadDrive (int group, int value) ;
extern int getAlt (int pin) ;
extern void pwmToneWrite (int pin, int freq) ;
extern void digitalWriteByte (int value) ;
extern unsigned int digitalReadByte (void) ;
extern void pwmSetMode (int mode) ;
extern void pwmSetRange (unsigned int range) ;
extern void pwmSetClock (int divisor) ;
extern void gpioClockSet (int pin, int freq) ;
// Interrupts
// (Also Pi hardware specific)
extern int waitForInterrupt (int pin, int mS) ;
extern int wiringPiISR (int pin, int mode, void (*function)(void)) ;
// Threads
extern int piThreadCreate (void *(*fn)(void *)) ;
extern void piLock (int key) ;
extern void piUnlock (int key) ;
// Schedulling priority
extern int piHiPri (const int pri) ;
// Extras from arduino land
extern void delay (unsigned int howLong) ;
extern void delayMicroseconds (unsigned int howLong) ;
extern unsigned int millis (void) ;
extern unsigned int micros (void) ;
#ifdef __cplusplus
}#endif
#endif
/*
* wiringPi.c:
* Arduino like Wiring library for the Raspberry Pi.
* This is a stub for Linux.
***********************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <sys/time.h>
#include "wiringPi.h"
const char *piModelNames [16] = { "Stubbed wiringPi" };
const char *piRevisionNames [16] = { "n/a" };
const char *piMakerNames [16] = { "cdelord.fr" };
const int piMemorySize [ 8] = { 0 };
struct wiringPiNodeStruct *wiringPiNodes = NULL;
// Internal
int wiringPiFailure (int fatal, const char *message, ...)
{va_list ap;
va_start(ap, message);
vprintf(message, ap);
va_end(ap);
exit(fatal);
}
// Core wiringPi functions
struct wiringPiNodeStruct *wiringPiFindNode (int pin) ;
struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) ;
int wiringPiSetup (void) { return 0; }
int wiringPiSetupSys (void) { return 0; }
int wiringPiSetupGpio (void) { return 0; }
int wiringPiSetupPhys (void) { return 0; }
void pinModeAlt (int pin, int mode) ;
void pinMode (int pin, int mode) { }
void pullUpDnControl (int pin, int pud) ;
int digitalRead (int pin)
{static int pinDec[1024] = {0};
static int pinVal[1024] = {0};
if (pinDec[pin] > 0)
{
pinDec[pin]--;
}else
{switch (pin)
{case 2:
2 ? HIGH : LOW;
pinVal[pin] = random()%500;
pinDec[pin] = break;
default:
1, "The pin %d is not simulated.", pin);
wiringPiFailure(break;
}
}return !!pinVal[pin];
}void digitalWrite (int pin, int value)
{//printf("digitalWrite(pin = %d, value = %d)\n", pin, value);
}void pwmWrite (int pin, int value) ;
int analogRead (int pin) ;
void analogWrite (int pin, int value) ;
// PiFace specifics
// (Deprecated)
int wiringPiSetupPiFace (void) { return 0; }
int wiringPiSetupPiFaceForGpioProg (void) { return 0; } // Don't use this - for gpio program only
// On-Board Raspberry Pi hardware specific stuff
int piBoardRev (void) { return 0; }
void piBoardId (int *model, int *rev, int *mem, int *maker, int *overVolted)
{0;
*model = 0;
*rev = 0;
*mem = 0;
*maker = 0;
*overVolted =
}int wpiPinToGpio (int wpiPin) ;
int physPinToGpio (int physPin) ;
void setPadDrive (int group, int value) ;
int getAlt (int pin) ;
void pwmToneWrite (int pin, int freq) { }
void digitalWriteByte (int value) ;
unsigned int digitalReadByte (void) ;
void pwmSetMode (int mode) { };
void pwmSetRange (unsigned int range) ;
void pwmSetClock (int divisor) ;
void gpioClockSet (int pin, int freq) ;
// Interrupts
// (Also Pi hardware specific)
int waitForInterrupt (int pin, int mS) ;
int wiringPiISR (int pin, int mode, void (*function)(void)) ;
// Threads
int piThreadCreate (void *(*fn)(void *)) ;
void piLock (int key) ;
void piUnlock (int key) ;
// Schedulling priority
int piHiPri (const int pri) ;
// Extras from arduino land
void delay (unsigned int howLong) ;
void delayMicrosecondsHard (unsigned int howLong)
{struct timeval tNow, tLong, tEnd ;
gettimeofday (&tNow, NULL) ;1000000 ;
tLong.tv_sec = howLong / 1000000 ;
tLong.tv_usec = howLong %
timeradd (&tNow, &tLong, &tEnd) ;
while (timercmp (&tNow, &tEnd, <))
gettimeofday (&tNow, NULL) ;
}
void delayMicroseconds (unsigned int howLong)
{struct timespec sleeper ;
unsigned int uSecs = howLong % 1000000 ;
unsigned int wSecs = howLong / 1000000 ;
/**/ if (howLong == 0)
return ;
else if (howLong < 100)
delayMicrosecondsHard (howLong) ;else
{
sleeper.tv_sec = wSecs ;long)(uSecs * 1000L) ;
sleeper.tv_nsec = (
nanosleep (&sleeper, NULL) ;
}
}
unsigned int millis (void) ;
unsigned int micros (void) ;
The STATUS
state machine collects information about the state of the software and prints it.
/******************************************************************/
/* file: status.h */
/* */
/* Status state machine. It displays information on the state of */
/* the software. */
/******************************************************************/
#include "demo.h"
void STATUS_init();
void STATUS_run();
void STATUS_cleanup();
void STATUS_act(int act);
void STATUS_light(int light, int confirmedLight);
void STATUS_music(int mode, int f, int f2);
/******************************************************************/
/* file: status.c */
/* */
/* Status state machine. It displays information on the state of */
/* the software. */
/******************************************************************/
#include <string.h>
#include "status.h"
#include "music.h"
static const char *MODES[] =
{"PLAY",
[PLAY] = "FADEIN",
[FADEIN] = "fadeout",
[FADEOUT] = "night",
[NIGHT] = "stopped",
[STOPPED] =
};
static const char *GPIO_STATES[] =
{"HIGH",
[HIGH] = "low",
[LOW] =
};
static const char *LIGHT_STATES[] =
{"DAY",
[TRUE] = "night",
[FALSE] =
};
typedef struct
{int level;
int updated;
int act;
int light, confirmedLight;
int mode, f, f2;
} Status_t;
/* There is only one instance of the status machine */
static Status_t status;
void STATUS_init()
{0, sizeof(status));
memset(&status,
status.updated = FALSE;
}
void STATUS_run()
{if (status.updated)
{switch (status.level)
{case 2:
" [ACT: %-4s] \r",
printf(
GPIO_STATES[status.act]
);break;
case 3:
" [ACT: %-4s] [MUSIC: %-7s / %4d / %4d] \r",
printf(
GPIO_STATES[status.act],
MODES[status.mode], status.f, status.f2
);break;
case 4:
" [ACT: %-4s] [LIGHT: %d / %-5s] [MUSIC: %-7s / %4d / %4d] \r",
printf(
GPIO_STATES[status.act],
status.light, LIGHT_STATES[status.confirmedLight],
MODES[status.mode], status.f, status.f2
);break;
default:
break;
}
fflush(stdout);
status.updated = FALSE;
}
}
void STATUS_cleanup()
{"\n");
printf(
}
static int max(int a, int b)
{return a > b ? a : b;
}
void STATUS_act(int act)
{2);
status.level = max(status.level, if (act != status.act)
{
status.act = act;
status.updated = TRUE;
}
}
void STATUS_light(int light, int confirmedLight)
{4);
status.level = max(status.level, if (light != status.light || confirmedLight != status.confirmedLight)
{
status.light = light;
status.confirmedLight = confirmedLight;
status.updated = TRUE;
}
}
void STATUS_music(int mode, int f, int f2)
{3);
status.level = max(status.level, if (mode != status.mode || f != status.f || f2 != status.f2)
{
status.mode = mode;
status.f = f;
status.f2 = f2;
status.updated = TRUE;
} }
/******************************************************************/
/* file: clock.h */
/* */
/* Clock state machine. Clocks can count execution cycles */
/* and generate rising edges. */
/* A clock is defined by a period and an offset (date of the */
/* first rising edge) in µs. */
/******************************************************************/
#ifndef __CLOCK_STATE_MACHINE__
#define __CLOCK_STATE_MACHINE__
#include "demo.h"
/* Clock state */
typedef struct
{int period_us; /* period of the clock in µs */
int offset_us; /* offset of the clock in µs */
int t; /* time in µs since the start of the period */
int time_us; /* current time in µs */
int ticks; /* number of cycles since the clock started */
} CLOCK_t;
/* Clock initialisation method */
void CLOCK_init(CLOCK_t *c, int period_us, int offset_us);
/* Clock main loop method */
void CLOCK_run(CLOCK_t *c);
double CLOCK_time(CLOCK_t *c); /* current time in seconds */
int CLOCK_time_ms(CLOCK_t *c); /* current time in ms */
int CLOCK_time_us(CLOCK_t *c); /* current time in µs */
int CLOCK_edge(CLOCK_t *c); /* is the current cycle a rising edge */
int CLOCK_ticks(CLOCK_t *c); /* number of cycles since the beginning */
double CLOCK_ratio(CLOCK_t *c); /* position within the current cycle */
#endif
/******************************************************************/
/******************************************************************/
/* file: clock.c */
/* */
/* Clock state machine: implementation (see clock.h) */
/******************************************************************/
#include "clock.h"
void CLOCK_init(CLOCK_t *c, int period_us, int offset_us)
{
c->period_us = period_us;
c->offset_us = offset_us;0 ? period_us - offset_us : 0;
c->t = offset_us > 0;
c->time_us = 0;
c->ticks =
}
void CLOCK_run(CLOCK_t *c)
{
c->ticks++;
c->time_us += CYCLE;
c->t += CYCLE;if (c->t >= c->period_us)
{0;
c->t =
}
}
double CLOCK_time(CLOCK_t *c) { return c->time_us/1e6; }
int CLOCK_time_ms(CLOCK_t *c) { return c->time_us/1000; }
int CLOCK_time_us(CLOCK_t *c) { return c->time_us; }
int CLOCK_edge(CLOCK_t *c) { return c->t == 0; }
int CLOCK_ticks(CLOCK_t *c) { return c->ticks; }
double CLOCK_ratio(CLOCK_t *c) { return ((double)c->t) / c->period_us; }
/******************************************************************/
/******************************************************************/
/* file: blink.h */
/* */
/* Blinking LED state machine. The LED is periodically switched */
/* on and off. */
/******************************************************************/
#ifndef __BLINK_STATE_MACHINE__
#define __BLINK_STATE_MACHINE__
#include "demo.h"
#include "clock.h"
/* Blinking LED state */
typedef struct
{int pin; /* pin on which the LED is connected */
/* internal clock of the blinking LED */
CLOCK_t clock; enum
{
BLINK_LED_OFF,
BLINK_LED_ON,/* current LED state */
} state; int killed; /* kill flag to stop the led */
} BLINK_t;
/* Blinking LED initialisation method */
void BLINK_init(BLINK_t *q, int pin, int period_in_us);
/* The blinking period can be modified */
void BLINK_reschedule(BLINK_t *q, int period_in_us);
/* Blinking LED main loop method */
void BLINK_run(BLINK_t *q);
/* This method is called to kill the state machine. */
void BLINK_kill(BLINK_t *q);
/* The state machine is alive until it is killed. */
int BLINK_isalive(BLINK_t *q);
/* Cleanup function (to leave the LED switched off at the end) */
void BLINK_cleanup(BLINK_t *q);
#endif
/******************************************************************/
/******************************************************************/
/* file: blink.c */
/* */
/* Blinking LED state machine: implementation (see blink.h) */
/******************************************************************/
#include "blink.h"
#include "status.h"
/* Blinking LED initialisation method */
void BLINK_init(BLINK_t *q, int pin, int period_in_us)
{
q->killed = FALSE;
q->pin = pin;0);
CLOCK_init(&q->clock, period_in_us,
q->state = BLINK_LED_OFF;
pinMode(q->pin, OUTPUT);
}
/* The blinking period can be modified */
void BLINK_reschedule(BLINK_t *q, int period_in_us)
{
q->clock.period_us = period_in_us;
}
/* Blinking LED main loop method */
void BLINK_run(BLINK_t *q)
{switch (q->state)
{/* if the LED is off during the first half of the clock */
/* period it must be switched on. */
case BLINK_LED_OFF:
if (CLOCK_ratio(&q->clock) < 0.5)
{
q->state = BLINK_LED_ON;
digitalWrite(q->pin, HIGH);
STATUS_act(HIGH);
}break;
/* if the LED is on during the second half of the clock */
/* period it must be switched off. */
case BLINK_LED_ON:
if (CLOCK_ratio(&q->clock) >= 0.5)
{
q->state = BLINK_LED_OFF;
digitalWrite(q->pin, LOW);
STATUS_act(LOW);
}break;
}/* the clock shall also run. */
CLOCK_run(&q->clock);
}
/* This method is called to kill the state machine. */
void BLINK_kill(BLINK_t *q)
{
q->killed = TRUE;
}
/* The state machine is alive until it is killed. */
int BLINK_isalive(BLINK_t *q)
{return !q->killed;
}
/* Cleanup function (to leave the LED switched off at the end) */
void BLINK_cleanup(BLINK_t *q)
{
digitalWrite(q->pin, LOW);
}
/******************************************************************/
/******************************************************************/
/* file: music.h */
/* */
/* Music state machine. The music is generated on a PWM output. */
/******************************************************************/
#ifndef __MUSIC_STATE_MACHINE__
#define __MUSIC_STATE_MACHINE__
#include "demo.h"
#ifdef LIGHTSENSOR
#include "light.h"
#endif
/* Music state */
/* Music generation mode */
typedef enum { STOPPED, PLAY, FADEOUT, NIGHT, FADEIN } musicMode_t;
/* Frequency range used by the random generator */
#define FMIN 110 /* Hz */
#define FMAX 880 /* Hz */
/* Full state machine state */
typedef struct
{int ticks; /* number of clock ticks */
int fade_slowdown; /* slowdown in fade out/in mode */
int f; /* current frequency */
int f2; /* target frequency */
/* music generation mode */
musicMode_t mode; int led; /* music LED pin number */
int pwm; /* PWM GPIO pin number */
int killed; /* kill flag to stop the music */
#ifdef LIGHTSENSOR
/* light sensor state machine */
LightSensor_t *sensor; #endif
} MUSIC_t;
/* Initialisation method */
#ifdef LIGHTSENSOR
void MUSIC_init(MUSIC_t *q, int led, int pwm, int fade_slowdown, LightSensor_t *sensor);
#else
void MUSIC_init(MUSIC_t *q, int led, int pwm, int fade_slowdown);
#endif
/* The music generator is alive until it is killed. */
int MUSIC_isalive(MUSIC_t *q);
/* This metod changes the current music generation mode. */
void MUSIC_mode(MUSIC_t *q, musicMode_t mode);
/* This methods kills the music state machine. */
void MUSIC_kill(MUSIC_t *q);
/* Computes and eventually plays a different tone at each cycle. */
void MUSIC_run(MUSIC_t *q);
/* Stops the music. */
void MUSIC_cleanup(MUSIC_t *q);
#endif
/******************************************************************/
/******************************************************************/
/* file: music.c */
/* */
/* Music state machine: implementation (see music.h) */
/******************************************************************/
#include "music.h"
#include "status.h"
/* Initialisation method */
#ifdef LIGHTSENSOR
void MUSIC_init(MUSIC_t *q, int led, int pwm, int fade_slowdown, LightSensor_t *sensor)
#else
void MUSIC_init(MUSIC_t *q, int led, int pwm, int fade_slowdown)
#endif
{0;
q->ticks =
q->fade_slowdown = fade_slowdown;0;
q->f = 0;
q->f2 =
q->mode = PLAY;
q->led = led;
q->pwm = pwm;
q->killed = FALSE;
pinMode(q->led, OUTPUT);
pinMode(q->pwm, PWM_OUTPUT);
pwmSetMode(PWM_MODE_MS);#ifdef LIGHTSENSOR
q->sensor = sensor;#endif
}
/* The music generator is alive until it is killed. */
int MUSIC_isalive(MUSIC_t *q)
{return q->mode != STOPPED;
}
/* This metod changes the current music generation mode. */
void MUSIC_mode(MUSIC_t *q, musicMode_t mode)
{
q->mode = mode;
}
/* This methods kills the music state machine. */
void MUSIC_kill(MUSIC_t *q)
{
MUSIC_mode(q, FADEOUT);
q->killed = TRUE;
digitalWrite(q->led, LOW);
}
/* Computes and eventually plays a different tone at each cycle. */
void MUSIC_run(MUSIC_t *q)
{switch (q->mode)
{
/* Play mode: constantly updates and plays f */
/* until f == f2. */
/* Then choose a new target frequency. */
/* The music may be stopped (Fadeout mode) */
/* when the light is switched off. */
case PLAY:
if (q->f != q->f2)
{/* continue playing towards the same frequency */
if (q->f < q->f2) q->f++;
if (q->f > q->f2) q->f--;
}else
{/* find a new tone */
q->f2 = FMIN + random()%(FMAX-FMIN);
digitalWrite(q->led, q->f2 > q->f ? HIGH : LOW);
}#ifdef LIGHTSENSOR
if (!LIGHTSENSOR_value(q->sensor)) q->mode = FADEOUT;
#endif
break;
/* Fadeout mode: constantly decreases and plays f */
/* until f == 0. */
/* Then stops the music generation. */
/* The music may be restarted in Fadein */
/* mode if the light is switched on. */
case FADEOUT:
if (q->f > 0 && q->ticks%q->fade_slowdown == 0) q->f--;
if (q->f <= 0) q->mode = q->killed ? STOPPED : NIGHT;
digitalWrite(q->led, LOW);#ifdef LIGHTSENSOR
if (!q->killed && LIGHTSENSOR_value(q->sensor)) q->mode = FADEIN;
#endif
break;
/* Fadein mode: constantly increases and plays f */
/* while f < f2. */
/* Then starts normal Play mode. */
/* The music may be stopped in Fadeout */
/* mode if the light is switched off. */
case FADEIN:
if (q->f < q->f2 && q->ticks%q->fade_slowdown == 0) q->f++;
if (q->f >= q->f2) q->mode = PLAY;
digitalWrite(q->led, HIGH);#ifdef LIGHTSENSOR
if (!LIGHTSENSOR_value(q->sensor)) q->mode = FADEOUT;
#endif
break;
/* Night mode: plays nothing */
/* The music may be restarted in Fadein */
/* mode if the light is switched on. */
case NIGHT:
#ifdef LIGHTSENSOR
if (!q->killed && LIGHTSENSOR_value(q->sensor)) q->mode = FADEIN;
#endif
break;
/* Stop mode: plays nothing */
/* and waits for the sequencer to exit. */
case STOPPED:
0;
q->f = break;
}
/* Play the current tone */
pwmToneWrite(q->pwm, q->f);
STATUS_music(q->mode, q->f, q->f2);
q->ticks++;
}
/* Stops the music. */
void MUSIC_cleanup(MUSIC_t *q)
{0);
pwmToneWrite(q->pwm,
digitalWrite(q->led, LOW);
}
/******************************************************************/
/******************************************************************/
/* file: light.h */
/* */
/* Light sensor state machine. It reads and filters the light */
/* sensor values. */
/******************************************************************/
#ifndef __LIGHT_STATE_MACHINE__
#define __LIGHT_STATE_MACHINE__
#include "demo.h"
/* Light state */
typedef struct
{int pin; /* GPIO pin number of the sensor */
int confirm; /* number of cycles the input is stable */
int value; /* current value acquired on the GPIO */
int confirmedValue; /* value previously confirmed */
int confirmationPeriod; /* number of confirmation cycles */
} LightSensor_t;
/* Light sensor initialisation */
void LIGHTSENSOR_init(LightSensor_t *q, int pin, int confirmation_in_us);
/* Currently confirmed value */
int LIGHTSENSOR_value(LightSensor_t *q);
/* Reads and filters the light sensor value. */
void LIGHTSENSOR_run(LightSensor_t *q);
/* The light sensor is considered always alive. */
int LIGHTSENSOR_isalive(LightSensor_t *q);
/* Stops the light sensor acquisition. */
void LIGHTSENSOR_cleanup(LightSensor_t *q);
#endif
/******************************************************************/
/******************************************************************/
/* file: light.c */
/* */
/* Light sensor state machine: implementation (see light.h) */
/******************************************************************/
#include "light.h"
#include "status.h"
void LIGHTSENSOR_init(LightSensor_t *q, int pin, int confirmation_in_us)
{
q->pin = pin;0;
q->confirm = 0;
q->value =
q->confirmationPeriod = confirmation_in_us / CYCLE;
pinMode(q->pin, INPUT);
q->confirmedValue = q->value = digitalRead(q->pin);
}
int LIGHTSENSOR_value(LightSensor_t *q)
{return q->confirmedValue;
}
void LIGHTSENSOR_run(LightSensor_t *q)
{int value = digitalRead(q->pin);
if (value == q->value)
{/* same value than the previous cycle */
q->confirm++;if (q->confirm >= q->confirmationPeriod)
{/* same value for `q->confirmationPeriod` cycles */
q->confirmedValue = value;
}
}else
{/* value not stable => start a new confirmation phase */
q->value = value;0;
q->confirm =
}
STATUS_light(q->value, q->confirmedValue);
}
int LIGHTSENSOR_isalive(LightSensor_t *q)
{return TRUE;
}
void LIGHTSENSOR_cleanup(LightSensor_t *q)
{
}
/******************************************************************/
/******************************************************************/
/* file: ex1-Clock.c */
/* */
/* Clock usage example. */
/******************************************************************/
#include "demo.h"
#include "clock.h"
/* Clocks are statically allocated "objects" */
CLOCK_t c1, c2;
void init()
{/* Initialisation of the state machines */
500 MS, 250 MS);
CLOCK_init(&c1, 1 S, 0 MS);
CLOCK_init(&c2,
}
int isalive()
{/* Let's run for 5 seconds... */
return CLOCK_time(&c1) < 5.0;
}
void run()
{/* Some outputs to see that the clocks are running */
int e1 = CLOCK_edge(&c1);
int e2 = CLOCK_edge(&c2);
if (e1 || e2)
{/* print "CLOCK" in upper case on rising edges */
"[%s 1: %7.3f / %9d] [%s 2: %7.3f / %9d]\n",
printf("CLOCK" : "clock", CLOCK_time(&c1), CLOCK_ticks(&c1),
e1 ? "CLOCK" : "clock", CLOCK_time(&c2), CLOCK_ticks(&c2));
e2 ?
}
/* Execute one step */
CLOCK_run(&c1);
CLOCK_run(&c2);
}
void interrupted()
{
}
void cleanup()
{
}
/******************************************************************/
/******************************************************************/
/* file: ex2-BlinkingLED.c */
/* */
/* The famous Raspberry Pi "hello world": Blinking LED example. */
/******************************************************************/
#include "demo.h"
#include "status.h"
#include "blink.h"
#define ACTIVITY_LED 7 /* BCM GPIO 4 */
#define ACTIVITY_PERIOD (1 S)
/* The activity LED that eternally blinks to show that the */
/* software is running. */
BLINK_t activity;
void init()
{/* Initialisation of the state machines */
BLINK_init(&activity, ACTIVITY_LED, ACTIVITY_PERIOD);
STATUS_init();
}
int isalive()
{/* Continue while no interruption signal is received. */
return BLINK_isalive(&activity);
}
void run()
{
BLINK_run(&activity);
STATUS_run();
}
void cleanup()
{
BLINK_cleanup(&activity);
STATUS_cleanup();
}
void interrupted()
{/* Interruption signal received => stop the demo */
BLINK_kill(&activity);
}
/******************************************************************/
/******************************************************************/
/* file: ex3-PWMOutput.c */
/* */
/* Unpleasant random music generator. */
/******************************************************************/
#include "demo.h"
#include "status.h"
#include "blink.h"
#include "music.h"
#define ACTIVITY_LED 7 /* BCM GPIO 4 */
#define MUSIC_LED 0 /* BCM GPIO 0 */
#define MUSIC_PWM 1 /* BCM GPIO 18 */
#define ACTIVITY_PERIOD (1 S)
#define FADE_SLOWDOWN 4
/* The activity LED that eternally blinks to show that the */
/* software is running. */
BLINK_t activity;
/* The music state machine that generates random music according */
/* to its generation mode. */
MUSIC_t music;
void init()
{/* Initialisation of the state machines */
BLINK_init(&activity, ACTIVITY_LED, ACTIVITY_PERIOD);
MUSIC_init(&music, MUSIC_LED, MUSIC_PWM, FADE_SLOWDOWN);
STATUS_init();
}
int isalive()
{return BLINK_isalive(&activity) && MUSIC_isalive(&music);
}
void run()
{
BLINK_run(&activity);
MUSIC_run(&music);
STATUS_run();
}
void cleanup()
{
BLINK_cleanup(&activity);
MUSIC_cleanup(&music);
STATUS_cleanup();
}
void interrupted()
{/* Makes the LED blink faster while the program is stopping. */
4);
BLINK_reschedule(&activity, ACTIVITY_PERIOD//* Also tells the music state machine to stop the music. */
MUSIC_kill(&music);
}
/******************************************************************/
/******************************************************************/
/* file: ex4-LightSensor.c */
/* */
/* Unpleasant random music generator */
/* moderated with a light sensor */
/******************************************************************/
#include "demo.h"
#include "status.h"
#include "blink.h"
#include "music.h"
#include "light.h"
#define ACTIVITY_LED 7 /* BCM GPIO 4 */
#define MUSIC_LED 0 /* BCM GPIO 0 */
#define MUSIC_PWM 1 /* BCM GPIO 18 */
#define LIGHT_INPUT 2 /* BCM GPIO 27 */
#define ACTIVITY_PERIOD (1 S)
#define LIGHT_CONFIRMATION (100 MS)
#define FADE_SLOWDOWN 4
/* The activity LED that eternally blinks to show that */
/* the software is running. */
BLINK_t activity;
/* The music state machine that generates random music according */
/* to its generation mode. */
MUSIC_t music;
/* The light sensor confirmation state machines. */
LightSensor_t light;
void init()
{/* Initialisation of the state machines */
BLINK_init(&activity, ACTIVITY_LED, ACTIVITY_PERIOD);
LIGHTSENSOR_init(&light, LIGHT_INPUT, LIGHT_CONFIRMATION);
MUSIC_init(&music, MUSIC_LED, MUSIC_PWM, FADE_SLOWDOWN, &light);
STATUS_init();
}
int isalive()
{return BLINK_isalive(&activity) && MUSIC_isalive(&music) &&
LIGHTSENSOR_isalive(&light);
}
void run()
{
BLINK_run(&activity);
LIGHTSENSOR_run(&light);
MUSIC_run(&music);
STATUS_run();
}
void cleanup()
{
BLINK_cleanup(&activity);
MUSIC_cleanup(&music);
LIGHTSENSOR_cleanup(&light);
STATUS_cleanup();
}
void interrupted()
{/* Makes the LED blink faster while the program is stopping. */
4);
BLINK_reschedule(&activity, ACTIVITY_PERIOD//* Also tells the music state machine to stop the music. */
MUSIC_kill(&music);
}
/******************************************************************/