@@ -35,11 +35,11 @@ LIBS = -lwiringPi | |||||
# Should not alter anything below this line | # Should not alter anything below this line | ||||
############################################################################### | ############################################################################### | ||||
SRC = test1.c test2.c speed.c lcd.c wfi.c piface.c | |||||
SRC = test1.c test2.c speed.c lcd.c wfi.c piface.c gertboard.c nes.c delayTest.c softPwm.c | |||||
OBJ = test1.o test2.o speed.o lcd.o wfi.o piface.o | |||||
OBJ = test1.o test2.o speed.o lcd.o wfi.o piface.o gertboard.o nes.o delayTest.o softPwm.o | |||||
all: test1 test2 speed lcd wfi piface | |||||
all: test1 test2 speed lcd wfi piface gertboard nes softPwm | |||||
test1: test1.o | test1: test1.o | ||||
@echo [link] | @echo [link] | ||||
@@ -65,13 +65,30 @@ piface: piface.o | |||||
@echo [link] | @echo [link] | ||||
$(CC) -o $@ piface.o $(LDFLAGS) $(LIBS) -lpthread | $(CC) -o $@ piface.o $(LDFLAGS) $(LIBS) -lpthread | ||||
gertboard: gertboard.o | |||||
@echo [link] | |||||
$(CC) -o $@ gertboard.o $(LDFLAGS) $(LIBS) -lm | |||||
nes: nes.o | |||||
@echo [link] | |||||
$(CC) -o $@ nes.o $(LDFLAGS) $(LIBS) -lm | |||||
softPwm: softPwm.o | |||||
@echo [link] | |||||
$(CC) -o $@ softPwm.o $(LDFLAGS) $(LIBS) -lm -lpthread | |||||
delayTest: delayTest.o | |||||
@echo [link] | |||||
$(CC) -o $@ delayTest.o $(LDFLAGS) $(LIBS) | |||||
.c.o: | .c.o: | ||||
@echo [CC] $< | @echo [CC] $< | ||||
@$(CC) -c $(CFLAGS) $< -o $@ | @$(CC) -c $(CFLAGS) $< -o $@ | ||||
clean: | clean: | ||||
rm -f $(OBJ) *~ core tags test1 test2 speed lcd wfi piface | |||||
rm -f $(OBJ) *~ core tags test1 test2 speed lcd wfi piface gertboard nes delayTest softPwm | |||||
tags: $(SRC) | tags: $(SRC) | ||||
@echo [ctags] | @echo [ctags] | ||||
@@ -0,0 +1,68 @@ | |||||
#include <stdio.h> | |||||
#include <unistd.h> | |||||
#include <wiringPi.h> | |||||
#include <time.h> | |||||
#include <sys/types.h> | |||||
#include <sys/time.h> | |||||
#define CYCLES 1000 | |||||
#define DELAY 99 | |||||
int main() | |||||
{ | |||||
int x ; | |||||
struct timeval t1, t2 ; | |||||
long long t ; | |||||
unsigned int max, min ; | |||||
unsigned int values [CYCLES] ; | |||||
max = 0 ; | |||||
min = 1000000 ; | |||||
if (wiringPiSetup () == -1) | |||||
return 1 ; | |||||
piHiPri (10) ; | |||||
sleep (1) ; | |||||
// Baseline test | |||||
gettimeofday (&t1, NULL) ; | |||||
gettimeofday (&t2, NULL) ; | |||||
t = t2.tv_usec - t1.tv_usec ; | |||||
printf ("Baseline test: %lld\n", t); | |||||
for (x = 0 ; x < CYCLES ; ++x) | |||||
{ | |||||
gettimeofday (&t1, NULL) ; | |||||
delayMicroseconds (DELAY) ; | |||||
gettimeofday (&t2, NULL) ; | |||||
t = t2.tv_usec - t1.tv_usec ; | |||||
if (t > max) max = t ; | |||||
if (t < min) min = t ; | |||||
values [x] = t ; | |||||
} | |||||
printf ("Done: Max: %d, min: %d\n", max, min) ; | |||||
for (x = 0 ; x < CYCLES ; ++x) | |||||
{ | |||||
printf ("%4d", values [x]) ; | |||||
if (values [x] > DELAY) | |||||
printf (".") ; | |||||
else if (values [x] < DELAY) | |||||
printf ("-") ; | |||||
else | |||||
printf (" ") ; | |||||
if (((x + 1) % 20) == 0) | |||||
printf ("\n") ; | |||||
} | |||||
printf ("\n") ; | |||||
return 0 ; | |||||
} |
@@ -0,0 +1,77 @@ | |||||
/* | |||||
* gertboard.c: | |||||
* Simple test for the SPI bus on the Gertboard | |||||
* | |||||
* Hardware setup: | |||||
* D/A port 0 jumpered to A/D port 0. | |||||
* | |||||
* We output a sine wave on D/A port 0 and sample A/D port 0. We then | |||||
* copy this value to D/A port 1 and use a 'scope on both D/A ports | |||||
* to check all's well. | |||||
* | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <stdint.h> | |||||
#include <math.h> | |||||
#define B_SIZE 200 | |||||
#undef DO_TIMING | |||||
#include <wiringPi.h> | |||||
#include <gertboard.h> | |||||
int main (void) | |||||
{ | |||||
double angle ; | |||||
int i ; | |||||
uint32_t x1 ; | |||||
int buffer [B_SIZE] ; | |||||
#ifdef DO_TIMING | |||||
unsigned int now, then ; | |||||
#endif | |||||
printf ("Raspberry Pi Gertboard SPI test program\n") ; | |||||
if (wiringPiSetupSys () < 0) | |||||
return -1 ; | |||||
if (gertboardSPISetup () < 0) | |||||
return 1 ; | |||||
// Generate a Sine Wave | |||||
for (i = 0 ; i < B_SIZE ; ++i) | |||||
{ | |||||
angle = ((double)i / (double)B_SIZE) * M_PI * 2.0 ; | |||||
buffer [i] = (int)rint ((sin (angle)) * 127.0 + 128.0) ; | |||||
} | |||||
for (;;) | |||||
{ | |||||
#ifdef DO_TIMING | |||||
then = millis () ; | |||||
#endif | |||||
for (i = 0 ; i < B_SIZE ; ++i) | |||||
{ | |||||
gertboardAnalogWrite (0, buffer [i]) ; | |||||
#ifndef DO_TIMING | |||||
x1 = gertboardAnalogRead (0) ; | |||||
gertboardAnalogWrite (1, x1 >> 2) ; // 10-bit A/D, 8-bit D/A | |||||
#endif | |||||
} | |||||
#ifdef DO_TIMING | |||||
now = millis () ; | |||||
printf ("%4d mS, %9.7f S/sample", now - then, ((double)(now - then) / 1000.0) / (double)B_SIZE) ; | |||||
printf (" -> %9.4f samples/sec \n", 1 / (((double)(now - then) / 1000.0) / (double)B_SIZE)) ; | |||||
#endif | |||||
} | |||||
return 0 ; | |||||
} |
@@ -0,0 +1,44 @@ | |||||
#include <stdio.h> | |||||
#include <errno.h> | |||||
#include <string.h> | |||||
#include <wiringPi.h> | |||||
#include <piNes.h> | |||||
#define BLANK "| " | |||||
int main () | |||||
{ | |||||
int joystick ; | |||||
unsigned int buttons ; | |||||
if (wiringPiSetup () == -1) | |||||
{ | |||||
fprintf (stdout, "oops: %s\n", strerror (errno)) ; | |||||
return 1 ; | |||||
} | |||||
if ((joystick = setupNesJoystick (2, 1, 0)) == -1) | |||||
{ | |||||
fprintf (stdout, "Unable to setup joystick\n") ; | |||||
return 1 ; | |||||
} | |||||
for (;;) | |||||
{ | |||||
buttons = readNesJoystick (joystick) ; | |||||
if ((buttons & NES_UP) != 0) printf ("| UP " ) ; else printf (BLANK) ; | |||||
if ((buttons & NES_DOWN) != 0) printf ("| DOWN " ) ; else printf (BLANK) ; | |||||
if ((buttons & NES_LEFT) != 0) printf ("| LEFT " ) ; else printf (BLANK) ; | |||||
if ((buttons & NES_RIGHT) != 0) printf ("|RIGHT " ) ; else printf (BLANK) ; | |||||
if ((buttons & NES_SELECT) != 0) printf ("|SELECT" ) ; else printf (BLANK) ; | |||||
if ((buttons & NES_START) != 0) printf ("|START " ) ; else printf (BLANK) ; | |||||
if ((buttons & NES_A) != 0) printf ("| A " ) ; else printf (BLANK) ; | |||||
if ((buttons & NES_B) != 0) printf ("| B " ) ; else printf (BLANK) ; | |||||
printf ("|\n") ; | |||||
} | |||||
return 0 ; | |||||
} |
@@ -0,0 +1,69 @@ | |||||
#include <stdio.h> | |||||
#include <errno.h> | |||||
#include <string.h> | |||||
#include <wiringPi.h> | |||||
#include <softPwm.h> | |||||
#define RANGE 100 | |||||
#define NUM_LEDS 12 | |||||
int ledMap [NUM_LEDS] = { 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13 } ; | |||||
int values [NUM_LEDS] = { 0, 17, 32, 50, 67, 85, 100, 85, 67, 50, 32, 17 } ; | |||||
int main () | |||||
{ | |||||
int i, j ; | |||||
char buf [80] ; | |||||
if (wiringPiSetup () == -1) | |||||
{ | |||||
fprintf (stdout, "oops: %s\n", strerror (errno)) ; | |||||
return 1 ; | |||||
} | |||||
for (i = 0 ; i < NUM_LEDS ; ++i) | |||||
{ | |||||
softPwmCreate (ledMap [i], 0, RANGE) ; | |||||
printf ("%3d, %3d, %3d\n", i, ledMap [i], values [i]) ; | |||||
} | |||||
fgets (buf, 80, stdin) ; | |||||
// Bring all up one by one: | |||||
for (i = 0 ; i < NUM_LEDS ; ++i) | |||||
for (j = 0 ; j <= 100 ; ++j) | |||||
{ | |||||
softPwmWrite (ledMap [i], j) ; | |||||
delay (10) ; | |||||
} | |||||
fgets (buf, 80, stdin) ; | |||||
// Down fast | |||||
for (i = 100 ; i > 0 ; --i) | |||||
{ | |||||
for (j = 0 ; j < NUM_LEDS ; ++j) | |||||
softPwmWrite (ledMap [j], i) ; | |||||
delay (10) ; | |||||
} | |||||
fgets (buf, 80, stdin) ; | |||||
for (;;) | |||||
{ | |||||
for (i = 0 ; i < NUM_LEDS ; ++i) | |||||
softPwmWrite (ledMap [i], values [i]) ; | |||||
delay (50) ; | |||||
i = values [0] ; | |||||
for (j = 0 ; j < NUM_LEDS - 1 ; ++j) | |||||
values [j] = values [j + 1] ; | |||||
values [NUM_LEDS - 1] = i ; | |||||
} | |||||
} |
@@ -41,7 +41,7 @@ OBJ = gpio.o | |||||
all: gpio | all: gpio | ||||
gpio: gpio.o | |||||
gpio: gpio.o /usr/local/lib/libwiringPi.a | |||||
@echo [LD] | @echo [LD] | ||||
@$(CC) -o $@ gpio.o $(LDFLAGS) $(LIBS) | @$(CC) -o $@ gpio.o $(LDFLAGS) $(LIBS) | ||||
@@ -4,28 +4,55 @@ | |||||
gpio \- Command-line access to Raspberry Pi and PiFace GPIO | gpio \- Command-line access to Raspberry Pi and PiFace GPIO | ||||
.SH SYNOPSIS | .SH SYNOPSIS | ||||
.TP | |||||
.B gpio | .B gpio | ||||
.RB [ \-v ] | |||||
.TP | |||||
.B \-v | |||||
.PP | |||||
.B gpio | .B gpio | ||||
.RB [ \-g ] | |||||
.RB < read/write/pwm/mode ...> | |||||
.TP | |||||
.B [ \-g ] | |||||
.B read/write/pwm/mode ... | |||||
.PP | |||||
.B gpio | .B gpio | ||||
.RB [ \-p ] | |||||
.RB < read/write/mode ...> | |||||
.TP | |||||
.B [ \-p ] | |||||
.B read/write/mode | |||||
.B ... | |||||
.PP | |||||
.B gpio | |||||
.B unexportall/exports | |||||
.PP | |||||
.B gpio | |||||
.B export/edge/unexport | |||||
.B ... | |||||
.PP | |||||
.B gpio | .B gpio | ||||
.RB < export/edge/unexport/unexportall/exports ...> | |||||
.B drive | |||||
group value | |||||
.PP | |||||
.B gpio | |||||
.B pwm-bal/pwm-ms | |||||
.PP | |||||
.B gpio | |||||
.B pwmr | |||||
range | |||||
.PP | |||||
.B gpio | |||||
.B load \ i2c/spi | |||||
.PP | |||||
.B gpio | |||||
.B gbr | |||||
channel | |||||
.PP | |||||
.B gpio | |||||
.B gbw | |||||
channel value | |||||
.SH DESCRIPTION | .SH DESCRIPTION | ||||
.B GPIO | .B GPIO | ||||
is a command line tool to allow the user easy access to the GPIO pins | |||||
on the Raspberry Pi. It's designed for simple testing and diagnostic | |||||
purposes, but can be used in shell scripts for general if somewhat slow | |||||
control of the GPIO pins. | |||||
is a swiss army knofe of a command line tool to allow the user easy | |||||
access to the GPIO pins on the Raspberry Pi and the SPI A/D and D/A | |||||
convertors on the Gertboard. It's designed for simple testing and | |||||
diagnostic purposes, but can be used in shell scripts for general if | |||||
somewhat slow control of the GPIO pins. | |||||
Additionally, it can be used to set the exports in the \fI/sys/class/gpio\fR | Additionally, it can be used to set the exports in the \fI/sys/class/gpio\fR | ||||
system directory to allow subsequent programs to use the \fR/sys/class/gpio\fR | system directory to allow subsequent programs to use the \fR/sys/class/gpio\fR | ||||
@@ -65,6 +92,14 @@ use the literals \fIup\fR, \fIdown\fR or \fItri\fR to set the internal | |||||
pull-up, pull-down or tristate (off) controls. | pull-up, pull-down or tristate (off) controls. | ||||
.TP | .TP | ||||
.B unexportall | |||||
Un-Export all the GPIO pins in the /sys/class/gpio directory. | |||||
.TP | |||||
.B exports | |||||
Print a list (if any) of all the exported GPIO pins and their current values. | |||||
.TP | |||||
.B export | .B export | ||||
Export a GPIO pin in the \fI/sys/class/gpio\fR directory. Use like the | Export a GPIO pin in the \fI/sys/class/gpio\fR directory. Use like the | ||||
mode command above however only \fIin\fR and \fIout\fR are supported at | mode command above however only \fIin\fR and \fIout\fR are supported at | ||||
@@ -96,12 +131,41 @@ requiring root/sudo. | |||||
Un-Export a GPIO pin in the /sys/class/gpio directory. | Un-Export a GPIO pin in the /sys/class/gpio directory. | ||||
.TP | .TP | ||||
.B unexportall | |||||
Un-Export all the GPIO pins in the /sys/class/gpio directory. | |||||
.B drive | |||||
group value | |||||
Change the pad driver value for the given pad group to the supplied drive | |||||
value. Group is 0, 1 or 2 and value is 0-7. Do not use unless you are | |||||
absolutely sure you know what you're doing. | |||||
.TP | .TP | ||||
.B exports | |||||
Print a list (if any) of all the exported GPIO pins and their current values. | |||||
.B pwm-bal/pwm-ms | |||||
Change the PWM mode to balanced (the default) or mark:space ratio (traditional) | |||||
.TP | |||||
.B pwmr | |||||
Change the PWM range register. The default is 1024. | |||||
.TP | |||||
.B load i2c/spi | |||||
This loads the i2c or the spi drivers into the system and changes the permissions on | |||||
the associated /dev/ entries so that the current user has access to them. | |||||
.TP | |||||
.B gbr | |||||
channel | |||||
This reads the analog to digital convertor on the Gertboard on the given | |||||
channel. The board jumpers need to be in-place to do this operation. | |||||
.TP | |||||
.B gbw | |||||
channel value | |||||
This writes the supplied value to the output channel on the Gertboards | |||||
SPI digital to analogue convertor. | |||||
The board jumpers need to be in-place to do this operation. | |||||
.SH "WiringPi vs. GPIO Pin numbering" | .SH "WiringPi vs. GPIO Pin numbering" | ||||
@@ -170,7 +234,7 @@ Gordon Henderson | |||||
.SH "REPORTING BUGS" | .SH "REPORTING BUGS" | ||||
Report bugs to <gordon@drogon.net> | |||||
Report bugs to <projects@drogon.net> | |||||
.SH COPYRIGHT | .SH COPYRIGHT | ||||
@@ -1,6 +1,7 @@ | |||||
/* | /* | ||||
* gpio.c: | * gpio.c: | ||||
* Set-UID command-line interface to the Raspberry Pi's GPIO | |||||
* Swiss-Army-Knife, Set-UID command-line interface to the Raspberry | |||||
* Pi's GPIO. | |||||
* Copyright (c) 2012 Gordon Henderson | * Copyright (c) 2012 Gordon Henderson | ||||
*********************************************************************** | *********************************************************************** | ||||
* This file is part of wiringPi: | * This file is part of wiringPi: | ||||
@@ -21,7 +22,6 @@ | |||||
*********************************************************************** | *********************************************************************** | ||||
*/ | */ | ||||
#include <wiringPi.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
@@ -32,15 +32,144 @@ | |||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <wiringPi.h> | |||||
#include <gertboard.h> | |||||
#ifndef TRUE | |||||
# define TRUE (1==1) | |||||
# define FALSE (1==2) | |||||
#endif | |||||
#define VERSION "1.0" | |||||
#define VERSION "1.2" | |||||
static int wpMode ; | static int wpMode ; | ||||
char *usage = "Usage: gpio -v\n" | char *usage = "Usage: gpio -v\n" | ||||
" gpio -h\n" | |||||
" gpio [-g] <read/write/pwm/mode> ...\n" | " gpio [-g] <read/write/pwm/mode> ...\n" | ||||
" gpio [-p] <read/write/mode> ...\n" | " gpio [-p] <read/write/mode> ...\n" | ||||
" gpio <export/edge/unexport/unexportall/exports> ..." ; | |||||
" gpio export/edge/unexport/unexportall/exports ...\n" | |||||
" gpio drive <group> <value>\n" | |||||
" gpio pwm-bal/pwm-ms \n" | |||||
" gpio pwmr <range> \n" | |||||
" gpio load spi/i2c\n" | |||||
" gpio gbr <channel>\n" | |||||
" gpio gbw <channel> <value>\n" ; | |||||
/* | |||||
* changeOwner: | |||||
* Change the ownership of the file to the real userId of the calling | |||||
* program so we can access it. | |||||
********************************************************************************* | |||||
*/ | |||||
static void changeOwner (char *cmd, char *file) | |||||
{ | |||||
uid_t uid = getuid () ; | |||||
uid_t gid = getgid () ; | |||||
if (chown (file, uid, gid) != 0) | |||||
{ | |||||
if (errno == ENOENT) // Warn that it's not there | |||||
fprintf (stderr, "%s: Warning: File not present: %s\n", cmd, file) ; | |||||
else | |||||
{ | |||||
fprintf (stderr, "%s: Unable to change ownership of %s: %s\n", cmd, file, strerror (errno)) ; | |||||
exit (1) ; | |||||
} | |||||
} | |||||
} | |||||
/* | |||||
* moduleLoaded: | |||||
* Return true/false if the supplied module is loaded | |||||
********************************************************************************* | |||||
*/ | |||||
static int moduleLoaded (char *modName) | |||||
{ | |||||
int len = strlen (modName) ; | |||||
int found = FALSE ; | |||||
FILE *fd = fopen ("/proc/modules", "r") ; | |||||
char line [80] ; | |||||
if (fd == NULL) | |||||
{ | |||||
fprintf (stderr, "gpio: Unable to check modules: %s\n", strerror (errno)) ; | |||||
exit (1) ; | |||||
} | |||||
while (fgets (line, 80, fd) != NULL) | |||||
{ | |||||
if (strncmp (line, modName, len) != 0) | |||||
continue ; | |||||
found = TRUE ; | |||||
break ; | |||||
} | |||||
fclose (fd) ; | |||||
return found ; | |||||
} | |||||
/* | |||||
* doLoad: | |||||
* Load either the spi or i2c modules and change device ownerships, etc. | |||||
********************************************************************************* | |||||
*/ | |||||
static void _doLoadUsage (char *argv []) | |||||
{ | |||||
fprintf (stderr, "Usage: %s load <spi/i2c>\n", argv [0]) ; | |||||
exit (1) ; | |||||
} | |||||
static void doLoad (int argc, char *argv []) | |||||
{ | |||||
char *module ; | |||||
char cmd [80] ; | |||||
char *file1, *file2 ; | |||||
if (argc != 3) | |||||
_doLoadUsage (argv) ; | |||||
/**/ if (strcasecmp (argv [2], "spi") == 0) | |||||
{ | |||||
module = "spi_bcm2708" ; | |||||
file1 = "/dev/spidev0.0" ; | |||||
file2 = "/dev/spidev0.1" ; | |||||
} | |||||
else if (strcasecmp (argv [2], "i2c") == 0) | |||||
{ | |||||
module = "i2c_bcm2708" ; | |||||
file1 = "/dev/i2c-0" ; | |||||
file2 = "/dev/i2c-1" ; | |||||
} | |||||
else | |||||
_doLoadUsage (argv) ; | |||||
if (!moduleLoaded (module)) | |||||
{ | |||||
sprintf (cmd, "modprobe %s", module) ; | |||||
system (cmd) ; | |||||
} | |||||
if (!moduleLoaded (module)) | |||||
{ | |||||
fprintf (stderr, "%s: Unable to load %s\n", argv [0], module) ; | |||||
exit (1) ; | |||||
} | |||||
sleep (1) ; // To let things get settled | |||||
changeOwner (argv [0], file1) ; | |||||
changeOwner (argv [0], file2) ; | |||||
} | |||||
/* | /* | ||||
@@ -49,7 +178,7 @@ char *usage = "Usage: gpio -v\n" | |||||
********************************************************************************* | ********************************************************************************* | ||||
*/ | */ | ||||
void doExports (void) | |||||
static void doExports (int argc, char *argv []) | |||||
{ | { | ||||
int fd ; | int fd ; | ||||
int i, l, first ; | int i, l, first ; | ||||
@@ -140,8 +269,6 @@ void doExport (int argc, char *argv []) | |||||
int pin ; | int pin ; | ||||
char *mode ; | char *mode ; | ||||
char fName [128] ; | char fName [128] ; | ||||
uid_t uid ; | |||||
gid_t gid ; | |||||
if (argc != 4) | if (argc != 4) | ||||
{ | { | ||||
@@ -183,27 +310,11 @@ void doExport (int argc, char *argv []) | |||||
// Change ownership so the current user can actually use it! | // Change ownership so the current user can actually use it! | ||||
uid = getuid () ; | |||||
gid = getgid () ; | |||||
sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; | sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; | ||||
if (chown (fName, uid, gid) != 0) | |||||
{ | |||||
fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ; | |||||
exit (1) ; | |||||
} | |||||
// Also change ownership of the edge file - if it exists | |||||
changeOwner (argv [0], fName) ; | |||||
sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ; | sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ; | ||||
if (chown (fName, uid, gid) != 0) | |||||
{ | |||||
if (errno != ENOENT) // Silently ignore File not found - older kernel | |||||
{ | |||||
fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ; | |||||
exit (1) ; | |||||
} | |||||
} | |||||
changeOwner (argv [0], fName) ; | |||||
} | } | ||||
@@ -222,8 +333,6 @@ void doEdge (int argc, char *argv []) | |||||
int pin ; | int pin ; | ||||
char *mode ; | char *mode ; | ||||
char fName [128] ; | char fName [128] ; | ||||
uid_t uid ; | |||||
gid_t gid ; | |||||
if (argc != 4) | if (argc != 4) | ||||
{ | { | ||||
@@ -231,8 +340,7 @@ void doEdge (int argc, char *argv []) | |||||
exit (1) ; | exit (1) ; | ||||
} | } | ||||
pin = atoi (argv [2]) ; | |||||
pin = atoi (argv [2]) ; | |||||
mode = argv [3] ; | mode = argv [3] ; | ||||
// Export the pin and set direction to input | // Export the pin and set direction to input | ||||
@@ -263,40 +371,23 @@ void doEdge (int argc, char *argv []) | |||||
exit (1) ; | exit (1) ; | ||||
} | } | ||||
/**/ if (strcasecmp (mode, "none") == 0) | |||||
fprintf (fd, "none\n") ; | |||||
else if (strcasecmp (mode, "rising") == 0) | |||||
fprintf (fd, "rising\n") ; | |||||
else if (strcasecmp (mode, "falling") == 0) | |||||
fprintf (fd, "falling\n") ; | |||||
else if (strcasecmp (mode, "both") == 0) | |||||
fprintf (fd, "both\n") ; | |||||
/**/ if (strcasecmp (mode, "none") == 0) fprintf (fd, "none\n") ; | |||||
else if (strcasecmp (mode, "rising") == 0) fprintf (fd, "rising\n") ; | |||||
else if (strcasecmp (mode, "falling") == 0) fprintf (fd, "falling\n") ; | |||||
else if (strcasecmp (mode, "both") == 0) fprintf (fd, "both\n") ; | |||||
else | else | ||||
{ | { | ||||
fprintf (stderr, "%s: Invalid mode: %s. Should be none, rising, falling or both\n", argv [1], mode) ; | fprintf (stderr, "%s: Invalid mode: %s. Should be none, rising, falling or both\n", argv [1], mode) ; | ||||
exit (1) ; | exit (1) ; | ||||
} | } | ||||
// Change ownership so the current user can actually use it! | |||||
uid = getuid () ; | |||||
gid = getgid () ; | |||||
// Change ownership of the value and edge files, so the current user can actually use it! | |||||
sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; | sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; | ||||
if (chown (fName, uid, gid) != 0) | |||||
{ | |||||
fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ; | |||||
exit (1) ; | |||||
} | |||||
// Also change ownership of the edge file | |||||
changeOwner (argv [0], fName) ; | |||||
sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ; | sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ; | ||||
if (chown (fName, uid, gid) != 0) | |||||
{ | |||||
fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ; | |||||
exit (1) ; | |||||
} | |||||
changeOwner (argv [0], fName) ; | |||||
fclose (fd) ; | fclose (fd) ; | ||||
} | } | ||||
@@ -383,18 +474,12 @@ void doMode (int argc, char *argv []) | |||||
mode = argv [3] ; | mode = argv [3] ; | ||||
/**/ if (strcasecmp (mode, "in") == 0) | |||||
pinMode (pin, INPUT) ; | |||||
else if (strcasecmp (mode, "out") == 0) | |||||
pinMode (pin, OUTPUT) ; | |||||
else if (strcasecmp (mode, "pwm") == 0) | |||||
pinMode (pin, PWM_OUTPUT) ; | |||||
else if (strcasecmp (mode, "up") == 0) | |||||
pullUpDnControl (pin, PUD_UP) ; | |||||
else if (strcasecmp (mode, "down") == 0) | |||||
pullUpDnControl (pin, PUD_DOWN) ; | |||||
else if (strcasecmp (mode, "tri") == 0) | |||||
pullUpDnControl (pin, PUD_OFF) ; | |||||
/**/ if (strcasecmp (mode, "in") == 0) pinMode (pin, INPUT) ; | |||||
else if (strcasecmp (mode, "out") == 0) pinMode (pin, OUTPUT) ; | |||||
else if (strcasecmp (mode, "pwm") == 0) pinMode (pin, PWM_OUTPUT) ; | |||||
else if (strcasecmp (mode, "up") == 0) pullUpDnControl (pin, PUD_UP) ; | |||||
else if (strcasecmp (mode, "down") == 0) pullUpDnControl (pin, PUD_DOWN) ; | |||||
else if (strcasecmp (mode, "tri") == 0) pullUpDnControl (pin, PUD_OFF) ; | |||||
else | else | ||||
{ | { | ||||
fprintf (stderr, "%s: Invalid mode: %s. Should be in/out/pwm/up/down/tri\n", argv [1], mode) ; | fprintf (stderr, "%s: Invalid mode: %s. Should be in/out/pwm/up/down/tri\n", argv [1], mode) ; | ||||
@@ -402,13 +487,125 @@ void doMode (int argc, char *argv []) | |||||
} | } | ||||
} | } | ||||
/* | |||||
* doPadDrive: | |||||
* gpio drive group value | |||||
********************************************************************************* | |||||
*/ | |||||
static void doPadDrive (int argc, char *argv []) | |||||
{ | |||||
int group, val ; | |||||
if (argc != 4) | |||||
{ | |||||
fprintf (stderr, "Usage: %s drive group value\n", argv [0]) ; | |||||
exit (1) ; | |||||
} | |||||
group = atoi (argv [2]) ; | |||||
val = atoi (argv [3]) ; | |||||
if ((group < 0) || (group > 2)) | |||||
{ | |||||
fprintf (stderr, "%s: drive group not 0, 1 or 2: %d\n", argv [0], group) ; | |||||
exit (1) ; | |||||
} | |||||
if ((val < 0) || (val > 7)) | |||||
{ | |||||
fprintf (stderr, "%s: drive value not 0-7: %d\n", argv [0], val) ; | |||||
exit (1) ; | |||||
} | |||||
setPadDrive (group, val) ; | |||||
} | |||||
/* | |||||
* doGbw: | |||||
* gpio gbw channel value | |||||
********************************************************************************* | |||||
*/ | |||||
static void doGbw (int argc, char *argv []) | |||||
{ | |||||
int channel, value ; | |||||
if (argc != 4) | |||||
{ | |||||
fprintf (stderr, "Usage: %s gbr <channel> <value>\n", argv [0]) ; | |||||
exit (1) ; | |||||
} | |||||
channel = atoi (argv [2]) ; | |||||
value = atoi (argv [3]) ; | |||||
if ((channel < 0) || (channel > 1)) | |||||
{ | |||||
fprintf (stderr, "%s: channel must be 0 or 1\n", argv [0]) ; | |||||
exit (1) ; | |||||
} | |||||
if ((value < 0) || (value > 1023)) | |||||
{ | |||||
fprintf (stderr, "%s: value must be from 0 to 255\n", argv [0]) ; | |||||
exit (1) ; | |||||
} | |||||
if (gertboardSPISetup () == -1) | |||||
{ | |||||
fprintf (stderr, "Unable to initialise the Gertboard SPI interface: %s\n", strerror (errno)) ; | |||||
exit (1) ; | |||||
} | |||||
gertboardAnalogWrite (channel, value) ; | |||||
} | |||||
/* | |||||
* doGbr: | |||||
* gpio gbr channel | |||||
********************************************************************************* | |||||
*/ | |||||
static void doGbr (int argc, char *argv []) | |||||
{ | |||||
int channel ; | |||||
if (argc != 3) | |||||
{ | |||||
fprintf (stderr, "Usage: %s gbr <channel>\n", argv [0]) ; | |||||
exit (1) ; | |||||
} | |||||
channel = atoi (argv [2]) ; | |||||
if ((channel < 0) || (channel > 1)) | |||||
{ | |||||
fprintf (stderr, "%s: channel must be 0 or 1\n", argv [0]) ; | |||||
exit (1) ; | |||||
} | |||||
if (gertboardSPISetup () == -1) | |||||
{ | |||||
fprintf (stderr, "Unable to initialise the Gertboard SPI interface: %s\n", strerror (errno)) ; | |||||
exit (1) ; | |||||
} | |||||
printf ("%d\n",gertboardAnalogRead (channel)) ; | |||||
} | |||||
/* | /* | ||||
* doWrite: | * doWrite: | ||||
* gpio write pin value | * gpio write pin value | ||||
********************************************************************************* | ********************************************************************************* | ||||
*/ | */ | ||||
void doWrite (int argc, char *argv []) | |||||
static void doWrite (int argc, char *argv []) | |||||
{ | { | ||||
int pin, val ; | int pin, val ; | ||||
@@ -490,6 +687,39 @@ void doPwm (int argc, char *argv []) | |||||
/* | /* | ||||
* doPwmMode: doPwmRange: | |||||
* Change the PWM mode and Range values | |||||
********************************************************************************* | |||||
*/ | |||||
static void doPwmMode (int mode) | |||||
{ | |||||
pwmSetMode (mode) ; | |||||
} | |||||
static void doPwmRange (int argc, char *argv []) | |||||
{ | |||||
unsigned int range ; | |||||
if (argc != 3) | |||||
{ | |||||
fprintf (stderr, "Usage: %s pwmr <range>\n", argv [0]) ; | |||||
exit (1) ; | |||||
} | |||||
range = (unsigned int)strtoul (argv [2], NULL, 10) ; | |||||
if (range == 0) | |||||
{ | |||||
fprintf (stderr, "%s: range must be > 0\n", argv [0]) ; | |||||
exit (1) ; | |||||
} | |||||
pwmSetRange (range) ; | |||||
} | |||||
/* | |||||
* main: | * main: | ||||
* Start here | * Start here | ||||
********************************************************************************* | ********************************************************************************* | ||||
@@ -505,10 +735,10 @@ int main (int argc, char *argv []) | |||||
return 1 ; | return 1 ; | ||||
} | } | ||||
if (geteuid () != 0) | |||||
if (strcasecmp (argv [1], "-h") == 0) | |||||
{ | { | ||||
fprintf (stderr, "%s: Must be root to run\n", argv [0]) ; | |||||
return 1 ; | |||||
printf ("%s: %s\n", argv [0], usage) ; | |||||
return 0 ; | |||||
} | } | ||||
if (strcasecmp (argv [1], "-v") == 0) | if (strcasecmp (argv [1], "-v") == 0) | ||||
@@ -516,21 +746,54 @@ int main (int argc, char *argv []) | |||||
printf ("gpio version: %s\n", VERSION) ; | printf ("gpio version: %s\n", VERSION) ; | ||||
printf ("Copyright (c) 2012 Gordon Henderson\n") ; | printf ("Copyright (c) 2012 Gordon Henderson\n") ; | ||||
printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ; | printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ; | ||||
printf ("For details type: %s -warranty\n", argv [0]) ; | |||||
return 0 ; | return 0 ; | ||||
} | } | ||||
if (strcasecmp (argv [1], "-warranty") == 0) | |||||
{ | |||||
printf ("gpio version: %s\n", VERSION) ; | |||||
printf ("Copyright (c) 2012 Gordon Henderson\n") ; | |||||
printf ("\n") ; | |||||
printf (" This program is free software; you can redistribute it and/or modify\n") ; | |||||
printf (" it under the terms of the GNU Leser General Public License as published\n") ; | |||||
printf (" by the Free Software Foundation, either version 3 of the License, or\n") ; | |||||
printf (" (at your option) any later version.\n") ; | |||||
printf ("\n") ; | |||||
printf (" This program is distributed in the hope that it will be useful,\n") ; | |||||
printf (" but WITHOUT ANY WARRANTY; without even the implied warranty of\n") ; | |||||
printf (" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n") ; | |||||
printf (" GNU Lesser General Public License for more details.\n") ; | |||||
printf ("\n") ; | |||||
printf (" You should have received a copy of the GNU Lesser General Public License\n") ; | |||||
printf (" along with this program. If not, see <http://www.gnu.org/licenses/>.\n") ; | |||||
printf ("\n") ; | |||||
return 0 ; | |||||
} | |||||
if (geteuid () != 0) | |||||
{ | |||||
fprintf (stderr, "%s: Must be root to run. Program should be suid root. This is an error.\n", argv [0]) ; | |||||
return 1 ; | |||||
} | |||||
// Initial test for /sys/class/gpio operations: | // Initial test for /sys/class/gpio operations: | ||||
/**/ if (strcasecmp (argv [1], "exports" ) == 0) | |||||
{ doExports () ; return 0 ; } | |||||
else if (strcasecmp (argv [1], "export" ) == 0) | |||||
{ doExport (argc, argv) ; return 0 ; } | |||||
else if (strcasecmp (argv [1], "edge" ) == 0) | |||||
{ doEdge (argc, argv) ; return 0 ; } | |||||
else if (strcasecmp (argv [1], "unexportall") == 0) | |||||
{ doUnexportall (argc, argv) ; return 0 ; } | |||||
else if (strcasecmp (argv [1], "unexport") == 0) | |||||
{ doUnexport (argc, argv) ; return 0 ; } | |||||
/**/ if (strcasecmp (argv [1], "exports" ) == 0) { doExports (argc, argv) ; return 0 ; } | |||||
else if (strcasecmp (argv [1], "export" ) == 0) { doExport (argc, argv) ; return 0 ; } | |||||
else if (strcasecmp (argv [1], "edge" ) == 0) { doEdge (argc, argv) ; return 0 ; } | |||||
else if (strcasecmp (argv [1], "unexportall") == 0) { doUnexportall (argc, argv) ; return 0 ; } | |||||
else if (strcasecmp (argv [1], "unexport" ) == 0) { doUnexport (argc, argv) ; return 0 ; } | |||||
// Check for drive or load commands: | |||||
if (strcasecmp (argv [1], "drive") == 0) { doPadDrive (argc, argv) ; return 0 ; } | |||||
if (strcasecmp (argv [1], "load" ) == 0) { doLoad (argc, argv) ; return 0 ; } | |||||
// Gertboard commands | |||||
if (strcasecmp (argv [1], "gbr" ) == 0) { doGbr (argc, argv) ; return 0 ; } | |||||
if (strcasecmp (argv [1], "gbw" ) == 0) { doGbw (argc, argv) ; return 0 ; } | |||||
// Check for -g argument | // Check for -g argument | ||||
@@ -538,7 +801,7 @@ int main (int argc, char *argv []) | |||||
{ | { | ||||
if (wiringPiSetupGpio () == -1) | if (wiringPiSetupGpio () == -1) | ||||
{ | { | ||||
fprintf (stderr, "%s: Unable to initialise GPIO in GPIO mode.\n", argv [0]) ; | |||||
fprintf (stderr, "%s: Unable to initialise GPIO mode.\n", argv [0]) ; | |||||
exit (1) ; | exit (1) ; | ||||
} | } | ||||
@@ -570,23 +833,30 @@ int main (int argc, char *argv []) | |||||
{ | { | ||||
if (wiringPiSetup () == -1) | if (wiringPiSetup () == -1) | ||||
{ | { | ||||
fprintf (stderr, "%s: Unable to initialise GPIO in wiringPi mode\n", argv [0]) ; | |||||
fprintf (stderr, "%s: Unable to initialise wiringPi mode\n", argv [0]) ; | |||||
exit (1) ; | exit (1) ; | ||||
} | } | ||||
wpMode = WPI_MODE_PINS ; | wpMode = WPI_MODE_PINS ; | ||||
} | } | ||||
/**/ if (strcasecmp (argv [1], "write" ) == 0) | |||||
doWrite (argc, argv) ; | |||||
else if (strcasecmp (argv [1], "read" ) == 0) | |||||
doRead (argc, argv) ; | |||||
else if (strcasecmp (argv [1], "mode" ) == 0) | |||||
doMode (argc, argv) ; | |||||
else if (strcasecmp (argv [1], "pwm" ) == 0) | |||||
doPwm (argc, argv) ; | |||||
// Check for PWM operations | |||||
if (wpMode != WPI_MODE_PIFACE) | |||||
{ | |||||
if (strcasecmp (argv [1], "pwm-bal") == 0) { doPwmMode (PWM_MODE_BAL) ; return 0 ; } | |||||
if (strcasecmp (argv [1], "pwm-ms") == 0) { doPwmMode (PWM_MODE_MS) ; return 0 ; } | |||||
if (strcasecmp (argv [1], "pwmr") == 0) { doPwmRange (argc, argv) ; return 0 ; } | |||||
} | |||||
// Check for wiring commands | |||||
/**/ if (strcasecmp (argv [1], "read" ) == 0) doRead (argc, argv) ; | |||||
else if (strcasecmp (argv [1], "write") == 0) doWrite (argc, argv) ; | |||||
else if (strcasecmp (argv [1], "pwm" ) == 0) doPwm (argc, argv) ; | |||||
else if (strcasecmp (argv [1], "mode" ) == 0) doMode (argc, argv) ; | |||||
else | else | ||||
{ | { | ||||
fprintf (stderr, "%s: Unknown command: %s. (read/write/pwm/mode expected)\n", argv [0], argv [1]) ; | |||||
fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ; | |||||
exit (1) ; | exit (1) ; | ||||
} | } | ||||
return 0 ; | return 0 ; | ||||
@@ -0,0 +1,122 @@ | |||||
/* | |||||
* gertboard.c: | |||||
* Access routines for the SPI devices on the Gertboard | |||||
* Copyright (c) 2012 Gordon Henderson | |||||
* | |||||
* The Gertboard has: | |||||
* | |||||
* An MCP3002 dual-channel A to D convertor connected | |||||
* to the SPI bus, selected by chip-select A, and: | |||||
* | |||||
* An MCP4802 dual-channel D to A convertor connected | |||||
* to the SPI bus, selected via chip-select B. | |||||
* | |||||
*********************************************************************** | |||||
* 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/>. | |||||
*********************************************************************** | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <stdint.h> | |||||
#include <fcntl.h> | |||||
#include <sys/ioctl.h> | |||||
#include <linux/spi/spidev.h> | |||||
#include "wiringPiSPI.h" | |||||
#include "gertboard.h" | |||||
// The A-D convertor won't run at more than 1MHz @ 3.3v | |||||
#define SPI_ADC_SPEED 1000000 | |||||
#define SPI_DAC_SPEED 1000000 | |||||
#define SPI_A2D 0 | |||||
#define SPI_D2A 1 | |||||
/* | |||||
* gertboardAnalogWrite: | |||||
* Write an 8-bit data value to the MCP4802 Analog to digital | |||||
* convertor on the Gertboard. | |||||
********************************************************************************* | |||||
*/ | |||||
void gertboardAnalogWrite (int chan, int value) | |||||
{ | |||||
uint8_t spiData [2] ; | |||||
uint8_t chanBits, dataBits ; | |||||
if (chan == 0) | |||||
chanBits = 0x30 ; | |||||
else | |||||
chanBits = 0xB0 ; | |||||
chanBits |= ((value >> 4) & 0x0F) ; | |||||
dataBits = ((value << 4) & 0xF0) ; | |||||
spiData [0] = chanBits ; | |||||
spiData [1] = dataBits ; | |||||
wiringPiSPIDataRW (SPI_D2A, spiData, 2) ; | |||||
} | |||||
/* | |||||
* gertboardAnalogRead: | |||||
* Return the analog value of the given channel (0/1). | |||||
* The A/D is a 10-bit device | |||||
********************************************************************************* | |||||
*/ | |||||
int gertboardAnalogRead (int chan) | |||||
{ | |||||
uint8_t spiData [2] ; | |||||
uint8_t chanBits ; | |||||
if (chan == 0) | |||||
chanBits = 0b11010000 ; | |||||
else | |||||
chanBits = 0b11110000 ; | |||||
spiData [0] = chanBits ; | |||||
spiData [1] = 0 ; | |||||
wiringPiSPIDataRW (SPI_A2D, spiData, 2) ; | |||||
return ((spiData [0] << 7) | (spiData [1] >> 1)) & 0x3FF ; | |||||
} | |||||
/* | |||||
* gertboardSPISetup: | |||||
* Initialise the SPI bus, etc. | |||||
********************************************************************************* | |||||
*/ | |||||
int gertboardSPISetup (void) | |||||
{ | |||||
if (wiringPiSPISetup (SPI_A2D, SPI_ADC_SPEED) < 0) | |||||
return -1 ; | |||||
if (wiringPiSPISetup (SPI_D2A, SPI_DAC_SPEED) < 0) | |||||
return -1 ; | |||||
return 0 ; | |||||
} |
@@ -0,0 +1,39 @@ | |||||
/* | |||||
* gertboard.h: | |||||
* Access routines for the SPI devices on the Gertboard | |||||
* Copyright (c) 2012 Gordon Henderson | |||||
* | |||||
* The Gertboard has an MCP4802 dual-channel D to A convertor | |||||
* connected to the SPI bus, selected via chip-select B. | |||||
* | |||||
*********************************************************************** | |||||
* 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/>. | |||||
*********************************************************************** | |||||
*/ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
extern void gertboardAnalogWrite (int chan, int value) ; | |||||
extern int gertboardAnalogRead (int chan) ; | |||||
extern int gertboardSPISetup (void) ; | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif |
@@ -33,5 +33,13 @@ extern void lcdPutchar (int fd, uint8_t data) ; | |||||
extern void lcdPuts (int fd, char *string) ; | extern void lcdPuts (int fd, char *string) ; | ||||
extern void lcdPrintf (int fd, char *message, ...) ; | extern void lcdPrintf (int fd, char *message, ...) ; | ||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
extern int lcdInit (int rows, int cols, int bits, int rs, int strb, | extern int lcdInit (int rows, int cols, int bits, int rs, int strb, | ||||
int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7) ; | int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7) ; | ||||
#ifdef __cplusplus | |||||
} | |||||
#endif |
@@ -0,0 +1,113 @@ | |||||
/* | |||||
* piNes.c: | |||||
* Driver for the NES Joystick controller on the Raspberry Pi | |||||
* Copyright (c) 2012 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/>. | |||||
*********************************************************************** | |||||
*/ | |||||
#include <wiringPi.h> | |||||
#include "piNes.h" | |||||
#define MAX_NES_JOYSTICKS 8 | |||||
#define NES_RIGHT 0x01 | |||||
#define NES_LEFT 0x02 | |||||
#define NES_DOWN 0x04 | |||||
#define NES_UP 0x08 | |||||
#define NES_START 0x10 | |||||
#define NES_SELECT 0x20 | |||||
#define NES_B 0x40 | |||||
#define NES_A 0x80 | |||||
#define PULSE_TIME 25 | |||||
// Data to store the pins for each controller | |||||
struct nesPinsStruct | |||||
{ | |||||
unsigned int cPin, dPin, lPin ; | |||||
} ; | |||||
static struct nesPinsStruct nesPins [MAX_NES_JOYSTICKS] ; | |||||
static int joysticks = 0 ; | |||||
/* | |||||
* setupNesJoystick: | |||||
* Create a new NES joystick interface, program the pins, etc. | |||||
********************************************************************************* | |||||
*/ | |||||
int setupNesJoystick (int dPin, int cPin, int lPin) | |||||
{ | |||||
if (joysticks == MAX_NES_JOYSTICKS) | |||||
return -1 ; | |||||
nesPins [joysticks].dPin = dPin ; | |||||
nesPins [joysticks].cPin = cPin ; | |||||
nesPins [joysticks].lPin = lPin ; | |||||
digitalWrite (lPin, LOW) ; | |||||
digitalWrite (cPin, LOW) ; | |||||
pinMode (lPin, OUTPUT) ; | |||||
pinMode (cPin, OUTPUT) ; | |||||
pinMode (dPin, INPUT) ; | |||||
return joysticks++ ; | |||||
} | |||||
/* | |||||
* readNesJoystick: | |||||
* Do a single scan of the NES Joystick. | |||||
********************************************************************************* | |||||
*/ | |||||
unsigned int readNesJoystick (int joystick) | |||||
{ | |||||
unsigned int value = 0 ; | |||||
int i ; | |||||
struct nesPinsStruct *pins = &nesPins [joystick] ; | |||||
// Toggle Latch - which presents the first bit | |||||
digitalWrite (pins->lPin, HIGH) ; delayMicroseconds (PULSE_TIME) ; | |||||
digitalWrite (pins->lPin, LOW) ; delayMicroseconds (PULSE_TIME) ; | |||||
// Read first bit | |||||
value = digitalRead (pins->dPin) ; | |||||
// Now get the next 7 bits with the clock | |||||
for (i = 0 ; i < 7 ; ++i) | |||||
{ | |||||
digitalWrite (pins->cPin, HIGH) ; delayMicroseconds (PULSE_TIME) ; | |||||
digitalWrite (pins->cPin, LOW) ; delayMicroseconds (PULSE_TIME) ; | |||||
value = (value << 1) | digitalRead (pins->dPin) ; | |||||
} | |||||
return value ^ 0xFF ; | |||||
} |
@@ -0,0 +1,45 @@ | |||||
/* | |||||
* piNes.h: | |||||
* Driver for the NES Joystick controller on the Raspberry Pi | |||||
* Copyright (c) 2012 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/>. | |||||
*********************************************************************** | |||||
*/ | |||||
#define MAX_NES_JOYSTICKS 8 | |||||
#define NES_RIGHT 0x01 | |||||
#define NES_LEFT 0x02 | |||||
#define NES_DOWN 0x04 | |||||
#define NES_UP 0x08 | |||||
#define NES_START 0x10 | |||||
#define NES_SELECT 0x20 | |||||
#define NES_B 0x40 | |||||
#define NES_A 0x80 | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
extern int setupNesJoystick (int dPin, int cPin, int lPin) ; | |||||
extern unsigned int readNesJoystick (int joystick) ; | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif |
@@ -0,0 +1,130 @@ | |||||
/* | |||||
* softPwm.c: | |||||
* Provide 2 channels of software driven PWM. | |||||
* Copyright (c) 2012 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/>. | |||||
*********************************************************************** | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <pthread.h> | |||||
#include "wiringPi.h" | |||||
#include "softPwm.h" | |||||
#define MAX_PINS 64 | |||||
// The PWM Frequency is derived from the "pulse time" below. Essentially, | |||||
// the frequency is a function of the range and this pulse time. | |||||
// The total period will be range * pulse time in uS, so a pulse time | |||||
// of 100 and a range of 100 gives a period of 100 * 100 = 10,000 uS | |||||
// which is a frequency of 100Hz. | |||||
// | |||||
// It's possible to get a higher frequency by lowering the pulse time, | |||||
// however CPU uage will skyrocket as wiringPi uses a hard-loop to time | |||||
// periods under 100uS - this is because the Linux timer calls are just | |||||
// accurate at all, and have an overhead. | |||||
// | |||||
// Another way to increase the frequency is to reduce the range - however | |||||
// that reduces the overall output accuracy... | |||||
#define PULSE_TIME 100 | |||||
static int marks [MAX_PINS] ; | |||||
static int range [MAX_PINS] ; | |||||
int newPin = -1 ; | |||||
/* | |||||
* softPwmThread: | |||||
* Thread to do the actual PWM output | |||||
********************************************************************************* | |||||
*/ | |||||
static PI_THREAD (softPwmThread) | |||||
{ | |||||
int pin, mark, space ; | |||||
pin = newPin ; | |||||
newPin = -1 ; | |||||
piHiPri (50) ; | |||||
for (;;) | |||||
{ | |||||
mark = marks [pin] ; | |||||
space = range [pin] - mark ; | |||||
if (mark != 0) | |||||
digitalWrite (pin, HIGH) ; | |||||
delayMicroseconds (mark * 100) ; | |||||
if (space != 0) | |||||
digitalWrite (pin, LOW) ; | |||||
delayMicroseconds (space * 100) ; | |||||
} | |||||
return NULL ; | |||||
} | |||||
/* | |||||
* softPwmWrite: | |||||
* Write a PWM value to the given pin | |||||
********************************************************************************* | |||||
*/ | |||||
void softPwmWrite (int pin, int value) | |||||
{ | |||||
pin &= 63 ; | |||||
/**/ if (value < 0) | |||||
value = 0 ; | |||||
else if (value > range [pin]) | |||||
value = range [pin] ; | |||||
marks [pin] = value ; | |||||
} | |||||
/* | |||||
* softPwmCreate: | |||||
* Create a new PWM thread. | |||||
********************************************************************************* | |||||
*/ | |||||
int softPwmCreate (int pin, int initialValue, int pwmRange) | |||||
{ | |||||
int res ; | |||||
pinMode (pin, OUTPUT) ; | |||||
digitalWrite (pin, LOW) ; | |||||
marks [pin] = initialValue ; | |||||
range [pin] = pwmRange ; | |||||
newPin = pin ; | |||||
res = piThreadCreate (softPwmThread) ; | |||||
while (newPin != -1) | |||||
delay (1) ; | |||||
return res ; | |||||
} |
@@ -0,0 +1,34 @@ | |||||
/* | |||||
* softPwm.h: | |||||
* Provide 2 channels of software driven PWM. | |||||
* Copyright (c) 2012 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/>. | |||||
*********************************************************************** | |||||
*/ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
extern int softPwmCreate (int pin, int value, int range) ; | |||||
extern void softPwmWrite (int pin, int value) ; | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif |
@@ -71,12 +71,16 @@ | |||||
// Function stubs | // Function stubs | ||||
void (*pinMode) (int pin, int mode) ; | |||||
void (*pullUpDnControl) (int pin, int pud) ; | |||||
void (*digitalWrite) (int pin, int value) ; | |||||
void (*pwmWrite) (int pin, int value) ; | |||||
int (*digitalRead) (int pin) ; | |||||
int (*waitForInterrupt) (int pin, int mS) ; | |||||
void (*pinMode) (int pin, int mode) ; | |||||
void (*pullUpDnControl) (int pin, int pud) ; | |||||
void (*digitalWrite) (int pin, int value) ; | |||||
void (*pwmWrite) (int pin, int value) ; | |||||
void (*setPadDrive) (int group, int value) ; | |||||
int (*digitalRead) (int pin) ; | |||||
int (*waitForInterrupt) (int pin, int mS) ; | |||||
void (*delayMicroseconds) (unsigned int howLong) ; | |||||
void (*pwmSetMode) (int mode) ; | |||||
void (*pwmSetRange) (unsigned int range) ; | |||||
#ifndef TRUE | #ifndef TRUE | ||||
@@ -84,6 +88,11 @@ int (*waitForInterrupt) (int pin, int mS) ; | |||||
#define FALSE (1==2) | #define FALSE (1==2) | ||||
#endif | #endif | ||||
// BCM Magic | |||||
#define BCM_PASSWORD 0x5A000000 | |||||
// Port function select bits | // Port function select bits | ||||
#define FSEL_INPT 0b000 | #define FSEL_INPT 0b000 | ||||
@@ -100,10 +109,11 @@ int (*waitForInterrupt) (int pin, int mS) ; | |||||
// Take from Gert/Doms code. Some of this is not in the manual | // Take from Gert/Doms code. Some of this is not in the manual | ||||
// that I can find )-: | // that I can find )-: | ||||
#define BCM2708_PERI_BASE 0x20000000 | |||||
#define BCM2708_PERI_BASE 0x20000000 | |||||
#define GPIO_PADS (BCM2708_PERI_BASE + 0x100000) | #define GPIO_PADS (BCM2708_PERI_BASE + 0x100000) | ||||
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) | #define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) | ||||
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) | #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) | ||||
#define GPIO_TIMER (BCM2708_PERI_BASE + 0x00B000) | |||||
#define GPIO_PWM (BCM2708_PERI_BASE + 0x20C000) | #define GPIO_PWM (BCM2708_PERI_BASE + 0x20C000) | ||||
#define PAGE_SIZE (4*1024) | #define PAGE_SIZE (4*1024) | ||||
@@ -137,12 +147,27 @@ int (*waitForInterrupt) (int pin, int mS) ; | |||||
#define PWM0_SERIAL 0x0002 // Run in serial mode | #define PWM0_SERIAL 0x0002 // Run in serial mode | ||||
#define PWM0_ENABLE 0x0001 // Channel Enable | #define PWM0_ENABLE 0x0001 // Channel Enable | ||||
// Timer | |||||
#define TIMER_LOAD (0x400 >> 2) | |||||
#define TIMER_VALUE (0x404 >> 2) | |||||
#define TIMER_CONTROL (0x408 >> 2) | |||||
#define TIMER_IRQ_CLR (0x40C >> 2) | |||||
#define TIMER_IRQ_RAW (0x410 >> 2) | |||||
#define TIMER_IRQ_MASK (0x414 >> 2) | |||||
#define TIMER_RELOAD (0x418 >> 2) | |||||
#define TIMER_PRE_DIV (0x41C >> 2) | |||||
#define TIMER_COUNTER (0x420 >> 2) | |||||
// Locals to hold pointers to the hardware | // Locals to hold pointers to the hardware | ||||
static volatile uint32_t *gpio ; | static volatile uint32_t *gpio ; | ||||
static volatile uint32_t *pwm ; | static volatile uint32_t *pwm ; | ||||
static volatile uint32_t *clk ; | static volatile uint32_t *clk ; | ||||
static volatile uint32_t *pads ; | |||||
static volatile uint32_t *timer ; | |||||
static volatile uint32_t *timerIrqRaw ; | |||||
// The BCM2835 has 54 GPIO pins. | // The BCM2835 has 54 GPIO pins. | ||||
// BCM2835 data sheet, Page 90 onwards. | // BCM2835 data sheet, Page 90 onwards. | ||||
@@ -273,6 +298,8 @@ static uint8_t gpioToFEN [] = | |||||
// gpioToPUDCLK | // gpioToPUDCLK | ||||
// (Word) offset to the Pull Up Down Clock regsiter | // (Word) offset to the Pull Up Down Clock regsiter | ||||
#define GPPUD 37 | |||||
static uint8_t gpioToPUDCLK [] = | static uint8_t gpioToPUDCLK [] = | ||||
{ | { | ||||
38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, | 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, | ||||
@@ -352,30 +379,42 @@ void pinModeGpio (int pin, int mode) | |||||
if (!pwmRunning) | if (!pwmRunning) | ||||
{ | { | ||||
// Gert/Doms Values | |||||
*(clk + PWMCLK_DIV) = 0x5A000000 | (32<<12) ; // set pwm div to 32 (19.2/3 = 600KHz) | |||||
*(clk + PWMCLK_CNTL) = 0x5A000011 ; // Source=osc and enable | |||||
digitalWrite (pin, LOW) ; | |||||
*(pwm + PWM_CONTROL) = 0 ; // Disable PWM | |||||
*(pwm + PWM_CONTROL) = 0 ; // Stop PWM | |||||
delayMicroseconds (10) ; | delayMicroseconds (10) ; | ||||
*(pwm + PWM0_RANGE) = 0x400 ; | |||||
delayMicroseconds (10) ; | |||||
*(pwm + PWM1_RANGE) = 0x400 ; | |||||
// Gert/Doms Values | |||||
*(clk + PWMCLK_DIV) = BCM_PASSWORD | (32<<12) ; // set pwm div to 32 (19.2/32 = 600KHz) | |||||
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // Source=osc and enable | |||||
delayMicroseconds (10) ; | delayMicroseconds (10) ; | ||||
*(pwm + PWM0_RANGE) = 0x400 ; delayMicroseconds (10) ; | |||||
*(pwm + PWM1_RANGE) = 0x400 ; delayMicroseconds (10) ; | |||||
// Enable PWMs | // Enable PWMs | ||||
*(pwm + PWM0_DATA) = 512 ; | *(pwm + PWM0_DATA) = 512 ; | ||||
*(pwm + PWM1_DATA) = 512 ; | *(pwm + PWM1_DATA) = 512 ; | ||||
// Balanced mode (default) | |||||
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; | *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; | ||||
pwmRunning = TRUE ; | |||||
} | } | ||||
} | } | ||||
// When we change mode of any pin, we remove the pull up/downs | // When we change mode of any pin, we remove the pull up/downs | ||||
// Or we used to... Hm. Commented out now because for some wieird reason, | |||||
// it seems to block subsequent attempts to set the pull up/downs and I've | |||||
// not quite gotten to the bottom of why this happens | |||||
// The down-side is that the pull up/downs are rememberd in the SoC between | |||||
// power cycles, so it's going to be a good idea to explicitly set them in | |||||
// any new code. | |||||
// | |||||
// pullUpDnControl (pin, PUD_OFF) ; | |||||
pullUpDnControl (pin, PUD_OFF) ; | |||||
} | } | ||||
void pinModeWPi (int pin, int mode) | void pinModeWPi (int pin, int mode) | ||||
@@ -389,6 +428,38 @@ void pinModeSys (int pin, int mode) | |||||
} | } | ||||
/* | |||||
* pwmControl: | |||||
* Allow the user to control some of the PWM functions | |||||
********************************************************************************* | |||||
*/ | |||||
void pwmSetModeWPi (int mode) | |||||
{ | |||||
if (mode == PWM_MODE_MS) | |||||
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE | PWM0_MS_MODE | PWM1_MS_MODE ; | |||||
else | |||||
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; | |||||
} | |||||
void pwmSetModeSys (int mode) | |||||
{ | |||||
return ; | |||||
} | |||||
void pwmSetRangeWPi (unsigned int range) | |||||
{ | |||||
*(pwm + PWM0_RANGE) = range ; delayMicroseconds (10) ; | |||||
*(pwm + PWM1_RANGE) = range ; delayMicroseconds (10) ; | |||||
} | |||||
void pwmSetRangeSys (unsigned int range) | |||||
{ | |||||
return ; | |||||
} | |||||
#ifdef notYetReady | #ifdef notYetReady | ||||
/* | /* | ||||
* pinED01: | * pinED01: | ||||
@@ -414,12 +485,12 @@ void pinEnableED01Pi (int pin) | |||||
void digitalWriteWPi (int pin, int value) | void digitalWriteWPi (int pin, int value) | ||||
{ | { | ||||
int gpioPin = pinToGpio [pin & 63] ; | |||||
pin = pinToGpio [pin & 63] ; | |||||
if (value == LOW) | if (value == LOW) | ||||
*(gpio + gpioToGPCLR [gpioPin]) = 1 << gpioPin ; | |||||
*(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ; | |||||
else | else | ||||
*(gpio + gpioToGPSET [gpioPin]) = 1 << gpioPin ; | |||||
*(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ; | |||||
} | } | ||||
void digitalWriteGpio (int pin, int value) | void digitalWriteGpio (int pin, int value) | ||||
@@ -427,9 +498,9 @@ void digitalWriteGpio (int pin, int value) | |||||
pin &= 63 ; | pin &= 63 ; | ||||
if (value == LOW) | if (value == LOW) | ||||
*(gpio + gpioToGPCLR [pin]) = 1 << pin ; | |||||
*(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ; | |||||
else | else | ||||
*(gpio + gpioToGPSET [pin]) = 1 << pin ; | |||||
*(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ; | |||||
} | } | ||||
void digitalWriteSys (int pin, int value) | void digitalWriteSys (int pin, int value) | ||||
@@ -452,28 +523,55 @@ void digitalWriteSys (int pin, int value) | |||||
********************************************************************************* | ********************************************************************************* | ||||
*/ | */ | ||||
void pwmWriteWPi (int pin, int value) | |||||
void pwmWriteGpio (int pin, int value) | |||||
{ | { | ||||
int port, gpioPin ; | |||||
int port ; | |||||
gpioPin = pinToGpio [pin & 63] ; | |||||
port = gpioToPwmPort [gpioPin] ; | |||||
pin = pin & 63 ; | |||||
port = gpioToPwmPort [pin] ; | |||||
*(pwm + port) = value & 0x3FF ; | |||||
*(pwm + port) = value ; | |||||
} | } | ||||
void pwmWriteGpio (int pin, int value) | |||||
void pwmWriteWPi (int pin, int value) | |||||
{ | |||||
pwmWriteGpio (pinToGpio [pin & 63], value) ; | |||||
} | |||||
void pwmWriteSys (int pin, int value) | |||||
{ | |||||
return ; | |||||
} | |||||
/* | |||||
* setPadDrive: | |||||
* Set the PAD driver value | |||||
********************************************************************************* | |||||
*/ | |||||
void setPadDriveWPi (int group, int value) | |||||
{ | { | ||||
int port, gpioPin ; | |||||
uint32_t wrVal ; | |||||
gpioPin = pin & 63 ; | |||||
port = gpioToPwmPort [gpioPin] ; | |||||
if ((group < 0) || (group > 2)) | |||||
return ; | |||||
*(pwm + port) = value & 0x3FF ; | |||||
wrVal = BCM_PASSWORD | 0x18 | (value & 7) ; | |||||
*(pads + group + 11) = wrVal ; | |||||
#ifdef DEBUG_PADS | |||||
printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ; | |||||
printf ("Read : %08X\n", *(pads + group + 11)) ; | |||||
#endif | |||||
} | } | ||||
void setPadDriveGpio (int group, int value) | |||||
{ | |||||
setPadDriveWPi (group, value) ; | |||||
} | |||||
void pwmWriteSys (int pin, int value) | |||||
void setPadDriveSys (int group, int value) | |||||
{ | { | ||||
return ; | return ; | ||||
} | } | ||||
@@ -487,13 +585,9 @@ void pwmWriteSys (int pin, int value) | |||||
int digitalReadWPi (int pin) | int digitalReadWPi (int pin) | ||||
{ | { | ||||
int gpioPin ; | |||||
pin &= 63 ; | |||||
gpioPin = pinToGpio [pin] ; | |||||
pin = pinToGpio [pin & 63] ; | |||||
if ((*(gpio + gpioToGPLEV [gpioPin]) & (1 << gpioPin)) != 0) | |||||
if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) | |||||
return HIGH ; | return HIGH ; | ||||
else | else | ||||
return LOW ; | return LOW ; | ||||
@@ -503,7 +597,7 @@ int digitalReadGpio (int pin) | |||||
{ | { | ||||
pin &= 63 ; | pin &= 63 ; | ||||
if ((*(gpio + gpioToGPLEV [pin]) & (1 << pin)) != 0) | |||||
if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) | |||||
return HIGH ; | return HIGH ; | ||||
else | else | ||||
return LOW ; | return LOW ; | ||||
@@ -533,30 +627,21 @@ int digitalReadSys (int pin) | |||||
********************************************************************************* | ********************************************************************************* | ||||
*/ | */ | ||||
void pullUpDnControlWPi (int pin, int pud) | |||||
void pullUpDnControlGpio (int pin, int pud) | |||||
{ | { | ||||
pin = pinToGpio [pin & 63] ; | |||||
pin &= 63 ; | |||||
pud &= 3 ; | |||||
*(gpio + 37) = pud ; | |||||
delayMicroseconds (10) ; | |||||
*(gpio + gpioToPUDCLK [pin]) = 1 << pin ; | |||||
delayMicroseconds (10) ; | |||||
*(gpio + GPPUD) = pud ; delayMicroseconds (5) ; | |||||
*(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ; delayMicroseconds (5) ; | |||||
*(gpio + 37) = 0 ; | |||||
*(gpio + gpioToPUDCLK [pin]) = 0 ; | |||||
*(gpio + GPPUD) = 0 ; delayMicroseconds (5) ; | |||||
*(gpio + gpioToPUDCLK [pin]) = 0 ; delayMicroseconds (5) ; | |||||
} | } | ||||
void pullUpDnControlGpio (int pin, int pud) | |||||
void pullUpDnControlWPi (int pin, int pud) | |||||
{ | { | ||||
pin &= 63 ; | |||||
*(gpio + 37) = pud ; | |||||
delayMicroseconds (10) ; | |||||
*(gpio + gpioToPUDCLK [pin]) = 1 << pin ; | |||||
delayMicroseconds (10) ; | |||||
*(gpio + 37) = 0 ; | |||||
*(gpio + gpioToPUDCLK [pin]) = 0 ; | |||||
pullUpDnControlGpio (pinToGpio [pin & 63], pud) ; | |||||
} | } | ||||
void pullUpDnControlSys (int pin, int pud) | void pullUpDnControlSys (int pin, int pud) | ||||
@@ -615,6 +700,94 @@ int waitForInterruptGpio (int pin, int mS) | |||||
/* | |||||
* delay: | |||||
* Wait for some number of milli seconds | |||||
********************************************************************************* | |||||
*/ | |||||
void delay (unsigned int howLong) | |||||
{ | |||||
struct timespec sleeper, dummy ; | |||||
sleeper.tv_sec = (time_t)(howLong / 1000) ; | |||||
sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ; | |||||
nanosleep (&sleeper, &dummy) ; | |||||
} | |||||
/* | |||||
* delayMicroseconds: | |||||
* This is somewhat intersting. It seems that on the Pi, a single call | |||||
* to nanosleep takes some 80 to 130 microseconds anyway, so while | |||||
* obeying the standards (may take longer), it's not always what we | |||||
* want! | |||||
* | |||||
* So what I'll do now is if the delay is less than 100uS we'll do it | |||||
* in a hard loop, watching a built-in counter on the ARM chip. This is | |||||
* somewhat sub-optimal in that it uses 100% CPU, something not an issue | |||||
* in a microcontroller, but under a multi-tasking, multi-user OS, it's | |||||
* wastefull, however we've no real choice )-: | |||||
********************************************************************************* | |||||
*/ | |||||
void delayMicrosecondsSys (unsigned int howLong) | |||||
{ | |||||
struct timespec sleeper, dummy ; | |||||
sleeper.tv_sec = 0 ; | |||||
sleeper.tv_nsec = (long)(howLong * 1000) ; | |||||
nanosleep (&sleeper, &dummy) ; | |||||
} | |||||
void delayMicrosecondsHard (unsigned int howLong) | |||||
{ | |||||
*(timer + TIMER_LOAD) = howLong ; | |||||
*(timer + TIMER_IRQ_CLR) = 0 ; | |||||
while (*timerIrqRaw == 0) | |||||
; | |||||
} | |||||
void delayMicrosecondsWPi (unsigned int howLong) | |||||
{ | |||||
struct timespec sleeper, dummy ; | |||||
/**/ if (howLong == 0) | |||||
return ; | |||||
else if (howLong < 100) | |||||
delayMicrosecondsHard (howLong) ; | |||||
else | |||||
{ | |||||
sleeper.tv_sec = 0 ; | |||||
sleeper.tv_nsec = (long)(howLong * 1000) ; | |||||
nanosleep (&sleeper, &dummy) ; | |||||
} | |||||
} | |||||
/* | |||||
* millis: | |||||
* Return a number of milliseconds as an unsigned int. | |||||
********************************************************************************* | |||||
*/ | |||||
unsigned int millis (void) | |||||
{ | |||||
struct timeval tv ; | |||||
unsigned long long t1 ; | |||||
gettimeofday (&tv, NULL) ; | |||||
t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; | |||||
return (uint32_t)(t1 - epoch) ; | |||||
} | |||||
/* | /* | ||||
* wiringPiSetup: | * wiringPiSetup: | ||||
* Must be called once at the start of your program execution. | * Must be called once at the start of your program execution. | ||||
@@ -627,20 +800,19 @@ int waitForInterruptGpio (int pin, int mS) | |||||
int wiringPiSetup (void) | int wiringPiSetup (void) | ||||
{ | { | ||||
int fd ; | int fd ; | ||||
uint8_t *gpioMem, *pwmMem, *clkMem ; | |||||
uint8_t *gpioMem, *pwmMem, *clkMem, *padsMem, *timerMem ; | |||||
struct timeval tv ; | struct timeval tv ; | ||||
#ifdef DEBUG_PADS | |||||
uint8_t *gpioMem, *padsMem, *pwmMem, *clkMem ; | |||||
uint32_t *pads ; | |||||
#endif | |||||
pinMode = pinModeWPi ; | |||||
pullUpDnControl = pullUpDnControlWPi ; | |||||
digitalWrite = digitalWriteWPi ; | |||||
pwmWrite = pwmWriteWPi ; | |||||
digitalRead = digitalReadWPi ; | |||||
waitForInterrupt = waitForInterruptWPi ; | |||||
pinMode = pinModeWPi ; | |||||
pullUpDnControl = pullUpDnControlWPi ; | |||||
digitalWrite = digitalWriteWPi ; | |||||
pwmWrite = pwmWriteWPi ; | |||||
setPadDrive = setPadDriveWPi ; | |||||
digitalRead = digitalReadWPi ; | |||||
waitForInterrupt = waitForInterruptWPi ; | |||||
delayMicroseconds = delayMicrosecondsWPi ; | |||||
pwmSetMode = pwmSetModeWPi ; | |||||
pwmSetRange = pwmSetRangeWPi ; | |||||
// Open the master /dev/memory device | // Open the master /dev/memory device | ||||
@@ -711,7 +883,8 @@ int wiringPiSetup (void) | |||||
return -1 ; | return -1 ; | ||||
} | } | ||||
#ifdef DEBUG_PADS | |||||
// The drive pads | |||||
if ((padsMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) | if ((padsMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) | ||||
{ | { | ||||
fprintf (stderr, "wiringPiSetup: padsMem malloc failed: %s\n", strerror (errno)) ; | fprintf (stderr, "wiringPiSetup: padsMem malloc failed: %s\n", strerror (errno)) ; | ||||
@@ -728,14 +901,41 @@ int wiringPiSetup (void) | |||||
fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ; | fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ; | ||||
return -1 ; | return -1 ; | ||||
} | } | ||||
printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ; | |||||
printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ; | |||||
// *(pads + 11) = 0x1F ; | |||||
printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ; | |||||
#ifdef DEBUG_PADS | |||||
printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ; | |||||
printf (" -> %08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ; | |||||
#endif | #endif | ||||
// The system timer | |||||
if ((timerMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) | |||||
{ | |||||
fprintf (stderr, "wiringPiSetup: timerMem malloc failed: %s\n", strerror (errno)) ; | |||||
return -1 ; | |||||
} | |||||
if (((uint32_t)timerMem % PAGE_SIZE) != 0) | |||||
timerMem += PAGE_SIZE - ((uint32_t)timerMem % PAGE_SIZE) ; | |||||
timer = (uint32_t *)mmap(timerMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_TIMER) ; | |||||
if ((int32_t)timer < 0) | |||||
{ | |||||
fprintf (stderr, "wiringPiSetup: mmap failed (timer): %s\n", strerror (errno)) ; | |||||
return -1 ; | |||||
} | |||||
// Set the timer to free-running, 1MHz. | |||||
// 0xF9 is 249, the timer divide is base clock / (divide+1) | |||||
// so base clock is 250MHz / 250 = 1MHz. | |||||
*(timer + TIMER_CONTROL) = 0x0000280 ; | |||||
*(timer + TIMER_PRE_DIV) = 0x00000F9 ; | |||||
timerIrqRaw = timer + TIMER_IRQ_RAW ; | |||||
// Initialise our epoch for millis() | |||||
gettimeofday (&tv, NULL) ; | gettimeofday (&tv, NULL) ; | ||||
epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; | epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; | ||||
@@ -759,12 +959,16 @@ int wiringPiSetupGpio (void) | |||||
if (x != 0) | if (x != 0) | ||||
return x ; | return x ; | ||||
pinMode = pinModeGpio ; | |||||
pullUpDnControl = pullUpDnControlGpio ; | |||||
digitalWrite = digitalWriteGpio ; | |||||
pwmWrite = pwmWriteGpio ; | |||||
digitalRead = digitalReadGpio ; | |||||
waitForInterrupt = waitForInterruptGpio ; | |||||
pinMode = pinModeGpio ; | |||||
pullUpDnControl = pullUpDnControlGpio ; | |||||
digitalWrite = digitalWriteGpio ; | |||||
pwmWrite = pwmWriteGpio ; | |||||
setPadDrive = setPadDriveGpio ; | |||||
digitalRead = digitalReadGpio ; | |||||
waitForInterrupt = waitForInterruptGpio ; | |||||
delayMicroseconds = delayMicrosecondsWPi ; // Same | |||||
pwmSetMode = pwmSetModeWPi ; | |||||
pwmSetRange = pwmSetRangeWPi ; | |||||
return 0 ; | return 0 ; | ||||
} | } | ||||
@@ -785,12 +989,17 @@ int wiringPiSetupSys (void) | |||||
struct timeval tv ; | struct timeval tv ; | ||||
char fName [128] ; | char fName [128] ; | ||||
pinMode = pinModeSys ; | |||||
pullUpDnControl = pullUpDnControlSys ; | |||||
digitalWrite = digitalWriteSys ; | |||||
pwmWrite = pwmWriteSys ; | |||||
digitalRead = digitalReadSys ; | |||||
waitForInterrupt = waitForInterruptSys ; | |||||
pinMode = pinModeSys ; | |||||
pullUpDnControl = pullUpDnControlSys ; | |||||
digitalWrite = digitalWriteSys ; | |||||
pwmWrite = pwmWriteSys ; | |||||
setPadDrive = setPadDriveSys ; | |||||
digitalRead = digitalReadSys ; | |||||
waitForInterrupt = waitForInterruptSys ; | |||||
delayMicroseconds = delayMicrosecondsSys ; | |||||
pwmSetMode = pwmSetModeSys ; | |||||
pwmSetRange = pwmSetRangeSys ; | |||||
// Open and scan the directory, looking for exported GPIOs, and pre-open | // Open and scan the directory, looking for exported GPIOs, and pre-open | ||||
// the 'value' interface to speed things up for later | // the 'value' interface to speed things up for later | ||||
@@ -808,51 +1017,3 @@ int wiringPiSetupSys (void) | |||||
return 0 ; | return 0 ; | ||||
} | } | ||||
/* | |||||
* delay: delayMicroseconds | |||||
* Wait for some number of milli/micro seconds | |||||
********************************************************************************* | |||||
*/ | |||||
void delay (unsigned int howLong) | |||||
{ | |||||
struct timespec sleeper, dummy ; | |||||
sleeper.tv_sec = (time_t)(howLong / 1000) ; | |||||
sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ; | |||||
nanosleep (&sleeper, &dummy) ; | |||||
} | |||||
void delayMicroseconds (unsigned int howLong) | |||||
{ | |||||
struct timespec sleeper, dummy ; | |||||
sleeper.tv_sec = 0 ; | |||||
sleeper.tv_nsec = (long)(howLong * 1000) ; | |||||
nanosleep (&sleeper, &dummy) ; | |||||
} | |||||
/* | |||||
* millis: | |||||
* Return a number of milliseconds as an unsigned int. | |||||
********************************************************************************* | |||||
*/ | |||||
unsigned int millis (void) | |||||
{ | |||||
struct timeval tv ; | |||||
unsigned long long t1 ; | |||||
gettimeofday (&tv, NULL) ; | |||||
t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; | |||||
return (uint32_t)(t1 - epoch) ; | |||||
} |
@@ -41,6 +41,12 @@ | |||||
#define PUD_DOWN 1 | #define PUD_DOWN 1 | ||||
#define PUD_UP 2 | #define PUD_UP 2 | ||||
// PWM | |||||
#define PWM_MODE_MS 0 | |||||
#define PWM_MODE_BAL 1 | |||||
// Function prototypes | // Function prototypes | ||||
// c++ wrappers thanks to a commend by Nick Lott | // c++ wrappers thanks to a commend by Nick Lott | ||||
// (and others on the Raspberry Pi forums) | // (and others on the Raspberry Pi forums) | ||||
@@ -58,11 +64,15 @@ extern int wiringPiSetupPiFace (void) ; | |||||
extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio program only | extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio program only | ||||
extern void (*pinMode) (int pin, int mode) ; | |||||
extern void (*pullUpDnControl) (int pin, int pud) ; | |||||
extern void (*digitalWrite) (int pin, int value) ; | |||||
extern void (*pwmWrite) (int pin, int value) ; | |||||
extern int (*digitalRead) (int pin) ; | |||||
extern void (*pinMode) (int pin, int mode) ; | |||||
extern void (*pullUpDnControl) (int pin, int pud) ; | |||||
extern void (*digitalWrite) (int pin, int value) ; | |||||
extern void (*pwmWrite) (int pin, int value) ; | |||||
extern void (*setPadDrive) (int group, int value) ; | |||||
extern int (*digitalRead) (int pin) ; | |||||
extern void (*delayMicroseconds) (unsigned int howLong) ; | |||||
extern void (*pwmSetMode) (int mode) ; | |||||
extern void (*pwmSetRange) (unsigned int range) ; | |||||
// Interrupts | // Interrupts | ||||
@@ -84,7 +94,6 @@ extern int piHiPri (int pri) ; | |||||
// Extras from arduino land | // Extras from arduino land | ||||
extern void delay (unsigned int howLong) ; | extern void delay (unsigned int howLong) ; | ||||
extern void delayMicroseconds (unsigned int howLong) ; | |||||
extern unsigned int millis (void) ; | extern unsigned int millis (void) ; | ||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
@@ -0,0 +1,117 @@ | |||||
/* | |||||
* wiringPiSPI.c: | |||||
* Simplified SPI access routines | |||||
* Copyright (c) 2012 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/>. | |||||
*********************************************************************** | |||||
*/ | |||||
#include <stdint.h> | |||||
#include <fcntl.h> | |||||
#include <sys/ioctl.h> | |||||
#include <linux/spi/spidev.h> | |||||
#include "wiringPiSPI.h" | |||||
// The SPI bus parameters | |||||
// Variables as they need to be passed as pointers later on | |||||
static char *spiDev0 = "/dev/spidev0.0" ; | |||||
static char *spiDev1 = "/dev/spidev0.1" ; | |||||
static uint8_t spiMode = 0 ; | |||||
static uint8_t spiBPW = 8 ; | |||||
static uint16_t spiDelay = 0; | |||||
static uint32_t spiSpeeds [2] ; | |||||
static int spiFds [2] ; | |||||
/* | |||||
* wiringPiSPIGetFd: | |||||
* Return the file-descriptor for the given channel | |||||
********************************************************************************* | |||||
*/ | |||||
int wiringPiSPIGetFd (int channel) | |||||
{ | |||||
return spiFds [channel &1] ; | |||||
} | |||||
/* | |||||
* wiringPiSPIDataRW: | |||||
* Write and Read a block of data over the SPI bus. | |||||
* Note the data ia being read into the transmit buffer, so will | |||||
* overwrite it! | |||||
* This is also a full-duplex operation. | |||||
********************************************************************************* | |||||
*/ | |||||
int wiringPiSPIDataRW (int channel, unsigned char *data, int len) | |||||
{ | |||||
struct spi_ioc_transfer spi ; | |||||
channel &= 1 ; | |||||
spi.tx_buf = (unsigned long)data ; | |||||
spi.rx_buf = (unsigned long)data ; | |||||
spi.len = len ; | |||||
spi.delay_usecs = spiDelay ; | |||||
spi.speed_hz = spiSpeeds [channel] ; | |||||
spi.bits_per_word = spiBPW ; | |||||
return ioctl (spiFds [channel], SPI_IOC_MESSAGE(1), &spi) ; | |||||
} | |||||
/* | |||||
* wiringPiSPISetup: | |||||
* Open the SPI device, and set it up, etc. | |||||
********************************************************************************* | |||||
*/ | |||||
int wiringPiSPISetup (int channel, int speed) | |||||
{ | |||||
int fd ; | |||||
channel &= 1 ; | |||||
if ((fd = open (channel == 0 ? spiDev0 : spiDev1, O_RDWR)) < 0) | |||||
return -1 ; | |||||
spiSpeeds [channel] = speed ; | |||||
spiFds [channel] = fd ; | |||||
// Set SPI parameters. | |||||
// Why are we reading it afterwriting it? I've no idea, but for now I'm blindly | |||||
// copying example code I've seen online... | |||||
if (ioctl (fd, SPI_IOC_WR_MODE, &spiMode) < 0) return -1 ; | |||||
if (ioctl (fd, SPI_IOC_RD_MODE, &spiMode) < 0) return -1 ; | |||||
if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) return -1 ; | |||||
if (ioctl (fd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0) return -1 ; | |||||
if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) return -1 ; | |||||
if (ioctl (fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) return -1 ; | |||||
return fd ; | |||||
} |
@@ -0,0 +1,35 @@ | |||||
/* | |||||
* wiringPiSPI.h: | |||||
* Simplified SPI access routines | |||||
* Copyright (c) 2012 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/>. | |||||
*********************************************************************** | |||||
*/ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
int wiringPiSPIGetFd (int channel) ; | |||||
int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ; | |||||
int wiringPiSPISetup (int channel, int speed) ; | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif |
@@ -20,8 +20,6 @@ | |||||
*********************************************************************** | *********************************************************************** | ||||
*/ | */ | ||||
#undef DEBUG | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
@@ -49,10 +47,6 @@ int serialOpen (char *device, int baud) | |||||
speed_t myBaud ; | speed_t myBaud ; | ||||
int status, fd ; | int status, fd ; | ||||
#ifdef DEBUG | |||||
printf ("openSerialPort: <%s> baud: $d\n", device, baud) ; | |||||
#endif | |||||
switch (baud) | switch (baud) | ||||
{ | { | ||||
case 50: myBaud = B50 ; break ; | case 50: myBaud = B50 ; break ; | ||||
@@ -86,22 +80,22 @@ int serialOpen (char *device, int baud) | |||||
tcgetattr (fd, &options) ; | tcgetattr (fd, &options) ; | ||||
cfmakeraw (&options) ; | |||||
cfsetispeed (&options, myBaud) ; | |||||
cfsetospeed (&options, myBaud) ; | |||||
cfmakeraw (&options) ; | |||||
cfsetispeed (&options, myBaud) ; | |||||
cfsetospeed (&options, myBaud) ; | |||||
options.c_cflag |= (CLOCAL | CREAD) ; | |||||
options.c_cflag &= ~PARENB ; | |||||
options.c_cflag &= ~CSTOPB ; | |||||
options.c_cflag &= ~CSIZE ; | |||||
options.c_cflag |= CS8 ; | |||||
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ; | |||||
options.c_oflag &= ~OPOST ; | |||||
options.c_cflag |= (CLOCAL | CREAD) ; | |||||
options.c_cflag &= ~PARENB ; | |||||
options.c_cflag &= ~CSTOPB ; | |||||
options.c_cflag &= ~CSIZE ; | |||||
options.c_cflag |= CS8 ; | |||||
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ; | |||||
options.c_oflag &= ~OPOST ; | |||||
options.c_cc [VMIN] = 0 ; | |||||
options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds) | |||||
options.c_cc [VMIN] = 0 ; | |||||
options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds) | |||||
tcsetattr (fd, TCSANOW, &options) ; | |||||
tcsetattr (fd, TCSANOW | TCSAFLUSH, &options) ; | |||||
ioctl (fd, TIOCMGET, &status); | ioctl (fd, TIOCMGET, &status); | ||||
@@ -117,6 +111,18 @@ int serialOpen (char *device, int baud) | |||||
/* | /* | ||||
* serialFlush: | |||||
* Flush the serial buffers (both tx & rx) | |||||
********************************************************************************* | |||||
*/ | |||||
void serialFlush (int fd) | |||||
{ | |||||
tcflush (fd, TCIOFLUSH) ; | |||||
} | |||||
/* | |||||
* serialClose: | * serialClose: | ||||
* Release the serial port | * Release the serial port | ||||
********************************************************************************* | ********************************************************************************* | ||||
@@ -26,6 +26,7 @@ extern "C" { | |||||
extern int serialOpen (char *device, int baud) ; | extern int serialOpen (char *device, int baud) ; | ||||
extern void serialClose (int fd) ; | extern void serialClose (int fd) ; | ||||
extern void serialFlush (int fd) ; | |||||
extern void serialPutchar (int fd, unsigned char c) ; | extern void serialPutchar (int fd, unsigned char c) ; | ||||
extern void serialPuts (int fd, char *s) ; | extern void serialPuts (int fd, char *s) ; | ||||
extern void serialPrintf (int fd, char *message, ...) ; | extern void serialPrintf (int fd, char *message, ...) ; | ||||