package rpio import ( "fmt" "os" "testing" "time" ) func TestMain(m *testing.M) { println("Note: bcm pins 2 and 3 has to be directly connected") if err := Open(); err != nil { panic(err) } defer Close() os.Exit(m.Run()) } func TestInterrupt(t *testing.T) { logIrqRegs(t) EnableIRQs(1 << 49) EnableIRQs(1 << 50) EnableIRQs(1 << 51) EnableIRQs(1 << 52) logIrqRegs(t) DisableIRQs(1 << 49) DisableIRQs(1 << 50) DisableIRQs(1 << 51) DisableIRQs(1 << 52) logIrqRegs(t) EnableIRQs(irqsBackup) } func TestEvent(t *testing.T) { src := Pin(3) src.Mode(Output) pin := Pin(2) pin.Mode(Input) pin.PullDown() t.Run("rising edge", func(t *testing.T) { pin.Detect(RiseEdge) src.Low() for i := 0; ; i++ { src.High() time.Sleep(time.Second / 10) if pin.EdgeDetected() { t.Log("edge rised") } else { t.Errorf("Rise event should be detected") } if i == 5 { break } src.Low() } time.Sleep(time.Second / 10) if pin.EdgeDetected() { t.Error("Rise should not be detected, no change since last call") } pin.Detect(NoEdge) src.High() if pin.EdgeDetected() { t.Error("Rise should not be detected, events disabled") } }) t.Run("falling edge", func(t *testing.T) { pin.Detect(FallEdge) src.High() for i := 0; ; i++ { src.Low() time.Sleep(time.Second / 10) if pin.EdgeDetected() { t.Log("edge fallen") } else { t.Errorf("Fall event should be detected") } if i == 5 { break } src.High() } time.Sleep(time.Second / 10) if pin.EdgeDetected() { t.Error("Fall should not be detected, no change since last call") } pin.Detect(NoEdge) src.Low() if pin.EdgeDetected() { t.Error("Fall should not be detected, events disabled") } }) t.Run("both edges", func(t *testing.T) { pin.Detect(AnyEdge) src.Low() for i := 0; i < 5; i++ { src.High() if pin.EdgeDetected() { t.Log("edge detected") } else { t.Errorf("Rise event shoud be detected") } src.Low() if pin.EdgeDetected() { t.Log("edge detected") } else { t.Errorf("Fall edge should be detected") } } pin.Detect(NoEdge) src.High() src.Low() if pin.EdgeDetected() { t.Errorf("No edge should be detected, events disabled") } }) // If this frā½eezes your pi, // add `dtoverlay=gpio-no-irq` to `/boot/config.txt` and restart your pi, // or run as root. t.Run("multiple edges", func(t *testing.T) { EnableIRQs(15 << 49) // all 4 gpio_int[] logIrqRegs(t) src.High() pin.Detect(FallEdge) logIrqRegs(t) for i := 0; i < 10000; i++ { time.Sleep(time.Millisecond) src.High() time.Sleep(time.Millisecond) src.Low() } logIrqRegs(t) if !pin.EdgeDetected() { t.Errorf("Edge not detected") } logIrqRegs(t) pin.Detect(NoEdge) logIrqRegs(t) EnableIRQs(irqsBackup) }) } func BenchmarkGpio(b *testing.B) { src := Pin(3) src.Mode(Output) src.Low() pin := Pin(2) pin.Mode(Input) pin.PullDown() oldWrite := func(pin Pin, state State) { p := uint8(pin) setReg := p/32 + 7 clearReg := p/32 + 10 memlock.Lock() defer memlock.Unlock() if state == Low { gpioMem[clearReg] = 1 << (p & 31) } else { gpioMem[setReg] = 1 << (p & 31) } } oldToggle := func(pin Pin) { switch ReadPin(pin) { case Low: oldWrite(pin, High) case High: oldWrite(pin, Low) } } b.Run("write", func(b *testing.B) { b.Run("old", func(b *testing.B) { for i := 0; i < b.N; i++ { if i%2 == 0 { oldWrite(src, High) } else { oldWrite(src, Low) } } }) b.Run("new", func(b *testing.B) { for i := 0; i < b.N; i++ { if i%2 == 0 { WritePin(src, High) } else { WritePin(src, Low) } } }) }) b.Run("toggle", func(b *testing.B) { b.Run("old", func(b *testing.B) { for i := 0; i < b.N; i++ { oldToggle(src) } }) b.Run("new", func(b *testing.B) { for i := 0; i < b.N; i++ { TogglePin(src) } }) }) } func logIrqRegs(t *testing.T) { fmt.Printf("PENDING(% X) FIQ(% X) ENAB(% X) DISAB(% X)\n", intrMem8[0x200:0x20C], intrMem8[0x20C:0x210], intrMem8[0x210:0x21C], intrMem8[0x21C:0x228], ) }