From ced6ff6ea6a01b4f7d3ced25dc5e64bb7c954a9f Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Thu, 9 May 2024 15:37:18 +0200 Subject: [PATCH 01/14] #239 --- VERSION | 2 +- gpio/gpio.1 | 9 +- gpio/gpio.c | 326 +++------------------------------------------------- version.h | 4 +- 4 files changed, 27 insertions(+), 314 deletions(-) diff --git a/VERSION b/VERSION index eb39e53..5a95802 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3 +3.5 diff --git a/gpio/gpio.1 b/gpio/gpio.1 index 7b71596..bf5864a 100644 --- a/gpio/gpio.1 +++ b/gpio/gpio.1 @@ -48,7 +48,7 @@ high | low range .PP .B gpio -.B load \ i2c/spi ... +.B i2cd .PP .B gpio .B gbr @@ -67,8 +67,7 @@ converters 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. -It can also control the IO's on the PiFace IO board and load the SPI and I2C -kernel modules if required. +It can also control the IO's on the PiFace IO board. .SH OPTIONS @@ -207,6 +206,10 @@ Change the PWM mode to balanced (the default) or mark:space ratio (traditional) .B pwmr Change the PWM range register. The default is 1024. +.TP +.B i2cd +Executes i2c-detect for the default I2C port on the P1 connector. + .TP .B gbr channel diff --git a/gpio/gpio.c b/gpio/gpio.c index af853ab..d468ed9 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -72,15 +72,11 @@ char *usage = "Usage: gpio -v\n" " gpio ...\n" " gpio \n" " gpio readall\n" -// " gpio unexportall/exports\n" -// " gpio export/edge/unexport ...\n" " gpio wfi \n" " gpio drive \n" " gpio pwm-bal/pwm-ms \n" " gpio pwmr \n" " gpio pwmc \n" - " gpio load spi/i2c\n" - " gpio unload spi/i2c\n" " gpio i2cd/i2cdetect\n" " gpio rbx/rbd\n" " gpio wb \n" @@ -110,287 +106,6 @@ static int decodePin (const char *str) #endif -/* - * findExecutable: - * Code to locate the path to the given executable. We have a fixed list - * of locations to try which completely overrides any $PATH environment. - * This may be detrimental, however it avoids the reliance on $PATH - * which may be a security issue when this program is run a set-uid-root. - ********************************************************************************* - */ - -static const char *searchPath [] = -{ - "/sbin", - "/usr/sbin", - "/bin", - "/usr/bin", - NULL, -} ; - -static char *findExecutable (const char *progName) -{ - static char *path = NULL ; - int len = strlen (progName) ; - int i = 0 ; - struct stat statBuf ; - - for (i = 0 ; searchPath [i] != NULL ; ++i) - { - path = malloc (strlen (searchPath [i]) + len + 2) ; - sprintf (path, "%s/%s", searchPath [i], progName) ; - - if (stat (path, &statBuf) == 0) - return path ; - free (path) ; - } - - return NULL ; -} - - -/* - * 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) - { - -// Removed (ignoring) the check for not existing as I'm fed-up with morons telling me that -// the warning message is an error. - - if (errno != ENOENT) - fprintf (stderr, "%s: Unable to change ownership of %s: %s\n", cmd, file, strerror (errno)) ; - } -} - - -/* - * 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 /proc/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 checkDevTree (char *argv []) -{ - struct stat statBuf ; - - if (stat ("/proc/device-tree", &statBuf) == 0) // We're on a devtree system ... - { - fprintf (stderr, -"%s: Unable to load/unload modules as this Pi has the device tree enabled.\n" -" You need to run the raspi-config program (as root) and select the\n" -" modules (SPI or I2C) that you wish to load/unload there and reboot.\n", argv [0]) ; - exit (1) ; - } -} - -static void _doLoadUsage (char *argv []) -{ - fprintf (stderr, "Usage: %s load [I2C baudrate in Kb/sec]\n", argv [0]) ; - exit (1) ; -} - -static void doLoad (int argc, char *argv []) -{ - char *module1, *module2 ; - char cmd [80] ; - char *file1, *file2 ; - char args1 [32], args2 [32] ; - - checkDevTree (argv) ; - - if (argc < 3) - _doLoadUsage (argv) ; - - args1 [0] = args2 [0] = 0 ; - - /**/ if (strcasecmp (argv [2], "spi") == 0) - { - module1 = "spidev" ; - module2 = "spi_bcm2708" ; - file1 = "/dev/spidev0.0" ; - file2 = "/dev/spidev0.1" ; - if (argc == 4) - { - fprintf (stderr, "%s: Unable to set the buffer size now. Load aborted. Please see the man page.\n", argv [0]) ; - exit (1) ; - } - else if (argc > 4) - _doLoadUsage (argv) ; - } - else if (strcasecmp (argv [2], "i2c") == 0) - { - module1 = "i2c_dev" ; - module2 = "i2c_bcm2708" ; - file1 = "/dev/i2c-0" ; - file2 = "/dev/i2c-1" ; - if (argc == 4) - sprintf (args2, " baudrate=%d", atoi (argv [3]) * 1000) ; - else if (argc > 4) - _doLoadUsage (argv) ; - } - else - _doLoadUsage (argv) ; - - if (findExecutable ("modprobe") == NULL) - printf ("No found\n") ; - - if (!moduleLoaded (module1)) - { - sprintf (cmd, "%s %s%s", findExecutable (MODPROBE), module1, args1) ; - int ret = system(cmd); - if (ret == -1) { - perror("Error executing command"); - } else if (WIFEXITED(ret)) { - int exit_status = WEXITSTATUS(ret); - if (exit_status != 0) { - fprintf(stderr, "Command failed with exit status %d\n", exit_status); - } - } else { - fprintf(stderr, "Command terminated by signal\n"); - } - } - - if (!moduleLoaded (module2)) - { - sprintf (cmd, "%s %s%s", findExecutable (MODPROBE), module2, args2) ; - int ret = system(cmd); - if (ret == -1) { - perror("Error executing command"); - } else if (WIFEXITED(ret)) { - int exit_status = WEXITSTATUS(ret); - if (exit_status != 0) { - fprintf(stderr, "Command failed with exit status %d\n", exit_status); - } - } else { - fprintf(stderr, "Command terminated by signal\n"); - } - } - - if (!moduleLoaded (module2)) - { - fprintf (stderr, "%s: Unable to load %s\n", argv [0], module2) ; - exit (1) ; - } - - sleep (1) ; // To let things get settled - - changeOwner (argv [0], file1) ; - changeOwner (argv [0], file2) ; -} - - -/* - * doUnLoad: - * Un-Load either the spi or i2c modules and change device ownerships, etc. - ********************************************************************************* - */ - -static void _doUnLoadUsage (char *argv []) -{ - fprintf (stderr, "Usage: %s unload \n", argv [0]) ; - exit (1) ; -} - -static void doUnLoad (int argc, char *argv []) -{ - char *module1, *module2 ; - char cmd [80] ; - - checkDevTree (argv) ; - - if (argc != 3) - _doUnLoadUsage (argv) ; - - /**/ if (strcasecmp (argv [2], "spi") == 0) - { - module1 = "spidev" ; - module2 = "spi_bcm2708" ; - } - else if (strcasecmp (argv [2], "i2c") == 0) - { - module1 = "i2c_dev" ; - module2 = "i2c_bcm2708" ; - } - else - _doUnLoadUsage (argv) ; - - if (moduleLoaded (module1)) - { - sprintf (cmd, "%s %s", findExecutable (RMMOD), module1) ; - int ret = system(cmd); - if (ret == -1) { - perror("Error executing command"); - } else if (WIFEXITED(ret)) { - int exit_status = WEXITSTATUS(ret); - if (exit_status != 0) { - fprintf(stderr, "Command failed with exit status %d\n", exit_status); - } - } else { - fprintf(stderr, "Command terminated by signal\n"); - } - } - - if (moduleLoaded (module2)) - { - sprintf (cmd, "%s %s", findExecutable (RMMOD), module2) ; - int ret = system(cmd); - if (ret == -1) { - perror("Error executing command"); - } else if (WIFEXITED(ret)) { - int exit_status = WEXITSTATUS(ret); - if (exit_status != 0) { - fprintf(stderr, "Command failed with exit status %d\n", exit_status); - } - } else { - fprintf(stderr, "Command terminated by signal\n"); - } - } -} - /* * doI2Cdetect: @@ -398,28 +113,19 @@ static void doUnLoad (int argc, char *argv []) ********************************************************************************* */ -static void doI2Cdetect (UNU int argc, char *argv []) +static void doI2Cdetect (const char *progName) { int port = piGpioLayout () == GPIO_LAYOUT_PI1_REV1 ? 0 : 1 ; - char *c, *command ; + char command[64]; - if ((c = findExecutable (I2CDETECT)) == NULL) - { - fprintf (stderr, "%s: Unable to find i2cdetect command: %s\n", argv [0], strerror (errno)) ; - return ; + snprintf(command, 64, "i2cdetect -y %d", port); + int ret = system(command); + if (ret < 0) { + fprintf (stderr, "%s: Unable to run i2cdetect: %s\n", progName, strerror(errno)); } - - if (!moduleLoaded ("i2c_dev")) - { - fprintf (stderr, "%s: The I2C kernel module(s) are not loaded.\n", argv [0]) ; - return ; + if (0x7F00 == (ret & 0xFF00)) { + fprintf (stderr, "%s: i2cdetect not found, please install i2c-tools\n", progName); } - - command = malloc (strlen (c) + 16) ; - sprintf (command, "%s -y %d", c, port) ; - if (system (command) < 0) - fprintf (stderr, "%s: Unable to run i2cdetect: %s\n", argv [0], strerror (errno)) ; - } @@ -427,6 +133,10 @@ void SYSFS_DEPRECATED(const char *progName) { fprintf(stderr, "%s: GPIO Sysfs Interface for Userspace is deprecated (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).\n Function is now useless and empty.\n\n", progName); } +void LOAD_DEPRECATED(const char *progName) { + fprintf(stderr, "%s: load/unload modules is deprecated. You need to run the raspi-config program (as root) and select the interface option (SPI or I2C) that you wish to de-/activate.\n\n", progName); +} + /* * doExports: -> deprecated, removed * List all GPIO exports @@ -1269,7 +979,7 @@ int main (int argc, char *argv []) exit (EXIT_FAILURE) ; } -// Initial test for /sys/class/gpio operations: - -> deprecated, empty but still there +// Initial test for /sys/class/gpio operations: --> deprecated, empty but still there /**/ if (strcasecmp (argv [1], "exports" ) == 0) { SYSFS_DEPRECATED(argv[0]); return 0 ; } else if (strcasecmp (argv [1], "export" ) == 0) { SYSFS_DEPRECATED(argv[0]); return 0 ; } @@ -1277,10 +987,10 @@ int main (int argc, char *argv []) else if (strcasecmp (argv [1], "unexport" ) == 0) { SYSFS_DEPRECATED(argv[0]); return 0 ; } else if (strcasecmp (argv [1], "unexportall") == 0) { SYSFS_DEPRECATED(argv[0]); return 0 ; } -// Check for load command: +// Check for un-/load command: --> deprecated, empty but still there - if (strcasecmp (argv [1], "load" ) == 0) { doLoad (argc, argv) ; return 0 ; } - if (strcasecmp (argv [1], "unload" ) == 0) { doUnLoad (argc, argv) ; return 0 ; } + if (strcasecmp (argv [1], "load" ) == 0) { LOAD_DEPRECATED(argv[0]) ; return 0 ; } + if (strcasecmp (argv [1], "unload" ) == 0) { LOAD_DEPRECATED(argv[0]) ; return 0 ; } // Check for usb power command @@ -1413,8 +1123,8 @@ int main (int argc, char *argv []) else if (strcasecmp (argv [1], "nreadall" ) == 0) doReadall () ; else if (strcasecmp (argv [1], "pins" ) == 0) doReadall () ; else if (strcasecmp (argv [1], "qmode" ) == 0) doQmode (argc, argv) ; - else if (strcasecmp (argv [1], "i2cdetect") == 0) doI2Cdetect (argc, argv) ; - else if (strcasecmp (argv [1], "i2cd" ) == 0) doI2Cdetect (argc, argv) ; + else if (strcasecmp (argv [1], "i2cdetect") == 0) doI2Cdetect (argv [0]) ; + else if (strcasecmp (argv [1], "i2cd" ) == 0) doI2Cdetect (argv [0]) ; else if (strcasecmp (argv [1], "reset" ) == 0) doReset (argv [0]) ; else if (strcasecmp (argv [1], "wb" ) == 0) doWriteByte (argc, argv) ; else if (strcasecmp (argv [1], "rbx" ) == 0) doReadByte (argc, argv, TRUE) ; diff --git a/version.h b/version.h index 6f3b26e..87082e3 100644 --- a/version.h +++ b/version.h @@ -1,3 +1,3 @@ -#define VERSION "3.3" +#define VERSION "3.5" #define VERSION_MAJOR 3 -#define VERSION_MINOR 3 +#define VERSION_MINOR 5 From 55469861299ae48e19e1b1d8d25f5b3b7d8ebd9a Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Sun, 12 May 2024 17:33:43 +0200 Subject: [PATCH 02/14] #243 --- VERSION | 2 +- version.h | 4 +- wiringPi/wiringPiI2C.c | 2 +- wiringPi/wiringPiI2C.h | 2 +- wiringPi/wiringPiSPI.c | 127 ++++++++++++++++++++++++++++++++--------- wiringPi/wiringPiSPI.h | 12 +++- 6 files changed, 115 insertions(+), 34 deletions(-) diff --git a/VERSION b/VERSION index 2f4b607..5a95802 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.4 +3.5 diff --git a/version.h b/version.h index a018dc1..87082e3 100644 --- a/version.h +++ b/version.h @@ -1,3 +1,3 @@ -#define VERSION "3.4" +#define VERSION "3.5" #define VERSION_MAJOR 3 -#define VERSION_MINOR 4 +#define VERSION_MINOR 5 diff --git a/wiringPi/wiringPiI2C.c b/wiringPi/wiringPiI2C.c index 0bd166a..95131c3 100644 --- a/wiringPi/wiringPiI2C.c +++ b/wiringPi/wiringPiI2C.c @@ -1,7 +1,7 @@ /* * wiringPiI2C.c: * Simplified I2C access routines - * Copyright (c) 2013 Gordon Henderson + * Copyright (c) 2013-2024 Gordon Henderson and contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ diff --git a/wiringPi/wiringPiI2C.h b/wiringPi/wiringPiI2C.h index d9660b9..112257a 100644 --- a/wiringPi/wiringPiI2C.h +++ b/wiringPi/wiringPiI2C.h @@ -1,7 +1,7 @@ /* * wiringPiI2C.h: * Simplified I2C access routines - * Copyright (c) 2013 Gordon Henderson + * Copyright (c) 2013-2024 Gordon Henderson and contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ diff --git a/wiringPi/wiringPiSPI.c b/wiringPi/wiringPiSPI.c index 94e32a8..480d18c 100644 --- a/wiringPi/wiringPiSPI.c +++ b/wiringPi/wiringPiSPI.c @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -32,9 +33,7 @@ #include #include #include - #include "wiringPi.h" - #include "wiringPiSPI.h" @@ -45,10 +44,50 @@ //static const char *spiDev1 = "/dev/spidev0.1" ; static const uint8_t spiBPW = 8 ; static const uint16_t spiDelay = 0 ; +//https://datasheets.raspberrypi.com/cm4/cm4-datasheet.pdf +const uint8_t WPI_MaxSPINumbers = 7 ; +const uint8_t WPI_MaxSPIChannels = 3 ; -static uint32_t spiSpeeds [2] ; -static int spiFds [2] ; +static uint32_t spiSpeeds [7][3] = +{ + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, +}; + +static int spiFds [7][3] = +{ + {-1, -1, -1}, + {-1, -1, -1}, + {-1, -1, -1}, + {-1, -1, -1}, + {-1, -1, -1}, + {-1, -1, -1}, + {-1, -1, -1}, +}; + + + +int SPICheckLimits(const int number, const int channel) { + if (channel<0 || channel>=WPI_MaxSPIChannels) { + fprintf (stderr, "wiringPiSPI: Invalid SPI channel (%d, valid range 0-%d)", channel, WPI_MaxSPIChannels-1); + return EINVAL; + } + if (number<0 || number>=WPI_MaxSPINumbers) { + fprintf (stderr, "wiringPiSPI: Invalid SPI number (%d, valid range 0-%d)", number, WPI_MaxSPINumbers-1); + return EINVAL; + } + + return 0; //sucess +} + + +#define RETURN_ON_LIMIT_FAIL int ret = SPICheckLimits(number, channel); if(ret!=0) { return ret; }; /* * wiringPiSPIGetFd: @@ -56,9 +95,16 @@ static int spiFds [2] ; ********************************************************************************* */ -int wiringPiSPIGetFd (int channel) +int wiringPiSPIxGetFd(const int number, int channel) { - return spiFds [channel & 1] ; + if (SPICheckLimits(number, channel)!=0) { + return -1; + } + return spiFds[number][channel]; +} + +int wiringPiSPIGetFd(int channel) { + return wiringPiSPIxGetFd(0, channel); } @@ -71,11 +117,11 @@ int wiringPiSPIGetFd (int channel) ********************************************************************************* */ -int wiringPiSPIDataRW (int channel, unsigned char *data, int len) +int wiringPiSPIxDataRW (const int number, const int channel, unsigned char *data, const int len) { struct spi_ioc_transfer spi ; - channel &= 1 ; + RETURN_ON_LIMIT_FAIL // Mentioned in spidev.h but not used in the original kernel documentation // test program )-: @@ -86,12 +132,15 @@ int wiringPiSPIDataRW (int channel, unsigned char *data, int len) spi.rx_buf = (unsigned long)data ; spi.len = len ; spi.delay_usecs = spiDelay ; - spi.speed_hz = spiSpeeds [channel] ; + spi.speed_hz = spiSpeeds [number][channel] ; spi.bits_per_word = spiBPW ; - return ioctl (spiFds [channel], SPI_IOC_MESSAGE(1), &spi) ; + return ioctl (spiFds[number][channel], SPI_IOC_MESSAGE(1), &spi) ; } +int wiringPiSPIDataRW (int channel, unsigned char *data, int len) { + return wiringPiSPIxDataRW(0, channel, data, len); +} /* * wiringPiSPISetupMode: @@ -99,46 +148,68 @@ int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ********************************************************************************* */ -int wiringPiSPISetupMode (int channel, int speed, int mode) + +int wiringPiSPIxSetupMode(const int number, const int channel, const int speed, const int mode) { int fd ; char spiDev [32] ; - mode &= 3 ; // Mode is 0, 1, 2 or 3 + RETURN_ON_LIMIT_FAIL + if (mode<0 || mode>3) { // Mode is 0, 1, 2 or 3 original + fprintf (stderr, "wiringPiSPI: Invalid mode (%d, valid range 0-%d)", mode, 3); + return EINVAL; + } -// Channel can be anything - lets hope for the best -// channel &= 1 ; // Channel is 0 or 1 - - snprintf (spiDev, 31, "/dev/spidev0.%d", channel) ; - - if ((fd = open (spiDev, O_RDWR)) < 0) - return wiringPiFailure (WPI_ALMOST, "Unable to open SPI device: %s\n", strerror (errno)) ; - - spiSpeeds [channel] = speed ; - spiFds [channel] = fd ; + snprintf (spiDev, 31, "/dev/spidev%d.%d", number, channel) ; + if ((fd = open (spiDev, O_RDWR)) < 0) { + return wiringPiFailure (WPI_ALMOST, "Unable to open SPI device %s: %s\n", spiDev, strerror (errno)) ; + } + spiSpeeds [number][channel] = speed ; + spiFds [number][channel] = fd ; // Set SPI parameters. if (ioctl (fd, SPI_IOC_WR_MODE, &mode) < 0) - return wiringPiFailure (WPI_ALMOST, "SPI Mode Change failure: %s\n", strerror (errno)) ; + return wiringPiFailure (WPI_ALMOST, "SPI mode change failure: %s\n", strerror (errno)) ; if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) - return wiringPiFailure (WPI_ALMOST, "SPI BPW Change failure: %s\n", strerror (errno)) ; + return wiringPiFailure (WPI_ALMOST, "SPI BPW change failure: %s\n", strerror (errno)) ; if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) - return wiringPiFailure (WPI_ALMOST, "SPI Speed Change failure: %s\n", strerror (errno)) ; + return wiringPiFailure (WPI_ALMOST, "SPI speed change failure: %s\n", strerror (errno)) ; return fd ; } +int wiringPiSPISetupMode (int channel, int speed, int mode) { + return wiringPiSPIxSetupMode (0, channel, speed, mode); +} + + /* * wiringPiSPISetup: * Open the SPI device, and set it up, etc. in the default MODE 0 ********************************************************************************* */ -int wiringPiSPISetup (int channel, int speed) -{ - return wiringPiSPISetupMode (channel, speed, 0) ; +int wiringPiSPISetup (int channel, int speed) { + return wiringPiSPIxSetupMode(0, channel, speed, 0) ; } + + +int wiringPiSPIxClose (const int number, const int channel) { + + RETURN_ON_LIMIT_FAIL + if (spiFds[number][channel]>0) { + ret = close(spiFds[number][channel]); + } + spiSpeeds [number][channel] = 0 ; + spiFds [number][channel] = -1 ; + return ret; +} + +int wiringPiSPIClose (const int channel) { + return wiringPiSPIxClose (0, channel); +} + diff --git a/wiringPi/wiringPiSPI.h b/wiringPi/wiringPiSPI.h index 44a8cfc..cd1bc03 100644 --- a/wiringPi/wiringPiSPI.h +++ b/wiringPi/wiringPiSPI.h @@ -1,7 +1,7 @@ /* * wiringPiSPI.h: * Simplified SPI access routines - * Copyright (c) 2012-2015 Gordon Henderson + * Copyright (c) 2012-2024 Gordon Henderson and contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ @@ -26,10 +26,20 @@ extern "C" { #endif + + int wiringPiSPIGetFd (int channel) ; int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ; int wiringPiSPISetupMode (int channel, int speed, int mode) ; int wiringPiSPISetup (int channel, int speed) ; +int wiringPiSPIClose (const int channel); //Interface 3.5 + +//Interface 3.5 +int wiringPiSPIxGetFd (const int number, const int channel) ; +int wiringPiSPIxDataRW (const int number, const int channel, unsigned char *data, const int len) ; +int wiringPiSPIxSetupMode (const int number, const int channel, const int speed, const int mode) ; +int wiringPiSPIxSetup (const int number, const int channel, const int speed) ; +int wiringPiSPIxClose (const int number, const int channel); #ifdef __cplusplus } From 01ea71461bb59a62abc9b6cb8dcfc4db44ca34fa Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Fri, 17 May 2024 20:03:06 +0200 Subject: [PATCH 03/14] #243 --- wiringPi/wiringPiSPI.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/wiringPi/wiringPiSPI.c b/wiringPi/wiringPiSPI.c index 480d18c..6145493 100644 --- a/wiringPi/wiringPiSPI.c +++ b/wiringPi/wiringPiSPI.c @@ -72,7 +72,6 @@ static int spiFds [7][3] = }; - int SPICheckLimits(const int number, const int channel) { if (channel<0 || channel>=WPI_MaxSPIChannels) { fprintf (stderr, "wiringPiSPI: Invalid SPI channel (%d, valid range 0-%d)", channel, WPI_MaxSPIChannels-1); @@ -119,13 +118,16 @@ int wiringPiSPIGetFd(int channel) { int wiringPiSPIxDataRW (const int number, const int channel, unsigned char *data, const int len) { - struct spi_ioc_transfer spi ; RETURN_ON_LIMIT_FAIL + if (-1==spiFds[number][channel]) { + fprintf (stderr, "wiringPiSPI: Invalid SPI number/channel (need wiringPiSPIxSetupMode before read/write)"); + return EBADF; + } + struct spi_ioc_transfer spi ; // Mentioned in spidev.h but not used in the original kernel documentation // test program )-: - memset (&spi, 0, sizeof (spi)) ; spi.tx_buf = (unsigned long)data ; From 54179784546ae37c7bb7a60b478c5171f9a544e9 Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Fri, 17 May 2024 20:53:11 +0200 Subject: [PATCH 04/14] #243 --- wiringPi/wiringPiSPI.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wiringPi/wiringPiSPI.c b/wiringPi/wiringPiSPI.c index 6145493..4657b38 100644 --- a/wiringPi/wiringPiSPI.c +++ b/wiringPi/wiringPiSPI.c @@ -75,11 +75,11 @@ static int spiFds [7][3] = int SPICheckLimits(const int number, const int channel) { if (channel<0 || channel>=WPI_MaxSPIChannels) { fprintf (stderr, "wiringPiSPI: Invalid SPI channel (%d, valid range 0-%d)", channel, WPI_MaxSPIChannels-1); - return EINVAL; + return -EINVAL; } if (number<0 || number>=WPI_MaxSPINumbers) { fprintf (stderr, "wiringPiSPI: Invalid SPI number (%d, valid range 0-%d)", number, WPI_MaxSPINumbers-1); - return EINVAL; + return -EINVAL; } return 0; //sucess @@ -122,7 +122,7 @@ int wiringPiSPIxDataRW (const int number, const int channel, unsigned char *data RETURN_ON_LIMIT_FAIL if (-1==spiFds[number][channel]) { fprintf (stderr, "wiringPiSPI: Invalid SPI number/channel (need wiringPiSPIxSetupMode before read/write)"); - return EBADF; + return -EBADF; } struct spi_ioc_transfer spi ; @@ -159,7 +159,7 @@ int wiringPiSPIxSetupMode(const int number, const int channel, const int speed, RETURN_ON_LIMIT_FAIL if (mode<0 || mode>3) { // Mode is 0, 1, 2 or 3 original fprintf (stderr, "wiringPiSPI: Invalid mode (%d, valid range 0-%d)", mode, 3); - return EINVAL; + return -EINVAL; } snprintf (spiDev, 31, "/dev/spidev%d.%d", number, channel) ; From 9819613cc07290420f485ebbc4e4838463eb1684 Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Sat, 18 May 2024 12:08:34 +0200 Subject: [PATCH 05/14] #243 unit test --- wiringPi/test/Makefile | 36 ++++- wiringPi/test/wiringpi_test1_sysfs.c | 4 +- wiringPi/test/wiringpi_test2_sysfs.c | 4 +- wiringPi/test/wiringpi_test3_device_wpi.c | 4 +- wiringPi/test/wiringpi_test4_device_phys.c | 4 +- wiringPi/test/wiringpi_test5_default.c | 4 +- wiringPi/test/wiringpi_test6_isr.c | 3 +- wiringPi/test/wiringpi_test7_version.c | 2 + wiringPi/test/wiringpi_xotest_test1_spi.c | 178 +++++++++++++++++++++ wiringPi/test/wpi_test.h | 102 +++++++++--- 10 files changed, 297 insertions(+), 44 deletions(-) create mode 100644 wiringPi/test/wiringpi_xotest_test1_spi.c diff --git a/wiringPi/test/Makefile b/wiringPi/test/Makefile index 6fb564f..9a95b73 100644 --- a/wiringPi/test/Makefile +++ b/wiringPi/test/Makefile @@ -4,7 +4,9 @@ LDFLAGS = tests = wiringpi_test1_sysfs wiringpi_test2_sysfs wiringpi_test3_device_wpi wiringpi_test4_device_phys wiringpi_test5_default wiringpi_test6_isr wiringpi_test7_version -all: $(tests) +xotests = wiringpi_xotest_test1_spi + +all: $(tests) $(xotests) wiringpi_test1_sysfs: ${CC} ${CFLAGS} wiringpi_test1_sysfs.c -o wiringpi_test1_sysfs -lwiringPi @@ -27,12 +29,42 @@ wiringpi_test6_isr: wiringpi_test7_version: ${CC} ${CFLAGS} wiringpi_test7_version.c -o wiringpi_test7_version -lwiringPi +wiringpi_xotest_test1_spi: + ${CC} ${CFLAGS} wiringpi_xotest_test1_spi.c -o wiringpi_xotest_test1_spi -lwiringPi + test: + @error_state=false ; \ for t in $(tests) ; do \ + echo === unit test: $${t} === ; \ + time ./$${t}; \ + if [ $$? -ne 0 ]; then \ + error_state=true ; \ + fi ; \ + echo ; echo ; \ + done ; \ + if [ "$$error_state" = true ]; then \ + echo "STD TEST FAILED"; \ + else \ + echo "STD TEST SUCCESS"; \ + fi + +xotest: + @error_state=false ; \ + for t in $(xotests) ; do \ echo === unit test: $${t} === ; \ time ./$${t} ; \ + if [ $$? -ne 0 ]; then \ + error_state=true ; \ + fi ; \ echo ; echo ; \ done + if [ "$$error_state" = true ]; then \ + echo "XO TEST FAILED"; \ + else \ + echo "XO TEST SUCCESS"; \ + fi clean: - for t in $(tests) ; do rm -fv $${t} ; done \ No newline at end of file + for t in $(tests) $(xotests) ; do \ + rm -fv $${t} ; \ + done diff --git a/wiringPi/test/wiringpi_test1_sysfs.c b/wiringPi/test/wiringpi_test1_sysfs.c index be90616..45a62fe 100644 --- a/wiringPi/test/wiringpi_test1_sysfs.c +++ b/wiringPi/test/wiringpi_test1_sysfs.c @@ -2,9 +2,7 @@ // Compile: gcc -Wall wiringpi_test1_device.c -o wiringpi_test1_device -lwiringPi #include "wpi_test.h" -#include #include -#include #include #include @@ -52,6 +50,6 @@ int main (void) { //Error wrong direction - only for fun digitalWrite(GPIO, LOW); - return(EXIT_SUCCESS); + return UnitTestState(); } diff --git a/wiringPi/test/wiringpi_test2_sysfs.c b/wiringPi/test/wiringpi_test2_sysfs.c index 454e112..0e5a0d2 100644 --- a/wiringPi/test/wiringpi_test2_sysfs.c +++ b/wiringPi/test/wiringpi_test2_sysfs.c @@ -2,9 +2,7 @@ // Compile: gcc -Wall wiringpi_test2_device.c -o wiringpi_test2_device -lwiringPi #include "wpi_test.h" -#include #include -#include #include #include @@ -50,5 +48,5 @@ int main (void) { CheckGPIO(GPIO, GPIOIN, LOW); delayMicroseconds(600000); - return(EXIT_SUCCESS); + return UnitTestState(); } diff --git a/wiringPi/test/wiringpi_test3_device_wpi.c b/wiringPi/test/wiringpi_test3_device_wpi.c index 179f09c..24af1bc 100644 --- a/wiringPi/test/wiringpi_test3_device_wpi.c +++ b/wiringPi/test/wiringpi_test3_device_wpi.c @@ -2,9 +2,7 @@ // Compile: gcc -Wall wiringpi_test3_device.c -o wiringpi_test3_device -lwiringPi #include "wpi_test.h" -#include #include -#include #include #include @@ -50,5 +48,5 @@ int main (void) { CheckGPIO(GPIO, GPIOIN, LOW); delayMicroseconds(600000); - return(EXIT_SUCCESS); + return UnitTestState(); } diff --git a/wiringPi/test/wiringpi_test4_device_phys.c b/wiringPi/test/wiringpi_test4_device_phys.c index 9970aa5..ecd07a5 100644 --- a/wiringPi/test/wiringpi_test4_device_phys.c +++ b/wiringPi/test/wiringpi_test4_device_phys.c @@ -2,9 +2,7 @@ // Compile: gcc -Wall wiringpi_test4_device.c -o wiringpi_test4_device -lwiringPi #include "wpi_test.h" -#include #include -#include #include #include @@ -50,5 +48,5 @@ int main (void) { CheckGPIO(GPIO, GPIOIN, LOW); delayMicroseconds(600000); - return(EXIT_SUCCESS); + return UnitTestState(); } diff --git a/wiringPi/test/wiringpi_test5_default.c b/wiringPi/test/wiringpi_test5_default.c index e025aaf..ac58be9 100644 --- a/wiringPi/test/wiringpi_test5_default.c +++ b/wiringPi/test/wiringpi_test5_default.c @@ -2,9 +2,7 @@ // Compile: gcc -Wall wiringpi_test1_device.c -o wiringpi_test1_device -lwiringPi #include "wpi_test.h" -#include #include -#include #include #include @@ -52,6 +50,6 @@ int main (void) { //Error wrong direction - only for fun digitalWrite(GPIO, LOW); - return(EXIT_SUCCESS); + return UnitTestState(); } diff --git a/wiringPi/test/wiringpi_test6_isr.c b/wiringPi/test/wiringpi_test6_isr.c index bae44b2..24f1496 100644 --- a/wiringPi/test/wiringpi_test6_isr.c +++ b/wiringPi/test/wiringpi_test6_isr.c @@ -4,7 +4,6 @@ #include "wpi_test.h" #include #include -#include #include #include @@ -166,5 +165,5 @@ int main (void) { } pinMode(OUTpin, INPUT); - return 0 ; + return UnitTestState(); } diff --git a/wiringPi/test/wiringpi_test7_version.c b/wiringPi/test/wiringpi_test7_version.c index 0850252..843dcc9 100644 --- a/wiringPi/test/wiringpi_test7_version.c +++ b/wiringPi/test/wiringpi_test7_version.c @@ -8,4 +8,6 @@ int main (void) { CheckSame("version major", major, VERSION_MAJOR); CheckSame("version minor", minor, VERSION_MINOR); + + return UnitTestState(); } \ No newline at end of file diff --git a/wiringPi/test/wiringpi_xotest_test1_spi.c b/wiringPi/test/wiringpi_xotest_test1_spi.c new file mode 100644 index 0000000..a04cfe9 --- /dev/null +++ b/wiringPi/test/wiringpi_xotest_test1_spi.c @@ -0,0 +1,178 @@ +// WiringPi test program: SPI functions (need XO hardware) +// Compile: gcc -Wall wiringpi_xotest_test1_spi.c -o wiringpi_xotest_test1_spi -lwiringPi + +#include +#include +#include +#include +#include "wpi_test.h" +#include + +#define TRUE (1==1) +#define FALSE (!TRUE) +#define CHAN_CONFIG_SINGLE 8 +#define CHAN_CONFIG_DIFF 0 + +const float fRefVoltage = 3.3f; +const float fResolution = 4096; //12-Bit +const int spiChannel = 1; +const int spiSpeed = 1000000; // MHz + + + +int AnalogRead(int spiChannel, int analogChannel, int* returnvalue) { + if (analogChannel<0 || analogChannel>1) { + return -1; + } + + unsigned char spiData[3]; + unsigned char chanBits; + + if (analogChannel == 0) { + chanBits = 0b11010000; + } else { + chanBits = 0b11110000; + } + spiData[0] = chanBits; + spiData[1] = 0; + spiData[2] = 0; + *returnvalue = wiringPiSPIxDataRW(0, spiChannel, spiData, 3); + return ((spiData [0] << 9) | (spiData [1] << 1) | (spiData[2] >> 7)) & 0xFFF; +} + +void checkVoltage(float expect, const char* szexpect) { + int returnvalue; + + //int CH0 = AnalogRead(spiChannel, 0, &returnvalue); + int CH1 = AnalogRead(spiChannel, 1, &returnvalue); + //float value0 = CH0 * fRefVoltage / fResolution; + float value1 = CH1 * fRefVoltage / fResolution; + CheckSameFloat(szexpect, value1, expect); + delayMicroseconds(300); +} + + +int main(int argc, char *argv []){ + + const int GPIOIn = 29; + int hSPI; + //int CH0; + int CH1; + int major, minor; + + wiringPiVersion(&major, &minor); + printf("Testing SPI functions with WiringPi %d.%d\n",major, minor); + printf("------------------------------------------\n\n"); + + wiringPiSetup(); + + if ((hSPI = wiringPiSPISetup (spiChannel, spiSpeed)) < 0) { + FailAndExitWithErrno("wiringPiSPISetup", hSPI); + } + + int hSPIOld=hSPI; + //printf("\nSPI fd = %d\n call close now\n", hSPI); + int ret = wiringPiSPIClose(spiChannel); + if (ret!=0) { + FailAndExitWithErrno("wiringPiSPIClose", ret); + } + + if ((hSPI = wiringPiSPIxSetupMode(0, spiChannel, spiSpeed, 0)) < 0) { + FailAndExitWithErrno("wiringPiSPIxSetup", hSPI); + } + + CheckSame("SPISetup, Close and SPIxSetup handle", hSPI, hSPIOld); + + int returnvalue; + //CH0 = AnalogRead(spiChannel, 0, &returnvalue); + CH1 = AnalogRead(spiChannel, 1, &returnvalue); + CheckSame("SPI reading ioctl result (byte count) ", returnvalue, 3); + //float value0 = CH0 * fRefVoltage / fResolution; + //float value1 = CH1 * fRefVoltage / fResolution; + + pinMode(21, OUTPUT); + pinMode(22, INPUT); + pinMode(24, INPUT); + pinMode(25, INPUT); + pinMode(27, INPUT); + pinMode(28, INPUT); + pinMode(GPIOIn, INPUT); + + + digitalWriteEx(21, GPIOIn, LOW); + checkVoltage(0.1f, "Analog value 1xLow"); + checkVoltage(0.1f, "Analog value 1xLow"); + + digitalWriteEx(21, GPIOIn, HIGH); + checkVoltage(3.0f, "Analog value 1xHigh"); + + pinMode(22, OUTPUT); + digitalWriteEx(22, -1, LOW); + checkVoltage(1.55f, "Analog value Half (1H/1L)"); + + digitalWriteEx(22, GPIOIn, HIGH); + checkVoltage(3.1f, "Analog value 2xHigh"); + + pinMode(24, OUTPUT); + digitalWriteEx(24, GPIOIn, HIGH); + checkVoltage(3.2f, "Analog value 3xHigh"); + + digitalWriteEx(24, -1, LOW); + checkVoltage(2.2f, "Analog value 2xHigh/1xLow"); + checkVoltage(2.2f, "Analog value 2xHigh/1xLow"); + + pinMode(25, OUTPUT); + digitalWriteEx(25, GPIOIn, HIGH); + checkVoltage(2.475f, "Analog value 3xHigh/1xLow"); + + digitalWriteEx(25, -1, LOW); + checkVoltage(1.65f, "Analog value Half (2H/2L)"); + + pinMode(27, OUTPUT); + digitalWriteEx(27, GPIOIn, HIGH); + checkVoltage(1.98f, "Analog value 3xHigh/2xLow"); + + digitalWriteEx(27, -1, LOW); + checkVoltage(1.32f, "Analog value Half (2H/3L)"); + + pinMode(28, OUTPUT); + digitalWriteEx(28, GPIOIn, LOW); + checkVoltage(1.100f, "Analog value 2xHigh/4xLow"); + + digitalWriteEx(28, GPIOIn, HIGH); + checkVoltage(1.65f, "Analog value Half (3H/3L)"); + + digitalWriteEx(27, GPIOIn, HIGH); + checkVoltage(2.2f, "Analog value 4xHigh/2xLow"); + + digitalWriteEx(25, GPIOIn, HIGH); + checkVoltage(2.75f, "Analog value 5xHigh/1xLow"); + + digitalWriteEx(24, GPIOIn, HIGH); + checkVoltage(3.3f, "Analog value 6xHigh"); + + CH1 = AnalogRead(3, 1, &returnvalue); + CheckSame("\nReading Wrong channel 3 result ", CH1, 0); + CheckSame("\nReading Wrong channel 3 ioctl result ", returnvalue, -EINVAL); + CH1 = AnalogRead(2, 1, &returnvalue); + CheckSame("\nReading Wrong channel 2 result ", CH1, 0); + CheckSame("\nReading Wrong channel 3 ioctl result ", returnvalue, -EBADF); + + pinMode(22, INPUT); + pinMode(21, INPUT); + pinMode(24, INPUT); + pinMode(25, INPUT); + pinMode(27, INPUT); + pinMode(28, INPUT); + + ret = wiringPiSPIxClose(0, spiChannel); + CheckSame("wiringPiSPIxClose result", ret, 0); + if (ret!=0) { + FailAndExitWithErrno("wiringPiSPIxClose", ret); + } + ret = wiringPiSPIxGetFd(0, spiChannel); + CheckSame("Fd after close", ret, -1); + + return UnitTestState(); +} + diff --git a/wiringPi/test/wpi_test.h b/wiringPi/test/wpi_test.h index be4e1f9..6d1b30b 100644 --- a/wiringPi/test/wpi_test.h +++ b/wiringPi/test/wpi_test.h @@ -1,48 +1,100 @@ #include #include +#include +#include +#include +#include #define COLORDEF "\x1B[0m" #define COLORRED "\x1B[31m" #define COLORGRN "\x1B[32m" +#define BOLD "\x1B[1m" +#define FINALCOLRED "\x1B[7;49;91m" +#define FINALCOLGRN "\x1B[7;49;32m" + + +unsigned int globalError = 0; void CheckGPIO(int GPIO, int GPIOIN, int out) { - int in = digitalRead(GPIOIN); - int read = digitalRead(GPIO); - int pass = 0; - if (out==in && in==read) { - pass = 1; - } - if (pass) { - printf("GPIO%d = %d (GPIO%d = %d) -> %spassed%s\n", GPIOIN, in, GPIO, read, COLORGRN, COLORDEF ); - } else { - printf("GPIO%d = %d (GPIO%d = %d) -> %sfailed%s\n", GPIOIN, in, GPIO, read, COLORRED, COLORDEF ); - } + int in = out; + if (GPIOIN>=0) { + in = digitalRead(GPIOIN); + } + int readback = digitalRead(GPIO); + + int pass = 0; + if (out==readback && in==out) { + pass = 1; + } + + if (GPIOIN>=0) { + printf("set GPIO%02d = %d (readback %d), in GPIO%02d = %d ", GPIO, out, readback, GPIOIN, in); + } else { + printf("set GPIO%02d = %d (readback %d) ", GPIO, out, readback); + } + + if (pass) { + printf("-> %spassed%s\n", COLORGRN, COLORDEF ); + } else { + globalError=1; + printf("-> %sfailed%s\n", COLORRED, COLORDEF ); + } } void digitalWriteEx(int GPIO, int GPIOIN, int mode) { - digitalWrite(GPIO, mode); - printf("out = %d ", mode); - delayMicroseconds(5000); - CheckGPIO(GPIO, GPIOIN, mode); + digitalWrite(GPIO, mode); + delayMicroseconds(5000); + CheckGPIO(GPIO, GPIOIN, mode); } void pullUpDnControlEx (int GPIO, int GPIOIN, int mode) { - pullUpDnControl (GPIO, mode); - int out = mode==PUD_UP ? 1:0; - printf("in = %4s ", mode==PUD_UP ? "up":"down"); - delayMicroseconds(5000); - CheckGPIO(GPIO, GPIOIN, out); + pullUpDnControl (GPIO, mode); + int out = mode==PUD_UP ? 1:0; + printf("in = %4s ", mode==PUD_UP ? "up":"down"); + delayMicroseconds(5000); + CheckGPIO(GPIO, GPIOIN, out); } void CheckSame(const char* msg, int value, int expect) { - if (value==expect) { - printf("%s -> %spassed%s\n", msg, COLORGRN, COLORDEF ); - } else { - printf("%s -> %sfailed%s\n", msg, COLORRED, COLORDEF ); - } + if (value==expect) { + printf("%39s (% 3d==% 3d) -> %spassed%s\n", msg, value, expect, COLORGRN, COLORDEF); + } else { + printf("%39s (% 3d<>% 3d) -> %sfailed%s\n", msg, value, expect, COLORRED, COLORDEF); + globalError=1; + } } + + +void CheckSameFloat(const char* msg, float value, float expect) { + if (fabs(value-expect)<0.08) { + printf("%35s (%.3f==%.3f) -> %spassed%s \n", msg, value, expect, COLORGRN, COLORDEF); + } else { + printf("%35s (%.3f<>%.3f) -> %sfailed%s \n" , msg, value, expect, COLORRED, COLORDEF); + globalError=1; + } +} + + +int UnitTestState() { + printf("\n\nUNIT TEST STATE: "); + if (globalError) { + printf(" %sFAILED%s\n\n", FINALCOLRED, COLORDEF); + return EXIT_FAILURE; + } else { + printf(" %sPASSED%s\n\n", FINALCOLGRN, COLORDEF); + return EXIT_SUCCESS; + } +} + + +void FailAndExitWithErrno(const char* msg, int ret) { + printf("%s (Return=%d, Err: %s) -> %sfailed%s \n" , msg, ret, strerror(errno), COLORRED, COLORDEF); + globalError=1; + exit(UnitTestState()); +} + From 5f74d22a95c707510f4122160e2a5db74c636486 Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Sat, 18 May 2024 12:56:55 +0200 Subject: [PATCH 06/14] #243 unit test --- wiringPi/test/Makefile | 2 +- wiringPi/test/wiringpi_xotest_test1_spi.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wiringPi/test/Makefile b/wiringPi/test/Makefile index 9a95b73..e448f16 100644 --- a/wiringPi/test/Makefile +++ b/wiringPi/test/Makefile @@ -50,7 +50,7 @@ test: xotest: @error_state=false ; \ - for t in $(xotests) ; do \ + for t in $(tests) $(xotests) ; do \ echo === unit test: $${t} === ; \ time ./$${t} ; \ if [ $$? -ne 0 ]; then \ diff --git a/wiringPi/test/wiringpi_xotest_test1_spi.c b/wiringPi/test/wiringpi_xotest_test1_spi.c index a04cfe9..1acd694 100644 --- a/wiringPi/test/wiringpi_xotest_test1_spi.c +++ b/wiringPi/test/wiringpi_xotest_test1_spi.c @@ -104,14 +104,14 @@ int main(int argc, char *argv []){ checkVoltage(0.1f, "Analog value 1xLow"); digitalWriteEx(21, GPIOIn, HIGH); - checkVoltage(3.0f, "Analog value 1xHigh"); + checkVoltage(3.1f, "Analog value 1xHigh"); pinMode(22, OUTPUT); digitalWriteEx(22, -1, LOW); checkVoltage(1.55f, "Analog value Half (1H/1L)"); digitalWriteEx(22, GPIOIn, HIGH); - checkVoltage(3.1f, "Analog value 2xHigh"); + checkVoltage(3.2f, "Analog value 2xHigh"); pinMode(24, OUTPUT); digitalWriteEx(24, GPIOIn, HIGH); @@ -172,7 +172,7 @@ int main(int argc, char *argv []){ } ret = wiringPiSPIxGetFd(0, spiChannel); CheckSame("Fd after close", ret, -1); - + return UnitTestState(); } From 4d6a1f7df867796970227257e7dd393df701f40d Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Sat, 18 May 2024 13:00:47 +0200 Subject: [PATCH 07/14] #243 unit test --- wiringPi/test/wiringpi_xotest_test1_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiringPi/test/wiringpi_xotest_test1_spi.c b/wiringPi/test/wiringpi_xotest_test1_spi.c index 1acd694..722c3f7 100644 --- a/wiringPi/test/wiringpi_xotest_test1_spi.c +++ b/wiringPi/test/wiringpi_xotest_test1_spi.c @@ -108,7 +108,7 @@ int main(int argc, char *argv []){ pinMode(22, OUTPUT); digitalWriteEx(22, -1, LOW); - checkVoltage(1.55f, "Analog value Half (1H/1L)"); + checkVoltage(1.65f, "Analog value Half (1H/1L)"); digitalWriteEx(22, GPIOIn, HIGH); checkVoltage(3.2f, "Analog value 2xHigh"); From d7debf2875c15f5d08ef1622d41f2649f97c6156 Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Sat, 18 May 2024 13:43:48 +0200 Subject: [PATCH 08/14] #243 unit test result blinking --- wiringPi/test/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wiringPi/test/Makefile b/wiringPi/test/Makefile index e448f16..d144baf 100644 --- a/wiringPi/test/Makefile +++ b/wiringPi/test/Makefile @@ -43,9 +43,9 @@ test: echo ; echo ; \ done ; \ if [ "$$error_state" = true ]; then \ - echo "STD TEST FAILED"; \ + echo "\n\e[5mSTD TEST FAILED\e[0m\n"; \ else \ - echo "STD TEST SUCCESS"; \ + echo "\n\e[5mSTD TEST SUCCESS\e[0m\n"; \ fi xotest: @@ -59,9 +59,9 @@ xotest: echo ; echo ; \ done if [ "$$error_state" = true ]; then \ - echo "XO TEST FAILED"; \ + echo "\n\e[5mSTD/XO TEST FAILED\e[0m\n"; \ else \ - echo "XO TEST SUCCESS"; \ + echo "\n\e[5mSTD/XO TEST SUCCESS\e[0m\n"; \ fi clean: From 4db79da55b0bcb69df59b6c6486018bdbc3838b5 Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Thu, 30 May 2024 16:52:04 +0200 Subject: [PATCH 09/14] #244 add API call getPinModeAlt --- wiringPi/test/wiringpi_test5_default.c | 60 +++++++++++++++++++++++--- wiringPi/test/wpi_test.h | 20 +++++++++ wiringPi/wiringPi.c | 22 ++++++++-- wiringPi/wiringPi.h | 20 +++++++++ 4 files changed, 113 insertions(+), 9 deletions(-) diff --git a/wiringPi/test/wiringpi_test5_default.c b/wiringPi/test/wiringpi_test5_default.c index ac58be9..003e89d 100644 --- a/wiringPi/test/wiringpi_test5_default.c +++ b/wiringPi/test/wiringpi_test5_default.c @@ -10,6 +10,34 @@ const int GPIO = 19; const int GPIOIN = 26; const int ToggleValue = 4; +int RaspberryPiModel = -1; + + +void SetAndCheckMode(int pin, int mode) { + enum WPIPinALT AltGpio = WPI_ALT_UNKNOWN; + + switch(mode) { + case INPUT: + pinMode(pin, INPUT); + AltGpio = getPinModeAlt(pin); + CheckSame("Pin mode input", AltGpio, WPI_ALT_INPUT); + break; + case OUTPUT: + pinMode(pin, OUTPUT); + AltGpio = getPinModeAlt(pin); + CheckSame("Pin mode output", AltGpio, WPI_ALT_OUTPUT); + break; + case PM_OFF: + pinMode(pin, PM_OFF); + AltGpio = getPinModeAlt(pin); + CheckSame("Pin mode off(input)", AltGpio, (PI_MODEL_5 == RaspberryPiModel) ? WPI_NONE : WPI_ALT_INPUT); + break; + default: + pinMode(pin, mode); + printf("pinmode %d of pin %d not checked", mode, pin); + break; + } +} int main (void) { @@ -21,8 +49,23 @@ int main (void) { printf("wiringPiSetupGpio failed\n\n"); exit(EXIT_FAILURE); } - pinMode(GPIOIN, INPUT); - pinMode(GPIO, OUTPUT); + + int rev, mem, maker, overVolted; + piBoardId(&RaspberryPiModel, &rev, &mem, &maker, &overVolted); + CheckNotSame("Model: ", RaspberryPiModel, -1); + if (PI_MODEL_5 == RaspberryPiModel) { + printf("Raspberry Pi 5 with RP1 found\n"); + } else { + printf("Raspberry Pi with BCM GPIO found (not Pi 5)\n"); + } + + + enum WPIPinAlt AltGpio = WPI_ALT_UNKNOWN; + AltGpio = getPinModeAlt(23); + CheckSame("Pin mode default", AltGpio, PI_MODEL_5 == RaspberryPiModel ? WPI_NONE : WPI_ALT_INPUT); + + SetAndCheckMode(GPIOIN, INPUT); + SetAndCheckMode(GPIO, OUTPUT); printf("toggle %d times ...\n", ToggleValue); for (int loop=1; loop %spassed%s\n", msg, value, expect, COLORGRN, COLORDEF); + } else { + printf("%39s (%10s<>%10s) -> %sfailed%s\n", msg, value, expect, COLORRED, COLORDEF); + globalError=1; + } +} + + void CheckSame(const char* msg, int value, int expect) { if (value==expect) { printf("%39s (% 3d==% 3d) -> %spassed%s\n", msg, value, expect, COLORGRN, COLORDEF); @@ -70,6 +80,16 @@ void CheckSame(const char* msg, int value, int expect) { } +void CheckNotSame(const char* msg, int value, int expect) { + if (value!=expect) { + printf("%39s (% 3d<>% 3d) -> %spassed%s\n", msg, value, expect, COLORGRN, COLORDEF); + } else { + printf("%39s (% 3d==% 3d) -> %sfailed%s\n", msg, value, expect, COLORRED, COLORDEF); + globalError=1; + } +} + + void CheckSameFloat(const char* msg, float value, float expect) { if (fabs(value-expect)<0.08) { printf("%35s (%.3f==%.3f) -> %spassed%s \n", msg, value, expect, COLORGRN, COLORDEF); diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c index ad81678..1cd1dba 100644 --- a/wiringPi/wiringPi.c +++ b/wiringPi/wiringPi.c @@ -156,8 +156,12 @@ const unsigned int RP1_DEBOUNCE_DEFAULT_VALUE = 4; const unsigned int RP1_DEBOUNCE_MASK = 0x7f; const unsigned int RP1_DEBOUNCE_DEFAULT = (RP1_DEBOUNCE_DEFAULT_VALUE << 5); +const unsigned int RP1_IRQRESET = 0x10000000; //CTRL Bit 28 + const unsigned int RP1_PAD_DEFAULT_0TO8 = (0x0B | 0x70); //Slewfast, Schmitt, PullUp, | 12mA, Input enable const unsigned int RP1_PAD_DEFAULT_FROM9 = (0x07 | 0x70); //Slewfast, Schmitt, PullDown, | 12mA, Input enable +const unsigned int RP1_PAD_IC_DEFAULT_0TO8 = 0x9A; //pull-up, Schmitt +const unsigned int RP1_PAD_IC_DEFAULT_FROM9 = 0x96; //pull-down, Schmitt const unsigned int RP1_PAD_DRIVE_MASK = 0x00000030; const unsigned int RP1_INV_PAD_DRIVE_MASK = ~(RP1_PAD_DRIVE_MASK); @@ -1314,6 +1318,11 @@ int getAlt (int pin) } +enum WPIPinALT getPinModeAlt(int pin) { + return (enum WPIPinALT) getAlt(pin); +} + + /* * pwmSetMode: * Select the native "balanced" mode, or standard mark:space mode @@ -1727,11 +1736,16 @@ void pinMode (int pin, int mode) fSel = gpioToGPFSEL [pin] ; shift = gpioToShift [pin] ; - if (mode == INPUT) { + if (INPUT==mode || PM_OFF==mode) { if (PI_MODEL_5 == RaspberryPiModel) { - pads[1+pin] = (pin<=8) ? RP1_PAD_DEFAULT_0TO8 : RP1_PAD_DEFAULT_FROM9; - gpio[2*pin+1] = RP1_FSEL_GPIO | RP1_DEBOUNCE_DEFAULT; // GPIO - rio[RP1_RIO_OE + RP1_CLR_OFFSET] = 1< Date: Fri, 31 May 2024 17:33:39 +0200 Subject: [PATCH 10/14] add API call getPinModeAlt --- wiringPi/wiringPi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c index 1cd1dba..22d2010 100644 --- a/wiringPi/wiringPi.c +++ b/wiringPi/wiringPi.c @@ -1318,8 +1318,8 @@ int getAlt (int pin) } -enum WPIPinALT getPinModeAlt(int pin) { - return (enum WPIPinALT) getAlt(pin); +enum WPIPinAlt getPinModeAlt(int pin) { + return (enum WPIPinAlt) getAlt(pin); } From c055adc469882a9bcd96a04afe0ca868d0dd3bf1 Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Fri, 31 May 2024 17:40:38 +0200 Subject: [PATCH 11/14] #244 add API call getPinModeAlt --- wiringPi/test/wiringpi_test5_default.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiringPi/test/wiringpi_test5_default.c b/wiringPi/test/wiringpi_test5_default.c index 003e89d..8223090 100644 --- a/wiringPi/test/wiringpi_test5_default.c +++ b/wiringPi/test/wiringpi_test5_default.c @@ -14,7 +14,7 @@ int RaspberryPiModel = -1; void SetAndCheckMode(int pin, int mode) { - enum WPIPinALT AltGpio = WPI_ALT_UNKNOWN; + enum WPIPinAlt AltGpio = WPI_ALT_UNKNOWN; switch(mode) { case INPUT: From 2a8e7fefd3243a8950b4fbfe06e38a5f670ccdc2 Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Fri, 31 May 2024 17:49:59 +0200 Subject: [PATCH 12/14] #250 --- wiringPi/pcf8574.c | 9 +- wiringPi/test/Makefile | 27 ++++- wiringPi/test/wiringpi_i2c_test1_pcf8574.c | 112 +++++++++++++++++++++ 3 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 wiringPi/test/wiringpi_i2c_test1_pcf8574.c diff --git a/wiringPi/pcf8574.c b/wiringPi/pcf8574.c index 402257e..61b4cc7 100644 --- a/wiringPi/pcf8574.c +++ b/wiringPi/pcf8574.c @@ -1,7 +1,7 @@ /* * pcf8574.c: * Extend wiringPi with the PCF8574 I2C GPIO expander chip - * Copyright (c) 2013 Gordon Henderson + * Copyright (c) 2013-2024 Gordon Henderson and contributors *********************************************************************** * This file is part of wiringPi: * https://github.com/WiringPi/WiringPi/ @@ -33,8 +33,9 @@ /* * myPinMode: - * The PCF8574 is an odd chip - the pins are effectively bi-directional, - * however the pins should be drven high when used as an input pin... + * The PCF8574 is a 8-Bit I/O Expander with Open-drain output. + * The pins are effectively bi-directional, + * however the pins should be driven high when used as an input pin... * So, we're effectively copying digitalWrite... ********************************************************************************* */ @@ -102,7 +103,7 @@ static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) * pcf8574Setup: * Create a new instance of a PCF8574 I2C GPIO interface. We know it * has 8 pins, so all we need to know here is the I2C address and the - * user-defined pin base. + * user-defined pin base. Default address (A0-A3 low) is 0x20. ********************************************************************************* */ diff --git a/wiringPi/test/Makefile b/wiringPi/test/Makefile index d144baf..cbcd3d8 100644 --- a/wiringPi/test/Makefile +++ b/wiringPi/test/Makefile @@ -6,7 +6,9 @@ tests = wiringpi_test1_sysfs wiringpi_test2_sysfs wiringpi_test3_device_wpi wiri xotests = wiringpi_xotest_test1_spi -all: $(tests) $(xotests) +i2ctests = wiringpi_i2c_test1_pcf8574 + +all: $(tests) $(xotests) $(i2ctests) wiringpi_test1_sysfs: ${CC} ${CFLAGS} wiringpi_test1_sysfs.c -o wiringpi_test1_sysfs -lwiringPi @@ -32,6 +34,9 @@ wiringpi_test7_version: wiringpi_xotest_test1_spi: ${CC} ${CFLAGS} wiringpi_xotest_test1_spi.c -o wiringpi_xotest_test1_spi -lwiringPi +wiringpi_i2c_test1_pcf8574: + ${CC} ${CFLAGS} wiringpi_i2c_test1_pcf8574.c -o wiringpi_i2c_test1_pcf8574 -lwiringPi + test: @error_state=false ; \ for t in $(tests) ; do \ @@ -51,7 +56,7 @@ test: xotest: @error_state=false ; \ for t in $(tests) $(xotests) ; do \ - echo === unit test: $${t} === ; \ + echo === XO unit test: $${t} === ; \ time ./$${t} ; \ if [ $$? -ne 0 ]; then \ error_state=true ; \ @@ -64,7 +69,23 @@ xotest: echo "\n\e[5mSTD/XO TEST SUCCESS\e[0m\n"; \ fi +i2ctest: + @error_state=false ; \ + for t in $(tests) $(i2ctests) ; do \ + echo === I2C unit test: $${t} === ; \ + time ./$${t} ; \ + if [ $$? -ne 0 ]; then \ + error_state=true ; \ + fi ; \ + echo ; echo ; \ + done + if [ "$$error_state" = true ]; then \ + echo "\n\e[5mSTD/I2C TEST FAILED\e[0m\n"; \ + else \ + echo "\n\e[5mSTD/I2C TEST SUCCESS\e[0m\n"; \ + fi + clean: - for t in $(tests) $(xotests) ; do \ + for t in $(tests) $(xotests) $(i2ctests) ; do \ rm -fv $${t} ; \ done diff --git a/wiringPi/test/wiringpi_i2c_test1_pcf8574.c b/wiringPi/test/wiringpi_i2c_test1_pcf8574.c new file mode 100644 index 0000000..19a699f --- /dev/null +++ b/wiringPi/test/wiringpi_i2c_test1_pcf8574.c @@ -0,0 +1,112 @@ +// WiringPi test program: I2C functions (need PCF8574) +// Compile: gcc -Wall wiringpi_i2c_test1.c -o wiringpi_i2c_test1 -lwiringPi + +#include "wpi_test.h" +#include "pcf8574.h" +#include "wiringPiI2C.h" + +const int pinBase = 1020; +const int i2cAdress = 0x20; + +int ShowAll() { + int in; + int value = 0; + + printf("pin: 0 1 2 3 4 5 6 7\nval: "); + for (int pin=0; pin<=7; ++pin) { + in = digitalRead(pinBase + pin); + printf("%d ", in); + if(in==HIGH) { value |= (0x01< Date: Sun, 2 Jun 2024 11:46:33 +0200 Subject: [PATCH 13/14] #243 simple MCP3202 SPI test --- wiringPi/test/wiringpi_spi_test1_mcp3202.c | 112 +++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 wiringPi/test/wiringpi_spi_test1_mcp3202.c diff --git a/wiringPi/test/wiringpi_spi_test1_mcp3202.c b/wiringPi/test/wiringpi_spi_test1_mcp3202.c new file mode 100644 index 0000000..886d2eb --- /dev/null +++ b/wiringPi/test/wiringpi_spi_test1_mcp3202.c @@ -0,0 +1,112 @@ +// WiringPi test program: SPI functions (need MCP3202 hardware @ CE1, ch0=Vdd, ch1=Vdd/2) +// Compile: gcc -Wall wiringpi_spi_test1_mcp3202.c -o wiringpi_spi_test1_mcp3202 -lwiringPi + +#include +#include +#include +#include +#include "wpi_test.h" +#include + +const float fRefVoltage = 3.3f; +const float fResolution = 4096; //12-Bit +const int spiChannel = 1; +const int spiSpeedInit = 250000; // Hz + + +int AnalogRead(int spiChannel, int analogChannel, int* returnvalue) { + if (analogChannel<0 || analogChannel>1) { + return -1; + } + + unsigned char spiData[3]; + unsigned char chanBits; + + if (analogChannel == 0) { + chanBits = 0b11010000; + } else { + chanBits = 0b11110000; + } + spiData[0] = chanBits; + spiData[1] = 0; + spiData[2] = 0; + *returnvalue = wiringPiSPIxDataRW(0, spiChannel, spiData, 3); + return ((spiData [0] << 9) | (spiData [1] << 1) | (spiData[2] >> 7)) & 0xFFF; +} + + +int main(int argc, char *argv []){ + + int hSPI; + int CH0,CH1; + float value0, value1; + int returnvalue; + int spiSpeed; + int major, minor; + + wiringPiVersion(&major, &minor); + printf("Testing SPI functions with WiringPi %d.%d\n",major, minor); + printf("------------------------------------------\n\n"); + + wiringPiSetup(); + spiSpeed = spiSpeedInit; + for (int testno=0; testno<=2; testno++) { + printf("\nTest 5d with %g MHz SPI Speed\n", spiSpeed/1000000.0f); + if ((hSPI = wiringPiSPISetup (spiChannel, spiSpeed)) < 0) { + FailAndExitWithErrno("wiringPiSPISetup", hSPI); + } + + int hSPIOld=hSPI; + //printf("\nSPI fd = %d\n call close now\n", hSPI); + int ret = wiringPiSPIClose(spiChannel); + if (ret!=0) { + FailAndExitWithErrno("wiringPiSPIClose", ret); + } + + if ((hSPI = wiringPiSPIxSetupMode(0, spiChannel, spiSpeed, 0)) < 0) { + FailAndExitWithErrno("wiringPiSPIxSetup", hSPI); + } + + CheckSame("SPISetup, Close and SPIxSetup handle", hSPI, hSPIOld); + + delayMicroseconds(500000); + returnvalue = -1; + CH0 = AnalogRead(spiChannel, 0, &returnvalue); + CheckSame("CH0 wiringPiSPIxDataRW return", returnvalue, 3); + value0 = CH0 * fRefVoltage / fResolution; + CheckSameFloat("CH0 value (VDD)", value0, 3.3f); + printf("\n"); + + delayMicroseconds(500000); + returnvalue = -1; + CH1 = AnalogRead(spiChannel, 1, &returnvalue); + CheckSame("CH1 wiringPiSPIxDataRW return", returnvalue, 3); + value1 = CH1 * fRefVoltage / fResolution; + CheckSameFloat("CH1 value (1/2)", value1, 1.65f); + printf("\n"); + + ret = wiringPiSPIxClose(0, spiChannel); + CheckSame("wiringPiSPIxClose result", ret, 0); + if (ret!=0) { + FailAndExitWithErrno("wiringPiSPIxClose", ret); + } + ret = wiringPiSPIxGetFd(0, spiChannel); + CheckSame("Fd after wiringPiSPIxGetFd", ret, -1); + + ret = wiringPiSPIGetFd(spiChannel); + CheckSame("Fd after wiringPiSPIGetFd", ret, -1); + + spiSpeed += spiSpeed; + } + + printf("\n"); + hSPI = wiringPiSPISetup (3, spiSpeedInit); + CheckSame("\nwiringPiSPISetup with wrong channel", hSPI, -22); + + // will result in exit! - not useful in test code + //hSPI = wiringPiSPIxSetupMode (3, 0, spiSpeedInit,0); + //CheckSame("\nwiringPiSPISetup with wrong channel", hSPI, -22); + + return UnitTestState(); +} + From 3de56b65cb808615f71ba5d000e85ad8f8aa8b4c Mon Sep 17 00:00:00 2001 From: mstroh76 Date: Sun, 2 Jun 2024 11:47:32 +0200 Subject: [PATCH 14/14] 3.6 version release --- VERSION | 2 +- version.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 5a95802..d70c8f8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.5 +3.6 diff --git a/version.h b/version.h index 87082e3..2d9c9fa 100644 --- a/version.h +++ b/version.h @@ -1,3 +1,3 @@ -#define VERSION "3.5" +#define VERSION "3.6" #define VERSION_MAJOR 3 -#define VERSION_MINOR 5 +#define VERSION_MINOR 6