commit 37813a2727656475dd85ecf03cda72b36b6d5b5a Author: Andrew Kay Date: Wed Jun 26 22:36:14 2019 -0500 Initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1b712bb --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2019, Andrew Kay + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7b36a5 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# coax-interface + +> Hello mainframe! + +coax-interface is a set of tools for interfacing with [IBM 3270](https://en.wikipedia.org/wiki/IBM_3270) type terminals. + +## Contents + +* [pycoax](pycoax) - Python IBM 3270 coaxial interface library +* [interface1](interface1) - A serial attached Arduino interface using the National Semiconductor DP8340 and DP8341 + +## See Also + +* [oec](https://github.com/lowobservable/oec) - An open replacement for the IBM 3174 Establishment Controller diff --git a/interface1/README.md b/interface1/README.md new file mode 100644 index 0000000..96ce304 --- /dev/null +++ b/interface1/README.md @@ -0,0 +1,32 @@ +# interface1 + +A serial attached Arduino interface using the National Semiconductor DP8340 and DP8341. + +## Schematic + +![Schematic](hardware/schematic.svg) + +## Materials + +This interface requires an [Arduino Mega](https://store.arduino.cc/usa/mega-2560-r3). + + Item | Quantity | Description | Reference | Part Number | Source +:----:|---------:|-------------------------------|-----------|-------------------------------|---------------- +1 | 1 | IBM 3270 Protocol Transmitter | U1 | National Semiconductor DP8340 | eBay - Obsolete +2 | 1 | IBM 3270 Protocol Receiver | U2 | National Semiconductor DP8341 | eBay - Obsolete +3 | 1 | Quad RS-422 Line Driver | U3 | Texas Instruments DS3487 | eBay - Obsolete +4 | 1 | Pulse Transformer - 1:1:1 | T1 | Pulse PE-5762 | eBay - Obsolete +5 | 1 | Crystal - 18.867 MHz | Y1 | IQD LFXTAL057125 * | [Mouser](https://www.mouser.com/ProductDetail/IQD/LFXTAL057125Bulk?qs=%2Fha2pyFaduieSzBxw7UAJRZlCXjBZuIKPyofrMyYW7wVunrhuBMeiQd4MCF50LLz) +6 | 2 | Resistor - 33 ohm | R2, R4 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-33-RC?qs=sGAEpiMZZMu61qfTUdNhGzoeXLT9qgk%252BV159XfY8c4Q%3D) +7 | 1 | Resistor - 120 ohm | R6 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-120-RC?qs=sGAEpiMZZMu61qfTUdNhG7Of23Pr6gu8rRE5UXBJoDw%3D) +8 | 2 | Resistor - 150 ohm | R1, R5 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-150-RC?qs=sGAEpiMZZMu61qfTUdNhG2ZzrN2CiS9nBcPQNrtAXYk%3D) +9 | 1 | Resistor - 500 ohm | R7 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-499-RC?qs=sGAEpiMZZMu61qfTUdNhG6lpw21m8SOsvE2iEnaSg1s%3D) +10 | 1 | Resistor - 510 ohm | R3 | | [Mouser](https://www.mouser.com/ProductDetail/Xicon/271-510-RC?qs=sGAEpiMZZMu61qfTUdNhG9RrhBeDi8B8FBVTnOgGHiw%3D) +11 | 1 | Capacitor - 30pF | C1 | | [Mouser](https://www.mouser.com/ProductDetail/Vishay-Cera-Mite/561R10TCCQ30?qs=sGAEpiMZZMt1mVBmZSXTPNbSVgF1iSv4q4pBhPBLwuM%3D) +12 | 1 | Coax Connector | J1 | | + +\* - SMD + +## Firmware + +The firmware currently provides the ability to send commands and receive responses - it is designed to be used to implement a terminal controller, not to emulate a terminal. diff --git a/interface1/firmware/CoaxTransceiver.cpp b/interface1/firmware/CoaxTransceiver.cpp new file mode 100644 index 0000000..63e3c57 --- /dev/null +++ b/interface1/firmware/CoaxTransceiver.cpp @@ -0,0 +1,305 @@ +// Copyright (c) 2019, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include + +#include "CoaxTransceiver.h" + +// Arduino Mega pins... +// +// Arduino Arduino Port Label DP8340N DP8341N +// Pin and Mask Pin Pin +// ---------|--------------|-----------------|---------|--------- +// 36 | PC1 | D2 | 10 | 14 +// 37 | PC0 | D3 | 9 | 15 +// 29 | PA7 | D4 | 8 | 16 +// 28 | PA6 | D5 | 7 | 17 +// 27 | PA5 | D6 | 6 | 18 +// 26 | PA4 | D7 | 5 | 19 +// 25 | PA3 | D8 | 4 | 20 +// 24 | PA2 | D9 | 3 | 21 +// 23 | PA1 | D10 | 2 | 22 +// 22 | PA0 | D11 | 1 | 23 +// --------- -------------- ----------------- --------- --------- +// 8 | PH5 0x20 | REGISTER LOAD | 23 | +// 9 | PH6 0x40 | REGISTERS FULL | 22 | +// 10 | | AUTO RESPONSE | 21 | +// 11 | | EVEN/ODD PARITY | 18 | +// 12 | PB6 0x40 | PARITY CONTROL | 19 | +// --------- -------------- ----------------- --------- --------- +// 18* | PD3 0x08 | RECEIVER ACTIVE | | 7 +// 2 | PE4 0x10 | DATA AVAILABLE | | 10 +// 3 | PE5 0x20 | ERROR | | 8 +// 4 | | DATA CONTROL | | 5 +// 5 | PE3 0x08 | REGISTER READ | | 9 +// 6 | PH3 0x08 | OUTPUT CONTROL | | 11 +// 7 | PH4 0x10 | OUTPUT ENABLE | | 13 +// +// * - Interrupt capable pin + +#define TX_REGISTER_LOAD_PIN 8 +#define TX_REGISTERS_FULL_PIN 9 +#define TX_AUTO_RESPONSE_PIN 10 +#define TX_EVEN_ODD_PARITY_PIN 11 +#define TX_PARITY_CONTROL_PIN 12 + +#define RX_ACTIVE_PIN 18 +#define RX_DATA_AVAILABLE_PIN 2 +#define RX_ERROR_PIN 3 +#define RX_DATA_CONTROL_PIN 4 +#define RX_REGISTER_READ_PIN 5 +#define RX_OUTPUT_CONTROL_PIN 6 +#define RX_OUTPUT_ENABLE_PIN 7 + +#define RX_STATE_DISABLED 0 +#define RX_STATE_WAITING 1 +#define RX_STATE_RECEIVING 2 +#define RX_STATE_RECEIVED 3 + +static volatile uint8_t CoaxTransceiver::rxState; +static volatile uint16_t *CoaxTransceiver::rxBuffer; +static volatile size_t CoaxTransceiver::rxBufferSize; +static volatile int /* ssize_t */ CoaxTransceiver::rxBufferCount; + +#define NOP __asm__("nop\n\t") + +static void CoaxTransceiver::setup() { + // Configure data bus. + dataBusSetup(); + + // Configure receiver (DP8341N). + rxSetup(); + + // Configure transmitter (DP8340N). + txSetup(); +} + +static int /* ssize_t */ CoaxTransceiver::transmitReceive(uint16_t commandWord, uint8_t *dataBuffer, size_t dataBufferCount, uint16_t *receiveBuffer, size_t receiveBufferSize, uint16_t timeout) { + int returnValue = transmit(commandWord, dataBuffer, dataBufferCount); + + if (returnValue < 0) { + return returnValue; + } + + return receive(receiveBuffer, receiveBufferSize, timeout); +} + +static void CoaxTransceiver::dataBusSetup() { + DDRA = B00000000; + DDRC = B00000000; +} + +static void CoaxTransceiver::rxSetup() { + // Data Control - Amplifier Inputs + pinMode(RX_DATA_CONTROL_PIN, OUTPUT); + + digitalWrite(RX_DATA_CONTROL_PIN, HIGH); + + // Register Read + pinMode(RX_REGISTER_READ_PIN, OUTPUT); + + digitalWrite(RX_REGISTER_READ_PIN, HIGH); + + // Output Control - Data + pinMode(RX_OUTPUT_CONTROL_PIN, OUTPUT); + + digitalWrite(RX_OUTPUT_CONTROL_PIN, HIGH); + + // Output Enable - Active + pinMode(RX_OUTPUT_ENABLE_PIN, OUTPUT); + + digitalWrite(RX_OUTPUT_ENABLE_PIN, HIGH); + + // Receiver Active + pinMode(RX_ACTIVE_PIN, INPUT); + + attachInterrupt(digitalPinToInterrupt(RX_ACTIVE_PIN), rxActiveInterrupt, RISING); + + // Data Available + pinMode(RX_DATA_AVAILABLE_PIN, INPUT); + + // Error + pinMode(RX_ERROR_PIN, INPUT); +} + +static void CoaxTransceiver::txSetup() { + // Register Load + pinMode(TX_REGISTER_LOAD_PIN, OUTPUT); + + digitalWrite(TX_REGISTER_LOAD_PIN, HIGH); + + // Auto Response - Data + pinMode(TX_AUTO_RESPONSE_PIN, OUTPUT); + + digitalWrite(TX_AUTO_RESPONSE_PIN, HIGH); + + // Even/Odd Parity - Even + pinMode(TX_EVEN_ODD_PARITY_PIN, OUTPUT); + + digitalWrite(TX_EVEN_ODD_PARITY_PIN, HIGH); + + // Parity Control - Data + pinMode(TX_PARITY_CONTROL_PIN, OUTPUT); + + digitalWrite(TX_PARITY_CONTROL_PIN, HIGH); + + // Registers Full + pinMode(TX_REGISTERS_FULL_PIN, INPUT); +} + +static int /* ssize_t */ CoaxTransceiver::transmit(uint16_t commandWord, uint8_t *dataBuffer, size_t dataCount) { + // Ensure receiver is inactive. + if (rxState != RX_STATE_DISABLED) { + return ERROR_TX_RECEIVER_ACTIVE; + } + + if ((PIND & 0x8) == 0x8) { + return ERROR_TX_RECEIVER_ACTIVE; + } + + // Disable interrupts. + noInterrupts(); + + // Disable receiver output. + PORTH &= ~0x10; // RX Output Enable - Low (Disable) + + // Configure data bus for output. + DDRA = B11111111; + DDRC = B00000011; + + // Send command word - we make an assumption here that TX_REGISTERS_FULL is not set. + PORTC = (PINC & 0xfc) | ((commandWord >> 8) & 0x3); + PORTA = commandWord & 0xff; + + PORTH &= ~0x20; // TX Register Load - Low (Load) + PORTH |= 0x20; // TX Register Load - High + + // Send data - offload parity computation to DP8340. + if (dataCount > 0) { + // Enable transmitter parity calculation. + PORTB &= ~0x40; // TX Parity Control - Low + + for (int index = 0; index < dataCount; index++) { + // Wait while TX Registers Full is high. + while ((PINH & 0x40) == 0x40) { + NOP; + } + + uint8_t data = dataBuffer[index]; + + PORTC = (PINC & 0xfc) | ((data >> 6) & 0x3); + PORTA = (data << 2); + + PORTH &= ~0x20; // TX Register Load - Low (Load) + PORTH |= 0x20; // TX Register Load - High + } + + // Disable transmitter parity calculation. + PORTB |= 0x40; // TX Parity Control - High + } + + // Configure data bus for input. + DDRA = B00000000; + DDRC = B00000000; + + // Enable receiver output. + PORTH |= 0x10; // RX Output Enable - High (Enable) + + // Enable interrupts. + interrupts(); + + return dataCount; +} + +static int /* ssize_t */ CoaxTransceiver::receive(uint16_t *buffer, size_t bufferSize, uint16_t timeout) { + rxBuffer = buffer; + rxBufferSize = bufferSize; + + rxState = RX_STATE_WAITING; + + if (timeout > 0) { + unsigned long startTime = millis(); + + while (rxState == RX_STATE_WAITING) { + // https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html#unsigned + if ((millis() - startTime) > timeout) { + rxState = RX_STATE_DISABLED; + return ERROR_RX_TIMEOUT; + } + } + } + + while (rxState != RX_STATE_RECEIVED) { + NOP; + } + + rxState = RX_STATE_DISABLED; + + return rxBufferCount; +} + +static void CoaxTransceiver::rxActiveInterrupt() { + uint16_t data; + uint8_t mask; + + if (rxState == RX_STATE_DISABLED) { + return; + } + + rxState = RX_STATE_RECEIVING; + + rxBufferCount = 0; + + do { + while ((PINE & 0x30) == 0) { + NOP; + } + + if (/* ERROR */ (PINE & 0x20) == 0x20) { + mask = 0x20; + + PORTH &= ~0x8; // Output Control - Low (Error) + PORTE &= ~0x8; // Register Read - Low + + // Read and mark as error. + data = (((PINC & 0x3) | 0x80) << 8) | PINA; + + PORTE |= 0x8; // Register Read - High + PORTH |= 0x8; // Output Control - High (Data) + } else if (/* DATA AVAILABLE */ (PINE & 0x10) == 0x10) { + mask = 0x10; + + PORTE &= ~0x8; // Register Read - Low + + // Read. + data = ((PINC & 0x3) << 8) | PINA; + + PORTE |= 0x8; // Register Read - High + } + + if (rxBufferCount >= rxBufferSize) { + rxBufferCount = ERROR_RX_OVERFLOW; + goto EXIT; + } + + rxBuffer[rxBufferCount++] = data; + + while ((PINE & mask) == mask) { + NOP; + } + } while ((PIND & 0x8) == 0x8); + +EXIT: + rxState = RX_STATE_RECEIVED; +} diff --git a/interface1/firmware/CoaxTransceiver.h b/interface1/firmware/CoaxTransceiver.h new file mode 100644 index 0000000..241587b --- /dev/null +++ b/interface1/firmware/CoaxTransceiver.h @@ -0,0 +1,40 @@ +// Copyright (c) 2019, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#pragma once + +#include + +#define ERROR_TX_RECEIVER_ACTIVE -1 +#define ERROR_RX_TIMEOUT -2 +#define ERROR_RX_OVERFLOW -3 + +class CoaxTransceiver { + public: + static void setup(); + static int /* ssize_t */ transmitReceive(uint16_t commandWord, uint8_t *dataBuffer, size_t dataBufferCount, uint16_t *receiveBuffer, size_t receiveBufferSize, uint16_t timeout); + + private: + static void dataBusSetup(); + static void rxSetup(); + static void txSetup(); + static int /* ssize_t */ transmit(uint16_t commandWord, uint8_t *dataBuffer, size_t dataCount); + static int /* ssize_t */ receive(uint16_t *buffer, size_t bufferSize, uint16_t timeout); + static void rxActiveInterrupt(); + + static volatile uint8_t rxState; + static volatile uint16_t *rxBuffer; + static volatile size_t rxBufferSize; + static volatile int /* ssize_t */ rxBufferCount; +}; diff --git a/interface1/firmware/firmware.ino b/interface1/firmware/firmware.ino new file mode 100644 index 0000000..a5a7f8c --- /dev/null +++ b/interface1/firmware/firmware.ino @@ -0,0 +1,304 @@ +// Copyright (c) 2019, Andrew Kay +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include + +#include "CoaxTransceiver.h" + +#define COMMAND_RESET 0x01 +#define COMMAND_EXECUTE 0x02 +#define COMMAND_EXECUTE_OFFLOAD 0x03 + +#define ERROR_INVALID_MESSAGE 1 +#define ERROR_UNKNOWN_COMMAND 2 +#define ERROR_UNKNOWN_OFFLOAD_COMMAND 3 + +#define UNPACK_DATA_WORD(w) (uint8_t) ((w >> 2) & 0xff) + +void handleResetCommand(uint8_t *buffer, int bufferCount) { + uint8_t response[] = { 0x01, 0x00, 0x00, 0x01 }; + + sendMessage(response, 4); +} + +void handleExecuteCommand(uint8_t *buffer, int bufferCount) { + if (bufferCount < 6) { + sendErrorMessage(ERROR_INVALID_MESSAGE); + return; + } + + uint16_t commandWord = (buffer[0] << 8) | buffer[1]; + uint16_t receiveCount = (buffer[2] << 8) | buffer[3]; + uint16_t timeout = (buffer[4] << 8) | buffer[5]; + + uint8_t *dataBuffer = buffer + 6; + uint16_t dataBufferCount = bufferCount - 6; + + uint16_t *receiveBuffer = (uint16_t *) (buffer + 2); + + bufferCount = CoaxTransceiver::transmitReceive(commandWord, dataBuffer, dataBufferCount, receiveBuffer, receiveCount, timeout); + + if (bufferCount < 0) { + sendErrorMessage(100 + ((-1) * bufferCount)); + return; + } + + // Send the response message. + buffer[1] = 0x01; + + bufferCount = 1 + (bufferCount * 2); + + sendMessage(buffer + 1, bufferCount); +} + +void handleExecuteOffloadCommand(uint8_t *buffer, int bufferCount) { + if (bufferCount < 1) { + sendErrorMessage(ERROR_INVALID_MESSAGE); + return; + } + + uint8_t command = buffer[0]; + + if (command == 0x01) { + handleOffloadLoadAddressCounter(buffer + 1, bufferCount - 1); + } else if (command == 0x02) { + handleOffloadWrite(buffer + 1, bufferCount - 1); + } else { + sendErrorMessage(ERROR_UNKNOWN_OFFLOAD_COMMAND); + } +} + +void handleOffloadLoadAddressCounter(uint8_t *buffer, int bufferCount) { + uint16_t response; + + if (bufferCount < 2) { + sendErrorMessage(ERROR_INVALID_MESSAGE); + return; + } + + uint8_t hi = buffer[0]; + uint8_t lo = buffer[1]; + + // TODO: error handling... + CoaxTransceiver::transmitReceive(/* LOAD_ADDRESS_COUNTER_HI */ 0x11, &hi, 1, &response, 1, 0); + CoaxTransceiver::transmitReceive(/* LOAD_ADDRESS_COUNTER_LO */ 0x51, &lo, 1, &response, 1, 0); + + // Send the response message. + uint8_t message[] = { 0x01 }; + + sendMessage(message, 1); +} + +void handleOffloadWrite(uint8_t *buffer, int bufferCount) { + uint16_t response; + + if (bufferCount < 5) { + sendErrorMessage(ERROR_INVALID_MESSAGE); + return; + } + + uint8_t addressHi = buffer[0]; + uint8_t addressLo = buffer[1]; + bool restoreOriginalAddress = buffer[2]; + uint16_t repeatCount = (buffer[3] << 8) | buffer[4]; + + uint8_t *dataBuffer = buffer + 5; + uint16_t dataBufferCount = bufferCount - 5; + + if (dataBufferCount < 1) { + sendErrorMessage(ERROR_INVALID_MESSAGE); + return; + } + + // Repeat the provided data if applicable. + if (repeatCount > 0) { + uint16_t dataBufferIndex = dataBufferCount; + + for (int repeatIndex = 0; repeatIndex < repeatCount; repeatIndex++) { + for (int index = 0; index < dataBufferCount; index++) { + dataBuffer[dataBufferIndex++] = dataBuffer[index]; + } + } + + dataBufferCount *= (repeatCount + 1); + } + + // Store original address if applicable. + uint8_t originalAddressHi; + uint8_t originalAddressLo; + + if (restoreOriginalAddress) { + CoaxTransceiver::transmitReceive(/* READ_ADDRESS_COUNTER_HI */ 0x15, NULL, 0, &response, 1, 0); + + originalAddressHi = UNPACK_DATA_WORD(response); + + CoaxTransceiver::transmitReceive(/* READ_ADDRESS_COUNTER_LO */ 0x55, NULL, 0, &response, 1, 0); + + originalAddressLo = UNPACK_DATA_WORD(response); + } + + // Move to start address if applicable. + if (!(addressHi == 0xff && addressLo == 0xff)) { + CoaxTransceiver::transmitReceive(/* LOAD_ADDRESS_COUNTER_HI */ 0x11, &addressHi, 1, &response, 1, 0); + CoaxTransceiver::transmitReceive(/* LOAD_ADDRESS_COUNTER_LO */ 0x51, &addressLo, 1, &response, 1, 0); + } + + // Write buffer. + CoaxTransceiver::transmitReceive(/* WRITE_DATA */ 0x31, dataBuffer, dataBufferCount, &response, 1, 0); + + // Restore original address if applicable. + if (restoreOriginalAddress) { + CoaxTransceiver::transmitReceive(/* LOAD_ADDRESS_COUNTER_HI */ 0x11, &originalAddressHi, 1, &response, 1, 0); + CoaxTransceiver::transmitReceive(/* LOAD_ADDRESS_COUNTER_LO */ 0x51, &originalAddressLo, 1, &response, 1, 0); + } + + // Send the response message. + uint8_t message[] = { 0x01 }; + + sendMessage(message, 1); +} + +void handleMessage(uint8_t *buffer, int bufferCount) { + if (bufferCount < 1) { + sendErrorMessage(ERROR_INVALID_MESSAGE); + return; + } + + uint8_t command = buffer[0]; + + if (command == COMMAND_RESET) { + handleResetCommand(buffer + 1, bufferCount - 1); + } else if (command == COMMAND_EXECUTE) { + handleExecuteCommand(buffer + 1, bufferCount - 1); + } else if (command == COMMAND_EXECUTE_OFFLOAD) { + handleExecuteOffloadCommand(buffer + 1, bufferCount - 1); + } else { + sendErrorMessage(ERROR_UNKNOWN_COMMAND); + } +} + +#define FRAME_END 0xc0 +#define FRAME_ESCAPE 0xdb +#define FRAME_ESCAPE_END 0xdc +#define FRAME_ESCAPE_ESCAPE 0xdd + +enum { + WAIT_START, + DATA, + ESCAPE +} frameState; + +#define FRAME_BUFFER_SIZE (25 * 80) + 32 + +uint8_t frameBuffer[FRAME_BUFFER_SIZE]; +int frameBufferCount = 0; + +void handleFrame(uint8_t *buffer, int bufferCount) { + if (bufferCount < 4) { + sendErrorMessage(ERROR_INVALID_MESSAGE); + return; + } + + int count = (buffer[0] << 8) | buffer[1]; + + if (bufferCount - 4 != count) { + sendErrorMessage(ERROR_INVALID_MESSAGE); + return; + } + + handleMessage(buffer + 2, count); +} + +void sendMessage(uint8_t *buffer, int bufferCount) { + Serial.write((char) FRAME_END); + + // Write the length. + Serial.write((char) bufferCount >> 8); + Serial.write((char) bufferCount); + + for (int index = 0; index < bufferCount; index++) { + if (buffer[index] == FRAME_END) { + Serial.write((char) FRAME_ESCAPE); + Serial.write((char) FRAME_ESCAPE_END); + } else if (buffer[index] == FRAME_ESCAPE) { + Serial.write((char) FRAME_ESCAPE); + Serial.write((char) FRAME_ESCAPE_ESCAPE); + } else { + Serial.write((char) buffer[index]); + } + } + + // Write the placeholder for checksum. + Serial.write((char) 0x00); + Serial.write((char) 0x00); + + Serial.write((char) FRAME_END); + + Serial.flush(); +} + +void sendErrorMessage(uint8_t code) { + uint8_t message[] = { 0x02, code }; + + sendMessage(message, 2); +} + +void setup() { + // Configure serial port and state machine. + Serial.begin(115200); + + frameState = WAIT_START; + + while (Serial.available() > 0) { + Serial.read(); + } + + // Configure the transceiver. + CoaxTransceiver::setup(); +} + +void loop() { + if (Serial.available() > 0) { + uint8_t byte = Serial.read(); + + if (frameState == WAIT_START) { + if (byte == FRAME_END) { + frameState = DATA; + } + } else if (frameState == DATA) { + if (byte == FRAME_END) { + if (frameBufferCount > 0) { + handleFrame(frameBuffer, frameBufferCount); + } + + frameBufferCount = 0; + } else if (byte == FRAME_ESCAPE) { + frameState = ESCAPE; + } else { + // TODO: overflow... + frameBuffer[frameBufferCount++] = byte; + } + } else if (frameState == ESCAPE) { + if (byte == FRAME_ESCAPE_END) { + // TODO: overflow... + frameBuffer[frameBufferCount++] = FRAME_END; + } else if (byte == FRAME_ESCAPE_ESCAPE) { + // TODO: overflow... + frameBuffer[frameBufferCount++] = FRAME_ESCAPE; + } + + frameState = DATA; + } + } +} diff --git a/interface1/hardware/hardware-cache.lib b/interface1/hardware/hardware-cache.lib new file mode 100644 index 0000000..dfae49d --- /dev/null +++ b/interface1/hardware/hardware-cache.lib @@ -0,0 +1,256 @@ +EESchema-LIBRARY Version 2.4 +#encoding utf-8 +# +# Connector_Conn_Coaxial +# +DEF Connector_Conn_Coaxial J 0 40 Y N 1 F N +F0 "J" 10 120 50 H V C CNN +F1 "Connector_Conn_Coaxial" 115 0 50 V V C CNN +F2 "" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +$FPLIST + *BNC* + *SMA* + *SMB* + *SMC* + *Cinch* +$ENDFPLIST +DRAW +A -2 0 71 1636 0 0 1 10 N -70 20 70 0 +A -1 0 71 0 -1638 0 1 10 N 70 0 -70 -20 +C 0 0 20 0 1 8 N +P 2 0 1 0 -100 0 -20 0 N +P 2 0 1 0 0 -100 0 -70 N +X In 1 -200 0 100 R 50 50 1 1 P +X Ext 2 0 -200 100 U 50 50 1 1 P +ENDDRAW +ENDDEF +# +# Device_C +# +DEF Device_C C 0 10 N Y 1 F N +F0 "C" 25 100 50 H V L CNN +F1 "Device_C" 25 -100 50 H V L CNN +F2 "" 38 -150 50 H I C CNN +F3 "" 0 0 50 H I C CNN +$FPLIST + C_* +$ENDFPLIST +DRAW +P 2 0 1 20 -80 -30 80 -30 N +P 2 0 1 20 -80 30 80 30 N +X ~ 1 0 150 110 D 50 50 1 1 P +X ~ 2 0 -150 110 U 50 50 1 1 P +ENDDRAW +ENDDEF +# +# Device_Crystal +# +DEF Device_Crystal Y 0 40 N N 1 F N +F0 "Y" 0 150 50 H V C CNN +F1 "Device_Crystal" 0 -150 50 H V C CNN +F2 "" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +$FPLIST + Crystal* +$ENDFPLIST +DRAW +S -45 100 45 -100 0 1 12 N +P 2 0 1 0 -100 0 -75 0 N +P 2 0 1 20 -75 -50 -75 50 N +P 2 0 1 20 75 -50 75 50 N +P 2 0 1 0 100 0 75 0 N +X 1 1 -150 0 50 R 50 50 1 1 P +X 2 2 150 0 50 L 50 50 1 1 P +ENDDRAW +ENDDEF +# +# Device_R_US +# +DEF Device_R_US R 0 0 N Y 1 F N +F0 "R" 100 0 50 V V C CNN +F1 "Device_R_US" -100 0 50 V V C CNN +F2 "" 40 -10 50 V I C CNN +F3 "" 0 0 50 H I C CNN +$FPLIST + R_* +$ENDFPLIST +DRAW +P 2 0 1 0 0 -90 0 -100 N +P 2 0 1 0 0 90 0 100 N +P 5 0 1 0 0 -30 40 -45 0 -60 -40 -75 0 -90 N +P 5 0 1 0 0 30 40 15 0 0 -40 -15 0 -30 N +P 5 0 1 0 0 90 40 75 0 60 -40 45 0 30 N +X ~ 1 0 150 50 D 50 50 1 1 P +X ~ 2 0 -150 50 U 50 50 1 1 P +ENDDRAW +ENDDEF +# +# library_DP8340 +# +DEF library_DP8340 U 0 40 Y Y 1 F N +F0 "U" 0 -100 50 H V C CNN +F1 "library_DP8340" 0 100 50 H V C CNN +F2 "MODULE" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +DRAW +S -450 -750 450 750 1 0 0 N +X DI11 1 -750 550 300 R 50 50 1 1 U +X DI2 10 -750 -350 300 R 50 50 1 1 U +X CLK_OUT 11 -750 -450 300 R 50 50 1 1 U +X GND 12 -750 -550 300 R 50 50 1 1 U +X X1 13 750 -550 300 L 50 50 1 1 U +X X2 14 750 -450 300 L 50 50 1 1 U +X DATA_DLY 15 750 -350 300 L 50 50 1 1 U +X DATA_OUT1 16 750 -250 300 L 50 50 1 1 U +X DATA_OUT2 17 750 -150 300 L 50 50 1 1 U +X EVEN_ODD 18 750 -50 300 L 50 50 1 1 U +X PARITY_CTL 19 750 50 300 L 50 50 1 1 U +X DI10 2 -750 450 300 R 50 50 1 1 U +X TX_ACTIVE 20 750 150 300 L 50 50 1 1 U +X AUTO_RESP 21 750 250 300 L 50 50 1 1 U +X REG_FULL 22 750 350 300 L 50 50 1 1 U +X REG_LOAD 23 750 450 300 L 50 50 1 1 U +X VCC 24 750 550 300 L 50 50 1 1 U +X DI9 3 -750 350 300 R 50 50 1 1 U +X DI8 4 -750 250 300 R 50 50 1 1 U +X DI7 5 -750 150 300 R 50 50 1 1 U +X DI6 6 -750 50 300 R 50 50 1 1 U +X DI5 7 -750 -50 300 R 50 50 1 1 U +X DI4 8 -750 -150 300 R 50 50 1 1 U +X DI3 9 -750 -250 300 R 50 50 1 1 U +ENDDRAW +ENDDEF +# +# library_DP8341 +# +DEF library_DP8341 U 0 40 Y Y 1 F N +F0 "U" 0 -100 50 H V C CNN +F1 "library_DP8341" 0 100 50 H V C CNN +F2 "MODULE" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +DRAW +S -450 -750 450 750 1 0 0 N +X RX_DISABLE 1 -750 550 300 R 50 50 1 1 U +X DATA_AVAIL 10 -750 -350 300 R 50 50 1 1 U +X OUTPUT_CTL 11 -750 -450 300 R 50 50 1 1 U +X GND 12 -750 -550 300 R 50 50 1 1 U +X OUTPUT_EN 13 750 -550 300 L 50 50 1 1 U +X DO2 14 750 -450 300 L 50 50 1 1 U +X DO3 15 750 -350 300 L 50 50 1 1 U +X DO4 16 750 -250 300 L 50 50 1 1 U +X DO5 17 750 -150 300 L 50 50 1 1 U +X DO6 18 750 -50 300 L 50 50 1 1 U +X DO7 19 750 50 300 L 50 50 1 1 U +X +AMP_IN 2 -750 450 300 R 50 50 1 1 U +X DO8 20 750 150 300 L 50 50 1 1 U +X DO9 21 750 250 300 L 50 50 1 1 U +X DO10 22 750 350 300 L 50 50 1 1 U +X DO11 23 750 450 300 L 50 50 1 1 U +X VCC 24 750 550 300 L 50 50 1 1 U +X -AMP_IN 3 -750 350 300 R 50 50 1 1 U +X DATA 4 -750 250 300 R 50 50 1 1 U +X DATA_CTL 5 -750 150 300 R 50 50 1 1 U +X CLOCK 6 -750 50 300 R 50 50 1 1 U +X RX_ACTIVE 7 -750 -50 300 R 50 50 1 1 U +X ERROR 8 -750 -150 300 R 50 50 1 1 U +X REG_READ 9 -750 -250 300 R 50 50 1 1 U +ENDDRAW +ENDDEF +# +# library_DS3487 +# +DEF library_DS3487 U 0 40 Y Y 1 F N +F0 "U" 0 -100 50 H V C CNN +F1 "library_DS3487" 0 100 50 H V C CNN +F2 "MODULE" 0 0 50 H I C CNN +F3 "DOCUMENTATION" 0 0 50 H I C CNN +DRAW +S -450 -550 450 550 1 0 0 N +X PIN1 1 -750 350 300 R 50 50 1 1 U +X PIN10 10 750 -250 300 L 50 50 1 1 U +X PIN11 11 750 -150 300 L 50 50 1 1 U +X PIN12 12 750 -50 300 L 50 50 1 1 U +X PIN13 13 750 50 300 L 50 50 1 1 U +X PIN14 14 750 150 300 L 50 50 1 1 U +X PIN15 15 750 250 300 L 50 50 1 1 U +X PIN16 16 750 350 300 L 50 50 1 1 U +X PIN2 2 -750 250 300 R 50 50 1 1 U +X PIN3 3 -750 150 300 R 50 50 1 1 U +X PIN4 4 -750 50 300 R 50 50 1 1 U +X PIN5 5 -750 -50 300 R 50 50 1 1 U +X PIN6 6 -750 -150 300 R 50 50 1 1 U +X PIN7 7 -750 -250 300 R 50 50 1 1 U +X PIN8 8 -750 -350 300 R 50 50 1 1 U +X PIN9 9 750 -350 300 L 50 50 1 1 U +ENDDRAW +ENDDEF +# +# library_xxxx +# +DEF library_xxxx T 0 20 Y N 1 F N +F0 "T" 0 550 50 H V C CNN +F1 "library_xxxx" 0 -550 50 H V C CNN +F2 "Transformer_SMD:Pulse_PA2002NL-PA2008NL-PA2009NL" 0 0 50 H I C CNN +F3 "" -300 0 50 H I C CNN +DRAW +A -100 -90 30 900 -900 0 1 8 N -100 -60 -100 -120 +A -100 -30 30 900 -900 0 1 8 N -100 0 -100 -60 +A -100 30 30 900 -900 0 1 8 N -100 60 -100 0 +A 100 -390 30 -900 900 0 1 8 N 100 -420 100 -360 +A 100 -330 30 -900 900 0 1 8 N 100 -360 100 -300 +A 100 -270 30 -900 900 0 1 8 N 100 -300 100 -240 +A 100 -210 30 -900 900 0 1 8 N 100 -240 100 -180 +A 100 210 30 -900 900 0 1 8 N 100 180 100 240 +A 100 270 30 -900 900 0 1 8 N 100 240 100 300 +A 100 330 30 -900 900 0 1 8 N 100 300 100 360 +A 100 390 30 -900 900 0 1 8 N 100 360 100 420 +A -100 90 30 900 -900 1 1 8 N -100 120 -100 60 +C -100 90 10 0 1 0 F +C 100 -210 10 0 1 0 F +C 100 390 10 0 1 0 F +P 2 0 1 0 -100 -120 -100 -200 N +P 2 0 1 0 -100 200 -100 120 N +P 2 0 1 0 -25 425 -25 -425 N +P 2 0 1 0 25 425 25 -425 N +P 2 0 1 0 100 -420 100 -500 N +P 2 0 1 0 100 -100 100 -180 N +P 2 0 1 0 100 180 100 100 N +P 2 0 1 0 100 500 100 420 N +X ~ 1 200 500 100 L 50 50 1 1 P +X ~ 2 200 100 100 L 50 50 1 1 P +X ~ 3 -200 200 100 R 50 50 1 1 P +X ~ 4 -200 -200 100 R 50 50 1 1 P +X ~ 5 200 -100 100 L 50 50 1 1 P +X ~ 6 200 -500 100 L 50 50 1 1 P +ENDDRAW +ENDDEF +# +# power_GND +# +DEF power_GND #PWR 0 0 Y Y 1 F P +F0 "#PWR" 0 -250 50 H I C CNN +F1 "power_GND" 0 -150 50 H V C CNN +F2 "" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +DRAW +P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N +X GND 1 0 0 0 D 50 50 1 1 W N +ENDDRAW +ENDDEF +# +# power_VCC +# +DEF power_VCC #PWR 0 0 Y Y 1 F P +F0 "#PWR" 0 -150 50 H I C CNN +F1 "power_VCC" 0 150 50 H V C CNN +F2 "" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +DRAW +C 0 75 25 0 1 0 N +P 2 0 1 0 0 0 0 50 N +X VCC 1 0 0 0 U 50 50 1 1 W N +ENDDRAW +ENDDEF +# +#End Library diff --git a/interface1/hardware/hardware-rescue.dcm b/interface1/hardware/hardware-rescue.dcm new file mode 100644 index 0000000..5f3ed79 --- /dev/null +++ b/interface1/hardware/hardware-rescue.dcm @@ -0,0 +1,3 @@ +EESchema-DOCLIB Version 2.0 +# +#End Doc Library diff --git a/interface1/hardware/hardware.bak b/interface1/hardware/hardware.bak new file mode 100644 index 0000000..654ebd2 --- /dev/null +++ b/interface1/hardware/hardware.bak @@ -0,0 +1,557 @@ +EESchema Schematic File Version 4 +EELAYER 29 0 +EELAYER END +$Descr USLetter 11000 8500 +encoding utf-8 +Sheet 1 1 +Title "" +Date "" +Rev "" +Comp "" +Comment1 "" +Comment2 "" +Comment3 "" +Comment4 "Based on the typical application from the DP8340 and DP8341 data sheets" +$EndDescr +$Comp +L library:DP8340 U1 +U 1 1 5CFF4259 +P 4200 2500 +F 0 "U1" H 4200 3415 50 0000 C CNN +F 1 "DP8340" H 4200 3324 50 0000 C CNN +F 2 "MODULE" H 4200 2500 50 0001 C CNN +F 3 "" H 4200 2500 50 0001 C CNN + 1 4200 2500 + 1 0 0 -1 +$EndComp +$Comp +L Device:R_US R7 +U 1 1 5D005C33 +P 5450 3200 +F 0 "R7" H 5518 3246 50 0000 L CNN +F 1 "500" H 5518 3155 50 0000 L CNN +F 2 "" V 5490 3190 50 0001 C CNN +F 3 "~" H 5450 3200 50 0001 C CNN + 1 5450 3200 + 1 0 0 -1 +$EndComp +$Comp +L Device:Crystal Y1 +U 1 1 5D0074D0 +P 4950 3200 +F 0 "Y1" V 4996 3069 50 0000 R CNN +F 1 "Crystal" V 4905 3069 50 0000 R CNN +F 2 "" H 4950 3200 50 0001 C CNN +F 3 "~" H 4950 3200 50 0001 C CNN + 1 4950 3200 + 0 -1 -1 0 +$EndComp +$Comp +L power:VCC #PWR? +U 1 1 5D0081F3 +P 5200 3750 +F 0 "#PWR?" H 5200 3600 50 0001 C CNN +F 1 "VCC" H 5218 3923 50 0000 C CNN +F 2 "" H 5200 3750 50 0001 C CNN +F 3 "" H 5200 3750 50 0001 C CNN + 1 5200 3750 + -1 0 0 1 +$EndComp +$Comp +L Device:R_US R1 +U 1 1 5D01411B +P 8300 1800 +F 0 "R1" V 8505 1800 50 0000 C CNN +F 1 "150" V 8414 1800 50 0000 C CNN +F 2 "" V 8340 1790 50 0001 C CNN +F 3 "~" H 8300 1800 50 0001 C CNN + 1 8300 1800 + 0 -1 -1 0 +$EndComp +$Comp +L Device:R_US R2 +U 1 1 5D014636 +P 8300 2200 +F 0 "R2" V 8505 2200 50 0000 C CNN +F 1 "33" V 8414 2200 50 0000 C CNN +F 2 "" V 8340 2190 50 0001 C CNN +F 3 "~" H 8300 2200 50 0001 C CNN + 1 8300 2200 + 0 -1 -1 0 +$EndComp +$Comp +L Device:R_US R4 +U 1 1 5D01DB0F +P 8300 2600 +F 0 "R4" V 8505 2600 50 0000 C CNN +F 1 "33" V 8414 2600 50 0000 C CNN +F 2 "" V 8340 2590 50 0001 C CNN +F 3 "~" H 8300 2600 50 0001 C CNN + 1 8300 2600 + 0 -1 -1 0 +$EndComp +$Comp +L Device:R_US R5 +U 1 1 5D01DE87 +P 8300 3000 +F 0 "R5" V 8505 3000 50 0000 C CNN +F 1 "150" V 8414 3000 50 0000 C CNN +F 2 "" V 8340 2990 50 0001 C CNN +F 3 "~" H 8300 3000 50 0001 C CNN + 1 8300 3000 + 0 -1 -1 0 +$EndComp +$Comp +L Device:R_US R3 +U 1 1 5D026837 +P 8550 2400 +F 0 "R3" H 8618 2446 50 0000 L CNN +F 1 "510" H 8618 2355 50 0000 L CNN +F 2 "" V 8590 2390 50 0001 C CNN +F 3 "~" H 8550 2400 50 0001 C CNN + 1 8550 2400 + 1 0 0 -1 +$EndComp +Wire Wire Line + 7850 1500 7850 2200 +Wire Wire Line + 7850 2200 8150 2200 +Wire Wire Line + 6250 2250 6050 2250 +Wire Wire Line + 6050 2250 6050 1400 +Wire Wire Line + 6050 1400 7950 1400 +Wire Wire Line + 7950 1400 7950 1800 +Wire Wire Line + 7950 1800 8150 1800 +Wire Wire Line + 7850 2600 8150 2600 +Wire Wire Line + 8450 1800 8550 1800 +Wire Wire Line + 8550 1800 8550 2200 +Wire Wire Line + 8450 3000 8550 3000 +Wire Wire Line + 8550 3000 8550 2600 +Wire Wire Line + 8450 2200 8550 2200 +Connection ~ 8550 2200 +Wire Wire Line + 8550 2200 8550 2250 +Wire Wire Line + 8450 2600 8550 2600 +Connection ~ 8550 2600 +Wire Wire Line + 8550 2600 8550 2550 +Wire Wire Line + 4950 2850 5600 2850 +Wire Wire Line + 5600 2850 5600 2050 +Wire Wire Line + 5600 2050 6250 2050 +$Comp +L library:DS3487 U? +U 1 1 5D035700 +P 7000 2400 +F 0 "U?" H 7000 3115 50 0000 C CNN +F 1 "DS3487" H 7000 3024 50 0000 C CNN +F 2 "MODULE" H 7000 2400 50 0001 C CNN +F 3 "" H 7000 2400 50 0001 C CNN + 1 7000 2400 + 1 0 0 -1 +$EndComp +$Comp +L library:xxxx T1 +U 1 1 5D03C013 +P 9100 2700 +F 0 "T1" H 9100 3381 50 0000 C CNN +F 1 "xxxx" H 9100 3290 50 0000 C CNN +F 2 "Transformer_SMD:Pulse_PA2002NL-PA2008NL-PA2009NL" H 9100 2700 50 0001 C CNN +F 3 "https://productfinder.pulseeng.com/products/datasheets/P663.pdf" H 8800 2700 50 0001 C CNN + 1 9100 2700 + -1 0 0 -1 +$EndComp +Wire Wire Line + 8550 2200 8900 2200 +Wire Wire Line + 8550 2600 8900 2600 +$Comp +L Connector:Conn_Coaxial J1 +U 1 1 5D047BD2 +P 9700 2500 +F 0 "J1" H 9800 2475 50 0000 L CNN +F 1 "RG62" H 9800 2384 50 0000 L CNN +F 2 "" H 9700 2500 50 0001 C CNN +F 3 " ~" H 9700 2500 50 0001 C CNN + 1 9700 2500 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9700 2700 9700 2900 +Wire Wire Line + 9700 2900 9450 2900 +Wire Wire Line + 9300 2500 9450 2500 +$Comp +L Device:R_US R6 +U 1 1 5D04B24C +P 9450 2700 +F 0 "R6" H 9518 2746 50 0000 L CNN +F 1 "120" H 9518 2655 50 0000 L CNN +F 2 "" V 9490 2690 50 0001 C CNN +F 3 "~" H 9450 2700 50 0001 C CNN + 1 9450 2700 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9450 2550 9450 2500 +Connection ~ 9450 2500 +Wire Wire Line + 9450 2500 9500 2500 +Wire Wire Line + 9450 2850 9450 2900 +Connection ~ 9450 2900 +Wire Wire Line + 9450 2900 9300 2900 +$Comp +L power:GND #PWR? +U 1 1 5D04EB7E +P 6250 3000 +F 0 "#PWR?" H 6250 2750 50 0001 C CNN +F 1 "GND" H 6255 2827 50 0000 C CNN +F 2 "" H 6250 3000 50 0001 C CNN +F 3 "" H 6250 3000 50 0001 C CNN + 1 6250 3000 + 1 0 0 -1 +$EndComp +$Comp +L power:GND #PWR? +U 1 1 5D051C9E +P 3450 3350 +F 0 "#PWR?" H 3450 3100 50 0001 C CNN +F 1 "GND" H 3455 3177 50 0000 C CNN +F 2 "" H 3450 3350 50 0001 C CNN +F 3 "" H 3450 3350 50 0001 C CNN + 1 3450 3350 + 1 0 0 -1 +$EndComp +Wire Wire Line + 3450 3350 3450 3050 +$Comp +L Device:C C1 +U 1 1 5D05AC0A +P 5200 3600 +F 0 "C1" H 5315 3646 50 0000 L CNN +F 1 "30 pF" H 5315 3555 50 0000 L CNN +F 2 "" H 5238 3450 50 0001 C CNN +F 3 "~" H 5200 3600 50 0001 C CNN + 1 5200 3600 + 1 0 0 -1 +$EndComp +$Comp +L library:DP8341 U2 +U 1 1 5D0650F6 +P 4200 5100 +F 0 "U2" H 4200 4185 50 0000 C CNN +F 1 "DP8341" H 4200 4276 50 0000 C CNN +F 2 "MODULE" H 4200 5100 50 0001 C CNN +F 3 "" H 4200 5100 50 0001 C CNN + 1 4200 5100 + -1 0 0 1 +$EndComp +Wire Wire Line + 4950 5550 8700 5550 +Wire Wire Line + 8700 2800 8900 2800 +Wire Wire Line + 4950 5450 8800 5450 +Wire Wire Line + 8800 3200 8900 3200 +Wire Wire Line + 4950 5650 5750 5650 +Wire Wire Line + 3450 2950 3200 2950 +Wire Wire Line + 3200 4050 5250 4050 +Wire Wire Line + 5250 4050 5250 5150 +Wire Wire Line + 5250 5150 4950 5150 +Wire Wire Line + 3450 4650 3100 4650 +Wire Wire Line + 3100 2850 3450 2850 +Wire Wire Line + 3450 4750 3000 4750 +Wire Wire Line + 3000 2750 3450 2750 +Wire Wire Line + 3450 4850 2900 4850 +Wire Wire Line + 2900 2650 3450 2650 +Wire Wire Line + 3450 4950 2800 4950 +Wire Wire Line + 2800 2550 3450 2550 +Wire Wire Line + 3450 2450 2700 2450 +Wire Wire Line + 2700 5050 3450 5050 +Wire Wire Line + 3450 2350 2600 2350 +Wire Wire Line + 2600 5150 3450 5150 +Wire Wire Line + 3450 2250 2500 2250 +Wire Wire Line + 2500 5250 3450 5250 +Wire Wire Line + 3450 2150 2400 2150 +Wire Wire Line + 2400 5350 3450 5350 +Wire Wire Line + 3450 2050 2300 2050 +Wire Wire Line + 2300 5450 3450 5450 +Wire Wire Line + 3450 1950 2200 1950 +Wire Wire Line + 2200 5550 3450 5550 +Text GLabel 1100 5550 0 50 Input ~ 0 +MEGA22 +Wire Wire Line + 1100 5550 2200 5550 +Connection ~ 2200 5550 +Text GLabel 1100 5450 0 50 Input ~ 0 +MEGA23 +Wire Wire Line + 1100 5450 2300 5450 +Connection ~ 2300 5450 +Text GLabel 1100 5350 0 50 Input ~ 0 +MEGA24 +Text GLabel 1100 5250 0 50 Input ~ 0 +MEGA25 +Text GLabel 1100 5150 0 50 Input ~ 0 +MEGA26 +Text GLabel 1100 5050 0 50 Input ~ 0 +MEGA27 +Text GLabel 1100 4950 0 50 Input ~ 0 +MEGA28 +Text GLabel 1100 4850 0 50 Input ~ 0 +MEGA29 +Text GLabel 1100 4750 0 50 Input ~ 0 +MEGA37 +Text GLabel 1100 4650 0 50 Input ~ 0 +MEGA36 +Wire Wire Line + 1100 4650 3100 4650 +Connection ~ 3100 4650 +Wire Wire Line + 1100 4750 3000 4750 +Connection ~ 3000 4750 +Wire Wire Line + 1100 4850 2900 4850 +Connection ~ 2900 4850 +Wire Wire Line + 1100 4950 2800 4950 +Connection ~ 2800 4950 +Wire Wire Line + 1100 5050 2700 5050 +Connection ~ 2700 5050 +Wire Wire Line + 1100 5150 2600 5150 +Connection ~ 2600 5150 +Wire Wire Line + 1100 5250 2500 5250 +Connection ~ 2500 5250 +Wire Wire Line + 1100 5350 2400 5350 +Connection ~ 2400 5350 +Text GLabel 1050 4550 0 50 Input ~ 0 +MEGA7 +Wire Wire Line + 1050 4550 3450 4550 +Text GLabel 6100 4750 2 50 Input ~ 0 +MEGA2 +Text GLabel 6100 4950 2 50 Input ~ 0 +MEGA3 +Text GLabel 6100 4850 2 50 Input ~ 0 +MEGA5 +Text GLabel 6100 5250 2 50 Input ~ 0 +MEGA4 +Text GLabel 6100 4650 2 50 Input ~ 0 +MEGA6 +Wire Wire Line + 4950 4650 6100 4650 +Wire Wire Line + 4950 4750 6100 4750 +Wire Wire Line + 4950 4850 6100 4850 +Wire Wire Line + 4950 4950 6100 4950 +Wire Wire Line + 4950 5250 6100 5250 +$Comp +L power:GND #PWR? +U 1 1 5D0CF15F +P 4950 4350 +F 0 "#PWR?" H 4950 4100 50 0001 C CNN +F 1 "GND" H 4955 4177 50 0000 C CNN +F 2 "" H 4950 4350 50 0001 C CNN +F 3 "" H 4950 4350 50 0001 C CNN + 1 4950 4350 + -1 0 0 1 +$EndComp +Wire Wire Line + 4950 4350 4950 4550 +Text GLabel 6100 5050 2 50 Input ~ 0 +MEGA18 +Wire Wire Line + 4950 5050 6100 5050 +Text GLabel 5050 1050 1 50 Input ~ 0 +MEGA8 +Text GLabel 5150 1050 1 50 Input ~ 0 +META9 +Text GLabel 5250 1050 1 50 Input ~ 0 +MEGA10 +Text GLabel 5450 1050 1 50 Input ~ 0 +MEGA11 +Text GLabel 5350 1050 1 50 Input ~ 0 +MEGA12 +Wire Wire Line + 4950 2150 5150 2150 +Wire Wire Line + 5150 2150 5150 1050 +Wire Wire Line + 4950 2250 5250 2250 +Wire Wire Line + 5250 2250 5250 1050 +Wire Wire Line + 5350 1050 5350 2450 +Wire Wire Line + 5350 2450 4950 2450 +Wire Wire Line + 4950 2550 5450 2550 +Wire Wire Line + 5450 2550 5450 1050 +Wire Wire Line + 4950 2050 5050 2050 +Wire Wire Line + 5050 2050 5050 1050 +$Comp +L power:VCC #PWR? +U 1 1 5D110504 +P 3450 5900 +F 0 "#PWR?" H 3450 5750 50 0001 C CNN +F 1 "VCC" H 3468 6073 50 0000 C CNN +F 2 "" H 3450 5900 50 0001 C CNN +F 3 "" H 3450 5900 50 0001 C CNN + 1 3450 5900 + -1 0 0 1 +$EndComp +Wire Wire Line + 3450 5650 3450 5900 +$Comp +L power:VCC #PWR? +U 1 1 5D118163 +P 4950 1600 +F 0 "#PWR?" H 4950 1450 50 0001 C CNN +F 1 "VCC" H 4967 1773 50 0000 C CNN +F 2 "" H 4950 1600 50 0001 C CNN +F 3 "" H 4950 1600 50 0001 C CNN + 1 4950 1600 + 1 0 0 -1 +$EndComp +Wire Wire Line + 4950 1600 4950 1950 +Wire Wire Line + 4950 2950 5450 2950 +Wire Wire Line + 5450 2950 5450 3050 +Wire Wire Line + 4950 2350 5750 2350 +Wire Wire Line + 4950 3350 4950 3450 +Wire Wire Line + 4950 3450 5200 3450 +Wire Wire Line + 5200 3450 5450 3450 +Wire Wire Line + 5450 3450 5450 3350 +Connection ~ 5200 3450 +Wire Wire Line + 4950 2650 6250 2650 +Wire Wire Line + 5750 5650 5750 2350 +Connection ~ 5750 2350 +Wire Wire Line + 5750 2350 6250 2350 +Wire Wire Line + 3200 2950 3200 4050 +Wire Wire Line + 3100 2850 3100 4650 +Wire Wire Line + 3000 2750 3000 4750 +Wire Wire Line + 2900 2650 2900 4850 +Wire Wire Line + 2800 2550 2800 4950 +Wire Wire Line + 2700 2450 2700 5050 +Wire Wire Line + 2600 2350 2600 5150 +Wire Wire Line + 2500 2250 2500 5250 +Wire Wire Line + 2400 2150 2400 5350 +Wire Wire Line + 2300 2050 2300 5450 +Wire Wire Line + 2200 1950 2200 5550 +Wire Wire Line + 8700 2800 8700 5550 +Wire Wire Line + 8800 3200 8800 5450 +$Comp +L power:VCC #PWR? +U 1 1 5D1B82CE +P 7750 1750 +F 0 "#PWR?" H 7750 1600 50 0001 C CNN +F 1 "VCC" H 7767 1923 50 0000 C CNN +F 2 "" H 7750 1750 50 0001 C CNN +F 3 "" H 7750 1750 50 0001 C CNN + 1 7750 1750 + 1 0 0 -1 +$EndComp +Wire Wire Line + 6250 2750 6250 3000 +Wire Wire Line + 7850 3300 6050 3300 +Wire Wire Line + 6050 3300 6050 2550 +Wire Wire Line + 6050 2550 6250 2550 +Wire Wire Line + 7850 2600 7850 3300 +Wire Wire Line + 6250 2450 6150 2450 +Wire Wire Line + 6150 2450 6150 1500 +Wire Wire Line + 6150 1500 7850 1500 +Wire Wire Line + 6250 2150 5950 2150 +Wire Wire Line + 5950 2150 5950 3400 +Wire Wire Line + 5950 3400 7950 3400 +Wire Wire Line + 7950 3400 7950 3000 +Wire Wire Line + 7950 3000 8150 3000 +Wire Wire Line + 7750 1750 7750 2050 +$EndSCHEMATC diff --git a/interface1/hardware/hardware.kicad_pcb b/interface1/hardware/hardware.kicad_pcb new file mode 100644 index 0000000..02c8ecb --- /dev/null +++ b/interface1/hardware/hardware.kicad_pcb @@ -0,0 +1 @@ +(kicad_pcb (version 4) (host kicad "dummy file") ) diff --git a/interface1/hardware/hardware.pro b/interface1/hardware/hardware.pro new file mode 100644 index 0000000..152769c --- /dev/null +++ b/interface1/hardware/hardware.pro @@ -0,0 +1,33 @@ +update=22/05/2015 07:44:53 +version=1 +last_client=kicad +[general] +version=1 +RootSch= +BoardNm= +[pcbnew] +version=1 +LastNetListRead= +UseCmpFile=1 +PadDrill=0.600000000000 +PadDrillOvalY=0.600000000000 +PadSizeH=1.500000000000 +PadSizeV=1.500000000000 +PcbTextSizeV=1.500000000000 +PcbTextSizeH=1.500000000000 +PcbTextThickness=0.300000000000 +ModuleTextSizeV=1.000000000000 +ModuleTextSizeH=1.000000000000 +ModuleTextSizeThickness=0.150000000000 +SolderMaskClearance=0.000000000000 +SolderMaskMinWidth=0.000000000000 +DrawSegmentWidth=0.200000000000 +BoardOutlineThickness=0.100000000000 +ModuleOutlineThickness=0.150000000000 +[cvpcb] +version=1 +NetIExt=net +[eeschema] +version=1 +LibDir= +[eeschema/libraries] diff --git a/interface1/hardware/hardware.sch b/interface1/hardware/hardware.sch new file mode 100644 index 0000000..9f3babc --- /dev/null +++ b/interface1/hardware/hardware.sch @@ -0,0 +1,557 @@ +EESchema Schematic File Version 4 +EELAYER 29 0 +EELAYER END +$Descr USLetter 11000 8500 +encoding utf-8 +Sheet 1 1 +Title "" +Date "" +Rev "" +Comp "" +Comment1 "" +Comment2 "" +Comment3 "" +Comment4 "Based on the typical application from the DP8340 and DP8341 data sheets" +$EndDescr +$Comp +L library:DP8340 U1 +U 1 1 5CFF4259 +P 4200 2500 +F 0 "U1" H 4200 3415 50 0000 C CNN +F 1 "DP8340" H 4200 3324 50 0000 C CNN +F 2 "MODULE" H 4200 2500 50 0001 C CNN +F 3 "" H 4200 2500 50 0001 C CNN + 1 4200 2500 + 1 0 0 -1 +$EndComp +$Comp +L Device:R_US R7 +U 1 1 5D005C33 +P 5450 3200 +F 0 "R7" H 5518 3246 50 0000 L CNN +F 1 "500" H 5518 3155 50 0000 L CNN +F 2 "" V 5490 3190 50 0001 C CNN +F 3 "~" H 5450 3200 50 0001 C CNN + 1 5450 3200 + 1 0 0 -1 +$EndComp +$Comp +L Device:Crystal Y1 +U 1 1 5D0074D0 +P 4950 3200 +F 0 "Y1" V 4996 3069 50 0000 R CNN +F 1 "Crystal" V 4905 3069 50 0000 R CNN +F 2 "" H 4950 3200 50 0001 C CNN +F 3 "~" H 4950 3200 50 0001 C CNN + 1 4950 3200 + 0 -1 -1 0 +$EndComp +$Comp +L power:VCC #PWR? +U 1 1 5D0081F3 +P 5200 3750 +F 0 "#PWR?" H 5200 3600 50 0001 C CNN +F 1 "VCC" H 5218 3923 50 0000 C CNN +F 2 "" H 5200 3750 50 0001 C CNN +F 3 "" H 5200 3750 50 0001 C CNN + 1 5200 3750 + -1 0 0 1 +$EndComp +$Comp +L Device:R_US R1 +U 1 1 5D01411B +P 8300 1800 +F 0 "R1" V 8505 1800 50 0000 C CNN +F 1 "150" V 8414 1800 50 0000 C CNN +F 2 "" V 8340 1790 50 0001 C CNN +F 3 "~" H 8300 1800 50 0001 C CNN + 1 8300 1800 + 0 -1 -1 0 +$EndComp +$Comp +L Device:R_US R2 +U 1 1 5D014636 +P 8300 2200 +F 0 "R2" V 8505 2200 50 0000 C CNN +F 1 "33" V 8414 2200 50 0000 C CNN +F 2 "" V 8340 2190 50 0001 C CNN +F 3 "~" H 8300 2200 50 0001 C CNN + 1 8300 2200 + 0 -1 -1 0 +$EndComp +$Comp +L Device:R_US R4 +U 1 1 5D01DB0F +P 8300 2600 +F 0 "R4" V 8505 2600 50 0000 C CNN +F 1 "33" V 8414 2600 50 0000 C CNN +F 2 "" V 8340 2590 50 0001 C CNN +F 3 "~" H 8300 2600 50 0001 C CNN + 1 8300 2600 + 0 -1 -1 0 +$EndComp +$Comp +L Device:R_US R5 +U 1 1 5D01DE87 +P 8300 3000 +F 0 "R5" V 8505 3000 50 0000 C CNN +F 1 "150" V 8414 3000 50 0000 C CNN +F 2 "" V 8340 2990 50 0001 C CNN +F 3 "~" H 8300 3000 50 0001 C CNN + 1 8300 3000 + 0 -1 -1 0 +$EndComp +$Comp +L Device:R_US R3 +U 1 1 5D026837 +P 8550 2400 +F 0 "R3" H 8618 2446 50 0000 L CNN +F 1 "510" H 8618 2355 50 0000 L CNN +F 2 "" V 8590 2390 50 0001 C CNN +F 3 "~" H 8550 2400 50 0001 C CNN + 1 8550 2400 + 1 0 0 -1 +$EndComp +Wire Wire Line + 7850 1500 7850 2200 +Wire Wire Line + 7850 2200 8150 2200 +Wire Wire Line + 6250 2250 6050 2250 +Wire Wire Line + 6050 2250 6050 1400 +Wire Wire Line + 6050 1400 7950 1400 +Wire Wire Line + 7950 1400 7950 1800 +Wire Wire Line + 7950 1800 8150 1800 +Wire Wire Line + 7850 2600 8150 2600 +Wire Wire Line + 8450 1800 8550 1800 +Wire Wire Line + 8550 1800 8550 2200 +Wire Wire Line + 8450 3000 8550 3000 +Wire Wire Line + 8550 3000 8550 2600 +Wire Wire Line + 8450 2200 8550 2200 +Connection ~ 8550 2200 +Wire Wire Line + 8550 2200 8550 2250 +Wire Wire Line + 8450 2600 8550 2600 +Connection ~ 8550 2600 +Wire Wire Line + 8550 2600 8550 2550 +Wire Wire Line + 4950 2850 5600 2850 +Wire Wire Line + 5600 2850 5600 2050 +Wire Wire Line + 5600 2050 6250 2050 +$Comp +L library:DS3487 U3 +U 1 1 5D035700 +P 7000 2400 +F 0 "U3" H 7000 3115 50 0000 C CNN +F 1 "DS3487" H 7000 3024 50 0000 C CNN +F 2 "MODULE" H 7000 2400 50 0001 C CNN +F 3 "" H 7000 2400 50 0001 C CNN + 1 7000 2400 + 1 0 0 -1 +$EndComp +$Comp +L library:xxxx T1 +U 1 1 5D03C013 +P 9100 2700 +F 0 "T1" H 9100 3381 50 0000 C CNN +F 1 "PE-5762" H 9100 3290 50 0000 C CNN +F 2 "Transformer_SMD:Pulse_PA2002NL-PA2008NL-PA2009NL" H 9100 2700 50 0001 C CNN +F 3 "https://productfinder.pulseeng.com/products/datasheets/P663.pdf" H 8800 2700 50 0001 C CNN + 1 9100 2700 + -1 0 0 -1 +$EndComp +Wire Wire Line + 8550 2200 8900 2200 +Wire Wire Line + 8550 2600 8900 2600 +$Comp +L Connector:Conn_Coaxial J1 +U 1 1 5D047BD2 +P 9700 2500 +F 0 "J1" H 9800 2475 50 0000 L CNN +F 1 "RG62" H 9800 2384 50 0000 L CNN +F 2 "" H 9700 2500 50 0001 C CNN +F 3 " ~" H 9700 2500 50 0001 C CNN + 1 9700 2500 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9700 2700 9700 2900 +Wire Wire Line + 9700 2900 9450 2900 +Wire Wire Line + 9300 2500 9450 2500 +$Comp +L Device:R_US R6 +U 1 1 5D04B24C +P 9450 2700 +F 0 "R6" H 9518 2746 50 0000 L CNN +F 1 "120" H 9518 2655 50 0000 L CNN +F 2 "" V 9490 2690 50 0001 C CNN +F 3 "~" H 9450 2700 50 0001 C CNN + 1 9450 2700 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9450 2550 9450 2500 +Connection ~ 9450 2500 +Wire Wire Line + 9450 2500 9500 2500 +Wire Wire Line + 9450 2850 9450 2900 +Connection ~ 9450 2900 +Wire Wire Line + 9450 2900 9300 2900 +$Comp +L power:GND #PWR? +U 1 1 5D04EB7E +P 6250 3000 +F 0 "#PWR?" H 6250 2750 50 0001 C CNN +F 1 "GND" H 6255 2827 50 0000 C CNN +F 2 "" H 6250 3000 50 0001 C CNN +F 3 "" H 6250 3000 50 0001 C CNN + 1 6250 3000 + 1 0 0 -1 +$EndComp +$Comp +L power:GND #PWR? +U 1 1 5D051C9E +P 3450 3350 +F 0 "#PWR?" H 3450 3100 50 0001 C CNN +F 1 "GND" H 3455 3177 50 0000 C CNN +F 2 "" H 3450 3350 50 0001 C CNN +F 3 "" H 3450 3350 50 0001 C CNN + 1 3450 3350 + 1 0 0 -1 +$EndComp +Wire Wire Line + 3450 3350 3450 3050 +$Comp +L Device:C C1 +U 1 1 5D05AC0A +P 5200 3600 +F 0 "C1" H 5315 3646 50 0000 L CNN +F 1 "30 pF" H 5315 3555 50 0000 L CNN +F 2 "" H 5238 3450 50 0001 C CNN +F 3 "~" H 5200 3600 50 0001 C CNN + 1 5200 3600 + 1 0 0 -1 +$EndComp +$Comp +L library:DP8341 U2 +U 1 1 5D0650F6 +P 4200 5100 +F 0 "U2" H 4200 4185 50 0000 C CNN +F 1 "DP8341" H 4200 4276 50 0000 C CNN +F 2 "MODULE" H 4200 5100 50 0001 C CNN +F 3 "" H 4200 5100 50 0001 C CNN + 1 4200 5100 + -1 0 0 1 +$EndComp +Wire Wire Line + 4950 5550 8700 5550 +Wire Wire Line + 8700 2800 8900 2800 +Wire Wire Line + 4950 5450 8800 5450 +Wire Wire Line + 8800 3200 8900 3200 +Wire Wire Line + 4950 5650 5750 5650 +Wire Wire Line + 3450 2950 3200 2950 +Wire Wire Line + 3200 4050 5250 4050 +Wire Wire Line + 5250 4050 5250 5150 +Wire Wire Line + 5250 5150 4950 5150 +Wire Wire Line + 3450 4650 3100 4650 +Wire Wire Line + 3100 2850 3450 2850 +Wire Wire Line + 3450 4750 3000 4750 +Wire Wire Line + 3000 2750 3450 2750 +Wire Wire Line + 3450 4850 2900 4850 +Wire Wire Line + 2900 2650 3450 2650 +Wire Wire Line + 3450 4950 2800 4950 +Wire Wire Line + 2800 2550 3450 2550 +Wire Wire Line + 3450 2450 2700 2450 +Wire Wire Line + 2700 5050 3450 5050 +Wire Wire Line + 3450 2350 2600 2350 +Wire Wire Line + 2600 5150 3450 5150 +Wire Wire Line + 3450 2250 2500 2250 +Wire Wire Line + 2500 5250 3450 5250 +Wire Wire Line + 3450 2150 2400 2150 +Wire Wire Line + 2400 5350 3450 5350 +Wire Wire Line + 3450 2050 2300 2050 +Wire Wire Line + 2300 5450 3450 5450 +Wire Wire Line + 3450 1950 2200 1950 +Wire Wire Line + 2200 5550 3450 5550 +Text GLabel 1100 5550 0 50 Input ~ 0 +MEGA22 +Wire Wire Line + 1100 5550 2200 5550 +Connection ~ 2200 5550 +Text GLabel 1100 5450 0 50 Input ~ 0 +MEGA23 +Wire Wire Line + 1100 5450 2300 5450 +Connection ~ 2300 5450 +Text GLabel 1100 5350 0 50 Input ~ 0 +MEGA24 +Text GLabel 1100 5250 0 50 Input ~ 0 +MEGA25 +Text GLabel 1100 5150 0 50 Input ~ 0 +MEGA26 +Text GLabel 1100 5050 0 50 Input ~ 0 +MEGA27 +Text GLabel 1100 4950 0 50 Input ~ 0 +MEGA28 +Text GLabel 1100 4850 0 50 Input ~ 0 +MEGA29 +Text GLabel 1100 4750 0 50 Input ~ 0 +MEGA37 +Text GLabel 1100 4650 0 50 Input ~ 0 +MEGA36 +Wire Wire Line + 1100 4650 3100 4650 +Connection ~ 3100 4650 +Wire Wire Line + 1100 4750 3000 4750 +Connection ~ 3000 4750 +Wire Wire Line + 1100 4850 2900 4850 +Connection ~ 2900 4850 +Wire Wire Line + 1100 4950 2800 4950 +Connection ~ 2800 4950 +Wire Wire Line + 1100 5050 2700 5050 +Connection ~ 2700 5050 +Wire Wire Line + 1100 5150 2600 5150 +Connection ~ 2600 5150 +Wire Wire Line + 1100 5250 2500 5250 +Connection ~ 2500 5250 +Wire Wire Line + 1100 5350 2400 5350 +Connection ~ 2400 5350 +Text GLabel 1050 4550 0 50 Input ~ 0 +MEGA7 +Wire Wire Line + 1050 4550 3450 4550 +Text GLabel 6100 4750 2 50 Input ~ 0 +MEGA2 +Text GLabel 6100 4950 2 50 Input ~ 0 +MEGA3 +Text GLabel 6100 4850 2 50 Input ~ 0 +MEGA5 +Text GLabel 6100 5250 2 50 Input ~ 0 +MEGA4 +Text GLabel 6100 4650 2 50 Input ~ 0 +MEGA6 +Wire Wire Line + 4950 4650 6100 4650 +Wire Wire Line + 4950 4750 6100 4750 +Wire Wire Line + 4950 4850 6100 4850 +Wire Wire Line + 4950 4950 6100 4950 +Wire Wire Line + 4950 5250 6100 5250 +$Comp +L power:GND #PWR? +U 1 1 5D0CF15F +P 4950 4350 +F 0 "#PWR?" H 4950 4100 50 0001 C CNN +F 1 "GND" H 4955 4177 50 0000 C CNN +F 2 "" H 4950 4350 50 0001 C CNN +F 3 "" H 4950 4350 50 0001 C CNN + 1 4950 4350 + -1 0 0 1 +$EndComp +Wire Wire Line + 4950 4350 4950 4550 +Text GLabel 6100 5050 2 50 Input ~ 0 +MEGA18 +Wire Wire Line + 4950 5050 6100 5050 +Text GLabel 5050 1050 1 50 Input ~ 0 +MEGA8 +Text GLabel 5150 1050 1 50 Input ~ 0 +META9 +Text GLabel 5250 1050 1 50 Input ~ 0 +MEGA10 +Text GLabel 5450 1050 1 50 Input ~ 0 +MEGA11 +Text GLabel 5350 1050 1 50 Input ~ 0 +MEGA12 +Wire Wire Line + 4950 2150 5150 2150 +Wire Wire Line + 5150 2150 5150 1050 +Wire Wire Line + 4950 2250 5250 2250 +Wire Wire Line + 5250 2250 5250 1050 +Wire Wire Line + 5350 1050 5350 2450 +Wire Wire Line + 5350 2450 4950 2450 +Wire Wire Line + 4950 2550 5450 2550 +Wire Wire Line + 5450 2550 5450 1050 +Wire Wire Line + 4950 2050 5050 2050 +Wire Wire Line + 5050 2050 5050 1050 +$Comp +L power:VCC #PWR? +U 1 1 5D110504 +P 3450 5900 +F 0 "#PWR?" H 3450 5750 50 0001 C CNN +F 1 "VCC" H 3468 6073 50 0000 C CNN +F 2 "" H 3450 5900 50 0001 C CNN +F 3 "" H 3450 5900 50 0001 C CNN + 1 3450 5900 + -1 0 0 1 +$EndComp +Wire Wire Line + 3450 5650 3450 5900 +$Comp +L power:VCC #PWR? +U 1 1 5D118163 +P 4950 1600 +F 0 "#PWR?" H 4950 1450 50 0001 C CNN +F 1 "VCC" H 4967 1773 50 0000 C CNN +F 2 "" H 4950 1600 50 0001 C CNN +F 3 "" H 4950 1600 50 0001 C CNN + 1 4950 1600 + 1 0 0 -1 +$EndComp +Wire Wire Line + 4950 1600 4950 1950 +Wire Wire Line + 4950 2950 5450 2950 +Wire Wire Line + 5450 2950 5450 3050 +Wire Wire Line + 4950 2350 5750 2350 +Wire Wire Line + 4950 3350 4950 3450 +Wire Wire Line + 4950 3450 5200 3450 +Wire Wire Line + 5200 3450 5450 3450 +Wire Wire Line + 5450 3450 5450 3350 +Connection ~ 5200 3450 +Wire Wire Line + 4950 2650 6250 2650 +Wire Wire Line + 5750 5650 5750 2350 +Connection ~ 5750 2350 +Wire Wire Line + 5750 2350 6250 2350 +Wire Wire Line + 3200 2950 3200 4050 +Wire Wire Line + 3100 2850 3100 4650 +Wire Wire Line + 3000 2750 3000 4750 +Wire Wire Line + 2900 2650 2900 4850 +Wire Wire Line + 2800 2550 2800 4950 +Wire Wire Line + 2700 2450 2700 5050 +Wire Wire Line + 2600 2350 2600 5150 +Wire Wire Line + 2500 2250 2500 5250 +Wire Wire Line + 2400 2150 2400 5350 +Wire Wire Line + 2300 2050 2300 5450 +Wire Wire Line + 2200 1950 2200 5550 +Wire Wire Line + 8700 2800 8700 5550 +Wire Wire Line + 8800 3200 8800 5450 +$Comp +L power:VCC #PWR? +U 1 1 5D1B82CE +P 7750 1750 +F 0 "#PWR?" H 7750 1600 50 0001 C CNN +F 1 "VCC" H 7767 1923 50 0000 C CNN +F 2 "" H 7750 1750 50 0001 C CNN +F 3 "" H 7750 1750 50 0001 C CNN + 1 7750 1750 + 1 0 0 -1 +$EndComp +Wire Wire Line + 6250 2750 6250 3000 +Wire Wire Line + 7850 3300 6050 3300 +Wire Wire Line + 6050 3300 6050 2550 +Wire Wire Line + 6050 2550 6250 2550 +Wire Wire Line + 7850 2600 7850 3300 +Wire Wire Line + 6250 2450 6150 2450 +Wire Wire Line + 6150 2450 6150 1500 +Wire Wire Line + 6150 1500 7850 1500 +Wire Wire Line + 6250 2150 5950 2150 +Wire Wire Line + 5950 2150 5950 3400 +Wire Wire Line + 5950 3400 7950 3400 +Wire Wire Line + 7950 3400 7950 3000 +Wire Wire Line + 7950 3000 8150 3000 +Wire Wire Line + 7750 1750 7750 2050 +$EndSCHEMATC diff --git a/interface1/hardware/library.bck b/interface1/hardware/library.bck new file mode 100644 index 0000000..81a0360 --- /dev/null +++ b/interface1/hardware/library.bck @@ -0,0 +1,9 @@ +EESchema-DOCLIB Version 2.0 +# +$CMP xxxx +D xxxx +K pulse +F https://productfinder.pulseeng.com/products/datasheets/P663.pdf +$ENDCMP +# +#End Doc Library diff --git a/interface1/hardware/library.dcm b/interface1/hardware/library.dcm new file mode 100644 index 0000000..81a0360 --- /dev/null +++ b/interface1/hardware/library.dcm @@ -0,0 +1,9 @@ +EESchema-DOCLIB Version 2.0 +# +$CMP xxxx +D xxxx +K pulse +F https://productfinder.pulseeng.com/products/datasheets/P663.pdf +$ENDCMP +# +#End Doc Library diff --git a/interface1/hardware/library.lib b/interface1/hardware/library.lib new file mode 100644 index 0000000..0e50d2b --- /dev/null +++ b/interface1/hardware/library.lib @@ -0,0 +1,144 @@ +EESchema-LIBRARY Version 2.4 +#encoding utf-8 +# +# DP8340 +# +DEF DP8340 U 0 40 Y Y 1 F N +F0 "U" 0 -100 50 H V C CNN +F1 "DP8340" 0 100 50 H V C CNN +F2 "MODULE" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +DRAW +S -450 -750 450 750 1 0 0 N +X DI11 1 -750 550 300 R 50 50 1 1 U +X DI2 10 -750 -350 300 R 50 50 1 1 U +X CLK_OUT 11 -750 -450 300 R 50 50 1 1 U +X GND 12 -750 -550 300 R 50 50 1 1 U +X X1 13 750 -550 300 L 50 50 1 1 U +X X2 14 750 -450 300 L 50 50 1 1 U +X DATA_DLY 15 750 -350 300 L 50 50 1 1 U +X DATA_OUT1 16 750 -250 300 L 50 50 1 1 U +X DATA_OUT2 17 750 -150 300 L 50 50 1 1 U +X EVEN_ODD 18 750 -50 300 L 50 50 1 1 U +X PARITY_CTL 19 750 50 300 L 50 50 1 1 U +X DI10 2 -750 450 300 R 50 50 1 1 U +X TX_ACTIVE 20 750 150 300 L 50 50 1 1 U +X AUTO_RESP 21 750 250 300 L 50 50 1 1 U +X REG_FULL 22 750 350 300 L 50 50 1 1 U +X REG_LOAD 23 750 450 300 L 50 50 1 1 U +X VCC 24 750 550 300 L 50 50 1 1 U +X DI9 3 -750 350 300 R 50 50 1 1 U +X DI8 4 -750 250 300 R 50 50 1 1 U +X DI7 5 -750 150 300 R 50 50 1 1 U +X DI6 6 -750 50 300 R 50 50 1 1 U +X DI5 7 -750 -50 300 R 50 50 1 1 U +X DI4 8 -750 -150 300 R 50 50 1 1 U +X DI3 9 -750 -250 300 R 50 50 1 1 U +ENDDRAW +ENDDEF +# +# DP8341 +# +DEF DP8341 U 0 40 Y Y 1 F N +F0 "U" 0 -100 50 H V C CNN +F1 "DP8341" 0 100 50 H V C CNN +F2 "MODULE" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +DRAW +S -450 -750 450 750 1 0 0 N +X RX_DISABLE 1 -750 550 300 R 50 50 1 1 U +X DATA_AVAIL 10 -750 -350 300 R 50 50 1 1 U +X OUTPUT_CTL 11 -750 -450 300 R 50 50 1 1 U +X GND 12 -750 -550 300 R 50 50 1 1 U +X OUTPUT_EN 13 750 -550 300 L 50 50 1 1 U +X DO2 14 750 -450 300 L 50 50 1 1 U +X DO3 15 750 -350 300 L 50 50 1 1 U +X DO4 16 750 -250 300 L 50 50 1 1 U +X DO5 17 750 -150 300 L 50 50 1 1 U +X DO6 18 750 -50 300 L 50 50 1 1 U +X DO7 19 750 50 300 L 50 50 1 1 U +X +AMP_IN 2 -750 450 300 R 50 50 1 1 U +X DO8 20 750 150 300 L 50 50 1 1 U +X DO9 21 750 250 300 L 50 50 1 1 U +X DO10 22 750 350 300 L 50 50 1 1 U +X DO11 23 750 450 300 L 50 50 1 1 U +X VCC 24 750 550 300 L 50 50 1 1 U +X -AMP_IN 3 -750 350 300 R 50 50 1 1 U +X DATA 4 -750 250 300 R 50 50 1 1 U +X DATA_CTL 5 -750 150 300 R 50 50 1 1 U +X CLOCK 6 -750 50 300 R 50 50 1 1 U +X RX_ACTIVE 7 -750 -50 300 R 50 50 1 1 U +X ERROR 8 -750 -150 300 R 50 50 1 1 U +X REG_READ 9 -750 -250 300 R 50 50 1 1 U +ENDDRAW +ENDDEF +# +# DS3487 +# +DEF DS3487 U 0 40 Y Y 1 F N +F0 "U" 0 -100 50 H V C CNN +F1 "DS3487" 0 100 50 H V C CNN +F2 "MODULE" 0 0 50 H I C CNN +F3 "DOCUMENTATION" 0 0 50 H I C CNN +DRAW +S -450 -550 450 550 1 0 0 N +X PIN1 1 -750 350 300 R 50 50 1 1 U +X PIN10 10 750 -250 300 L 50 50 1 1 U +X PIN11 11 750 -150 300 L 50 50 1 1 U +X PIN12 12 750 -50 300 L 50 50 1 1 U +X PIN13 13 750 50 300 L 50 50 1 1 U +X PIN14 14 750 150 300 L 50 50 1 1 U +X PIN15 15 750 250 300 L 50 50 1 1 U +X PIN16 16 750 350 300 L 50 50 1 1 U +X PIN2 2 -750 250 300 R 50 50 1 1 U +X PIN3 3 -750 150 300 R 50 50 1 1 U +X PIN4 4 -750 50 300 R 50 50 1 1 U +X PIN5 5 -750 -50 300 R 50 50 1 1 U +X PIN6 6 -750 -150 300 R 50 50 1 1 U +X PIN7 7 -750 -250 300 R 50 50 1 1 U +X PIN8 8 -750 -350 300 R 50 50 1 1 U +X PIN9 9 750 -350 300 L 50 50 1 1 U +ENDDRAW +ENDDEF +# +# xxxx +# +DEF xxxx T 0 20 Y N 1 F N +F0 "T" 0 550 50 H V C CNN +F1 "xxxx" 0 -550 50 H V C CNN +F2 "Transformer_SMD:Pulse_PA2002NL-PA2008NL-PA2009NL" 0 0 50 H I C CNN +F3 "" -300 0 50 H I C CNN +DRAW +A -100 -90 30 900 -900 0 1 8 N -100 -60 -100 -120 +A -100 -30 30 900 -900 0 1 8 N -100 0 -100 -60 +A -100 30 30 900 -900 0 1 8 N -100 60 -100 0 +A 100 -390 30 -900 900 0 1 8 N 100 -420 100 -360 +A 100 -330 30 -900 900 0 1 8 N 100 -360 100 -300 +A 100 -270 30 -900 900 0 1 8 N 100 -300 100 -240 +A 100 -210 30 -900 900 0 1 8 N 100 -240 100 -180 +A 100 210 30 -900 900 0 1 8 N 100 180 100 240 +A 100 270 30 -900 900 0 1 8 N 100 240 100 300 +A 100 330 30 -900 900 0 1 8 N 100 300 100 360 +A 100 390 30 -900 900 0 1 8 N 100 360 100 420 +A -100 90 30 900 -900 1 1 8 N -100 120 -100 60 +C -100 90 10 0 1 0 F +C 100 -210 10 0 1 0 F +C 100 390 10 0 1 0 F +P 2 0 1 0 -100 -120 -100 -200 N +P 2 0 1 0 -100 200 -100 120 N +P 2 0 1 0 -25 425 -25 -425 N +P 2 0 1 0 25 425 25 -425 N +P 2 0 1 0 100 -420 100 -500 N +P 2 0 1 0 100 -100 100 -180 N +P 2 0 1 0 100 180 100 100 N +P 2 0 1 0 100 500 100 420 N +X ~ 1 200 500 100 L 50 50 1 1 P +X ~ 2 200 100 100 L 50 50 1 1 P +X ~ 3 -200 200 100 R 50 50 1 1 P +X ~ 4 -200 -200 100 R 50 50 1 1 P +X ~ 5 200 -100 100 L 50 50 1 1 P +X ~ 6 200 -500 100 L 50 50 1 1 P +ENDDRAW +ENDDEF +# +#End Library diff --git a/interface1/hardware/schematic.svg b/interface1/hardware/schematic.svg new file mode 100644 index 0000000..78e155d --- /dev/null +++ b/interface1/hardware/schematic.svg @@ -0,0 +1,12844 @@ + + + +SVG Picture created as hardware.svg date 2019/06/12 20:53:28 + Picture generated by Eeschema-SVG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface1/hardware/sym-lib-table b/interface1/hardware/sym-lib-table new file mode 100644 index 0000000..b165bca --- /dev/null +++ b/interface1/hardware/sym-lib-table @@ -0,0 +1,3 @@ +(sym_lib_table + (lib (name library)(type Legacy)(uri ${KIPRJMOD}/library.lib)(options "")(descr "")) +) diff --git a/pycoax/.gitignore b/pycoax/.gitignore new file mode 100644 index 0000000..bdf77fd --- /dev/null +++ b/pycoax/.gitignore @@ -0,0 +1,112 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +VIRTUALENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json diff --git a/pycoax/LICENSE b/pycoax/LICENSE new file mode 100644 index 0000000..1b712bb --- /dev/null +++ b/pycoax/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2019, Andrew Kay + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/pycoax/README.md b/pycoax/README.md new file mode 100644 index 0000000..77e3649 --- /dev/null +++ b/pycoax/README.md @@ -0,0 +1,9 @@ +# pycoax + +Python IBM 3270 coaxial interface library. + +## Use + +You will need to build a [interface](../interface1) and connect it to your computer. + +See [examples](examples) for complete examples. diff --git a/pycoax/coax/__about__.py b/pycoax/coax/__about__.py new file mode 100644 index 0000000..b794fd4 --- /dev/null +++ b/pycoax/coax/__about__.py @@ -0,0 +1 @@ +__version__ = '0.1.0' diff --git a/pycoax/coax/__init__.py b/pycoax/coax/__init__.py new file mode 100644 index 0000000..f9415fc --- /dev/null +++ b/pycoax/coax/__init__.py @@ -0,0 +1,39 @@ +from .__about__ import __version__ + +from .interface1 import Interface1 + +from .protocol import ( + PollResponse, + PowerOnResetCompletePollResponse, + KeystrokePollResponse, + poll, + poll_ack, + read_status, + read_terminal_id, + read_extended_id, + read_address_counter_hi, + read_address_counter_lo, + read_data, + read_multiple, + reset, + load_control_register, + load_secondary_control, + load_mask, + load_address_counter_hi, + load_address_counter_lo, + write_data, + clear, + search_forward, + search_backward, + insert_byte, + start_operation, + diagnostic_reset +) + +from .exceptions import ( + InterfaceError, + ReceiveError, + InterfaceTimeout, + ReceiveTimeout, + ProtocolError +) diff --git a/pycoax/coax/exceptions.py b/pycoax/coax/exceptions.py new file mode 100644 index 0000000..8b4ac89 --- /dev/null +++ b/pycoax/coax/exceptions.py @@ -0,0 +1,19 @@ +""" +coax.exceptions +~~~~~~~~~~~~~~~ +""" + +class InterfaceError(Exception): + """An interface error occurred.""" + +class ReceiveError(Exception): + """A receive error occurred.""" + +class InterfaceTimeout(Exception): + """The interface timed out.""" + +class ReceiveTimeout(Exception): + """The receive operation timed out.""" + +class ProtocolError(Exception): + """A protocol error occurred.""" diff --git a/pycoax/coax/interface1.py b/pycoax/coax/interface1.py new file mode 100644 index 0000000..d3e98cf --- /dev/null +++ b/pycoax/coax/interface1.py @@ -0,0 +1,218 @@ +""" +coax.interface1 +~~~~~~~~~~~~~~~ +""" + +from enum import Flag +import itertools +import struct +from sliplib import SlipWrapper, ProtocolError + +from .exceptions import InterfaceError, InterfaceTimeout, ReceiveError, ReceiveTimeout + +class Interface1: + """A serial attached Arduino interface using the National Semiconductor + DP8340 and DP8341. + """ + + def __init__(self, serial): + if serial is None: + raise ValueError('Serial port is required') + + self.serial = serial + + self.slip_serial = SlipSerial(self.serial) + + def reset(self): + """Reset the interface.""" + original_serial_timeout = self.serial.timeout + + self.serial.reset_input_buffer() + + self._write_message(b'\x01') + + self.serial.timeout = 5 + + try: + message = self._read_message() + finally: + self.serial.timeout = original_serial_timeout + + if message[0] != 0x01: + raise _convert_error(message) + + if len(message) != 4: + raise InterfaceError('Invalid reset response') + + (major, minor, patch) = struct.unpack('BBB', message[1:]) + + return '{}.{}.{}'.format(major, minor, patch) + + def execute(self, command_word, data=None, response_length=1, timeout=None): + """Executes a command. + + :param command_word: the command to execute + :param data: optional bytearray containing command data + :param response_length: the expected response length + :param timeout: optional timeout in seconds + """ + timeout_milliseconds = 0 + + if timeout: + if self.serial.timeout and timeout > self.serial.timeout: + raise ValueError('Timeout cannot be greater than serial timeout') + + timeout_milliseconds = int(timeout * 1000) + + message = struct.pack(">BHHH", 0x02, command_word, response_length, + timeout_milliseconds) + + if data is not None: + message += data + + self._write_message(message) + + message = self._read_message() + + if message[0] != 0x01: + raise _convert_error(message) + + response_bytes = message[1:] + + response_words = [(hi << 8) | lo for (lo, hi) in zip(response_bytes[::2], + response_bytes[1::2])] + + # Handle any receiver (DP8341) errors that are included in the response words. + error_words = [word for word in response_words if (word & 0x8000) == 0x8000] + + if error_words: + raise _convert_receiver_errors(error_words) + + return response_words + + def offload_load_address_counter(self, address): + """Executes a combined LO and HI address counter load. + + :param address: the address + """ + parameters = struct.pack(">H", address) + + self._execute_offload(0x01, parameters) + + def offload_write(self, data, address=None, restore_original_address=False, repeat=0): + """Executes a complex write operation. + + :param data: the data + :param address: optional address to load before WRITE_DATA command + :param restore_original_address: restore the original data after write + :param repeat: repeat the data + """ + parameters = struct.pack(">HBH", 0xffff if address is None else address, + 0x01 if restore_original_address else 0x00, + repeat) + data + + self._execute_offload(0x02, parameters) + + def _execute_offload(self, command, parameters=None): + """Executes an offloaded command.""" + message = struct.pack("BB", 0x03, command) + + if parameters: + message += parameters + + self._write_message(message) + + message = self._read_message() + + if message[0] != 0x01: + raise _convert_error(message) + + def _read_message(self): + try: + message = self.slip_serial.recv_msg() + except ProtocolError: + raise InterfaceError('SLIP protocol error') + + if len(message) < 4: + raise InterfaceError('Invalid response message') + + (length,) = struct.unpack(">H", message[:2]) + + if length != len(message) - 4: + raise InterfaceError('Response message length mismatch') + + if length < 1: + raise InterfaceError('Empty response message') + + return message[2:-2] + + def _write_message(self, message): + self.slip_serial.send_msg(struct.pack(">H", len(message)) + message + struct.pack(">H", 0)) + +ERROR_MAP = { + 1: InterfaceError('Invalid request message'), + 2: InterfaceError('Unknown command'), + 3: InterfaceError('Unknown offload command'), + + 101: InterfaceError('Receiver active'), + 102: ReceiveTimeout(), + 103: ReceiveError('Receiver buffer overflow') +} + +def _convert_error(message): + if message[0] != 0x02: + return InterfaceError('Invalid response') + + if len(message) < 2: + return InterfaceError('Invalid error response') + + if message[1] in ERROR_MAP: + return ERROR_MAP[message[1]] + + return InterfaceError('Unknown error') + +class ReceiverErrorCode(Flag): + """Receiver (DP8341) error code.""" + DATA_OVERFLOW = 0x01 + PARITY = 0x02 + TRANSMIT_CHECK_CONDITIONS = 0x04 + INVALID_ENDING_SEQUENCE = 0x08 + MID_BID_TRANSITION = 0x10 + STARTING_SEQUENCE = 0x20 + RECEIVER_DISABLED = 0x40 + +def _parse_receiver_error(word): + return [code for code in ReceiverErrorCode if code & ReceiverErrorCode(word & 0x7f)] + +def _convert_receiver_errors(words): + codes = set(itertools.chain.from_iterable([_parse_receiver_error(word) for word + in words])) + + message = 'Receiver ' + ', '.join([code.name for code in codes]) + ' error' + + raise ReceiveError(message) + +class SlipSerial(SlipWrapper): + """sliplib wrapper for pySerial.""" + + def send_bytes(self, packet): + """Sends a packet over the serial port.""" + self.stream.write(packet) + self.stream.flush() + + def recv_bytes(self): + """Receive data from the serial port.""" + if self.stream.closed: + return b'' + + count = self.stream.in_waiting + + if count: + return self.stream.read(count) + + byte = self.stream.read(1) + + if byte == b'': + raise InterfaceTimeout() + + return byte diff --git a/pycoax/coax/parity.py b/pycoax/coax/parity.py new file mode 100644 index 0000000..419240e --- /dev/null +++ b/pycoax/coax/parity.py @@ -0,0 +1,26 @@ +""" +coax.parity +~~~~~~~~~~~ + +Single byte parity computation +""" + +# From http://p-nand-q.com/python/algorithms/math/bit-parity.html +def _parallel_swar(i): + i = i - ((i >> 1) & 0x55555555) + i = (i & 0x33333333) + ((i >> 2) & 0x33333333) + i = (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24 + return int(i % 2) + +_PARITY_LOOKUP = [_parallel_swar(i) for i in range(256)] + +def even_parity(byte): + """Compute even parity""" + if byte < 0 or byte > 255: + raise ValueError('Input must be between 0 and 255') + + return _PARITY_LOOKUP[byte] + +def odd_parity(byte): + """Compute odd parity""" + return int(not even_parity(byte)) diff --git a/pycoax/coax/protocol.py b/pycoax/coax/protocol.py new file mode 100644 index 0000000..a569fc6 --- /dev/null +++ b/pycoax/coax/protocol.py @@ -0,0 +1,238 @@ +""" +coax.protocol +~~~~~~~~~~~~~ +""" + +from enum import Enum + +from .exceptions import ProtocolError +from .parity import odd_parity + +class Command(Enum): + """Terminal command.""" + + # Read Commands + POLL = 0x01 + POLL_ACK = 0x11 + READ_STATUS = 0x0d + READ_TERMINAL_ID = 0x09 + READ_EXTENDED_ID = 0x07 + READ_ADDRESS_COUNTER_HI = 0x05 + READ_ADDRESS_COUNTER_LO = 0x15 + READ_DATA = 0x03 + READ_MULTIPLE = 0x0b + + # Write Commands + RESET = 0x02 + LOAD_CONTROL_REGISTER = 0x0a + LOAD_SECONDARY_CONTROL = 0x1a + LOAD_MASK = 0x16 + LOAD_ADDRESS_COUNTER_HI = 0x04 + LOAD_ADDRESS_COUNTER_LO = 0x14 + WRITE_DATA = 0x0c + CLEAR = 0x06 + SEARCH_FORWARD = 0x10 + SEARCH_BACKWARD = 0x12 + INSERT_BYTE = 0x0e + START_OPERATION = 0x08 + DIAGNOSTIC_RESET = 0x1c + +class PollResponse: + """Terminal POLL response.""" + + @staticmethod + def is_power_on_reset_complete(value): + """Is the response word a power on reset complete response?""" + return value == 0xa + + @staticmethod + def is_keystroke(value): + """Is the response word a keystroke response?""" + return ((value & 0x2) == 0x2) and ((value & 0x1) == 0) + + def __init__(self, value): + self.value = value + +class PowerOnResetCompletePollResponse(PollResponse): + """Terminal power-on-reset complete poll response.""" + + def __init__(self, value): + if not PollResponse.is_power_on_reset_complete(value): + raise ValueError('Invalid POR poll response') + + super().__init__(value) + +class KeystrokePollResponse(PollResponse): + """Terminal keystroke poll response.""" + + def __init__(self, value): + if not PollResponse.is_keystroke(value): + raise ValueError('Invalid keystroke poll response') + + super().__init__(value) + + self.scan_code = (value >> 2) & 0xff + +class TerminalId: + """Terminal model and keyboard.""" + + def __init__(self, value): + if (value & 0x1) != 0: + raise ValueError('Invalid terminal identifier') + + self.value = value + + self.model = (value & 0x0e) >> 1 + self.keyboard = (value & 0xf0) >> 4 + +def poll(interface, **kwargs): + """Execute a POLL command.""" + command_word = _pack_command_word(Command.POLL) + + response = interface.execute(command_word, **kwargs) + + if len(response) != 1: + raise ProtocolError('Expected 1 word POLL response') + + word = response[0] + + if word == 0: + return None + + if PollResponse.is_power_on_reset_complete(word): + return PowerOnResetCompletePollResponse(word) + + if PollResponse.is_keystroke(word): + return KeystrokePollResponse(word) + + return PollResponse(word) + +def poll_ack(interface, **kwargs): + """Execute a POLL_ACK command.""" + _execute_write_command(interface, Command.POLL_ACK, **kwargs) + +def read_status(interface): + """Execute a READ_STATUS command.""" + raise NotImplementedError + +def read_terminal_id(interface, **kwargs): + """Execute a READ_TERMINAL_ID command.""" + response = _execute_read_command(interface, Command.READ_TERMINAL_ID, **kwargs) + + return TerminalId(response[0]) + +def read_extended_id(interface, **kwargs): + """Execute a READ_EXTENDED_ID command.""" + return _execute_read_command(interface, Command.READ_EXTENDED_ID, 4, **kwargs) + +def read_address_counter_hi(interface, **kwargs): + """Execute a READ_ADDRESS_COUNTER_HI command.""" + return _execute_read_command(interface, Command.READ_ADDRESS_COUNTER_HI, **kwargs)[0] + +def read_address_counter_lo(interface, **kwargs): + """Execute a READ_ADDRESS_COUTER_LO command.""" + return _execute_read_command(interface, Command.READ_ADDRESS_COUNTER_LO, **kwargs)[0] + +def read_data(interface): + """Execute a READ_DATA command.""" + raise NotImplementedError + +def read_multiple(interface): + """Execute a READ_MULTIPLE command.""" + raise NotImplementedError + +def reset(interface): + """Execute a RESET command.""" + raise NotImplementedError + +def load_control_register(interface): + """Execute a LOAD_CONTROL_REGISTER command.""" + raise NotImplementedError + +def load_secondary_control(interface): + """Execute a LOAD_SECONDARY_CONTROL command.""" + raise NotImplementedError + +def load_mask(interface): + """Execute a LOAD_MASK command.""" + raise NotImplementedError + +def load_address_counter_hi(interface, address, **kwargs): + """Execute a LOAD_ADDRESS_COUNTER_HI command.""" + _execute_write_command(interface, Command.LOAD_ADDRESS_COUNTER_HI, bytes([address]), **kwargs) + +def load_address_counter_lo(interface, address, **kwargs): + """Execute a LOAD_ADDRESS_COUNTER_LO command.""" + _execute_write_command(interface, Command.LOAD_ADDRESS_COUNTER_LO, bytes([address]), **kwargs) + +def write_data(interface, data, **kwargs): + """Execute a WRITE_DATA command.""" + _execute_write_command(interface, Command.WRITE_DATA, data, **kwargs) + +def clear(interface): + """Execute a CLEAR command.""" + raise NotImplementedError + +def search_forward(interface): + """Execute a SEARCH_FORWARD command.""" + raise NotImplementedError + +def search_backward(interface): + """Execute a SEARCH_BACKWARD command.""" + raise NotImplementedError + +def insert_byte(interface): + """Execute a INSERT_BYTE command.""" + raise NotImplementedError + +def start_operation(interface): + """Execute a START_OPERATION command.""" + raise NotImplementedError + +def diagnostic_reset(interface): + """Execute a DIAGNOSTIC_RESET command.""" + raise NotImplementedError + +def _execute_read_command(interface, command, response_length=1): + """Execute a standard read command.""" + command_word = _pack_command_word(command) + + response_words = interface.execute(command_word, response_length=response_length) + + if len(response_words) != response_length: + raise ProtocolError(f'Expected {response_length} word {command.name} response') + + return _unpack_data_words(response_words) + +def _execute_write_command(interface, command, data=None): + """Execute a standard write command.""" + command_word = _pack_command_word(command) + + response_words = interface.execute(command_word, data) + + if len(response_words) != 1: + raise ProtocolError(f'Expected 1 word {command.name} response') + + if response_words[0] != 0: + raise ProtocolError('Expected TR/TA response') + +def _pack_command_word(command, address=0): + """Pack a command and address into a 10-bit command word for the interface.""" + return (address << 7) | (command.value << 2) | 0x1 + +def _unpack_data_words(words): + """Unpack the data bytes from 10-bit data words, performs parity checking.""" + return bytes([_unpack_data_word(word) for word in words]) + +def _unpack_data_word(word): + """Unpack the data byte from a 10-bit data word, performs parity checking.""" + if not (word & 0x1) == 0x0: + raise ProtocolError('Word does not have data bit set') + + byte = (word >> 2) & 0xff + parity = (word >> 1) & 0x1 + + if not odd_parity(byte) == parity: + raise ProtocolError('Parity error') + + return byte diff --git a/pycoax/examples/01_reset.py b/pycoax/examples/01_reset.py new file mode 100755 index 0000000..a608bdf --- /dev/null +++ b/pycoax/examples/01_reset.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +import sys +import time +from serial import Serial + +sys.path.append('..') + +from coax import Interface1, poll, poll_ack + +print('Opening serial port...') + +with Serial('/dev/ttyUSB0', 115200) as serial: + print('Sleeping to allow interface time to wake up...') + + time.sleep(3) + + interface = Interface1(serial) + + print('Resetting interface...') + + version = interface.reset() + + print(f'Firmware version is {version}') diff --git a/pycoax/examples/02_poll.py b/pycoax/examples/02_poll.py new file mode 100755 index 0000000..802ed25 --- /dev/null +++ b/pycoax/examples/02_poll.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +import sys +import time +from serial import Serial + +sys.path.append('..') + +from coax import Interface1, poll, poll_ack + +print('Opening serial port...') + +with Serial('/dev/ttyUSB0', 115200) as serial: + print('Sleeping to allow interface time to wake up...') + + time.sleep(3) + + interface = Interface1(serial) + + print('Resetting interface...') + + version = interface.reset() + + print(f'Firmware version is {version}') + + print('POLL...') + + poll_response = poll(interface, timeout=5) + + print(poll_response) + + if poll_response: + print('POLL_ACK...') + + poll_ack(interface) diff --git a/pycoax/examples/03_read_terminal_id.py b/pycoax/examples/03_read_terminal_id.py new file mode 100755 index 0000000..7c1e4b4 --- /dev/null +++ b/pycoax/examples/03_read_terminal_id.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +import sys +import time +from serial import Serial + +sys.path.append('..') + +from coax import Interface1, read_terminal_id + +print('Opening serial port...') + +with Serial('/dev/ttyUSB0', 115200) as serial: + print('Sleeping to allow interface time to wake up...') + + time.sleep(3) + + interface = Interface1(serial) + + print('Resetting interface...') + + version = interface.reset() + + print(f'Firmware version is {version}') + + print('READ_TERMINAL_ID...') + + terminal_id = read_terminal_id(interface) + + print(terminal_id) diff --git a/pycoax/examples/04_hello_world.py b/pycoax/examples/04_hello_world.py new file mode 100755 index 0000000..0bca84f --- /dev/null +++ b/pycoax/examples/04_hello_world.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +import sys +import time +from serial import Serial + +sys.path.append('..') + +from coax import Interface1, read_address_counter_hi, read_address_counter_lo, load_address_counter_hi, load_address_counter_lo, write_data + +print('Opening serial port...') + +with Serial('/dev/ttyUSB0', 115200) as serial: + print('Sleeping to allow interface time to wake up...') + + time.sleep(3) + + interface = Interface1(serial) + + print('Resetting interface...') + + version = interface.reset() + + print(f'Firmware version is {version}') + + print('LOAD_ADDRESS_COUNTER_HI...') + + load_address_counter_hi(interface, 0) + + print('LOAD_ADDRESS_COUNTER_LO...') + + load_address_counter_lo(interface, 80) + + print('WRITE_DATA...') + + write_data(interface, bytes.fromhex('a7 84 8b 8b 8e 33 00 96 8e 91 8b 83 19')) + + print('READ_ADDRESS_COUNTER_HI...') + + hi = read_address_counter_hi(interface) + + print('READ_ADDRESS_COUNTER_LO...') + + lo = read_address_counter_lo(interface) + + print(f'hi = {hi:02x}, lo = {lo:02x}') diff --git a/pycoax/examples/05_offload_write.py b/pycoax/examples/05_offload_write.py new file mode 100755 index 0000000..082d6d9 --- /dev/null +++ b/pycoax/examples/05_offload_write.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +import sys +import time +from serial import Serial + +sys.path.append('..') + +from coax import Interface1 + +print('Opening serial port...') + +with Serial('/dev/ttyUSB0', 115200) as serial: + print('Sleeping to allow interface time to wake up...') + + time.sleep(3) + + interface = Interface1(serial) + + print('Resetting interface...') + + version = interface.reset() + + print(f'Firmware version is {version}') + + for n in range(10): + print(f'Writing line {n + 1}...') + + address = ((7 + n) * 80) + 80 + + interface.offload_write(b'\x80', address=address, repeat=n) diff --git a/pycoax/requirements.txt b/pycoax/requirements.txt new file mode 100644 index 0000000..0409260 --- /dev/null +++ b/pycoax/requirements.txt @@ -0,0 +1,2 @@ +pyserial==3.4 +sliplib==0.3.0 diff --git a/pycoax/run_unit_tests.sh b/pycoax/run_unit_tests.sh new file mode 100755 index 0000000..62ce822 --- /dev/null +++ b/pycoax/run_unit_tests.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +python -m unittest discover tests diff --git a/pycoax/setup.py b/pycoax/setup.py new file mode 100644 index 0000000..5e988cc --- /dev/null +++ b/pycoax/setup.py @@ -0,0 +1,35 @@ +import os +from setuptools import setup + +ABOUT = {} + +with open(os.path.join(os.path.dirname(__file__), "coax", "__about__.py")) as file: + exec(file.read(), ABOUT) + +LONG_DESCRIPTION = """# pycoax + +Python IBM 3270 coaxial interface library. + +See [GitHub](https://github.com/lowobservable/coax-interface#readme) for more information. +""" + +setup( + name='pycoax', + version=ABOUT['__version__'], + description='IBM 3270 coaxial interface', + url='https://github.com/lowobservable/coax-interface', + author='Andrew Kay', + author_email='projects@ajk.me', + packages=['coax'], + install_requires=['pyserial==3.4', 'sliplib==0.3.0'], + long_description=LONG_DESCRIPTION, + long_description_content_type='text/markdown', + classifiers=[ + 'Development Status :: 3 - Alpha', + 'License :: OSI Approved :: ISC License (ISCL)', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Topic :: Communications', + 'Topic :: Terminals' + ] +) diff --git a/pycoax/tests/__init__.py b/pycoax/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pycoax/tests/context.py b/pycoax/tests/context.py new file mode 100644 index 0000000..1581836 --- /dev/null +++ b/pycoax/tests/context.py @@ -0,0 +1,4 @@ +import sys +import os + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) diff --git a/pycoax/tests/test_interface1.py b/pycoax/tests/test_interface1.py new file mode 100644 index 0000000..8d50864 --- /dev/null +++ b/pycoax/tests/test_interface1.py @@ -0,0 +1,264 @@ +import unittest +from unittest.mock import Mock +import sliplib + +import context + +from coax import Interface1, InterfaceError, ReceiveError, ReceiveTimeout + +class Interface1ResetTestCase(unittest.TestCase): + def setUp(self): + self.serial = Mock() + + self.serial.timeout = None + + self.interface = Interface1(self.serial) + + self.interface._write_message = Mock() + self.interface._read_message = Mock(return_value=bytes.fromhex('01 01 02 03')) + + def test_message_is_sent(self): + # Act + self.interface.reset() + + # Assert + self.interface._write_message.assert_called_with(bytes.fromhex('01')) + + def test_version_is_formatted_correctly(self): + self.assertEqual(self.interface.reset(), '1.2.3') + + def test_timeout_is_restored_after_reset(self): + # Arrange + self.serial.timeout = 123 + + # Act + self.interface.reset() + + # Assert + self.assertEqual(self.serial.timeout, 123) + + def test_invalid_message_length_is_handled_correctly(self): + # Arrange + self.interface._read_message = Mock(return_value=bytes.fromhex('01 01')) + + # Act and assert + with self.assertRaisesRegex(InterfaceError, 'Invalid reset response'): + self.interface.reset() + + def test_error_is_handled_correctly(self): + # Arrange + self.interface._read_message = Mock(return_value=bytes.fromhex('02 01')) + + # Act and assert + with self.assertRaisesRegex(InterfaceError, 'Invalid request message'): + self.interface.reset() + +class Interface1ExecuteTestCase(unittest.TestCase): + def setUp(self): + self.serial = Mock() + + self.serial.timeout = None + + self.interface = Interface1(self.serial) + + self.interface._write_message = Mock() + self.interface._read_message = Mock(return_value=bytes.fromhex('01 00')) + + def test_message_is_sent_without_data(self): + # Act + self.interface.execute(0b0000001001) + + # Assert + self.interface._write_message.assert_called_with(bytes.fromhex('02 00 09 00 01 00 00')) + + def test_message_is_sent_with_data(self): + # Act + self.interface.execute(0b0000110001, data=bytes.fromhex('de ad be ef')) + + # Assert + self.interface._write_message.assert_called_with(bytes.fromhex('02 00 31 00 01 00 00 de ad be ef')) + + def test_message_is_sent_with_response_length(self): + # Act + self.interface.execute(0b0000011101, response_length=4) + + # Assert + self.interface._write_message.assert_called_with(bytes.fromhex('02 00 1d 00 04 00 00')) + + def test_timeout_cannot_exceed_serial_timeout(self): + # Arrange + self.serial.timeout = 2.0 + + # Act and assert + with self.assertRaisesRegex(ValueError, 'Timeout cannot be greater than serial timeout'): + self.interface.execute(0b0000000101, timeout=3) + + def test_message_is_sent_with_timeout(self): + # Act + self.interface.execute(0b0000000101, timeout=3) + + # Assert + self.interface._write_message.assert_called_with(bytes.fromhex('02 00 05 00 01 0b b8')) + + # TODO... interface timeout... + + def test_receive_timeout_is_handled_correctly(self): + # Arrange + self.interface._read_message = Mock(return_value=bytes.fromhex('02 66')) + + # Act and assert + with self.assertRaises(ReceiveTimeout): + self.interface.execute(0b0000000101) + + def test_receive_error_is_handled_correctly(self): + # Arrange + self.interface._read_message = Mock(return_value=bytes.fromhex('02 67')) + + # Act and assert + with self.assertRaisesRegex(ReceiveError, 'Receiver buffer overflow'): + self.interface.execute(0b0000000101) + + def test_interface_error_is_handled_correctly(self): + # Arrange + self.interface._read_message = Mock(return_value=bytes.fromhex('03')) + + # Act and assert + with self.assertRaisesRegex(InterfaceError, 'Invalid response'): + self.interface.execute(0b0000000101) + + def test_response_words_are_unpacked(self): + # Arrange + self.interface._read_message = Mock(return_value=bytes.fromhex('01 01 02 03 04')) + + # Act + response_words = self.interface.execute(0b0000011101, response_length=4) + + # Assert + self.assertEqual(response_words, [0x0201, 0x0403]) + + def test_receiver_error_is_handled_correctly(self): + # Arrange + self.interface._read_message = Mock(return_value=bytes.fromhex('01 a0 80')) + + # Act and assert + with self.assertRaisesRegex(ReceiveError, 'Receiver STARTING_SEQUENCE error'): + self.interface.execute(0b0000011101, response_length=4) + +class Interface1OffloadLoadAddressCounterTestCase(unittest.TestCase): + def setUp(self): + self.serial = Mock() + + self.interface = Interface1(self.serial) + + self.interface._execute_offload = Mock() + + def test(self): + # Act + self.interface.offload_load_address_counter(960) + + # Assert + self.interface._execute_offload.assert_called_with(0x01, bytes.fromhex('03 c0')) + +class Interface1OffloadWriteTestCase(unittest.TestCase): + def setUp(self): + self.serial = Mock() + + self.interface = Interface1(self.serial) + + self.interface._execute_offload = Mock() + + def test_message_is_sent_with_data(self): + # Act + self.interface.offload_write(bytes.fromhex('de ad be ef')) + + # Assert + self.interface._execute_offload.assert_called_with(0x02, bytes.fromhex('ff ff 00 00 00 de ad be ef')) + + def test_message_is_sent_with_address(self): + # Act + self.interface.offload_write(bytes.fromhex('de ad be ef'), address=960) + + # Assert + self.interface._execute_offload.assert_called_with(0x02, bytes.fromhex('03 c0 00 00 00 de ad be ef')) + + def test_message_is_sent_with_restore_original_address(self): + # Act + self.interface.offload_write(bytes.fromhex('de ad be ef'), restore_original_address=True) + + # Assert + self.interface._execute_offload.assert_called_with(0x02, bytes.fromhex('ff ff 01 00 00 de ad be ef')) + + def test_message_is_sent_with_repeat(self): + # Act + self.interface.offload_write(bytes.fromhex('de ad be ef'), repeat=1) + + # Assert + self.interface._execute_offload.assert_called_with(0x02, bytes.fromhex('ff ff 00 00 01 de ad be ef')) + +class Interface1ReadMessageTestCase(unittest.TestCase): + def setUp(self): + self.serial = Mock() + + self.interface = Interface1(self.serial) + + self.interface.slip_serial = Mock() + + def test(self): + # Arrange + self.interface.slip_serial.recv_msg = Mock(return_value=bytes.fromhex('00 04 01 02 03 04 00 00')) + + # Act + message = self.interface._read_message() + + # Assert + self.assertEqual(message, bytes.fromhex('01 02 03 04')) + + def test_protocol_error_is_handled_correctly(self): + # Arrange + self.interface.slip_serial.recv_msg = Mock(side_effect=sliplib.ProtocolError) + + # Act and assert + with self.assertRaisesRegex(InterfaceError, 'SLIP protocol error'): + self.interface._read_message() + + def test_invalid_message_length_is_handled_correctly(self): + # Arrange + self.interface.slip_serial.recv_msg = Mock(return_value=bytes.fromhex('00')) + + # Act and assert + with self.assertRaisesRegex(InterfaceError, 'Invalid response message'): + self.interface._read_message() + + def test_message_length_mismatch_is_handled_correctly(self): + # Arrange + self.interface.slip_serial.recv_msg = Mock(return_value=bytes.fromhex('00 05 01 02 03 04 00 00')) + + # Act and assert + with self.assertRaisesRegex(InterfaceError, 'Response message length mismatch'): + self.interface._read_message() + + def test_empty_message_is_handled_correctly(self): + # Arrange + self.interface.slip_serial.recv_msg = Mock(return_value=bytes.fromhex('00 00 00 00')) + + # Act and assert + with self.assertRaisesRegex(InterfaceError, 'Empty response message'): + self.interface._read_message() + +class Interface1WriteMessageTestCase(unittest.TestCase): + def setUp(self): + self.serial = Mock() + + self.interface = Interface1(self.serial) + + self.interface.slip_serial = Mock() + + def test(self): + # Act + self.interface._write_message(bytes.fromhex('01 02 03 04')) + + # Assert + self.interface.slip_serial.send_msg.assert_called_with(bytes.fromhex('00 04 01 02 03 04 00 00')) + +if __name__ == '__main__': + unittest.main() diff --git a/pycoax/tests/test_parity.py b/pycoax/tests/test_parity.py new file mode 100644 index 0000000..0a73fe2 --- /dev/null +++ b/pycoax/tests/test_parity.py @@ -0,0 +1,34 @@ +import unittest + +import context + +from coax.parity import even_parity, odd_parity + +class EvenParityTestCase(unittest.TestCase): + def test_with_even_input(self): + self.assertEqual(even_parity(0b00000000), 0) + + def test_with_odd_input(self): + self.assertEqual(even_parity(0b00000001), 1) + + def test_with_out_of_range_input(self): + for input in [-1, 256]: + with self.subTest(input=input): + with self.assertRaises(ValueError): + even_parity(input) + +class OddParityTestCase(unittest.TestCase): + def test_with_even_input(self): + self.assertEqual(odd_parity(0b00000000), 1) + + def test_with_odd_input(self): + self.assertEqual(odd_parity(0b00000001), 0) + + def test_with_out_of_range_input(self): + for input in [-1, 256]: + with self.subTest(input=input): + with self.assertRaises(ValueError): + odd_parity(input) + +if __name__ == '__main__': + unittest.main() diff --git a/pycoax/tests/test_protocol.py b/pycoax/tests/test_protocol.py new file mode 100644 index 0000000..1520f7d --- /dev/null +++ b/pycoax/tests/test_protocol.py @@ -0,0 +1,99 @@ +import unittest +from unittest.mock import Mock + +import context + +from coax import PollResponse, KeystrokePollResponse, ProtocolError +from coax.protocol import Command, _execute_read_command, _execute_write_command, _pack_command_word, _unpack_data_words, _unpack_data_word + +class PollResponseTestCase(unittest.TestCase): + def test_is_power_on_reset_complete(self): + self.assertTrue(PollResponse.is_power_on_reset_complete(0b0000001010)) + + def test_is_keystroke(self): + self.assertTrue(PollResponse.is_keystroke(0b1111111110)) + +class KeystrokePollResponseTestCase(unittest.TestCase): + def test(self): + # Act + response = KeystrokePollResponse(0b1111111110) + + # Assert + self.assertEqual(response.scan_code, 0xff) + + def test_not_a_keystroke(self): + with self.assertRaisesRegex(ValueError, 'Invalid keystroke poll response'): + response = KeystrokePollResponse(0b0000001000) + +class ExecuteReadCommandTestCase(unittest.TestCase): + def setUp(self): + self.interface = Mock() + + def test(self): + # Arrange + self.interface.execute = Mock(return_value=[0b0000000010]) + + # Act and assert + self.assertEqual(_execute_read_command(self.interface, Command.READ_TERMINAL_ID), bytes.fromhex('00')) + + def test_unexpected_response_length(self): + # Arrange + self.interface.execute = Mock(return_value=[]) + + # Act and assert + with self.assertRaisesRegex(ProtocolError, 'Expected 1 word READ_TERMINAL_ID response'): + _execute_read_command(self.interface, Command.READ_TERMINAL_ID) + +class ExecuteWriteCommandTestCase(unittest.TestCase): + def setUp(self): + self.interface = Mock() + + def test(self): + # Arrange + self.interface.execute = Mock(return_value=[0b0000000000]) + + # Act and assert + _execute_write_command(self.interface, Command.WRITE_DATA, bytes.fromhex('de ad be ef')) + + def test_unexpected_response_length(self): + # Arrange + self.interface.execute = Mock(return_value=[]) + + # Act and assert + with self.assertRaisesRegex(ProtocolError, 'Expected 1 word WRITE_DATA response'): + _execute_write_command(self.interface, Command.WRITE_DATA, bytes.fromhex('de ad be ef')) + + def test_not_tr_ta_response(self): + # Arrange + self.interface.execute = Mock(return_value=[0b0000000010]) + + # Act and assert + with self.assertRaisesRegex(ProtocolError, 'Expected TR/TA response'): + _execute_write_command(self.interface, Command.WRITE_DATA, bytes.fromhex('de ad be ef')) + +class PackCommandWordTestCase(unittest.TestCase): + def test_without_address(self): + self.assertEqual(_pack_command_word(Command.POLL_ACK), 0b001000101) + + def test_with_address(self): + self.assertEqual(_pack_command_word(Command.POLL_ACK, address=3), 0b111000101) + +class UnpackDataWordsTestCase(unittest.TestCase): + def test(self): + self.assertEqual(_unpack_data_words([0b0000000010, 0b1111111110]), bytes.fromhex('00 ff')) + +class UnpackDataWordTestCase(unittest.TestCase): + def test(self): + self.assertEqual(_unpack_data_word(0b0000000010), 0x00) + self.assertEqual(_unpack_data_word(0b1111111110), 0xff) + + def test_data_bit_not_set_error(self): + with self.assertRaisesRegex(ProtocolError, 'Word does not have data bit set'): + _unpack_data_word(0b0000000011) + + def test_parity_error(self): + with self.assertRaisesRegex(ProtocolError, 'Parity error'): + _unpack_data_word(0b0000000000) + +if __name__ == '__main__': + unittest.main()