├── p1am-isolated-rs485 ├── sketches │ ├── p1am-100-iso-rs485 │ │ ├── macaddr.h │ │ ├── macaddr.cpp │ │ └── p1am-100-iso-rs485.ino │ ├── p1am-100-iso-rs485-receiver │ │ ├── macaddr.h │ │ ├── macaddr.cpp │ │ └── p1am-100-iso-rs485-receiver.ino │ └── p1am-100-iso-rs485-sender │ │ ├── macaddr.h │ │ ├── macaddr.cpp │ │ └── p1am-100-iso-rs485-sender.ino └── boards │ └── v1 │ ├── p1am-proto-iso-rs485-board.png │ ├── p1am-proto-iso-rs485-bom.xlsx │ └── p1am-proto-iso-rs485-schematic.png ├── p1am-isolated-2x2-gpio ├── sketches │ ├── p1am-100-garage-door-monitor │ │ ├── macaddr.h │ │ ├── charrom.h │ │ ├── macaddr.cpp │ │ ├── display.h │ │ ├── charrom.cpp │ │ ├── display.cpp │ │ └── p1am-100-garage-door-monitor.ino │ └── p1am-100-proto-kitchen-sink │ │ ├── charrom.h │ │ ├── display.h │ │ ├── samd21dmx.h │ │ ├── samd21dmx.cpp │ │ ├── charrom.cpp │ │ ├── p1am-100-proto-kitchen-sink.ino │ │ └── display.cpp └── boards │ └── v1 │ └── P1AM-ISOLATED-2X2-GPIO-BOM.xlsx ├── README.md └── LICENSE /p1am-isolated-rs485/sketches/p1am-100-iso-rs485/macaddr.h: -------------------------------------------------------------------------------- 1 | void ReadMacAddress (uint8_t cs_pin, uint8_t *address); 2 | -------------------------------------------------------------------------------- /p1am-isolated-rs485/sketches/p1am-100-iso-rs485-receiver/macaddr.h: -------------------------------------------------------------------------------- 1 | void ReadMacAddress (uint8_t cs_pin, uint8_t *address); 2 | -------------------------------------------------------------------------------- /p1am-isolated-rs485/sketches/p1am-100-iso-rs485-sender/macaddr.h: -------------------------------------------------------------------------------- 1 | void ReadMacAddress (uint8_t cs_pin, uint8_t *address); 2 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-garage-door-monitor/macaddr.h: -------------------------------------------------------------------------------- 1 | void ReadMacAddress (uint8_t cs_pin, uint8_t *address); 2 | -------------------------------------------------------------------------------- /p1am-isolated-rs485/boards/v1/p1am-proto-iso-rs485-board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikerglen/p1am-proto-experiments/HEAD/p1am-isolated-rs485/boards/v1/p1am-proto-iso-rs485-board.png -------------------------------------------------------------------------------- /p1am-isolated-rs485/boards/v1/p1am-proto-iso-rs485-bom.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikerglen/p1am-proto-experiments/HEAD/p1am-isolated-rs485/boards/v1/p1am-proto-iso-rs485-bom.xlsx -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-garage-door-monitor/charrom.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHARROM_H__ 2 | #define __CHARROM_H__ 3 | 4 | extern const unsigned char charrom[128][5]; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-proto-kitchen-sink/charrom.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHARROM_H__ 2 | #define __CHARROM_H__ 3 | 4 | extern const unsigned char charrom[128][5]; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/boards/v1/P1AM-ISOLATED-2X2-GPIO-BOM.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikerglen/p1am-proto-experiments/HEAD/p1am-isolated-2x2-gpio/boards/v1/P1AM-ISOLATED-2X2-GPIO-BOM.xlsx -------------------------------------------------------------------------------- /p1am-isolated-rs485/boards/v1/p1am-proto-iso-rs485-schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bikerglen/p1am-proto-experiments/HEAD/p1am-isolated-rs485/boards/v1/p1am-proto-iso-rs485-schematic.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # p1am-proto-experiments 2 | Various board and libraries to fit the Automation Direct P1AM-PROTO enclosure. 3 | Everything here is untested. Use at your own risk. I'll accept pull requests with any corrections or other contributions. 4 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-proto-kitchen-sink/display.h: -------------------------------------------------------------------------------- 1 | class Display 2 | { 3 | private: 4 | 5 | uint8_t cs_pin, rs_pin, blank_pin, reset_pin; 6 | 7 | 8 | public: 9 | 10 | Display (void); 11 | 12 | ~Display (void); 13 | 14 | void begin (uint8_t cs_pin, uint8_t rs_pin, uint8_t blank_pin, uint8_t reset_pin); 15 | 16 | void write (String s); 17 | 18 | void scrollMessage (String s); 19 | bool scrollBusy (void); 20 | 21 | bool tick (void *); 22 | }; 23 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-garage-door-monitor/macaddr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static SPISettings eepromSPISettings (1000000, MSBFIRST, SPI_MODE0); 4 | 5 | void ReadMacAddress (uint8_t cs_pin, uint8_t *address) 6 | { 7 | SPI.beginTransaction (eepromSPISettings); 8 | digitalWrite (cs_pin, 0); 9 | SPI.transfer (0x03); 10 | SPI.transfer (0xFA); 11 | for (uint8_t i = 0; i < 6; i++) { 12 | address[i] = SPI.transfer (0x00); 13 | } 14 | digitalWrite (cs_pin, 1); 15 | SPI.endTransaction (); 16 | } 17 | -------------------------------------------------------------------------------- /p1am-isolated-rs485/sketches/p1am-100-iso-rs485/macaddr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "macaddr.h" 3 | 4 | static SPISettings eepromSPISettings (1000000, MSBFIRST, SPI_MODE0); 5 | 6 | void ReadMacAddress (uint8_t cs_pin, uint8_t *address) 7 | { 8 | SPI.beginTransaction (eepromSPISettings); 9 | digitalWrite (cs_pin, 0); 10 | SPI.transfer (0x03); 11 | SPI.transfer (0xFA); 12 | for (uint8_t i = 0; i < 6; i++) { 13 | address[i] = SPI.transfer (0x00); 14 | } 15 | digitalWrite (cs_pin, 1); 16 | SPI.endTransaction (); 17 | } 18 | -------------------------------------------------------------------------------- /p1am-isolated-rs485/sketches/p1am-100-iso-rs485-receiver/macaddr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "macaddr.h" 3 | 4 | static SPISettings eepromSPISettings (1000000, MSBFIRST, SPI_MODE0); 5 | 6 | void ReadMacAddress (uint8_t cs_pin, uint8_t *address) 7 | { 8 | SPI.beginTransaction (eepromSPISettings); 9 | digitalWrite (cs_pin, 0); 10 | SPI.transfer (0x03); 11 | SPI.transfer (0xFA); 12 | for (uint8_t i = 0; i < 6; i++) { 13 | address[i] = SPI.transfer (0x00); 14 | } 15 | digitalWrite (cs_pin, 1); 16 | SPI.endTransaction (); 17 | } 18 | -------------------------------------------------------------------------------- /p1am-isolated-rs485/sketches/p1am-100-iso-rs485-sender/macaddr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "macaddr.h" 3 | 4 | static SPISettings eepromSPISettings (1000000, MSBFIRST, SPI_MODE0); 5 | 6 | void ReadMacAddress (uint8_t cs_pin, uint8_t *address) 7 | { 8 | SPI.beginTransaction (eepromSPISettings); 9 | digitalWrite (cs_pin, 0); 10 | SPI.transfer (0x03); 11 | SPI.transfer (0xFA); 12 | for (uint8_t i = 0; i < 6; i++) { 13 | address[i] = SPI.transfer (0x00); 14 | } 15 | digitalWrite (cs_pin, 1); 16 | SPI.endTransaction (); 17 | } 18 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-garage-door-monitor/display.h: -------------------------------------------------------------------------------- 1 | class Display 2 | { 3 | private: 4 | 5 | uint8_t cs_pin, rs_pin, blank_pin, reset_pin; 6 | 7 | 8 | public: 9 | 10 | Display (void); 11 | 12 | ~Display (void); 13 | 14 | void begin (uint8_t cs_pin, uint8_t rs_pin, uint8_t blank_pin, uint8_t reset_pin); 15 | 16 | void write (String s); 17 | 18 | void scrollMessage (String s, bool reset); 19 | bool scrollBusy (void); 20 | 21 | bool tick (void *); 22 | 23 | void heartbeat (uint8_t col, uint8_t row); 24 | }; 25 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-proto-kitchen-sink/samd21dmx.h: -------------------------------------------------------------------------------- 1 | // loosely based on LXSAMD21DMX by Claude Heintz 2 | 3 | #ifndef __samd21dmx_h_ 4 | #define __samd21dmx_h_ 5 | 6 | #define DMX_SLOTS 96 7 | 8 | #define DMX_BREAK_BAUD 90000 9 | #define DMX_DATA_BAUD 250000 10 | 11 | #define DMX_STATE_BREAK 0 12 | #define DMX_STATE_START 1 13 | #define DMX_STATE_DATA 2 14 | #define DMX_STATE_IDLE 3 15 | 16 | class samd21dmx { 17 | 18 | public: 19 | 20 | samd21dmx (); 21 | ~samd21dmx (); 22 | 23 | void begin (void); 24 | void tx (uint8_t *txslots); 25 | void transmissionComplete (void); 26 | void dataRegisterEmpty (void); 27 | 28 | bool busy; 29 | uint8_t state; 30 | uint16_t next_send_slot; 31 | uint8_t slots[DMX_SLOTS]; 32 | }; 33 | 34 | extern samd21dmx dmx; 35 | extern Uart SerialDMX; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Glen Akins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | If you want to buy me a beer and tell me about your project sometime, 16 | that would be appreciated too. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-proto-kitchen-sink/samd21dmx.cpp: -------------------------------------------------------------------------------- 1 | // loosely based on LXSAMD21DMX by Claude Heintz 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "samd21dmx.h" 9 | 10 | samd21dmx dmx; 11 | 12 | Uart SerialDMX (&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); 13 | 14 | void SERCOM5_Handler () 15 | { 16 | // digitalWrite (11, HIGH); 17 | 18 | if ( SERCOM5->USART.INTFLAG.bit.TXC ) { 19 | dmx.transmissionComplete(); 20 | } else if ( SERCOM5->USART.INTFLAG.bit.DRE ) { 21 | dmx.dataRegisterEmpty(); 22 | } 23 | 24 | // digitalWrite (11, LOW); 25 | } 26 | 27 | void setBaudRate (uint32_t baudrate) 28 | { 29 | SERCOM5->USART.CTRLA.bit.ENABLE = 0x0u; 30 | uint16_t sampleRateValue = 16; 31 | uint32_t baudTimes8 = (SystemCoreClock * 8) / (sampleRateValue * baudrate); 32 | SERCOM5->USART.BAUD.FRAC.FP = (baudTimes8 % 8); 33 | SERCOM5->USART.BAUD.FRAC.BAUD = (baudTimes8 / 8); 34 | SERCOM5->USART.CTRLA.bit.ENABLE = 0x1u; 35 | } 36 | 37 | samd21dmx::samd21dmx () 38 | { 39 | } 40 | 41 | samd21dmx::~samd21dmx () 42 | { 43 | } 44 | 45 | void samd21dmx::begin (void) 46 | { 47 | SerialDMX.begin (250000, SERIAL_8N2); 48 | SERCOM5->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_RXC | 49 | SERCOM_USART_INTENCLR_ERROR; 50 | 51 | pinPeripheral (0ul, PIO_SERCOM_ALT); 52 | pinPeripheral (1ul, PIO_SERCOM_ALT); 53 | this->busy = false; 54 | this->state = DMX_STATE_BREAK; 55 | this->next_send_slot = DMX_SLOTS; 56 | } 57 | 58 | void samd21dmx::tx (uint8_t *txslots) 59 | { 60 | if (!this->busy) { 61 | this->busy = true; 62 | for (int i = 0; i < DMX_SLOTS; i++) { 63 | this->slots[i] = txslots[i]; 64 | } 65 | this->state = DMX_STATE_BREAK; 66 | transmissionComplete (); 67 | } 68 | } 69 | 70 | void samd21dmx::transmissionComplete (void) 71 | { 72 | if (this->state == DMX_STATE_BREAK) { 73 | setBaudRate (DMX_BREAK_BAUD); 74 | this->state = DMX_STATE_START; 75 | next_send_slot = 0; 76 | SERCOM5->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE; 77 | SERCOM5->USART.INTENSET.reg = SERCOM_USART_INTENSET_TXC; 78 | SERCOM5->USART.DATA.reg = 0; 79 | } else if (this->state == DMX_STATE_IDLE) { 80 | SERCOM5->USART.INTFLAG.bit.TXC = 1; 81 | SERCOM5->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE; 82 | SERCOM5->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_TXC; 83 | this->state = DMX_STATE_BREAK; 84 | this->busy = false; 85 | } else if (this->state == DMX_STATE_START) { 86 | setBaudRate(DMX_DATA_BAUD); 87 | this->state = DMX_STATE_DATA; 88 | SERCOM5->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_TXC; 89 | SERCOM5->USART.INTENSET.reg = SERCOM_USART_INTENSET_DRE; 90 | SERCOM5->USART.DATA.reg = 0; 91 | } 92 | } 93 | 94 | void samd21dmx::dataRegisterEmpty (void) 95 | { 96 | if (next_send_slot < DMX_SLOTS) { 97 | SERCOM5->USART.DATA.reg = this->slots[next_send_slot++]; 98 | } else { 99 | this->state = DMX_STATE_IDLE; 100 | SERCOM5->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE; 101 | SERCOM5->USART.INTENSET.reg = SERCOM_USART_INTENSET_TXC; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /p1am-isolated-rs485/sketches/p1am-100-iso-rs485/p1am-100-iso-rs485.ino: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------------- 2 | // INCLUDES 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "macaddr.h" 10 | 11 | 12 | //--------------------------------------------------------------------------------------------- 13 | // DEFINES 14 | // 15 | 16 | #define PIN_E48_CS_n 2 17 | #define PIN_XCVR_DE 1 18 | #define PIN_XCVR_RE_n 0 19 | 20 | 21 | //--------------------------------------------------------------------------------------------- 22 | // PROTOTYPES 23 | // 24 | 25 | 26 | //--------------------------------------------------------------------------------------------- 27 | // GLOBALS 28 | // 29 | 30 | // serial number / Ethernet MAC address 31 | uint8_t MAC_ADDR[6] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 32 | 33 | // re-enable serial 1 because I commented out this code in the P1AM-100 variants.cpp file 34 | Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); 35 | void SERCOM5_Handler() { Serial1.IrqHandler(); } 36 | 37 | 38 | //--------------------------------------------------------------------------------------------- 39 | // setup 40 | // 41 | 42 | void setup (void) 43 | { 44 | //---------------------------------------- 45 | // initialize system 46 | //---------------------------------------- 47 | 48 | // initialize built-in LED pin as an output 49 | pinMode (LED_BUILTIN, OUTPUT); 50 | digitalWrite (LED_BUILTIN, LOW); 51 | 52 | // intialize built-in toggle switch as an input 53 | pinMode (SWITCH_BUILTIN, INPUT); 54 | 55 | // deassert serial eeprom chip select 56 | pinMode (PIN_E48_CS_n, OUTPUT); 57 | digitalWrite (PIN_E48_CS_n, HIGH); 58 | 59 | // disable transceiver output 60 | pinMode (PIN_XCVR_DE, OUTPUT); 61 | digitalWrite (PIN_XCVR_DE, LOW); 62 | 63 | // disable receiver input 64 | pinMode (PIN_XCVR_RE_n, OUTPUT); 65 | digitalWrite (PIN_XCVR_RE_n, HIGH); 66 | 67 | // initialize SPI 68 | SPI.begin (); 69 | 70 | // enable console serial port 71 | Serial.begin (9600); 72 | 73 | // enable transceiver serial port 74 | Serial1.begin (9600); 75 | 76 | // wait 500 ms for serial port to open 77 | delay (500); 78 | 79 | while (!Serial) { 80 | ; // wait for serial port to connect. Needed for native USB port only 81 | } 82 | 83 | // display hello world 84 | Serial.printf ("Hello, world!\n\r"); 85 | 86 | //---------------------------------------- 87 | // read and display serial number / Ethernet MAC address 88 | //---------------------------------------- 89 | 90 | ReadMacAddress (PIN_E48_CS_n, MAC_ADDR); 91 | Serial.printf ("Board serial number / MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n\r", 92 | MAC_ADDR[0], MAC_ADDR[1], MAC_ADDR[2], MAC_ADDR[3], MAC_ADDR[4], MAC_ADDR[5]); 93 | } 94 | 95 | 96 | //--------------------------------------------------------------------------------------------- 97 | // loop 98 | // 99 | 100 | void loop (void) 101 | { 102 | uint8_t ch; 103 | 104 | if (digitalRead (SWITCH_BUILTIN)) { 105 | // enable driver and receiver 106 | digitalWrite (LED_BUILTIN, HIGH); 107 | digitalWrite (PIN_XCVR_DE, HIGH); 108 | digitalWrite (PIN_XCVR_RE_n, LOW); 109 | } else { 110 | // disable driver and receiver 111 | digitalWrite (LED_BUILTIN, LOW); 112 | digitalWrite (PIN_XCVR_DE, LOW); 113 | digitalWrite (PIN_XCVR_RE_n, HIGH); 114 | } 115 | 116 | // echo characters from console to transeiver 117 | if (Serial.available ()) { 118 | ch = Serial.read (); 119 | Serial1.write (ch); 120 | } 121 | 122 | // echo characters from transeiver to console 123 | if (Serial1.available ()) { 124 | ch = Serial1.read (); 125 | Serial.write (ch); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /p1am-isolated-rs485/sketches/p1am-100-iso-rs485-receiver/p1am-100-iso-rs485-receiver.ino: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------------- 2 | // INCLUDES 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "macaddr.h" 11 | 12 | 13 | //--------------------------------------------------------------------------------------------- 14 | // DEFINES 15 | // 16 | 17 | #define PIN_E48_CS_n 2 18 | #define PIN_XCVR_DE 1 19 | #define PIN_XCVR_RE_n 0 20 | 21 | 22 | //--------------------------------------------------------------------------------------------- 23 | // PROTOTYPES 24 | // 25 | 26 | bool tick_Run (void *); 27 | 28 | 29 | //--------------------------------------------------------------------------------------------- 30 | // GLOBALS 31 | // 32 | 33 | // serial number / Ethernet MAC address 34 | uint8_t MAC_ADDR[6] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 35 | 36 | // re-enable serial 1 because I commented out this code in the P1AM-100 variants.cpp file 37 | Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); 38 | void SERCOM5_Handler() { Serial1.IrqHandler(); } 39 | 40 | // 20 ms / 50 Hz tick timer 41 | auto tickTimer = timer_create_default(); 42 | 43 | 44 | //--------------------------------------------------------------------------------------------- 45 | // setup 46 | // 47 | 48 | void setup (void) 49 | { 50 | //---------------------------------------- 51 | // initialize system 52 | //---------------------------------------- 53 | 54 | // initialize built-in LED pin as an output 55 | pinMode (LED_BUILTIN, OUTPUT); 56 | digitalWrite (LED_BUILTIN, LOW); 57 | 58 | // intialize built-in toggle switch as an input 59 | pinMode (SWITCH_BUILTIN, INPUT); 60 | 61 | // deassert serial eeprom chip select 62 | pinMode (PIN_E48_CS_n, OUTPUT); 63 | digitalWrite (PIN_E48_CS_n, HIGH); 64 | 65 | // disable transceiver output 66 | pinMode (PIN_XCVR_DE, OUTPUT); 67 | digitalWrite (PIN_XCVR_DE, LOW); 68 | 69 | // enable receiver input 70 | pinMode (PIN_XCVR_RE_n, OUTPUT); 71 | digitalWrite (PIN_XCVR_RE_n, LOW); 72 | 73 | // initialize SPI 74 | SPI.begin (); 75 | 76 | // enable console serial port 77 | Serial.begin (9600); 78 | 79 | // enable transceiver serial port 80 | Serial1.begin (9600); 81 | 82 | // wait 500 ms for serial port to open 83 | delay (500); 84 | 85 | // display hello world 86 | Serial.printf ("Hello, world!\n\r"); 87 | 88 | //---------------------------------------- 89 | // read and display serial number / Ethernet MAC address 90 | //---------------------------------------- 91 | 92 | ReadMacAddress (PIN_E48_CS_n, MAC_ADDR); 93 | Serial.printf ("Board serial number / MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n\r", 94 | MAC_ADDR[0], MAC_ADDR[1], MAC_ADDR[2], MAC_ADDR[3], MAC_ADDR[4], MAC_ADDR[5]); 95 | 96 | //---------------------------------------- 97 | // initialize P1 bus modules 98 | //---------------------------------------- 99 | 100 | while (!P1.init()){ 101 | ; //Wait for Modules to Sign on 102 | } 103 | 104 | //---------------------------------------- 105 | // initialize tick timer 106 | //---------------------------------------- 107 | 108 | tickTimer.every (20, tick_Run); 109 | } 110 | 111 | 112 | //--------------------------------------------------------------------------------------------- 113 | // loop 114 | // 115 | 116 | void loop (void) 117 | { 118 | uint8_t ioModuleStatus; 119 | 120 | tickTimer.tick (); 121 | 122 | if (digitalRead (SWITCH_BUILTIN)) { 123 | // turn built-in LED on 124 | digitalWrite (LED_BUILTIN, HIGH); 125 | } else { 126 | // turn built-in LED off 127 | digitalWrite (LED_BUILTIN, LOW); 128 | } 129 | 130 | if (Serial1.available ()) { 131 | ioModuleStatus = Serial1.read (); 132 | P1.writeDiscrete (ioModuleStatus, 1); 133 | Serial.printf ("%02x\n\r", ioModuleStatus); 134 | } 135 | } 136 | 137 | 138 | //--------------------------------------------------------------------------------------------- 139 | // tick_Run 140 | // 141 | 142 | bool tick_Run (void *) 143 | { 144 | // nothing to do here 145 | 146 | return true; 147 | } 148 | -------------------------------------------------------------------------------- /p1am-isolated-rs485/sketches/p1am-100-iso-rs485-sender/p1am-100-iso-rs485-sender.ino: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------------- 2 | // INCLUDES 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "macaddr.h" 11 | 12 | 13 | //--------------------------------------------------------------------------------------------- 14 | // DEFINES 15 | // 16 | 17 | #define PIN_E48_CS_n 2 18 | #define PIN_XCVR_DE 1 19 | #define PIN_XCVR_RE_n 0 20 | 21 | 22 | //--------------------------------------------------------------------------------------------- 23 | // PROTOTYPES 24 | // 25 | 26 | bool tick_Run (void *); 27 | 28 | 29 | //--------------------------------------------------------------------------------------------- 30 | // GLOBALS 31 | // 32 | 33 | // serial number / Ethernet MAC address 34 | uint8_t MAC_ADDR[6] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 35 | 36 | // re-enable serial 1 because I commented out this code in the P1AM-100 variants.cpp file 37 | Uart Serial1(&sercom5, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX); 38 | void SERCOM5_Handler() { Serial1.IrqHandler(); } 39 | 40 | // 20 ms / 50 Hz tick timer 41 | auto tickTimer = timer_create_default(); 42 | 43 | 44 | //--------------------------------------------------------------------------------------------- 45 | // setup 46 | // 47 | 48 | void setup (void) 49 | { 50 | //---------------------------------------- 51 | // initialize system 52 | //---------------------------------------- 53 | 54 | // initialize built-in LED pin as an output 55 | pinMode (LED_BUILTIN, OUTPUT); 56 | digitalWrite (LED_BUILTIN, LOW); 57 | 58 | // intialize built-in toggle switch as an input 59 | pinMode (SWITCH_BUILTIN, INPUT); 60 | 61 | // deassert serial eeprom chip select 62 | pinMode (PIN_E48_CS_n, OUTPUT); 63 | digitalWrite (PIN_E48_CS_n, HIGH); 64 | 65 | // enable transceiver output 66 | pinMode (PIN_XCVR_DE, OUTPUT); 67 | digitalWrite (PIN_XCVR_DE, HIGH); 68 | 69 | // disable receiver input 70 | pinMode (PIN_XCVR_RE_n, OUTPUT); 71 | digitalWrite (PIN_XCVR_RE_n, HIGH); 72 | 73 | // initialize SPI 74 | SPI.begin (); 75 | 76 | // enable console serial port 77 | Serial.begin (9600); 78 | 79 | // enable transceiver serial port 80 | Serial1.begin (9600); 81 | 82 | // wait 500 ms for serial port to open 83 | delay (500); 84 | 85 | // display hello world 86 | Serial.printf ("Hello, world!\n\r"); 87 | 88 | //---------------------------------------- 89 | // read and display serial number / Ethernet MAC address 90 | //---------------------------------------- 91 | 92 | ReadMacAddress (PIN_E48_CS_n, MAC_ADDR); 93 | Serial.printf ("Board serial number / MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n\r", 94 | MAC_ADDR[0], MAC_ADDR[1], MAC_ADDR[2], MAC_ADDR[3], MAC_ADDR[4], MAC_ADDR[5]); 95 | 96 | //---------------------------------------- 97 | // initialize P1 bus modules 98 | //---------------------------------------- 99 | 100 | while (!P1.init()){ 101 | ; //Wait for Modules to Sign on 102 | } 103 | 104 | //---------------------------------------- 105 | // initialize tick timer 106 | //---------------------------------------- 107 | 108 | tickTimer.every (20, tick_Run); 109 | } 110 | 111 | 112 | //--------------------------------------------------------------------------------------------- 113 | // loop 114 | // 115 | 116 | void loop (void) 117 | { 118 | uint8_t ch; 119 | 120 | tickTimer.tick (); 121 | 122 | if (digitalRead (SWITCH_BUILTIN)) { 123 | // turn built-in LED on 124 | digitalWrite (LED_BUILTIN, HIGH); 125 | } else { 126 | // turn built-in LED off 127 | digitalWrite (LED_BUILTIN, LOW); 128 | } 129 | } 130 | 131 | 132 | //--------------------------------------------------------------------------------------------- 133 | // tick_Run 134 | // 135 | 136 | bool tick_Run (void *) 137 | { 138 | uint8_t ioModuleStatus; 139 | 140 | // read slot 1 141 | ioModuleStatus = P1.readDiscrete (1); 142 | 143 | // send to console serial port 144 | Serial.printf ("%02x\n\r", ioModuleStatus); 145 | 146 | // send over RS-422 / RS-485 to remote module 147 | Serial1.write (ioModuleStatus); 148 | 149 | return true; 150 | } 151 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-garage-door-monitor/charrom.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // includes 3 | 4 | #include "charrom.h" 5 | 6 | 7 | //----------------------------------------------------------------------------- 8 | // globals 9 | // 10 | 11 | const unsigned char charrom[128][5] = { 12 | { 0x7f, 0x00, 0x00, 0x00, 0x00 }, // bar graph 1 13 | { 0x7f, 0x7f, 0x00, 0x00, 0x00 }, 14 | { 0x7f, 0x7f, 0x7f, 0x00, 0x00 }, 15 | { 0x7f, 0x7f, 0x7f, 0x7f, 0x00 }, 16 | { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, 17 | { 0, 0, 0, 0, 0 }, 18 | { 0, 0, 0, 0, 0 }, 19 | { 0, 0, 0, 0, 0 }, 20 | 21 | { 0x00, 0x00, 0x00, 0x00, 0x7f }, // bar graph 2 22 | { 0x00, 0x00, 0x00, 0x7f, 0x7f }, 23 | { 0x00, 0x00, 0x7f, 0x7f, 0x7f }, 24 | { 0x00, 0x7f, 0x7f, 0x7f, 0x7f }, 25 | { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, 26 | { 0, 0, 0, 0, 0 }, 27 | { 0, 0, 0, 0, 0 }, 28 | { 0, 0, 0, 0, 0 }, 29 | 30 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 31 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 32 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 33 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 34 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 35 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 36 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 37 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 38 | 39 | { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x20 space 40 | { 0x00, 0x4f, 0x00, 0x00, 0x00 }, // ! 41 | { 0x00, 0x03, 0x00, 0x03, 0x00 }, // " 42 | { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // # 43 | { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $ 44 | { 0x23, 0x13, 0x08, 0x64, 0x62 }, // % 45 | { 0x36, 0x49, 0x56, 0x20, 0x50 }, // & 46 | { 0x00, 0x0b, 0x07, 0x00, 0x00 }, // ' 47 | { 0x00, 0x00, 0x3e, 0x41, 0x00 }, // 0x28 ( 48 | { 0x00, 0x41, 0x3e, 0x00, 0x00 }, // ) 49 | { 0x08, 0x2a, 0x1c, 0x2a, 0x08 }, // * 50 | { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // + 51 | { 0x00, 0x58, 0x38, 0x00, 0x00 }, // , 52 | { 0x08, 0x08, 0x08, 0x08, 0x08 }, // - 53 | { 0x00, 0x30, 0x30, 0x00, 0x00 }, // . 54 | { 0x20, 0x10, 0x08, 0x04, 0x02 }, // / 55 | { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 0x30 0 56 | { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 1 57 | { 0x62, 0x51, 0x49, 0x49, 0x46 }, // 2 58 | { 0x22, 0x41, 0x49, 0x49, 0x36 }, // 3 59 | { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 4 60 | { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5 61 | { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 6 62 | { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7 63 | { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 0x38 8 64 | { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 9 65 | { 0x00, 0x36, 0x36, 0x00, 0x00 }, // : 66 | { 0x00, 0x5b, 0x3b, 0x00, 0x00 }, // ; 67 | { 0x00, 0x08, 0x14, 0x22, 0x41 }, // < 68 | { 0x14, 0x14, 0x14, 0x14, 0x14 }, // = 69 | { 0x41, 0x22, 0x14, 0x08, 0x00 }, // > 70 | { 0x02, 0x01, 0x51, 0x09, 0x06 }, // ? 71 | { 0x3e, 0x41, 0x5d, 0x55, 0x1e }, // 0x40 @ 72 | { 0x7e, 0x09, 0x09, 0x09, 0x7e }, // A 73 | { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // B 74 | { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // C 75 | { 0x7f, 0x41, 0x41, 0x41, 0x3e }, // D 76 | { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // E 77 | { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // F 78 | { 0x3e, 0x41, 0x41, 0x51, 0x32 }, // G 79 | { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // 0x48 H 80 | { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // I 81 | { 0x20, 0x40, 0x40, 0x40, 0x3f }, // J 82 | { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // K 83 | { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // L 84 | { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // M 85 | { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // N 86 | { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // O 87 | { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // 0x50 P 88 | { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // Q 89 | { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // R 90 | { 0x26, 0x49, 0x49, 0x49, 0x32 }, // S 91 | { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // T 92 | { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // U 93 | { 0x07, 0x18, 0x60, 0x18, 0x07 }, // V 94 | { 0x7f, 0x20, 0x18, 0x20, 0x7f }, // W 95 | { 0x63, 0x14, 0x08, 0x14, 0x63 }, // 0x58 X 96 | { 0x03, 0x04, 0x78, 0x04, 0x03 }, // Y 97 | { 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z 98 | { 0x00, 0x00, 0x7f, 0x41, 0x41 }, // [ 99 | { 0x02, 0x04, 0x08, 0x10, 0x20 }, // backslash 100 | { 0x41, 0x41, 0x7f, 0x00, 0x00 }, // ] 101 | { 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^ 102 | { 0x40, 0x40, 0x40, 0x40, 0x40 }, // _ 103 | { 0x00, 0x07, 0x0b, 0x00, 0x00 }, // 0x60 ` 104 | { 0x38, 0x44, 0x44, 0x3c, 0x40 }, // a 105 | { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // b 106 | { 0x38, 0x44, 0x44, 0x44, 0x20 }, // c 107 | { 0x38, 0x44, 0x44, 0x48, 0x7f }, // d 108 | { 0x38, 0x54, 0x54, 0x54, 0x08 }, // e 109 | { 0x08, 0x7e, 0x09, 0x02, 0x00 }, // f 110 | { 0x08, 0x14, 0x54, 0x54, 0x3c }, // g 111 | { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // 0x68 h 112 | { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // i 113 | { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // j 114 | { 0x00, 0x7f, 0x10, 0x28, 0x44 }, // k 115 | { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // l 116 | { 0x78, 0x04, 0x18, 0x04, 0x78 }, // m 117 | { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // n 118 | { 0x38, 0x44, 0x44, 0x44, 0x38 }, // o 119 | { 0x7c, 0x14, 0x24, 0x24, 0x18 }, // 0x70 p 120 | { 0x18, 0x24, 0x14, 0x7c, 0x40 }, // q 121 | { 0x00, 0x7c, 0x08, 0x04, 0x04 }, // r 122 | { 0x48, 0x54, 0x54, 0x54, 0x20 }, // s 123 | { 0x04, 0x3e, 0x44, 0x20, 0x00 }, // t 124 | { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // u 125 | { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // v 126 | { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // w 127 | { 0x44, 0x28, 0x10, 0x28, 0x44 }, // 0x78 x 128 | { 0x04, 0x48, 0x30, 0x08, 0x04 }, // y 129 | { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // z 130 | { 0x00, 0x08, 0x36, 0x41, 0x00 }, // { 131 | { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // | 132 | { 0x00, 0x41, 0x36, 0x08, 0x00 }, // } 133 | { 0x08, 0x04, 0x08, 0x10, 0x08 }, // ~ 134 | { 0x2a, 0x55, 0x2a, 0x55, 0x2a }, // checker 135 | }; 136 | 137 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-proto-kitchen-sink/charrom.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // includes 3 | 4 | #include "charrom.h" 5 | 6 | 7 | //----------------------------------------------------------------------------- 8 | // globals 9 | // 10 | 11 | const unsigned char charrom[128][5] = { 12 | { 0x7f, 0x00, 0x00, 0x00, 0x00 }, // bar graph 1 13 | { 0x7f, 0x7f, 0x00, 0x00, 0x00 }, 14 | { 0x7f, 0x7f, 0x7f, 0x00, 0x00 }, 15 | { 0x7f, 0x7f, 0x7f, 0x7f, 0x00 }, 16 | { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, 17 | { 0, 0, 0, 0, 0 }, 18 | { 0, 0, 0, 0, 0 }, 19 | { 0, 0, 0, 0, 0 }, 20 | 21 | { 0x00, 0x00, 0x00, 0x00, 0x7f }, // bar graph 2 22 | { 0x00, 0x00, 0x00, 0x7f, 0x7f }, 23 | { 0x00, 0x00, 0x7f, 0x7f, 0x7f }, 24 | { 0x00, 0x7f, 0x7f, 0x7f, 0x7f }, 25 | { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, 26 | { 0, 0, 0, 0, 0 }, 27 | { 0, 0, 0, 0, 0 }, 28 | { 0, 0, 0, 0, 0 }, 29 | 30 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 31 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 32 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 33 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 34 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 35 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 36 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 37 | { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 38 | 39 | { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 0x20 space 40 | { 0x00, 0x4f, 0x00, 0x00, 0x00 }, // ! 41 | { 0x00, 0x03, 0x00, 0x03, 0x00 }, // " 42 | { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // # 43 | { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $ 44 | { 0x23, 0x13, 0x08, 0x64, 0x62 }, // % 45 | { 0x36, 0x49, 0x56, 0x20, 0x50 }, // & 46 | { 0x00, 0x0b, 0x07, 0x00, 0x00 }, // ' 47 | { 0x00, 0x00, 0x3e, 0x41, 0x00 }, // 0x28 ( 48 | { 0x00, 0x41, 0x3e, 0x00, 0x00 }, // ) 49 | { 0x08, 0x2a, 0x1c, 0x2a, 0x08 }, // * 50 | { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // + 51 | { 0x00, 0x58, 0x38, 0x00, 0x00 }, // , 52 | { 0x08, 0x08, 0x08, 0x08, 0x08 }, // - 53 | { 0x00, 0x30, 0x30, 0x00, 0x00 }, // . 54 | { 0x20, 0x10, 0x08, 0x04, 0x02 }, // / 55 | { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 0x30 0 56 | { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 1 57 | { 0x62, 0x51, 0x49, 0x49, 0x46 }, // 2 58 | { 0x22, 0x41, 0x49, 0x49, 0x36 }, // 3 59 | { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 4 60 | { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5 61 | { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 6 62 | { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7 63 | { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 0x38 8 64 | { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 9 65 | { 0x00, 0x36, 0x36, 0x00, 0x00 }, // : 66 | { 0x00, 0x5b, 0x3b, 0x00, 0x00 }, // ; 67 | { 0x00, 0x08, 0x14, 0x22, 0x41 }, // < 68 | { 0x14, 0x14, 0x14, 0x14, 0x14 }, // = 69 | { 0x41, 0x22, 0x14, 0x08, 0x00 }, // > 70 | { 0x02, 0x01, 0x51, 0x09, 0x06 }, // ? 71 | { 0x3e, 0x41, 0x5d, 0x55, 0x1e }, // 0x40 @ 72 | { 0x7e, 0x09, 0x09, 0x09, 0x7e }, // A 73 | { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // B 74 | { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // C 75 | { 0x7f, 0x41, 0x41, 0x41, 0x3e }, // D 76 | { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // E 77 | { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // F 78 | { 0x3e, 0x41, 0x41, 0x51, 0x32 }, // G 79 | { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // 0x48 H 80 | { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // I 81 | { 0x20, 0x40, 0x40, 0x40, 0x3f }, // J 82 | { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // K 83 | { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // L 84 | { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // M 85 | { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // N 86 | { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // O 87 | { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // 0x50 P 88 | { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // Q 89 | { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // R 90 | { 0x26, 0x49, 0x49, 0x49, 0x32 }, // S 91 | { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // T 92 | { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // U 93 | { 0x07, 0x18, 0x60, 0x18, 0x07 }, // V 94 | { 0x7f, 0x20, 0x18, 0x20, 0x7f }, // W 95 | { 0x63, 0x14, 0x08, 0x14, 0x63 }, // 0x58 X 96 | { 0x03, 0x04, 0x78, 0x04, 0x03 }, // Y 97 | { 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z 98 | { 0x00, 0x00, 0x7f, 0x41, 0x41 }, // [ 99 | { 0x02, 0x04, 0x08, 0x10, 0x20 }, // backslash 100 | { 0x41, 0x41, 0x7f, 0x00, 0x00 }, // ] 101 | { 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^ 102 | { 0x40, 0x40, 0x40, 0x40, 0x40 }, // _ 103 | { 0x00, 0x07, 0x0b, 0x00, 0x00 }, // 0x60 ` 104 | { 0x38, 0x44, 0x44, 0x3c, 0x40 }, // a 105 | { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // b 106 | { 0x38, 0x44, 0x44, 0x44, 0x20 }, // c 107 | { 0x38, 0x44, 0x44, 0x48, 0x7f }, // d 108 | { 0x38, 0x54, 0x54, 0x54, 0x08 }, // e 109 | { 0x08, 0x7e, 0x09, 0x02, 0x00 }, // f 110 | { 0x08, 0x14, 0x54, 0x54, 0x3c }, // g 111 | { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // 0x68 h 112 | { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // i 113 | { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // j 114 | { 0x00, 0x7f, 0x10, 0x28, 0x44 }, // k 115 | { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // l 116 | { 0x78, 0x04, 0x18, 0x04, 0x78 }, // m 117 | { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // n 118 | { 0x38, 0x44, 0x44, 0x44, 0x38 }, // o 119 | { 0x7c, 0x14, 0x24, 0x24, 0x18 }, // 0x70 p 120 | { 0x18, 0x24, 0x14, 0x7c, 0x40 }, // q 121 | { 0x00, 0x7c, 0x08, 0x04, 0x04 }, // r 122 | { 0x48, 0x54, 0x54, 0x54, 0x20 }, // s 123 | { 0x04, 0x3e, 0x44, 0x20, 0x00 }, // t 124 | { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // u 125 | { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // v 126 | { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // w 127 | { 0x44, 0x28, 0x10, 0x28, 0x44 }, // 0x78 x 128 | { 0x04, 0x48, 0x30, 0x08, 0x04 }, // y 129 | { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // z 130 | { 0x00, 0x08, 0x36, 0x41, 0x00 }, // { 131 | { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // | 132 | { 0x00, 0x41, 0x36, 0x08, 0x00 }, // } 133 | { 0x08, 0x04, 0x08, 0x10, 0x08 }, // ~ 134 | { 0x2a, 0x55, 0x2a, 0x55, 0x2a }, // checker 135 | }; 136 | 137 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-proto-kitchen-sink/p1am-100-proto-kitchen-sink.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "charrom.h" 7 | #include "display.h" 8 | #include "samd21dmx.h" 9 | 10 | Display display; 11 | auto displayScrollTimer = timer_create_default (); 12 | auto mainLoopTimer = timer_create_default (); 13 | 14 | #define IN1_PIN 3 15 | #define IN2_PIN 4 16 | #define OUT1_PIN 6 17 | #define OUT2_PIN 7 18 | #define DMX_DIR_PIN A0 19 | #define E48_CS_PIN 2 20 | 21 | // TODO -- read from serial EEPROM 22 | byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 23 | 24 | // TODO -- get via DHCP 25 | IPAddress ip(192, 168, 180, 177); 26 | 27 | EthernetServer server(80); 28 | 29 | uint8_t effects_data[DMX_SLOTS]; 30 | 31 | String msg; 32 | uint8_t in1_state = 0; 33 | uint8_t in2_state = 0; 34 | uint8_t out1_state = 0; 35 | uint8_t out2_state = 0; 36 | 37 | File myFile; 38 | 39 | void setup() 40 | { 41 | // Open serial communications and wait for port to open: 42 | Serial.begin(9600); 43 | #ifdef NOPE 44 | while (!Serial) { 45 | ; // wait for serial port to connect. Needed for native USB port only 46 | } 47 | #endif 48 | Serial.printf ("Hello, world!\n\r"); 49 | 50 | // initialize opto inputs, relay outputs, EUI-48 EEPROM CS 51 | pinMode (IN1_PIN, INPUT); 52 | pinMode (IN2_PIN, INPUT); 53 | pinMode (OUT1_PIN, OUTPUT); 54 | digitalWrite (OUT1_PIN, 0); 55 | pinMode (OUT2_PIN, OUTPUT); 56 | digitalWrite (OUT2_PIN, 0); 57 | pinMode (E48_CS_PIN, OUTPUT); 58 | digitalWrite (E48_CS_PIN, 1); 59 | 60 | // initialize RS-485 / DMX 61 | pinMode (DMX_DIR_PIN, OUTPUT); 62 | digitalWrite (DMX_DIR_PIN, 1); 63 | dmx.begin (); 64 | for (int i = 0; i < DMX_SLOTS; i++) { 65 | effects_data[i] = 0x00; 66 | } 67 | dmx.tx (effects_data); 68 | 69 | // read MAC address 70 | // TODO 71 | 72 | // initialize display and display something 73 | display.begin (A1, A2, A5, A6); 74 | displayScrollTimer.every (200, displayTickWrapper); 75 | display.scrollMessage ("Hello, world! "); 76 | 77 | // initialize main loop timer to execute at 50 Hz 78 | mainLoopTimer.every (20, mainLoopTick); 79 | 80 | // start the Ethernet connection and the server: 81 | Ethernet.begin(mac, ip); 82 | server.begin(); 83 | Serial.print("server is at "); 84 | Serial.println(Ethernet.localIP()); 85 | 86 | Serial.print("Starting SD card..."); 87 | if (!SD.begin(28)) { 88 | Serial.println("SD card start failed!"); 89 | while (1); 90 | } 91 | Serial.println("SD card started."); 92 | } 93 | 94 | 95 | void loop() 96 | { 97 | displayScrollTimer.tick (); 98 | mainLoopTimer.tick (); 99 | 100 | // listen for incoming clients 101 | EthernetClient client = server.available(); 102 | if (client) { 103 | Serial.println("new client"); 104 | // an http request ends with a blank line 105 | boolean currentLineIsBlank = true; 106 | while (client.connected()) { 107 | if (client.available()) { 108 | char c = client.read(); 109 | Serial.write(c); 110 | // if you've gotten to the end of the line (received a newline 111 | // character) and the line is blank, the http request has ended, 112 | // so you can send a reply 113 | if (c == '\n' && currentLineIsBlank) { 114 | // send a standard http response header 115 | client.println("HTTP/1.1 200 OK"); 116 | client.println("Content-Type: text/html"); 117 | client.println("Connection: close"); // the connection will be closed after completion of the response 118 | // client.println("Refresh: 5"); // refresh the page automatically every 5 sec 119 | client.println(); 120 | client.println(""); 121 | client.println(""); 122 | client.println("Hello, world!
"); 123 | client.printf ("IN 1 is %d
", in1_state >= 2); 124 | client.printf ("IN 2 is %d
", in2_state >= 2); 125 | client.printf ("OUT 1 is %d
", out1_state); 126 | client.printf ("OUT 2 is %d
", out2_state); 127 | client.println ("test.txt contents: "); 128 | myFile = SD.open("test.txt", FILE_READ); 129 | while (myFile.available()) { 130 | client.write (myFile.read ()); 131 | } 132 | client.print ("
"); 133 | myFile.close(); 134 | client.println(""); 135 | break; 136 | } 137 | if (c == '\n') { 138 | // you're starting a new line 139 | currentLineIsBlank = true; 140 | } else if (c != '\r') { 141 | // you've gotten a character on the current line 142 | currentLineIsBlank = false; 143 | } 144 | } 145 | } 146 | // give the web browser time to receive the data 147 | delay(1); 148 | // close the connection: 149 | client.stop(); 150 | Serial.println("client disconnected"); 151 | } 152 | } 153 | 154 | 155 | bool displayTickWrapper (void *a) 156 | { 157 | return display.tick (a); 158 | } 159 | 160 | 161 | bool mainLoopTick (void *a) 162 | { 163 | uint8_t in1_raw = !digitalRead (IN1_PIN); 164 | uint8_t in2_raw = !digitalRead (IN2_PIN); 165 | uint8_t in1_pressed = 0; 166 | uint8_t in2_pressed = 0; 167 | 168 | switch (in1_state) { 169 | case 0: 170 | if (in1_raw) in1_state = 1; 171 | break; 172 | case 1: 173 | if (in1_raw) { 174 | in1_state = 2; 175 | in1_pressed = 1; 176 | } 177 | else in1_state = 0; 178 | break; 179 | case 2: 180 | if (!in1_raw) in1_state = 3; 181 | break; 182 | case 3: 183 | if (in1_raw) in1_state = 2; 184 | else in1_state = 0; 185 | break; 186 | default: 187 | in1_state = 0; 188 | break; 189 | } 190 | 191 | switch (in2_state) { 192 | case 0: 193 | if (in2_raw) in2_state = 1; 194 | break; 195 | case 1: 196 | if (in2_raw) { 197 | in2_state = 2; 198 | in2_pressed = 1; 199 | } 200 | else in2_state = 0; 201 | break; 202 | case 2: 203 | if (!in2_raw) in2_state = 3; 204 | break; 205 | case 3: 206 | if (in2_raw) in2_state = 2; 207 | else in2_state = 0; 208 | break; 209 | default: 210 | in2_state = 0; 211 | break; 212 | } 213 | 214 | uint8_t in1_down = in1_state >= 2; 215 | uint8_t in2_down = in2_state >= 2; 216 | 217 | if (in1_pressed) { 218 | out1_state = !out1_state; 219 | } 220 | 221 | if (in2_pressed) { 222 | out2_state = !out2_state; 223 | } 224 | 225 | digitalWrite (OUT1_PIN, out1_state); 226 | digitalWrite (OUT2_PIN, out2_state); 227 | 228 | msg = ""; 229 | msg.concat (in1_down ? "1" : "0"); 230 | msg.concat (in2_down ? "1" : "0"); 231 | msg.concat (out1_state ? "1" : "0"); 232 | msg.concat (out2_state ? "1" : "0"); 233 | if (!display.scrollBusy ()) { 234 | display.write (msg); 235 | } 236 | 237 | effects_data[0] = out1_state ? 0xff : 0x00; 238 | effects_data[1] = out2_state ? 0xff : 0x00; 239 | dmx.tx (effects_data); 240 | 241 | return true; 242 | } 243 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-proto-kitchen-sink/display.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "charrom.h" 5 | #include "display.h" 6 | 7 | static SPISettings displaySPISettings (1000000, MSBFIRST, SPI_MODE0); 8 | 9 | uint8_t scrollBusyFlag = 0; 10 | uint8_t scrollIndex = 0; 11 | uint8_t scrollBuffer[5]; 12 | RingBuffer scrollMessageBuffer; 13 | extern Timer<> displayScrollTimer; 14 | extern Timer<> mainLoopTimer; 15 | 16 | //--------------------------------------------------------------------------------------------- 17 | // constructor 18 | // 19 | 20 | Display::Display (void) 21 | { 22 | } 23 | 24 | 25 | //--------------------------------------------------------------------------------------------- 26 | // destructor 27 | // 28 | 29 | Display::~Display (void) 30 | { 31 | } 32 | 33 | 34 | //--------------------------------------------------------------------------------------------- 35 | // initialize everything 36 | // 37 | 38 | void Display::begin (uint8_t cs_pin, uint8_t rs_pin, uint8_t blank_pin, uint8_t reset_pin) 39 | { 40 | // save pins 41 | this->cs_pin = cs_pin; 42 | this->rs_pin = rs_pin; 43 | this->blank_pin = blank_pin; 44 | this->reset_pin = reset_pin; 45 | 46 | // initialize SPI 47 | SPI.begin (); 48 | 49 | // set pins as outputs 50 | pinMode (this->cs_pin, OUTPUT); 51 | pinMode (this->rs_pin, OUTPUT); 52 | pinMode (this->blank_pin, OUTPUT); 53 | pinMode (this->reset_pin, OUTPUT); 54 | 55 | // set pin defaults 56 | digitalWrite (this->blank_pin, 1); 57 | digitalWrite (this->cs_pin, 1); 58 | digitalWrite (this->rs_pin, 0); 59 | 60 | // reset display 61 | digitalWrite (this->reset_pin, 0); 62 | delay (100); 63 | digitalWrite (this->reset_pin, 1); 64 | delay (100); 65 | 66 | // configure display 67 | SPI.beginTransaction (displaySPISettings); 68 | digitalWrite (this->rs_pin, 1); 69 | digitalWrite (this->cs_pin, 0); 70 | SPI.transfer (0x7F); 71 | digitalWrite (this->cs_pin, 1); 72 | delay (5); 73 | digitalWrite (this->rs_pin, 1); 74 | digitalWrite (this->cs_pin, 0); 75 | SPI.transfer (0x80); 76 | digitalWrite (this->cs_pin, 1); 77 | SPI.endTransaction (); 78 | 79 | // clear display data 80 | SPI.beginTransaction (displaySPISettings); 81 | digitalWrite (this->rs_pin, 0); 82 | digitalWrite (this->cs_pin, 0); 83 | for (int i = 0; i < 4; i++) { 84 | for (int j = 0; j < 5; j++) { 85 | SPI.transfer (0x00); 86 | } 87 | } 88 | digitalWrite (this->cs_pin, 1); 89 | SPI.endTransaction (); 90 | 91 | /* 92 | // display some data 93 | SPI.beginTransaction (displaySPISettings); 94 | digitalWrite (this->rs_pin, 0); 95 | digitalWrite (this->cs_pin, 0); 96 | for (int i = 0; i < 4; i++) { 97 | for (int j = 0; j < 5; j++) { 98 | SPI.transfer (charrom['A'+i][j]); 99 | } 100 | } 101 | digitalWrite (this->cs_pin, 1); 102 | SPI.endTransaction (); 103 | */ 104 | 105 | // unblank display 106 | digitalWrite (this->blank_pin, 0); 107 | 108 | // initializie scrolling message state and buffer 109 | scrollBuffer[0] = ' '; 110 | scrollBuffer[1] = ' '; 111 | scrollBuffer[2] = ' '; 112 | scrollBuffer[3] = ' '; 113 | scrollBuffer[4] = ' '; 114 | scrollMessageBuffer.clear (); 115 | } 116 | 117 | 118 | //--------------------------------------------------------------------------------------------- 119 | // display a message immediately 120 | // shouldn't be called while scrollBusyFlag is set 121 | // 122 | 123 | void Display::write (String s) 124 | { 125 | uint8_t i, j, ch; 126 | 127 | // display some data 128 | SPI.beginTransaction (displaySPISettings); 129 | digitalWrite (this->rs_pin, 0); 130 | digitalWrite (this->cs_pin, 0); 131 | for (int i = 0; i < 4; i++) { 132 | if (i >= s.length ()) { 133 | ch = ' '; 134 | } else { 135 | ch = s.charAt (i); 136 | if (ch >= 128) { 137 | ch = ' '; 138 | } 139 | } 140 | for (int j = 0; j < 5; j++) { 141 | SPI.transfer (charrom[ch][j]); 142 | } 143 | } 144 | digitalWrite (this->cs_pin, 1); 145 | SPI.endTransaction (); 146 | } 147 | 148 | 149 | //--------------------------------------------------------------------------------------------- 150 | // add message to scrolling message buffer 151 | // if buffer is full, blocks until not full any more 152 | // calls display scroll and main loop timer tick functions so timers 153 | // continue to operate while blocked 154 | // 155 | 156 | void Display::scrollMessage (String s) 157 | { 158 | int i; 159 | 160 | scrollBusyFlag = 2; 161 | for (i = 0; i < s.length (); i++) { 162 | while (!scrollMessageBuffer.availableForStore ()) { 163 | displayScrollTimer.tick (); 164 | mainLoopTimer.tick (); 165 | } 166 | scrollMessageBuffer.store_char (s.charAt (i)); 167 | } 168 | } 169 | 170 | 171 | #ifdef NOPE 172 | //--------------------------------------------------------------------------------------------- 173 | // scroll column by column 174 | // 175 | 176 | // This scrolling doesn't look good because each character is exactly 5x7 and 177 | // they squish together when scrolled then unsuish with a bit of space 178 | // between them when column = 0. Going to scroll by whole character only. 179 | 180 | bool Display::tick (void *) 181 | { 182 | uint8_t i, adj, idx, col, ch; 183 | 184 | SPI.beginTransaction (displaySPISettings); 185 | digitalWrite (this->rs_pin, 0); 186 | digitalWrite (this->cs_pin, 0); 187 | 188 | // Serial.printf ("scrollIndex: %d\n\r", scrollIndex); 189 | // Serial.printf ("scrollBuffer: '%c%c%c%c%c\n\r'", 190 | // scrollBuffer[0], scrollBuffer[1], scrollBuffer[2], scrollBuffer[3], scrollBuffer[4]); 191 | 192 | for (int i = 0; i < 20; i++) { 193 | 194 | adj = i + scrollIndex; 195 | idx = adj / 5; 196 | col = adj % 5; 197 | ch = scrollBuffer[idx]; 198 | SPI.transfer (charrom[ch][col]); 199 | // Serial.printf (" %2d %2d %2d\n\r", adj, idx, col); 200 | } 201 | 202 | digitalWrite (this->cs_pin, 1); 203 | SPI.endTransaction (); 204 | 205 | scrollIndex++; 206 | if (scrollIndex >= 5) { 207 | scrollIndex = 0; 208 | for (i = 0; i < 4; i++) { 209 | scrollBuffer[i] = scrollBuffer[i+1]; 210 | } 211 | if (scrollMessageBuffer.available ()) { 212 | scrollBuffer[4] = scrollMessageBuffer.read_char (); 213 | } else { 214 | scrollBuffer[4] = ' '; 215 | if ((scrollBuffer[0] == ' ') && (scrollBuffer[1] == ' ') && (scrollBuffer[2] == ' ') && 216 | (scrollBuffer[3] == ' ') && (scrollBuffer[4] == ' ')) { 217 | scrollBusyFlag = false; 218 | } 219 | } 220 | } 221 | 222 | return true; 223 | } 224 | #endif 225 | 226 | 227 | //--------------------------------------------------------------------------------------------- 228 | // scroll character by character 229 | // 230 | 231 | bool Display::tick (void *) 232 | { 233 | uint8_t i, j; 234 | 235 | if (scrollBusyFlag) { 236 | SPI.beginTransaction (displaySPISettings); 237 | digitalWrite (this->rs_pin, 0); 238 | digitalWrite (this->cs_pin, 0); 239 | 240 | for (int i = 0; i < 4; i++) { 241 | for (int j = 0; j < 5; j++) { 242 | SPI.transfer (charrom[scrollBuffer[i]][j]); 243 | } 244 | } 245 | 246 | digitalWrite (this->cs_pin, 1); 247 | SPI.endTransaction (); 248 | 249 | for (i = 0; i < 4; i++) { 250 | scrollBuffer[i] = scrollBuffer[i+1]; 251 | } 252 | if (scrollMessageBuffer.available ()) { 253 | scrollBuffer[4] = scrollMessageBuffer.read_char (); 254 | Serial.printf ("1: %c%c%c%c%c %d\n\r", scrollBuffer[0], scrollBuffer[1], scrollBuffer[2], scrollBuffer[3], scrollBuffer[4], scrollBusyFlag); 255 | } else { 256 | scrollBuffer[4] = ' '; 257 | if ((scrollBuffer[0] == ' ') && (scrollBuffer[1] == ' ') && (scrollBuffer[2] == ' ') && 258 | (scrollBuffer[3] == ' ') && (scrollBuffer[4] == ' ')) { 259 | scrollBusyFlag--; 260 | } 261 | Serial.printf ("2: %c%c%c%c%c %d\n\r", scrollBuffer[0], scrollBuffer[1], scrollBuffer[2], scrollBuffer[3], scrollBuffer[4], scrollBusyFlag); 262 | } 263 | } 264 | 265 | return true; 266 | } 267 | 268 | 269 | //--------------------------------------------------------------------------------------------- 270 | // return state of scrollBusyFlag 271 | // 272 | 273 | bool Display::scrollBusy (void) 274 | { 275 | return (scrollBusyFlag != 0); 276 | } 277 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-garage-door-monitor/display.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "charrom.h" 5 | #include "display.h" 6 | 7 | static SPISettings displaySPISettings (1000000, MSBFIRST, SPI_MODE0); 8 | 9 | uint8_t scrollBusyFlag = 0; 10 | uint8_t scrollIndex = 0; 11 | uint8_t scrollBuffer[5]; 12 | RingBuffer scrollMessageBuffer; 13 | extern Timer<> displayScrollTimer; 14 | extern Timer<> mainLoopTimer; 15 | 16 | //--------------------------------------------------------------------------------------------- 17 | // constructor 18 | // 19 | 20 | Display::Display (void) 21 | { 22 | } 23 | 24 | 25 | //--------------------------------------------------------------------------------------------- 26 | // destructor 27 | // 28 | 29 | Display::~Display (void) 30 | { 31 | } 32 | 33 | 34 | //--------------------------------------------------------------------------------------------- 35 | // initialize everything 36 | // 37 | 38 | void Display::begin (uint8_t cs_pin, uint8_t rs_pin, uint8_t blank_pin, uint8_t reset_pin) 39 | { 40 | // save pins 41 | this->cs_pin = cs_pin; 42 | this->rs_pin = rs_pin; 43 | this->blank_pin = blank_pin; 44 | this->reset_pin = reset_pin; 45 | 46 | // initialize SPI 47 | SPI.begin (); 48 | 49 | // set pins as outputs 50 | pinMode (this->cs_pin, OUTPUT); 51 | pinMode (this->rs_pin, OUTPUT); 52 | pinMode (this->blank_pin, OUTPUT); 53 | pinMode (this->reset_pin, OUTPUT); 54 | 55 | // set pin defaults 56 | digitalWrite (this->blank_pin, 1); 57 | digitalWrite (this->cs_pin, 1); 58 | digitalWrite (this->rs_pin, 0); 59 | 60 | // reset display 61 | digitalWrite (this->reset_pin, 0); 62 | delay (100); 63 | digitalWrite (this->reset_pin, 1); 64 | delay (100); 65 | 66 | // configure display 67 | SPI.beginTransaction (displaySPISettings); 68 | digitalWrite (this->rs_pin, 1); 69 | digitalWrite (this->cs_pin, 0); 70 | SPI.transfer (0x7F); 71 | digitalWrite (this->cs_pin, 1); 72 | delay (5); 73 | digitalWrite (this->rs_pin, 1); 74 | digitalWrite (this->cs_pin, 0); 75 | SPI.transfer (0x80); 76 | digitalWrite (this->cs_pin, 1); 77 | SPI.endTransaction (); 78 | 79 | // clear display data 80 | SPI.beginTransaction (displaySPISettings); 81 | digitalWrite (this->rs_pin, 0); 82 | digitalWrite (this->cs_pin, 0); 83 | for (int i = 0; i < 4; i++) { 84 | for (int j = 0; j < 5; j++) { 85 | SPI.transfer (0x00); 86 | } 87 | } 88 | digitalWrite (this->cs_pin, 1); 89 | SPI.endTransaction (); 90 | 91 | /* 92 | // display some data 93 | SPI.beginTransaction (displaySPISettings); 94 | digitalWrite (this->rs_pin, 0); 95 | digitalWrite (this->cs_pin, 0); 96 | for (int i = 0; i < 4; i++) { 97 | for (int j = 0; j < 5; j++) { 98 | SPI.transfer (charrom['A'+i][j]); 99 | } 100 | } 101 | digitalWrite (this->cs_pin, 1); 102 | SPI.endTransaction (); 103 | */ 104 | 105 | // unblank display 106 | digitalWrite (this->blank_pin, 0); 107 | 108 | // initializie scrolling message state and buffer 109 | scrollBuffer[0] = ' '; 110 | scrollBuffer[1] = ' '; 111 | scrollBuffer[2] = ' '; 112 | scrollBuffer[3] = ' '; 113 | scrollBuffer[4] = ' '; 114 | scrollMessageBuffer.clear (); 115 | } 116 | 117 | 118 | //--------------------------------------------------------------------------------------------- 119 | // display a message immediately 120 | // shouldn't be called while scrollBusyFlag is set 121 | // 122 | 123 | void Display::write (String s) 124 | { 125 | uint8_t i, j, ch; 126 | 127 | // display some data 128 | SPI.beginTransaction (displaySPISettings); 129 | digitalWrite (this->rs_pin, 0); 130 | digitalWrite (this->cs_pin, 0); 131 | for (int i = 0; i < 4; i++) { 132 | if (i >= s.length ()) { 133 | ch = ' '; 134 | } else { 135 | ch = s.charAt (i); 136 | if (ch >= 128) { 137 | ch = ' '; 138 | } 139 | } 140 | for (int j = 0; j < 5; j++) { 141 | SPI.transfer (charrom[ch][j]); 142 | } 143 | } 144 | digitalWrite (this->cs_pin, 1); 145 | SPI.endTransaction (); 146 | } 147 | 148 | 149 | //--------------------------------------------------------------------------------------------- 150 | // add message to scrolling message buffer 151 | // if buffer is full, blocks until not full any more 152 | // calls display scroll and main loop timer tick functions so timers 153 | // continue to operate while blocked 154 | // 155 | 156 | void Display::scrollMessage (String s, bool reset) 157 | { 158 | int i; 159 | 160 | scrollBusyFlag = 2; 161 | 162 | if (reset) { 163 | scrollMessageBuffer.clear (); 164 | } 165 | 166 | for (i = 0; i < s.length (); i++) { 167 | while (!scrollMessageBuffer.availableForStore ()) { 168 | displayScrollTimer.tick (); 169 | // mainLoopTimer.tick (); 170 | } 171 | scrollMessageBuffer.store_char (s.charAt (i)); 172 | } 173 | } 174 | 175 | 176 | #ifdef NOPE 177 | //--------------------------------------------------------------------------------------------- 178 | // scroll column by column 179 | // 180 | 181 | // This scrolling doesn't look good because each character is exactly 5x7 and 182 | // they squish together when scrolled then unsuish with a bit of space 183 | // between them when column = 0. Going to scroll by whole character only. 184 | 185 | bool Display::tick (void *) 186 | { 187 | uint8_t i, adj, idx, col, ch; 188 | 189 | SPI.beginTransaction (displaySPISettings); 190 | digitalWrite (this->rs_pin, 0); 191 | digitalWrite (this->cs_pin, 0); 192 | 193 | // Serial.printf ("scrollIndex: %d\n\r", scrollIndex); 194 | // Serial.printf ("scrollBuffer: '%c%c%c%c%c\n\r'", 195 | // scrollBuffer[0], scrollBuffer[1], scrollBuffer[2], scrollBuffer[3], scrollBuffer[4]); 196 | 197 | for (int i = 0; i < 20; i++) { 198 | 199 | adj = i + scrollIndex; 200 | idx = adj / 5; 201 | col = adj % 5; 202 | ch = scrollBuffer[idx]; 203 | SPI.transfer (charrom[ch][col]); 204 | // Serial.printf (" %2d %2d %2d\n\r", adj, idx, col); 205 | } 206 | 207 | digitalWrite (this->cs_pin, 1); 208 | SPI.endTransaction (); 209 | 210 | scrollIndex++; 211 | if (scrollIndex >= 5) { 212 | scrollIndex = 0; 213 | for (i = 0; i < 4; i++) { 214 | scrollBuffer[i] = scrollBuffer[i+1]; 215 | } 216 | if (scrollMessageBuffer.available ()) { 217 | scrollBuffer[4] = scrollMessageBuffer.read_char (); 218 | } else { 219 | scrollBuffer[4] = ' '; 220 | if ((scrollBuffer[0] == ' ') && (scrollBuffer[1] == ' ') && (scrollBuffer[2] == ' ') && 221 | (scrollBuffer[3] == ' ') && (scrollBuffer[4] == ' ')) { 222 | scrollBusyFlag = false; 223 | } 224 | } 225 | } 226 | 227 | return true; 228 | } 229 | #endif 230 | 231 | 232 | //--------------------------------------------------------------------------------------------- 233 | // scroll character by character 234 | // 235 | 236 | bool Display::tick (void *) 237 | { 238 | uint8_t i, j; 239 | 240 | if (scrollBusyFlag) { 241 | SPI.beginTransaction (displaySPISettings); 242 | digitalWrite (this->rs_pin, 0); 243 | digitalWrite (this->cs_pin, 0); 244 | 245 | for (int i = 0; i < 4; i++) { 246 | for (int j = 0; j < 5; j++) { 247 | SPI.transfer (charrom[scrollBuffer[i]][j]); 248 | } 249 | } 250 | 251 | digitalWrite (this->cs_pin, 1); 252 | SPI.endTransaction (); 253 | 254 | for (i = 0; i < 4; i++) { 255 | scrollBuffer[i] = scrollBuffer[i+1]; 256 | } 257 | if (scrollMessageBuffer.available ()) { 258 | scrollBuffer[4] = scrollMessageBuffer.read_char (); 259 | // Serial.printf ("1: %c%c%c%c%c %d\n\r", scrollBuffer[0], scrollBuffer[1], scrollBuffer[2], scrollBuffer[3], scrollBuffer[4], scrollBusyFlag); 260 | } else { 261 | scrollBuffer[4] = ' '; 262 | if ((scrollBuffer[0] == ' ') && (scrollBuffer[1] == ' ') && (scrollBuffer[2] == ' ') && 263 | (scrollBuffer[3] == ' ') && (scrollBuffer[4] == ' ')) { 264 | scrollBusyFlag--; 265 | } 266 | // Serial.printf ("2: %c%c%c%c%c %d\n\r", scrollBuffer[0], scrollBuffer[1], scrollBuffer[2], scrollBuffer[3], scrollBuffer[4], scrollBusyFlag); 267 | } 268 | } 269 | 270 | return true; 271 | } 272 | 273 | 274 | //--------------------------------------------------------------------------------------------- 275 | // return state of scrollBusyFlag 276 | // 277 | 278 | bool Display::scrollBusy (void) 279 | { 280 | return (scrollBusyFlag != 0); 281 | } 282 | 283 | 284 | void Display::heartbeat (uint8_t col, uint8_t row) 285 | { 286 | SPI.beginTransaction (displaySPISettings); 287 | digitalWrite (this->rs_pin, 0); 288 | digitalWrite (this->cs_pin, 0); 289 | for (uint8_t i = 0; i < 20; i++) { 290 | if (i != col) { 291 | SPI.transfer (0x00); 292 | } else { 293 | SPI.transfer (0x01 << row); 294 | } 295 | } 296 | digitalWrite (this->cs_pin, 1); 297 | SPI.endTransaction (); 298 | } 299 | -------------------------------------------------------------------------------- /p1am-isolated-2x2-gpio/sketches/p1am-100-garage-door-monitor/p1am-100-garage-door-monitor.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "macaddr.h" 6 | #include "charrom.h" 7 | #include "display.h" 8 | 9 | #define RS485_DIR_PIN A0 10 | #define EUI48_CS_PIN 2 11 | #define IN1_PIN 3 12 | #define IN2_PIN 4 13 | #define OUT1_PIN 6 14 | #define OUT2_PIN 7 15 | 16 | Display display; 17 | auto displayScrollTimer = timer_create_default (); 18 | bool displayTickWrapper (void *a); 19 | auto mainLoopTimer = timer_create_default (); 20 | bool mainLoopTick (void *a); 21 | 22 | uint8_t in1_state = 0; 23 | uint8_t in2_state = 0; 24 | uint8_t out1_state = 0; 25 | uint8_t out2_state = 0; 26 | uint8_t heartbeat_timer = 0; 27 | uint8_t heartbeat_state = 0; 28 | 29 | bool lightsOffTimerEnabled = false; 30 | uint16_t lightsOffTimer = 0; 31 | 32 | // This MAC address is overwritten with the value from the EUI-48 serial EEPROM 33 | uint8_t mac[6] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 34 | IPAddress ip (192,168,180,177); 35 | IPAddress dns (1,1,1,1); 36 | EthernetClient client; 37 | void SetDoorOpenLight (bool state); 38 | void SetOverheadLights (bool state); 39 | 40 | void setup() 41 | { 42 | // Open serial communications and wait for port to open: 43 | Serial.begin(9600); 44 | #ifndef NOPE 45 | while (!Serial) { 46 | ; // wait for serial port to connect. Needed for native USB port only 47 | } 48 | #endif 49 | Serial.printf ("Hello, world!\n\r"); 50 | 51 | // initialize opto inputs, relay outputs 52 | pinMode (IN1_PIN, INPUT); 53 | pinMode (IN2_PIN, INPUT); 54 | pinMode (OUT1_PIN, OUTPUT); 55 | digitalWrite (OUT1_PIN, 0); 56 | pinMode (OUT2_PIN, OUTPUT); 57 | digitalWrite (OUT2_PIN, 0); 58 | pinMode (LED_BUILTIN, OUTPUT); 59 | digitalWrite (LED_BUILTIN, 0); 60 | 61 | // initialize RS-485 direction pin 62 | pinMode (RS485_DIR_PIN, OUTPUT); 63 | digitalWrite (RS485_DIR_PIN, 1); 64 | 65 | // initialize EUI-48 chip select pin 66 | pinMode (EUI48_CS_PIN, OUTPUT); 67 | digitalWrite (EUI48_CS_PIN, 1); 68 | 69 | // initialize display then display hello world message 70 | display.begin (A1, A2, A5, A6); 71 | displayScrollTimer.every (200, displayTickWrapper); 72 | display.scrollMessage ("Hello, world! ", true); 73 | 74 | // initialize main loop timer to execute at 50 Hz 75 | mainLoopTimer.every (20, mainLoopTick); 76 | 77 | // initialize input state variables based on state of garage door 78 | // so that things don't trigger immediately after power up 79 | in1_state = (!digitalRead (IN1_PIN)) ? 2 : 0; 80 | in2_state = (!digitalRead (IN2_PIN)) ? 2 : 0; 81 | 82 | // read mac address from serial EEPROM 83 | ReadMacAddress (EUI48_CS_PIN, mac); 84 | Serial.printf ("%02x:%02x:%02x:%02x:%02x:%02x\n\r", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 85 | 86 | char s[32]; 87 | snprintf (s, 32, "MAC: %02x:%02x:%02x:%02x:%02x:%02x ", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 88 | display.scrollMessage (s, false); 89 | 90 | // initialize Ethernet 91 | Ethernet.begin (mac); 92 | 93 | IPAddress ip = Ethernet.localIP (); 94 | snprintf (s, 32, "IP: %d.%d.%d.%d ", ip[0], ip[1], ip[2], ip[3]); 95 | display.scrollMessage (s, false); 96 | 97 | ip = Ethernet.dnsServerIP (); 98 | snprintf (s, 32, "DNS: %d.%d.%d.%d ", ip[0], ip[1], ip[2], ip[3]); 99 | display.scrollMessage (s, false); 100 | } 101 | 102 | 103 | void loop() 104 | { 105 | displayScrollTimer.tick (); 106 | mainLoopTimer.tick (); 107 | } 108 | 109 | 110 | bool displayTickWrapper (void *a) 111 | { 112 | return display.tick (a); 113 | } 114 | 115 | 116 | bool mainLoopTick (void *a) 117 | { 118 | //======================================== 119 | // read inputs and debounce 120 | //======================================== 121 | 122 | // read inputs 123 | uint8_t in1_raw = !digitalRead (IN1_PIN); 124 | uint8_t in2_raw = !digitalRead (IN2_PIN); 125 | 126 | // set state change triggers to no action 127 | uint8_t in1_turned_on = 0; 128 | uint8_t in2_turned_on = 0; 129 | uint8_t in1_turned_off = 0; 130 | uint8_t in2_turned_off = 0; 131 | 132 | // debounce input 1 and detect state changes 133 | switch (in1_state) { 134 | case 0: 135 | if (in1_raw) { 136 | in1_state = 1; 137 | } 138 | break; 139 | case 1: 140 | if (in1_raw) { 141 | in1_state = 2; 142 | in1_turned_on = 1; 143 | } else { 144 | in1_state = 0; 145 | } 146 | break; 147 | case 2: 148 | if (!in1_raw) { 149 | in1_state = 3; 150 | } 151 | break; 152 | case 3: 153 | if (in1_raw) { 154 | in1_state = 2; 155 | } else { 156 | in1_state = 0; 157 | in1_turned_off = 1; 158 | } 159 | break; 160 | default: 161 | in1_state = 0; 162 | break; 163 | } 164 | 165 | // debounce input 2 166 | switch (in2_state) { 167 | case 0: 168 | if (in2_raw) { 169 | in2_state = 1; 170 | } 171 | break; 172 | case 1: 173 | if (in2_raw) { 174 | in2_state = 2; 175 | in2_turned_on = 1; 176 | } else { 177 | in2_state = 0; 178 | } 179 | break; 180 | case 2: 181 | if (!in2_raw) { 182 | in2_state = 3; 183 | } 184 | break; 185 | case 3: 186 | if (in2_raw) { 187 | in2_state = 2; 188 | } else { 189 | in2_state = 0; 190 | in2_turned_off = 1; 191 | } 192 | break; 193 | default: 194 | in2_state = 0; 195 | break; 196 | } 197 | 198 | // compute on/off state of inputs from debounce state machines 199 | uint8_t in1_on = in1_state >= 2; 200 | uint8_t in2_on = in2_state >= 2; 201 | 202 | // builtin led is on when door is open 203 | digitalWrite (LED_BUILTIN, !in1_on); 204 | 205 | // check if door closed 206 | if (in1_turned_on) { 207 | display.scrollMessage ("Garage door closed.", true); 208 | 209 | // turn off indoor door open warning light 210 | SetDoorOpenLight (false); 211 | 212 | // enable lights off timer 213 | lightsOffTimerEnabled = true; 214 | lightsOffTimer = 5 * 60 * 50; // 5 minutes with a 50 Hz tick rate 215 | 216 | // send an IFTTT maker event 217 | // TODO 218 | } 219 | 220 | // check if door open 221 | if (in1_turned_off) { 222 | display.scrollMessage ("Garage door opened.", true); 223 | 224 | // turn on indoor door open warning light 225 | SetDoorOpenLight (true); 226 | 227 | // turn on overhead lights 228 | SetOverheadLights (true); 229 | 230 | // disable lights off timer 231 | lightsOffTimerEnabled = false; 232 | lightsOffTimer = 0; 233 | 234 | // send a text message 235 | // TODO 236 | 237 | // send an IFTTT maker event 238 | // TODO 239 | } 240 | 241 | // run timer and turn off overhead lights after five minutes 242 | if (lightsOffTimerEnabled) { 243 | lightsOffTimer--; 244 | if (lightsOffTimer == 0) { 245 | lightsOffTimerEnabled = false; 246 | display.scrollMessage ("Turning off overhead lights.", true); 247 | SetOverheadLights (false); 248 | } else { 249 | if (!display.scrollBusy ()) { 250 | uint16_t seconds = lightsOffTimer / 50; 251 | uint16_t minutes = seconds / 60; 252 | seconds = seconds % 60; 253 | char s[5]; 254 | snprintf (s, 5, "%01d:%02d", minutes, seconds); 255 | String msg = s; 256 | display.write (msg); 257 | } 258 | } 259 | } 260 | 261 | // increment heartbeat state and send data to display 262 | // if nothing else going on 263 | heartbeat_timer++; 264 | if (heartbeat_timer >= 4) { 265 | heartbeat_timer = 0; 266 | heartbeat_state++; 267 | if (heartbeat_state >= 140) { 268 | heartbeat_state = 0; 269 | } 270 | 271 | if (!display.scrollBusy () && !lightsOffTimerEnabled) { 272 | uint8_t col = heartbeat_state / 7; 273 | uint8_t row = heartbeat_state % 7; 274 | display.heartbeat (col, row); 275 | } 276 | } 277 | 278 | // eturn true to continue running timer 279 | return true; 280 | } 281 | 282 | 283 | void SetDoorOpenLight (bool state) 284 | { 285 | client.connect (IPAddress (192, 168, 180, 92), 2000); 286 | if (state) { 287 | // on 288 | client.print ("\r\n#ffffff\r\n#ffffff\r\n"); 289 | } else { 290 | // off 291 | client.print ("\r\n#000000\r\n#000000\r\n"); 292 | } 293 | delay (1); 294 | client.stop (); 295 | } 296 | 297 | 298 | void SetOverheadLights (bool state) 299 | { 300 | client.connect (IPAddress (192, 168, 180, 20), 80); 301 | if (state) { 302 | // on 303 | client.println ("GET /rest/nodes/3D%202E%2014%201/cmd/DON HTTP/1.1"); 304 | } else { 305 | // off 306 | client.println ("GET /rest/nodes/3D%202E%2014%201/cmd/DOF HTTP/1.1"); 307 | } 308 | client.println ("Authorization: Basic YWRtaW46eDNmZjcyaGs="); 309 | client.println ("Host: 192.168.180.20"); 310 | client.println ("Accept: \"/\""); 311 | client.println (); 312 | int startTime = millis (); 313 | int currTime; 314 | do { 315 | if (client.available ()) { 316 | char c = client.read (); 317 | } 318 | currTime = millis (); 319 | } while (client.connected () && (abs (currTime - startTime) < 1000)); 320 | client.stop (); 321 | } 322 | --------------------------------------------------------------------------------