i have this sources
first start.pl
use strict;
use warnings;
use hh;
print "Starting...\n";
my $abc={
VAL=>['alfa','beta'],
STUDENTS=>{
stud1=>{VAL=>['delta','gama']},
stud2=>{VAL=>['omega','upsilon']},
}
};
my $object=hh->new(catalog=>$abc);
and the package
package hh;
use strict;
use warnings;
sub new {
my $class=shift;
my $self={#_};
bless ($self,$class) ;
$self->_initialize("",['BEGIN']);
return $self ;
}
sub _initialize {
my $self=shift;
my $tab=shift;
my $carry=shift;
$tab=$tab."\t|";
if (defined $self->{VAL}){print "$tab Have val=",join(" ",#{$self->{VAL}}),"\n";push(#{$carry},#{$self->{VAL}})}
foreach my $k (sort {lc $a cmp lc $b} keys %{$self}){
print $tab,"carry=",$#{$carry}+1," "," ",$k,"\n";
if (ref($self->{$k}) eq 'HASH'){print "$tab Running initialize pentru $k\n";_initialize($self->{$k},$tab,$carry)}
}
return $self;
}
1;
the output is like this
Starting...
|carry=1 catalog
| Running initialize pentru catalog
| | Have val=alfa beta
| |carry=3 STUDENTS
| | Running initialize pentru STUDENTS
| | |carry=3 stud1
| | | Running initialize pentru stud1
| | | | Have val=delta gama
| | | |carry=5 VAL
| | |carry=5 stud2
| | | Running initialize pentru stud2
| | | | Have val=omega upsilon
| | | |carry=7 VAL
| |carry=7 VAL
Somehow i want to collect into an array the VAL arrays between top of tree and the walked element . Way the last VAL who is in the second level has 7 elements . I want to have only 2 elements (alfa and beta)
this is the expected output
Starting...
|carry=1 catalog
| Running initialize pentru catalog
| | Have val=alfa beta
| |carry=3 STUDENTS
| | Running initialize pentru STUDENTS
| | |carry=3 stud1
| | | Running initialize pentru stud1
| | | | Have val=delta gama
| | | |carry=5 VAL carry=5 (OK)
| | |carry=5 stud2
| | | Running initialize pentru stud2
| | | | Have val=omega upsilon
| | | |carry=7 VAL carry=5 (not ok this need only his values catalog alfa beta omega epsilon)
| |carry=7 VAL not ok (carry 3 only catalog alfa beta)
...
If you want to accumulate only the values in the current branch, you have to pass a copy of the carry array. [#$carry] dereferences the arrayref $carry and creates a new arrayref from the elements. I kept the original reference for the debug print at the end of the function. The more natural way would be to write $carry = [#$carry].
use strict;
use warnings;
package hh;
use Data::Dumper;
sub new {
my $class=shift;
my $self={#_};
bless ($self,$class) ;
$self->_initialize("",['BEGIN']);
return $self ;
}
sub _initialize {
my $self=shift;
my $tab=shift;
my $carry=shift;
$tab=$tab."\t|";
print "$tab _initialize() called with carry "," [",join(', ',#$carry),"]\n";
my $new_carry = [#$carry];
if (defined $self->{VAL}){
print "$tab Have found val=",join(" ",#{$self->{VAL}}),"\n";
print "$tab pushing ",join(" ",#{$self->{VAL}}),"\n";
push(#{$new_carry},#{$self->{VAL}})
}
print $tab," carry=",$#{$new_carry}+1," [",join(', ',#$new_carry),"]\n";
foreach my $k (sort {lc $a cmp lc $b} keys %{$self}){
if (ref($self->{$k}) eq 'HASH'){print "$tab Running initialize pentru $k\n";_initialize($self->{$k},$tab, $new_carry)}
}
print "$tab returning to previous level. carry was "," [",join(', ',#$carry),"]\n";
return $self;
}
package main;
print "Starting...\n";
my $abc={
VAL=>['alfa','beta'],
STUDENTS=>{
stud1=>{VAL=>['delta','gama']},
stud2=>{VAL=>['omega','upsilon']},
}
};
my $object=hh->new(catalog=>$abc);
This prints:
Starting...
| _initialized called with carry [BEGIN]
| carry=1 [BEGIN]
| Running initialize pentru catalog
| | _initialized called with carry [BEGIN]
| | Have found val=alfa beta
| | pushing alfa beta
| | carry=3 [BEGIN, alfa, beta]
| | Running initialize pentru STUDENTS
| | | _initialized called with carry [BEGIN, alfa, beta]
| | | carry=3 [BEGIN, alfa, beta]
| | | Running initialize pentru stud1
| | | | _initialized called with carry [BEGIN, alfa, beta]
| | | | Have found val=delta gama
| | | | pushing delta gama
| | | | carry=5 [BEGIN, alfa, beta, delta, gama]
| | | | returning to previous level. carry was [BEGIN, alfa, beta]
| | | Running initialize pentru stud2
| | | | _initialized called with carry [BEGIN, alfa, beta]
| | | | Have found val=omega upsilon
| | | | pushing omega upsilon
| | | | carry=5 [BEGIN, alfa, beta, omega, upsilon]
| | | | returning to previous level. carry was [BEGIN, alfa, beta]
| | | returning to previous level. carry was [BEGIN, alfa, beta]
| | returning to previous level. carry was [BEGIN]
| returning to previous level. carry was [BEGIN]
I have an RPi4.
Based on this link I need to have a version 2.52 of gpio to work properly on this device.
I have done this:
# cd /tmp
# wget https://project-downloads.drogon.net/wiringpi-latest.deb
# sudo dpkg -i wiringpi-latest.deb
# gpio -v
gpio version: 2.46
Also, writing to GPIO is not working, all ports are logic 1 after booting.
And git.drogon.net is unavailable.
What can I do now if I need to compile a software which relies on this library..?
UPDATE
I have cloned this repository as stevieb recommended.
It also has a pull request for supporting PI4 boards.
However even after applying that patch I'm not able to control the output pins of the PI4:
First get the current states of the pins:
# gpio readall
+-----+-----+---------+------+---+---Pi 4+--+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| | | 3.3v | | | 1 || 2 | | | 5v | | |
| 2 | 8 | SDA.1 | IN | 1 | 3 || 4 | | | 5v | | |
| 3 | 9 | SCL.1 | IN | 1 | 5 || 6 | | | 0v | | |
| 4 | 7 | GPIO. 7 | IN | 1 | 7 || 8 | 1 | IN | TxD | 15 | 14 |
| | | 0v | | | 9 || 10 | 1 | IN | RxD | 16 | 15 |
| 17 | 0 | GPIO. 0 | IN | 1 | 11 || 12 | 1 | IN | GPIO. 1 | 1 | 18 |
| 27 | 2 | GPIO. 2 | IN | 1 | 13 || 14 | | | 0v | | |
| 22 | 3 | GPIO. 3 | IN | 1 | 15 || 16 | 1 | IN | GPIO. 4 | 4 | 23 |
| | | 3.3v | | | 17 || 18 | 1 | ALT0 | GPIO. 5 | 5 | 24 |
| 10 | 12 | MOSI | IN | 1 | 19 || 20 | | | 0v | | |
| 9 | 13 | MISO | IN | 1 | 21 || 22 | 1 | IN | GPIO. 6 | 6 | 25 |
| 11 | 14 | SCLK | IN | 1 | 23 || 24 | 1 | ALT4 | CE0 | 10 | 8 |
| | | 0v | | | 25 || 26 | 1 | IN | CE1 | 11 | 7 |
| 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 |
| 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | |
| 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 1 | ALT5 | GPIO.26 | 26 | 12 |
| 13 | 23 | GPIO.23 | IN | 1 | 33 || 34 | | | 0v | | |
| 19 | 24 | GPIO.24 | IN | 1 | 35 || 36 | 1 | IN | GPIO.27 | 27 | 16 |
| 26 | 25 | GPIO.25 | IN | 1 | 37 || 38 | 1 | IN | GPIO.28 | 28 | 20 |
| | | 0v | | | 39 || 40 | 1 | IN | GPIO.29 | 29 | 21 |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+---Pi 4+--+---+------+---------+-----+-----+
Then set pin7 to output and check the result:
# gpio mode 7 out
# gpio readall
+-----+-----+---------+------+---+---Pi 4+--+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| | | 3.3v | | | 1 || 2 | | | 5v | | |
| 2 | 8 | SDA.1 | IN | 1 | 3 || 4 | | | 5v | | |
| 3 | 9 | SCL.1 | IN | 1 | 5 || 6 | | | 0v | | |
| 4 | 7 | GPIO. 7 | OUT | 1 | 7 || 8 | 1 | IN | TxD | 15 | 14 |
| | | 0v | | | 9 || 10 | 1 | IN | RxD | 16 | 15 |
| 17 | 0 | GPIO. 0 | IN | 1 | 11 || 12 | 1 | IN | GPIO. 1 | 1 | 18 |
| 27 | 2 | GPIO. 2 | IN | 1 | 13 || 14 | | | 0v | | |
| 22 | 3 | GPIO. 3 | IN | 1 | 15 || 16 | 1 | IN | GPIO. 4 | 4 | 23 |
| | | 3.3v | | | 17 || 18 | 1 | ALT0 | GPIO. 5 | 5 | 24 |
| 10 | 12 | MOSI | IN | 1 | 19 || 20 | | | 0v | | |
| 9 | 13 | MISO | IN | 1 | 21 || 22 | 1 | IN | GPIO. 6 | 6 | 25 |
| 11 | 14 | SCLK | IN | 1 | 23 || 24 | 1 | ALT4 | CE0 | 10 | 8 |
| | | 0v | | | 25 || 26 | 1 | IN | CE1 | 11 | 7 |
| 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 |
| 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | |
| 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 1 | ALT5 | GPIO.26 | 26 | 12 |
| 13 | 23 | GPIO.23 | IN | 1 | 33 || 34 | | | 0v | | |
| 19 | 24 | GPIO.24 | IN | 1 | 35 || 36 | 1 | IN | GPIO.27 | 27 | 16 |
| 26 | 25 | GPIO.25 | IN | 1 | 37 || 38 | 1 | IN | GPIO.28 | 28 | 20 |
| | | 0v | | | 39 || 40 | 1 | IN | GPIO.29 | 29 | 21 |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+---Pi 4+--+---+------+---------+-----+-----+
Then write 0 to pin7 and check the result:
# gpio write 7 0
# gpio readall
+-----+-----+---------+------+---+---Pi 4+--+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| | | 3.3v | | | 1 || 2 | | | 5v | | |
| 2 | 8 | SDA.1 | IN | 1 | 3 || 4 | | | 5v | | |
| 3 | 9 | SCL.1 | IN | 1 | 5 || 6 | | | 0v | | |
| 4 | 7 | GPIO. 7 | OUT | 1 | 7 || 8 | 1 | IN | TxD | 15 | 14 |
| | | 0v | | | 9 || 10 | 1 | IN | RxD | 16 | 15 |
| 17 | 0 | GPIO. 0 | IN | 1 | 11 || 12 | 1 | IN | GPIO. 1 | 1 | 18 |
| 27 | 2 | GPIO. 2 | IN | 1 | 13 || 14 | | | 0v | | |
| 22 | 3 | GPIO. 3 | IN | 1 | 15 || 16 | 1 | IN | GPIO. 4 | 4 | 23 |
| | | 3.3v | | | 17 || 18 | 1 | ALT0 | GPIO. 5 | 5 | 24 |
| 10 | 12 | MOSI | IN | 1 | 19 || 20 | | | 0v | | |
| 9 | 13 | MISO | IN | 1 | 21 || 22 | 1 | IN | GPIO. 6 | 6 | 25 |
| 11 | 14 | SCLK | IN | 1 | 23 || 24 | 1 | ALT4 | CE0 | 10 | 8 |
| | | 0v | | | 25 || 26 | 1 | IN | CE1 | 11 | 7 |
| 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 |
| 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | |
| 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 1 | ALT5 | GPIO.26 | 26 | 12 |
| 13 | 23 | GPIO.23 | IN | 1 | 33 || 34 | | | 0v | | |
| 19 | 24 | GPIO.24 | IN | 1 | 35 || 36 | 1 | IN | GPIO.27 | 27 | 16 |
| 26 | 25 | GPIO.25 | IN | 1 | 37 || 38 | 1 | IN | GPIO.28 | 28 | 20 |
| | | 0v | | | 39 || 40 | 1 | IN | GPIO.29 | 29 | 21 |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+---Pi 4+--+---+------+---------+-----+-----+
As you can see every pin is at logic state 1. Measuring it with a voltage meter also confirms this.
Does anyone has any idea on how can I modify the wiringPi library to be able to set the output values correctly?
Thanks
Gordon abandoned the Open Source side of wiringPi some time ago, and removed access to it completely.
I have reached out several times to him since then and I've yet to receive a response. I even went as far as to request paid access to his changes so that my own wrapper software can continue to work.
Apparently, you'll have to get access to the older source code and modify it yourself. There's this 'fork' of v2.46 that you could base the changes off of.
Do what Gordon says in this link and it works again:
cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb
Version 2.52 of wiringPi for Raspberry 4 (and the equivalent GPIO shell commands) helps a lot, but it does not properly implement pullUpDnControl(). As a result input-pins cannot be set to use internal pull-up/pull-down resistors.
Tested with GPIO/BCM pin 26 using
sudo raspi-gpio get | grep "GPIO 26"
shell command.
Tried to set pull-up/pull-down using:
pullUpDnControl(26, PUD_DOWN);
and
pullUpDnControl(26, PUD_UP);
under
wiringPiSetupGpio();
wiringPi setup in C.
No change reported using the "raspi-gpio" shell command.
Since the issue was a static setup failure for me, rather than give up on wiringPi completely I implemented a kludge work around. Since I could not get the equivalent GPIO shell command to work (for the same reason (as it is part of the wiringPi suite)), but Python has been maintained and works, I imbedded equivalent Python pin setup code in C, and thought it might be useful for someone (to keep wiringPi working through Raspberry Pi 4).
For those who might find this useful, here's test code. A 3-LED Cylon. LEDs attached to (resistor-buffered (200OHM)) ground on one end and each to a different pin (16, 20, and 21) on the other). A switch to ground on one end and pin 26 on the other. When the switch is pressed, the Cylon display turns into a glare from all 3 LEDs until the switch is released. Pin numbers are in the BCM series, shown by the shell command "gpio readall".
/* 3-LED Cylon testbed. Embedded Python GPIO pin setup code
* as a workaround to wiringPi v2.52 pullUpDnControl() bug.
* Send setup code to Python's stdin, as a short-lived child process.
* Sends Python equivalent to pullUpDnControl(26, PUD_UP); keeping
* the pin number (26) as a C #define.
* Use as needed.
* Alen Shapiro June 2020
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>
/* on */
#define FIX_GPIO 1 // replace pullUpDnControl on Raspberry Pi 4. Use Python as GPIO in the shell fails too */
#define MICRO_SLEEP (100*1000) /* 100 microseconds */
#define LOW 0
#define HIGH 1
/* BCM: gpio -g // wPi // Phys: gpio -1 */
#define LED1 16 // 27 // 36
#define LED2 20 // 28 // 38
#define LED3 21 // 29 // 40
#define PRESS 26 // 25 // 37
#if defined(FIX_GPIO)
struct fixGPIO {
char *pyLine;
int pin;
} fixGPIO[] = { // feed a three-argument fprintf() to popen() (so #define pins can be passed (one per line))
{ "import RPi.GPIO as GPIO\n", 0},
{ "GPIO.setmode(GPIO.BCM)\n", 0},
{ "GPIO.setwarnings(False)\n", 0},
{ "GPIO.setup(%d, GPIO.IN, pull_up_down=GPIO.PUD_UP)\n", PRESS},
{ (char *)NULL, 0}
};
FILE *pythonStream;
#endif /* defined(FIX_GPIO) */
int
main(void) {
int i;
wiringPiSetupGpio();
//wiringPiSetupPhys();
printf("Raspberry Pi 4 - direct Cylon Test\n");
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(PRESS, INPUT);
#if defined(FIX_GPIO)
if((pythonStream=popen("python", "w")) == NULL) {
fprintf(stderr, "Can't run python to set pin mode\n");
exit(1);
}
for(i=0 ; fixGPIO[i].pyLine ; i++)
fprintf(pythonStream, fixGPIO[i].pyLine, fixGPIO[i].pin);
pclose(pythonStream);
#else /* defined(FIX_GPIO) */
pullUpDnControl(PRESS, PUD_UP); /* fails on RPi-4 (as does shell GPIO) */
#endif /* defined(FIX_GPIO) */
while(1) {
if(digitalRead(PRESS) == LOW) { // Glaring Cylon
digitalWrite(LED1, HIGH);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, HIGH);
usleep(MICRO_SLEEP);
}
else { // Happy Cylon
digitalWrite(LED1, HIGH);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
usleep(MICRO_SLEEP);
digitalWrite(LED1, LOW);
digitalWrite(LED2, HIGH);
//digitalWrite(LED3, LOW);
usleep(MICRO_SLEEP);
//digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
digitalWrite(LED3, HIGH);
usleep(MICRO_SLEEP);
//digitalWrite(LED1, LOW);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, LOW);
usleep(MICRO_SLEEP);
}
}
}
Compiled with this Makefile:
CC=gcc
CLIBS= -lwiringPi
cylon: cylon.o
$(CC) -o cylon cylon.o $(CLIBS)
Here's a short live-photo of the Cylon testbed in action, ignore the Arduino which is just monitoring GPIO pin voltages (thanks John in Canada):
https://imgur.com/a/mlpr7Gr
ASIDE: Gordon... I'm sorry you've been put through the wringer by the lower end of a Gaussian Curve of people (just a tail, honest), and hope you're coming out the other end with sanity and health intact.
Although WiringPi is discontinued there was an unofficial patch (open-source is hard to kill, others will continue it).
Tested, and GPIO worked great on my RaspberryPi4 after applying that.
Patch:
diff -ruN wiringPi/wiringPi.c wiringPi/wiringPi.c
--- wiringPi/wiringPi.c
+++ wiringPi/wiringPi.c
## -215,6 +215,7 ## volatile unsigned int *_wiringPiTimerIrqRaw ;
#define GPIO_PERI_BASE_OLD 0x20000000
#define GPIO_PERI_BASE_NEW 0x3F000000
+#define GPIO_PERI_BASE_RP4 0xFE000000
static volatile unsigned int piGpioBase = 0 ;
## -547,6 +548,10 ## static uint8_t gpioToPUDCLK [] =
39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,
} ;
+#define PULLUPDN_OFFSET_2711_0 57
+#define PULLUPDN_OFFSET_2711_1 58
+#define PULLUPDN_OFFSET_2711_2 59
+#define PULLUPDN_OFFSET_2711_3 60
// gpioToPwmALT
// the ALT value to put a GPIO pin into PWM mode
## -814,7 +819,7 ## int piGpioLayout (void)
for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c)
*c = 0 ;
-
+
if (wiringPiDebug)
printf ("piGpioLayout: Revision string: %s\n", line) ;
## -883,7 +888,7 ## int piBoardRev (void)
* So the distinction between boards that I can see is:
*
* 0000 - Error
- * 0001 - Not used
+ * 0001 - Not used
*
* Original Pi boards:
* 0002 - Model B, Rev 1, 256MB, Egoman
## -955,6 +960,30 ## void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL)
piGpioLayoutOops ("Unable to open /proc/cpuinfo") ;
+ char buffer[12] ;
+ const char *ranges_file = "/proc/device-tree/soc/ranges" ;
+ int info_fd = open(ranges_file, O_RDONLY) ;
+
+ if (info_fd < 0) {
+ fprintf(stderr, "cannot open: %s", ranges_file) ;
+ exit (EXIT_FAILURE) ;
+ }
+
+ ssize_t n = read(info_fd, buffer, sizeof(buffer)) ;
+ close(info_fd) ;
+
+ if (n < 8) {
+ fprintf(stderr, "cannot read base address: %s", ranges_file) ;
+ exit (EXIT_FAILURE) ;
+ }
+
+ uint32_t gpio_base = (buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + (buffer[7] << 0) ;
+
+ if (!gpio_base)
+ {
+ gpio_base = (buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + (buffer[11] << 0) ;
+ }
+
while (fgets (line, 120, cpuFd) != NULL)
if (strncmp (line, "Revision", 8) == 0)
break ;
## -968,7 +997,7 ## void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c)
*c = 0 ;
-
+
if (wiringPiDebug)
printf ("piBoardId: Revision string: %s\n", line) ;
## -1007,7 +1036,7 ## void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
bMfg = (revision & (0x0F << 16)) >> 16 ;
bMem = (revision & (0x07 << 20)) >> 20 ;
bWarranty = (revision & (0x03 << 24)) != 0 ;
-
+
*model = bType ;
*rev = bRev ;
*mem = bMem ;
## -1034,7 +1063,7 ## void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
// If longer than 4, we'll assume it's been overvolted
*warranty = strlen (c) > 4 ;
-
+
// Extract last 4 characters:
c = c + strlen (c) - 4 ;
## -1073,8 +1102,11 ## void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
else { *model = 0 ; *rev = 0 ; *mem = 0 ; *maker = 0 ; }
}
+ if (gpio_base == GPIO_PERI_BASE_RP4) {
+ *model = PI_MODEL_4;
+ }
}
-
+
/*
## -1205,6 +1237,10 ## void pwmSetRange (unsigned int range)
void pwmSetClock (int divisor)
{
uint32_t pwm_control ;
+
+ if(piGpioBase == GPIO_PERI_BASE_RP4) {
+ divisor = 540*divisor/192;
+ }
divisor &= 4095 ;
if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO))
## -1260,7 +1296,7 ## void gpioClockSet (int pin, int freq)
pin = physToGpio [pin] ;
else if (wiringPiMode != WPI_MODE_GPIO)
return ;
-
+
divi = 19200000 / freq ;
divr = 19200000 % freq ;
divf = (int)((double)divr * 4096.0 / 19200000.0) ;
## -1504,11 +1540,31 ## void pullUpDnControl (int pin, int pud)
else if (wiringPiMode != WPI_MODE_GPIO)
return ;
- *(gpio + GPPUD) = pud & 3 ; delayMicroseconds (5) ;
- *(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ; delayMicroseconds (5) ;
-
- *(gpio + GPPUD) = 0 ; delayMicroseconds (5) ;
- *(gpio + gpioToPUDCLK [pin]) = 0 ; delayMicroseconds (5) ;
+ // Check GPIO register
+ int is2711 = *(gpio + PULLUPDN_OFFSET_2711_3) != 0x6770696f;
+ if(is2711) {
+ // Pi 4 Pull-up/down method
+ int pullreg = PULLUPDN_OFFSET_2711_0 + (pin >> 4);
+ int pullshift = (pin & 0xf) << 1;
+ unsigned int pullbits;
+ unsigned int pull = 0; // Turn PUD off by default
+ if (pud == PUD_UP) {
+ pull = 1;
+ } else if (pud == PUD_DOWN) {
+ pull = 2;
+ }
+ pullbits = *(gpio + pullreg);
+ pullbits &= ~(3 << pullshift);
+ pullbits |= (pull << pullshift);
+ *(gpio + pullreg) = pullbits;
+ } else {
+ // Legacy Pull-up/down method
+ *(gpio + GPPUD) = pud & 3 ; delayMicroseconds (5) ;
+ *(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ; delayMicroseconds (5) ;
+
+ *(gpio + GPPUD) = 0 ; delayMicroseconds (5) ;
+ *(gpio + gpioToPUDCLK [pin]) = 0 ; delayMicroseconds (5) ;
+ }
}
else // Extension module
{
## -1680,7 +1736,7 ## void pwmWrite (int pin, int value)
/*
* analogRead:
- * Read the analog value of a given Pin.
+ * Read the analog value of a given Pin.
* There is no on-board Pi analog hardware,
* so this needs to go to a new node.
*********************************************************************************
## -1699,7 +1755,7 ## int analogRead (int pin)
/*
* analogWrite:
- * Write the analog value to the given Pin.
+ * Write the analog value to the given Pin.
* There is no on-board Pi analog hardware,
* so this needs to go to a new node.
*********************************************************************************
## -1748,7 +1804,7 ## void pwmToneWrite (int pin, int freq)
* Write an 8-bit byte to the first 8 GPIO pins - try to do it as
* fast as possible.
* However it still needs 2 operations to set the bits, so any external
- * hardware must not rely on seeing a change as there will be a change
+ * hardware must not rely on seeing a change as there will be a change
* to set the outputs bits to zero, then another change to set the 1's
* Reading is just bit fiddling.
* These are wiringPi pin numbers 0..7, or BCM_GPIO pin numbers
## -1804,7 +1860,7 ## unsigned int digitalReadByte (void)
data = (data << 1) | x ;
}
}
- else
+ else
{
raw = *(gpio + gpioToGPLEV [0]) ; // First bank for these pins
for (pin = 0 ; pin < 8 ; ++pin)
## -1861,7 +1917,7 ## unsigned int digitalReadByte2 (void)
data = (data << 1) | x ;
}
}
- else
+ else
data = ((*(gpio + gpioToGPLEV [0])) >> 20) & 0xFF ; // First bank for these pins
return data ;
## -2265,6 +2321,9 ## int wiringPiSetup (void)
case PI_MODEL_ZERO: case PI_MODEL_ZERO_W:
piGpioBase = GPIO_PERI_BASE_OLD ;
break ;
+ case PI_MODEL_4:
+ piGpioBase = GPIO_PERI_BASE_RP4 ;
+ break ;
default:
piGpioBase = GPIO_PERI_BASE_NEW ;
## -2273,7 +2332,7 ## int wiringPiSetup (void)
// Open the master /dev/ memory control device
// Device strategy: December 2016:
-// Try /dev/mem. If that fails, then
+// Try /dev/mem. If that fails, then
// try /dev/gpiomem. If that fails then game over.
if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0)
## -2311,13 +2370,13 ## int wiringPiSetup (void)
pwm = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PWM) ;
if (pwm == MAP_FAILED)
return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (PWM) failed: %s\n", strerror (errno)) ;
-
+
// Clock control (needed for PWM)
clk = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_CLOCK_BASE) ;
if (clk == MAP_FAILED)
return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (CLOCK) failed: %s\n", strerror (errno)) ;
-
+
// The drive pads
pads = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PADS) ;
## -2437,7 +2496,7 ## int wiringPiSetupSys (void)
// Open and scan the directory, looking for exported GPIOs, and pre-open
// the 'value' interface to speed things up for later
-
+
for (pin = 0 ; pin < 64 ; ++pin)
{
sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
diff -ruN wiringPi/wiringPi.h wiringPi/wiringPi.h
--- wiringPi/wiringPi.h
+++ wiringPi/wiringPi.h
## -100,6 +100,7 ##
#define PI_MODEL_CM3 10
#define PI_MODEL_ZERO_W 12
#define PI_MODEL_3P 13
+#define PI_MODEL_4 14
#define PI_VERSION_1 0
#define PI_VERSION_1_1 1
Note that the patch should be executed inside of Wiring-Pi root (outside of it's wiringPi sub-directory).
Also, this is a copy of my other answer on RaspberryPi.StackExchange.com, and is not related to https://github.com/WiringPi/WiringPi (although, they are free to apply this, too).
Short version
What's the reasoning behind the mapper sometimes using ? and other times using ☐?
Unicode: €‚„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ
In 850: ?'".┼╬^%S<OZ''""☐--~Ts>ozY
^\_____________/^\_______/
| | | |
| best fit | best fit
| |
replacement replacement
CS Fiddle
Long Version
I was encoding some text to code page 850, and while a lot of characters that users use exist perfectly in the 850 code page, there are some that don't match exactly. Instead the mapper (e.g. .NET System.Text.Encoding, or Winapi WideStringToMultiByte) provides a best fit:
| Character | In code-page 850 |
|-----------|------------------|
| | |
| | |
| ‚ U+201A | ' |
| | |
| „ U+201E | " |
| … U+2026 | . |
| † U+2020 | ┼ |
| ‡ U+2021 | ╬ |
| ˆ U+02C6 | ^ |
| ‰ U+2030 | % |
| Š U+0160 | S |
| ‹ U+2039 | < |
| Œ U+0152 | O |
| | |
| Ž U+017D | Z |
| | |
| | |
| ‘ U+2018 | ' |
| ’ U+2019 | ' |
| “ U+201C | " |
| ” U+201D | " |
| | |
| – U+2013 | - |
| — U+2014 | - |
| ˜ U+02DC | ~ |
| ™ U+2122 | T |
| š U+0161 | s |
| › U+203A | > |
| œ U+0153 | o |
| | |
| ž U+017E | z |
| Ÿ U+0178 | Y |
These best fits are right, good, appropriate, wanted, and entirely reasonable:.
But some characters do not map:
| Character | In code-page 850 |
|-----------|------------------|
| € U+20AC | ? 0x37 | literally 0x37 (i.e. U+003F Question Mark)
| • U+2022 | ☐ 0x07 | literally 0x07 (i.e. U+0007 BELL)
What's the deal?
Why is it sometimes a question mark, and other times a ␇?
Note: This lack of mapping isn't terribly important to me. If the federal government doesn't support a reasonable encoding, then they'll take the garbage i give them. So i'm fine with it.
A problem comes later when i try to call MultiByteToWideChar to reverse the mapping, and the function fails due to invalid characters. And while i can try to figure out the issue with reverse encoding back into characters later; i'm curious what the encoding mapper is trying to tell me.
Bonus fun
The careful observer will understand why i chose the characters i did, in the order i did, and why there are gaps. I didn't want to mention it so as to confuse readers of the question.
The answer is both subtle, and obvious.
When performing a mapping, the encoder tries to perform a best-fit. And so while a lot of the characters don't exist in the target code-page; they can be approximated well enough.
Some characters don't have any equivalent, nor any best-fit mapping, and so are simply replaced with ?.
U+0037 QUESTION MARK
So the text:
The price of petrol is € 1.56 in Germany.
Will unfortunately become:
The price of petrol is ? 1.56 in Germany.
The question mark means that the character has no equivalent and was just lost.
The other character is more subtle
In ASCII, the first 32 characters are control characters, e.g.
13: Carriage Return (␍)
10: Line Feed (␊)
9: Horizontal Tab (␉)
11: Vertical Tab (␋)
7: Bell (␇)
27: Escape (␛)
30: Record Separator (␞)
These control code are generally unprintable. But code page 437 did something unique: they defined characters for those first 32 codes:
13: Eighth note (♪)
10: Inverse white circle (◙)
9: White circle (○)
11: Male Sign (♂)
7: Bullet (•)
27: Right Angle (∟)
30: Black up-pointing triangle (▲)
This has interesting implications if you had some text such as:
The price of petrol␍␊
• Germany: €1.56␍␊
• France: €1.49
When encoded in Code Page 850 becomes:
The price of petrol♪◙• Germany: ?1.56♪◙• France: €1.49
Notice 3 things:
The € symbol was lost; replaced with ?
The • symbol was retained
The CR LF symbols were lost; replaced with ♪ and ◙
Trying to decode the code page 437/850 back to real characters presents a problem:
If i want to retain my CRLF, i have to assume that the characters in the 1..32 range actually are ASCII control characters
The price of petrol␍␊
␇ Germany: €1.56␍␊
␇ France: €1.49
If i want to retain my characters (e.g. ¶, •, §) , i have to permanently lose my CRLF, and assume that the characters in 1..32 are actually characters:
The price of petrol♪◙• Germany: €1.56♪◙• France: €1.49
There's no good way out of this.
Ideally Code Page 437 would not have done this to the first 32 characters in the code page, and kept the control characters. And ideally anyone trying to convert the text to 437:
• The price of petrol is € 1.56 in Germany ♪sad song♪
would come back with
? The price of petrol is ? 1.56 in Germany ?sad song?
But that's not what the 437 code page is.
It's a horrible mess; where you have to pick your poison and die slowly.
Rest in Peace Michael Kaplan
This answer brought to you by "☼" (U+263c, a.k.a. WHITE SUN WITH RAYS)
A proud member of the glyph chars collection for more years than Seattle has seen sun
See Michael Kaplan's archived blog entry (🕗):
What the &%#$ does MB_USEGLYPHCHARS do?
I'm still angry at the Microsoft PM who shut down his blog out of spite.
I was reading up on perlvar when i came across this -
The status returned by the last pipe close, backtick (`` ) command, successful call to wait() or waitpid(), or from the system() operator. This is just the 16-bit status word returned by the traditional Unix wait() system call (or else is made up to look like it). Thus, the exit value of the subprocess is really ($?>> 8 ), and $? & 127 gives which signal
What is a 16-bit status word? what does the operation '$?>> 8' signify? and how does a 16-bit word like '512' get converted to '2' after i do '$?>> 8' on it?
A 16-bit word is merely an amount of memory 16-bits in size. The word "word" implies the CPU can read it from memory with one instruction. (e.g. I worked on a machine that had 64K bytes of memory, but the CPU could only access it as 32K 16-bit words.)
Interpreted as an unsigned integer, an 16-bit word would look like a number between 0 and 216-1 = 65,535, but it's not necessarily an unsigned integer. In the case of $?, it's used to stored three unsigned integers.
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 15| 14| 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
\-----------------------------/ \-/ \-------------------------/
Exit code core Signal that killed
(0..255) dumped (0..127)
(0..1)
If the OS wants to return "Exited with error code 2", it sets $? to (2 << 8) | (0 << 7) | (0 << 0).
+---+---+---+---+---+---+---+---+
| 2 | << 8
+---+---+---+---+---+---+---+---+
+---+
| 0 | << 7
+---+
+---+---+---+---+---+---+---+
| 0 | << 0
+---+---+---+---+---+---+---+
=================================================================
+---+---+---+---+---+---+---+---+
| 2 |
+---+---+---+---+---+---+---+---+
+---+
| 0 |
+---+
+---+---+---+---+---+---+---+
| 0 |
+---+---+---+---+---+---+---+
=================================================================
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 2 | 0 | 0 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
If the OS wants to return "killed by signal 5; core dumped", it sets $? to (0 << 8) | (1 << 7) | (5 << 0).
+---+---+---+---+---+---+---+---+
| 0 | << 8
+---+---+---+---+---+---+---+---+
+---+
| 1 | << 7
+---+
+---+---+---+---+---+---+---+
| 5 | << 0
+---+---+---+---+---+---+---+
=================================================================
+---+---+---+---+---+---+---+---+
| 0 |
+---+---+---+---+---+---+---+---+
+---+
| 1 |
+---+
+---+---+---+---+---+---+---+
| 5 |
+---+---+---+---+---+---+---+
=================================================================
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 | 1 | 5 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
$? >> 8 is simply doing the reverse operation.
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 2 | 0 | 0 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
>> 8
=================================================================
+---+---+---+---+---+---+---+---+
| 2 |
+---+---+---+---+---+---+---+---+
It returns the number stored in bits 8 and up.
A 16-bit value is a value that can be stored in sixteen binary bits. In hex that is 0 through to FFFF, or 65,535 in decimal.
A 16-bit status word is the value supplied by the Unix wait call that combines the process's exit status in the left-hand (most-significant) eight bits, a single bit indicating whether a core dump of the terminated process was produced, and the number of the signal, if any, that caused it to terminate in the right-hand (least-significant) seven bits.
Conventionally a zero value for the exit status indicates that the process has been successful, while a non-zero value indicates some sort of failure or informational state.
$? >> 8 indicates shifting the value to the right by eight bits, losing the right-hand (least-significant) eight bits (i.e. the core dump bit and signal number) and leaving the left-hand eight bits (the exit status). This is equivalent to dividing by 28 or 256.
Since $? >> 8 is equivalent to dividing $? by 28 or 256, if $? is 512 then $? >> 8 is 512 / 256, giving an exit status of 2.