From eed745eaca8af2a5f8a7a4e40e84828b8c155dc8 Mon Sep 17 00:00:00 2001 From: Uri Shaked Date: Sun, 10 May 2020 09:01:53 +0300 Subject: feat(gpio): add setPin() function close #26 --- src/peripherals/gpio.spec.ts | 23 +++++++++++++++++++++++ src/peripherals/gpio.ts | 20 ++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/peripherals/gpio.spec.ts b/src/peripherals/gpio.spec.ts index f3b1a0f..1dfaf7d 100644 --- a/src/peripherals/gpio.spec.ts +++ b/src/peripherals/gpio.spec.ts @@ -93,4 +93,27 @@ describe('GPIO', () => { expect(listener).toHaveBeenCalled(); }); }); + + describe('setPin', () => { + it('should set the value of the given pin', () => { + const cpu = new CPU(new Uint16Array(1024)); + const port = new AVRIOPort(cpu, portBConfig); + cpu.writeData(0x24, 0); // DDRB <- 0 + port.setPin(4, true); + expect(cpu.data[0x23]).toEqual(0x10); + port.setPin(4, false); + expect(cpu.data[0x23]).toEqual(0x0); + }); + + it('should only update PIN register when pin in Input mode', () => { + const cpu = new CPU(new Uint16Array(1024)); + const port = new AVRIOPort(cpu, portBConfig); + cpu.writeData(0x24, 0x10); // DDRB <- 0x10 + cpu.writeData(0x25, 0x0); // PORTB <- 0x0 + port.setPin(4, true); + expect(cpu.data[0x23]).toEqual(0x0); + cpu.writeData(0x24, 0x0); // DDRB <- 0x0 + expect(cpu.data[0x23]).toEqual(0x10); + }); + }); }); diff --git a/src/peripherals/gpio.ts b/src/peripherals/gpio.ts index ba3217b..e3c8eaa 100644 --- a/src/peripherals/gpio.ts +++ b/src/peripherals/gpio.ts @@ -92,10 +92,12 @@ export enum PinState { export class AVRIOPort { private listeners: GPIOListener[] = []; + private pinValue: u8 = 0; constructor(private cpu: CPU, private portConfig: AVRPortConfig) { cpu.writeHooks[portConfig.DDR] = (value, oldValue) => { const portValue = cpu.data[portConfig.PORT]; + this.updatePinRegister(portValue, value); this.writeGpio(value & portValue, oldValue & oldValue); }; cpu.writeHooks[portConfig.PORT] = (value: u8, oldValue: u8) => { @@ -103,6 +105,7 @@ export class AVRIOPort { cpu.data[portConfig.PORT] = value; value &= ddrMask; cpu.data[portConfig.PIN] = (cpu.data[portConfig.PIN] & ~ddrMask) | value; + this.updatePinRegister(value, ddrMask); this.writeGpio(value, oldValue & ddrMask); return true; }; @@ -145,6 +148,23 @@ export class AVRIOPort { } } + /** + * Sets the input value for the given pin. This is the value that + * will be returned when reading from the PIN register. + */ + setPin(index: number, value: boolean) { + const bitMask = 1 << index; + this.pinValue &= ~bitMask; + if (value) { + this.pinValue |= bitMask; + } + this.updatePinRegister(this.cpu.data[this.portConfig.PORT], this.cpu.data[this.portConfig.DDR]); + } + + private updatePinRegister(port: u8, ddr: u8) { + this.cpu.data[this.portConfig.PIN] = (this.pinValue & ~ddr) | (port & ddr); + } + private writeGpio(value: u8, oldValue: u8) { for (const listener of this.listeners) { listener(value, oldValue); -- cgit v1.2.3