diff --git a/firmware/app_layer_v1/features.c b/firmware/app_layer_v1/features.c index 0e8b467c8..d2c32bb02 100644 --- a/firmware/app_layer_v1/features.c +++ b/firmware/app_layer_v1/features.c @@ -57,7 +57,10 @@ static void PinsInit() { SetPinDigitalIn(i, 0); // all other pins: input, no-pull } for (i = 0; i < NUM_UART_MODULES; ++i) { - SetPinUart(0, i, 0, 0); // UART RX disabled + SetPinUart(0, i, 0, 0, 0); // UART RX disabled + // Why isn't TX reset? + SetPinUart(0, i, 0, 1, 0); // UART CTS disabled + SetPinUart(0, i, 1, 1, 0); // UART RTS disabled } // clear and enable global CN interrupts _CNIF = 0; @@ -110,33 +113,59 @@ void SetPinPwm(int pin, int pwm_num, int enable) { PinSetRpor(pin, enable ? (pwm_num == 8 ? 35 : 18 + pwm_num) : 0); } -void SetPinUart(int pin, int uart_num, int dir, int enable) { - log_printf("SetPinUart(%d, %d, %d, %d)", pin, uart_num, dir, enable); +void SetPinUart(int pin, int uart_num, int dir, int flow, int enable) { + log_printf("SetPinUart(%d, %d, %d, %d, %d)", pin, uart_num, dir, flow, enable); SAVE_PIN_FOR_LOG(pin); SAVE_UART_FOR_LOG(uart_num); - if (dir) { - // TX - const BYTE rp[] = { 3, 5, 28, 30 }; - PinSetRpor(pin, enable ? rp[uart_num] : 0); + if (!flow) { + if (dir) { + // TX + const BYTE rp[] = { 3, 5, 28, 30 }; + PinSetRpor(pin, enable ? rp[uart_num] : 0); + } else { + // RX + int rpin = enable ? PinToRpin(pin) : 0x3F; + switch (uart_num) { + case 0: + _U1RXR = rpin; + break; + + case 1: + _U2RXR = rpin; + break; + + case 2: + _U3RXR = rpin; + break; + + case 3: + _U4RXR = rpin; + break; + } + } } else { - // RX - int rpin = enable ? PinToRpin(pin) : 0x3F; - switch (uart_num) { - case 0: - _U1RXR = rpin; - break; + if (dir) { // RTS output + const BYTE rp[] = { 4, 6, 29, 31 }; + PinSetRpor(pin, enable ? rp[uart_num] : 0); + } else { // CTS input + int rpin = enable ? PinToRpin(pin) : 0x3F; + switch (uart_num) { + case 0: + _U1CTSR = rpin; + break; - case 1: - _U2RXR = rpin; - break; + case 1: + _U2CTSR = rpin; + break; - case 2: - _U3RXR = rpin; - break; + case 2: + _U3CTSR = rpin; + break; - case 3: - _U4RXR = rpin; - break; + case 3: + _U4CTSR = rpin; + break; + } } } } diff --git a/firmware/app_layer_v1/features.h b/firmware/app_layer_v1/features.h index c5093779e..90778153c 100644 --- a/firmware/app_layer_v1/features.h +++ b/firmware/app_layer_v1/features.h @@ -36,7 +36,7 @@ void SetPinDigitalOut(int pin, int value, int open_drain); void SetPinDigitalIn(int pin, int pull); void SetPinAnalogIn(int pin); void SetPinPwm(int pin, int pwm_num, int enable); -void SetPinUart(int pin, int uart_num, int dir, int enable); +void SetPinUart(int pin, int uart_num, int dir, int flow, int enable); void SetPinSpi(int pin, int spi_num, int mode, int enable); void SetPinInCap(int pin, int incap_num, int enable); void HardReset(); diff --git a/firmware/app_layer_v1/protocol.c b/firmware/app_layer_v1/protocol.c index e88840c57..273bcd75f 100644 --- a/firmware/app_layer_v1/protocol.c +++ b/firmware/app_layer_v1/protocol.c @@ -335,7 +335,8 @@ static BOOL MessageDone() { rx_msg.args.uart_config.rate, rx_msg.args.uart_config.speed4x, rx_msg.args.uart_config.two_stop_bits, - rx_msg.args.uart_config.parity); + rx_msg.args.uart_config.parity, + rx_msg.args.uart_config.flow); break; case SET_PIN_UART: @@ -344,6 +345,7 @@ static BOOL MessageDone() { SetPinUart(rx_msg.args.set_pin_uart.pin, rx_msg.args.set_pin_uart.uart_num, rx_msg.args.set_pin_uart.dir, + rx_msg.args.set_pin_uart.flow, rx_msg.args.set_pin_uart.enable); break; diff --git a/firmware/app_layer_v1/protocol_defs.h b/firmware/app_layer_v1/protocol_defs.h index d3d5b2608..5f08aa048 100644 --- a/firmware/app_layer_v1/protocol_defs.h +++ b/firmware/app_layer_v1/protocol_defs.h @@ -160,12 +160,19 @@ typedef struct PACKED { BYTE data[0]; } UART_DATA_ARGS; +typedef enum { + FLOW_NONE, + FLOW_IRDA, + FLOW_RTSCTS, + FLOW_RS485, +} UART_FLOW_MODE; + // uart config typedef struct PACKED { BYTE parity : 2; BYTE two_stop_bits : 1; BYTE speed4x : 1; - BYTE : 2; + BYTE flow : 2; BYTE uart_num : 2; WORD rate; } UART_CONFIG_ARGS; @@ -182,7 +189,8 @@ typedef struct PACKED { BYTE pin : 6; BYTE : 2; BYTE uart_num : 2; - BYTE : 4; + BYTE : 3; + BYTE flow : 1; BYTE dir : 1; BYTE enable : 1; } SET_PIN_UART_ARGS; diff --git a/firmware/app_layer_v1/uart.c b/firmware/app_layer_v1/uart.c index 06268108f..f9f8fe2ac 100644 --- a/firmware/app_layer_v1/uart.c +++ b/firmware/app_layer_v1/uart.c @@ -64,12 +64,13 @@ DEFINE_REG_SETTERS_1B(NUM_UART_MODULES, _U, TXIE) DEFINE_REG_SETTERS_1B(NUM_UART_MODULES, _U, TXIF) DEFINE_REG_SETTERS_1B(NUM_UART_MODULES, _U, TXIP) -static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop_bits, int parity, int external); +static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop_bits, int parity, + int flow_mode, int external); void UARTInit() { int i; for (i = 0; i < NUM_UART_MODULES; ++i) { - UARTConfigInternal(i, 0, 0, 0, 0, 0); + UARTConfigInternal(i, 0, 0, 0, 0, 0, 0); Set_URXIP[i](4); // RX int. priority 4 Set_UTXIP[i](4); // TX int. priority 4 } @@ -83,12 +84,15 @@ static inline void UARTSendStatus(int uart_num, int enabled) { AppProtocolSendMessage(&msg); } -static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop_bits, int parity, int external) { +static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop_bits, int parity, + int flow_mode, int external) { volatile UART* regs = uart_reg[uart_num]; UART_STATE* uart = &uarts[uart_num]; + // for irda, idle state is 0 for both RX and TX (i.e. for TFBS4711) + const int flow_map[] = {0x0000, 0x1010, 0x0200, 0x0a00}; // none, irda, rtscts, rs485/simplex if (external) { - log_printf("UARTConfig(%d, %d, %d, %d, %d)", uart_num, rate, speed4x, - two_stop_bits, parity); + log_printf("UARTConfig(%d, %d, %d, %d, %d, %d)", uart_num, rate, speed4x, + two_stop_bits, parity, flow_mode); } SAVE_UART_FOR_LOG(uart_num); Set_URXIE[uart_num](0); // disable RX int. @@ -106,7 +110,8 @@ static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop Set_URXIF[uart_num](0); // clear RX int. Set_UTXIF[uart_num](0); // clear TX int. Set_URXIE[uart_num](1); // enable RX int. - regs->uxmode = 0x8000 | (speed4x ? 0x0008 : 0x0000) | two_stop_bits | (parity << 1); // enable + regs->uxmode = 0x8000 | flow_map[flow_mode & 0x3] \ + | (speed4x ? 0x0008 : 0x0000) | two_stop_bits | (parity << 1); // enable regs->uxsta = 0x8400; // IRQ when TX buffer is empty, enable TX, IRQ when character received. uart->num_tx_since_last_report = TX_BUF_SIZE; } else { @@ -116,8 +121,8 @@ static void UARTConfigInternal(int uart_num, int rate, int speed4x, int two_stop } } -void UARTConfig(int uart_num, int rate, int speed4x, int two_stop_bits, int parity) { - UARTConfigInternal(uart_num, rate, speed4x, two_stop_bits, parity, 1); +void UARTConfig(int uart_num, int rate, int speed4x, int two_stop_bits, int parity, int flow_mode) { + UARTConfigInternal(uart_num, rate, speed4x, two_stop_bits, parity, flow_mode, 1); } @@ -225,4 +230,3 @@ void UARTTransmit(int uart_num, const void* data, int size) { #if NUM_UART_MODULES >= 4 DEFINE_INTERRUPT_HANDLERS(4) #endif - diff --git a/firmware/app_layer_v1/uart.h b/firmware/app_layer_v1/uart.h index 6bb1d5ce1..c4f8e2d6d 100644 --- a/firmware/app_layer_v1/uart.h +++ b/firmware/app_layer_v1/uart.h @@ -32,7 +32,7 @@ void UARTInit(); void UARTConfig(int uart_num, int rate, int speed4x, int two_stop_bits, - int parity); + int parity, int flow_mode); void UARTTransmit(int uart_num, const void* data, int size); void UARTTasks(); diff --git a/software/IOIOLib/src/ioio/lib/api/IOIO.java b/software/IOIOLib/src/ioio/lib/api/IOIO.java index 2f2de6ce8..d2a59f270 100644 --- a/software/IOIOLib/src/ioio/lib/api/IOIO.java +++ b/software/IOIOLib/src/ioio/lib/api/IOIO.java @@ -485,6 +485,17 @@ public PulseInput openPulseInput(int pin, PulseMode mode) * The parity mode, as in {@link Parity}. * @param stopbits * Number of stop bits, as in {@link StopBits}. + * @param mode + * Flow control mode, as in {@link FlowMode}. This can by FLOW_NONE, + * FLOW_IRDA, FLOW_RTSCTS, or FLOW_RS485. + * @param rts + * Pin number specification for the RTS (Request To Send) output pin. + * If the flow control mode is not FLOW_RTSCTS or FLOW_RS485, then + * this parameter is ignored. + * @param cts + * Pin number specification for the CTS (Clear To Send) input pin. + * If the flow control mode is not FLOW_RTSCTS or FLOW_RS485, then + * this parameter is ignored. * @return Interface of the assigned module. * @throws ConnectionLostException * Connection was lost before or during the execution of this @@ -496,20 +507,34 @@ public PulseInput openPulseInput(int pin, PulseMode mode) * @see Uart */ public Uart openUart(DigitalInput.Spec rx, DigitalOutput.Spec tx, int baud, - Parity parity, StopBits stopbits) throws ConnectionLostException; + Parity parity, StopBits stopbits, Uart.FlowMode mode, DigitalOutput.Spec rts, + DigitalInput.Spec cts) throws ConnectionLostException; /** * Shorthand for - * {@link #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits)} + * {@link #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec)} * , where the input pins use their default specs. {@link #INVALID_PIN} can - * be used on either pin if a TX- or RX-only UART is needed. + * be used on either pin if a TX- or RX-only UART is needed. The flow mode is FLOW_NONE. * * @see #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, - * Uart.StopBits) + * Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec) */ public Uart openUart(int rx, int tx, int baud, Parity parity, StopBits stopbits) throws ConnectionLostException; + /** + * Shorthand for + * {@link #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec)} + * , where the input pins use their default specs. {@link #INVALID_PIN} can + * be used on either pin if a TX- or RX-only UART is needed. + * + * @see #openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, + * Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec) + */ + public Uart openUart(int rx, int tx, int baud, Uart.Parity parity, + Uart.StopBits stopbits, Uart.FlowMode mode, int rts, + int cts) throws ConnectionLostException; + /** * Open a SPI master module, enabling communication with multiple * SPI-enabled slave modules. diff --git a/software/IOIOLib/src/ioio/lib/api/Uart.java b/software/IOIOLib/src/ioio/lib/api/Uart.java index dd59f34af..af40d2967 100644 --- a/software/IOIOLib/src/ioio/lib/api/Uart.java +++ b/software/IOIOLib/src/ioio/lib/api/Uart.java @@ -40,7 +40,7 @@ * asynchronous point-to-point data transfer. It typically serves for opening * consoles or as a basis for higher-level protocols, such as MIDI, RS-232 and * RS-485. Uart instances are obtained by calling - * {@link IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits)}. + * {@link IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec)}. *

* The UART protocol is completely symmetric - there is no "master" and "slave" * at this layer. Each end may send any number of bytes at arbitrary times, @@ -70,7 +70,7 @@ * * * @see IOIO#openUart(DigitalInput.Spec, DigitalOutput.Spec, int, Uart.Parity, - * Uart.StopBits) + * Uart.StopBits, Uart.FlowMode, DigitalOutput.Spec, DigitalInput.Spec) */ public interface Uart extends Closeable { /** Parity-bit mode. */ @@ -91,6 +91,19 @@ enum StopBits { TWO } + /** Flow control line modes */ + enum FlowMode { + /** No flow control. */ + NONE, + /** Use IRDA encode/decode and no flow control. */ + IRDA, + /** Use RTS/CTS lines for flow control. */ + RTSCTS, + /** Raise RTS when transmitting (for RS-485 transmit enable). + Note that CTS should be connected to RTS. */ + RS485, + } + /** * Gets the input stream. * diff --git a/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java b/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java index 088110e23..5617ae37d 100644 --- a/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java +++ b/software/IOIOLib/src/ioio/lib/impl/IOIOImpl.java @@ -456,13 +456,26 @@ public Uart openUart(int rx, int tx, int baud, Uart.Parity parity, Uart.StopBits stopbits) throws ConnectionLostException { return openUart(rx == INVALID_PIN ? null : new DigitalInput.Spec(rx), tx == INVALID_PIN ? null : new DigitalOutput.Spec(tx), baud, - parity, stopbits); + parity, stopbits, Uart.FlowMode.NONE, null, null); } + @Override + public Uart openUart(int rx, int tx, int baud, Uart.Parity parity, + Uart.StopBits stopbits, Uart.FlowMode mode, int rts, + int cts) throws ConnectionLostException { + return openUart(rx == INVALID_PIN ? null : new DigitalInput.Spec(rx), + tx == INVALID_PIN ? null : new DigitalOutput.Spec(tx), baud, + parity, stopbits, mode, + rts == INVALID_PIN ? null : new DigitalOutput.Spec(rts), + cts == INVALID_PIN ? null : new DigitalInput.Spec(cts)); + } + @Override synchronized public Uart openUart(DigitalInput.Spec rx, DigitalOutput.Spec tx, int baud, Uart.Parity parity, - Uart.StopBits stopbits) throws ConnectionLostException { + Uart.StopBits stopbits, Uart.FlowMode mode, DigitalOutput.Spec rts, + DigitalInput.Spec cts) throws ConnectionLostException { + // TODO(dchristian): make sure rts and cts are valid if flow is used checkState(); if (rx != null) { PinFunctionMap.checkSupportsPeripheralInput(rx.pin); @@ -472,30 +485,54 @@ synchronized public Uart openUart(DigitalInput.Spec rx, PinFunctionMap.checkSupportsPeripheralOutput(tx.pin); checkPinFree(tx.pin); } + if (rts != null) { + PinFunctionMap.checkSupportsPeripheralOutput(rts.pin); + checkPinFree(rts.pin); + } + if (cts != null) { + PinFunctionMap.checkSupportsPeripheralInput(cts.pin); + checkPinFree(cts.pin); + } + int rxPin = rx != null ? rx.pin : INVALID_PIN; int txPin = tx != null ? tx.pin : INVALID_PIN; - int uartNum = uartAllocator_.allocateModule(); - UartImpl uart = new UartImpl(this, txPin, rxPin, uartNum); + int rtsPin = rts != null ? rts.pin : INVALID_PIN; + int ctsPin = cts != null ? cts.pin : INVALID_PIN; + int uartNum = uartAllocator_.allocateModule(); + UartImpl uart = new UartImpl(this, txPin, rxPin, uartNum, + mode, rtsPin, ctsPin); addDisconnectListener(uart); incomingState_.addUartListener(uartNum, uart); try { - if (rx != null) { - openPins_[rx.pin] = true; - protocol_.setPinDigitalIn(rx.pin, rx.mode); - protocol_.setPinUart(rx.pin, uartNum, false, true); + // For compatibility, set RTS/CTS first. TX/RX will override if not supported. + if (rts != null) { + openPins_[rts.pin] = true; + protocol_.setPinDigitalOut(rts.pin, false, rts.mode); + protocol_.setPinUart(rts.pin, uartNum, true, true, true); } - if (tx != null) { - openPins_[tx.pin] = true; - protocol_.setPinDigitalOut(tx.pin, true, tx.mode); - protocol_.setPinUart(tx.pin, uartNum, true, true); + if (cts != null) { + openPins_[cts.pin] = true; + protocol_.setPinDigitalIn(cts.pin, cts.mode); + protocol_.setPinUart(cts.pin, uartNum, false, true, true); } + if (rx != null) { + openPins_[rx.pin] = true; + protocol_.setPinDigitalIn(rx.pin, rx.mode); + protocol_.setPinUart(rx.pin, uartNum, false, false, true); + } + if (tx != null) { + openPins_[tx.pin] = true; + protocol_.setPinDigitalOut(tx.pin, true, tx.mode); + protocol_.setPinUart(tx.pin, uartNum, true, false, true); + } boolean speed4x = true; int rate = Math.round(4000000.0f / baud) - 1; - if (rate > 65535) { + if ((rate > 65535) || (mode == Uart.FlowMode.IRDA)) { speed4x = false; rate = Math.round(1000000.0f / baud) - 1; } - protocol_.uartConfigure(uartNum, rate, speed4x, stopbits, parity); + protocol_.uartConfigure(uartNum, rate, speed4x, stopbits, parity, + mode); } catch (IOException e) { uart.close(); throw new ConnectionLostException(e); diff --git a/software/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java b/software/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java index ed99b9fbb..6eeffb72a 100644 --- a/software/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java +++ b/software/IOIOLib/src/ioio/lib/impl/IOIOProtocol.java @@ -361,13 +361,14 @@ synchronized public void uartData(int uartNum, int numBytes, byte data[]) } synchronized public void uartConfigure(int uartNum, int rate, - boolean speed4x, Uart.StopBits stopbits, Uart.Parity parity) + boolean speed4x, Uart.StopBits stopbits, Uart.Parity parity, Uart.FlowMode mode) throws IOException { int parbits = parity == Uart.Parity.EVEN ? 1 : (parity == Uart.Parity.ODD ? 2 : 0); + int modebits = mode.ordinal() & 0x3; beginBatch(); writeByte(UART_CONFIG); - writeByte((uartNum << 6) | (speed4x ? 0x08 : 0x00) + writeByte((uartNum << 6) | (modebits << 4) | (speed4x ? 0x08 : 0x00) | (stopbits == Uart.StopBits.TWO ? 0x04 : 0x00) | parbits); writeTwoBytes(rate); endBatch(); @@ -381,12 +382,13 @@ synchronized public void uartClose(int uartNum) throws IOException { endBatch(); } - synchronized public void setPinUart(int pin, int uartNum, boolean tx, + synchronized public void setPinUart(int pin, int uartNum, boolean tx, boolean flow, boolean enable) throws IOException { beginBatch(); writeByte(SET_PIN_UART); writeByte(pin); - writeByte((enable ? 0x80 : 0x00) | (tx ? 0x40 : 0x00) | uartNum); + // if flow && tx: set RTS. if flow && !tx: set CTS + writeByte((enable ? 0x80 : 0x00) | (tx ? 0x40 : 0x00) | (flow ? 0x20 : 0x00) | uartNum); endBatch(); } diff --git a/software/IOIOLib/src/ioio/lib/impl/UartImpl.java b/software/IOIOLib/src/ioio/lib/impl/UartImpl.java index 531704f1b..6d62d4880 100644 --- a/software/IOIOLib/src/ioio/lib/impl/UartImpl.java +++ b/software/IOIOLib/src/ioio/lib/impl/UartImpl.java @@ -46,14 +46,21 @@ class UartImpl extends AbstractResource implements DataModuleListener, Sender, U private final int uartNum_; private final int rxPinNum_; private final int txPinNum_; + private final Uart.FlowMode flowMode_; + private final int rtsPinNum_; + private final int ctsPinNum_; private final FlowControlledOutputStream outgoing_ = new FlowControlledOutputStream(this, MAX_PACKET); private final QueueInputStream incoming_ = new QueueInputStream(); - public UartImpl(IOIOImpl ioio, int txPin, int rxPin, int uartNum) throws ConnectionLostException { + public UartImpl(IOIOImpl ioio, int txPin, int rxPin, int uartNum, + Uart.FlowMode mode, int rtsPin, int ctsPin) throws ConnectionLostException { super(ioio); uartNum_ = uartNum; rxPinNum_ = rxPin; txPinNum_ = txPin; + flowMode_ = mode; + rtsPinNum_ = rtsPin; + ctsPinNum_ = ctsPin; } @Override @@ -82,6 +89,12 @@ synchronized public void close() { if (txPinNum_ != IOIO.INVALID_PIN) { ioio_.closePin(txPinNum_); } + if (rtsPinNum_ != IOIO.INVALID_PIN) { + ioio_.closePin(rtsPinNum_); + } + if (ctsPinNum_ != IOIO.INVALID_PIN) { + ioio_.closePin(ctsPinNum_); + } } @Override diff --git a/software/applications/IOIOTortureTest/src/ioio/tests/torture/TestProvider.java b/software/applications/IOIOTortureTest/src/ioio/tests/torture/TestProvider.java index 1a0e04d69..fc27669fe 100644 --- a/software/applications/IOIOTortureTest/src/ioio/tests/torture/TestProvider.java +++ b/software/applications/IOIOTortureTest/src/ioio/tests/torture/TestProvider.java @@ -57,7 +57,7 @@ public TestProvider(Activity activity, IOIO ioio, ResourceAllocator alloc) { } public synchronized TestRunner newTest() throws InterruptedException { - int selection = random_.nextInt(7); + int selection = random_.nextInt(8); switch (selection) { case 0: return new TypedTestRunner( @@ -80,6 +80,9 @@ public synchronized TestRunner newTest() throws InterruptedException { case 6: return new TypedTestRunner(new PwmIncapTest( ioio_, alloc_), incapAgg_); + case 7: + return new TypedTestRunner(new UartFlowTest( + ioio_, alloc_), uartAgg_); } return null; } diff --git a/software/applications/IOIOTortureTest/src/ioio/tests/torture/UartFlowTest.java b/software/applications/IOIOTortureTest/src/ioio/tests/torture/UartFlowTest.java new file mode 100644 index 000000000..0e595998c --- /dev/null +++ b/software/applications/IOIOTortureTest/src/ioio/tests/torture/UartFlowTest.java @@ -0,0 +1,140 @@ +package ioio.tests.torture; + +import ioio.lib.api.IOIO; +import ioio.lib.api.Uart; +import ioio.lib.api.exception.ConnectionLostException; +import ioio.tests.torture.ResourceAllocator.PeripheralType; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Random; + +import android.util.Log; + +import ioio.lib.api.Uart.FlowMode; + +public class UartFlowTest implements Test { + private final IOIO ioio_; + private final ResourceAllocator alloc_; + private final int pin1_; + private final int pin2_; + private final int pin3_; + private final int pin4_; + private int bytesVerified_; + private final static FlowMode[] modeMap_ = new FlowMode[] { + Uart.FlowMode.NONE, + Uart.FlowMode.IRDA, + Uart.FlowMode.RTSCTS, + Uart.FlowMode.RS485}; + private int modeCount_; + + public UartFlowTest(IOIO ioio, ResourceAllocator alloc) + throws InterruptedException { + final Random rand = new Random(); + ioio_ = ioio; + alloc_ = alloc; + pin1_ = alloc.allocatePinPair(ResourceAllocator.PIN_PAIR_PERIPHERAL); + pin2_ = pin1_ + 1; + pin3_ = alloc.allocatePinPair(ResourceAllocator.PIN_PAIR_PERIPHERAL); + alloc.allocPeripheral(PeripheralType.UART); + pin4_ = pin3_ + 1; + modeCount_ = rand.nextInt(3); + } + + @Override + public Boolean run() throws ConnectionLostException, InterruptedException { + Log.i("IOIOTortureTest", "Starting UartFlowTest on pins: " + pin1_ + ", " + + pin2_ + ", " + pin3_ + ", " + pin4_); + try { + if (!runTest(pin1_, pin2_, pin3_, pin4_)) { + return false; + } + if (!runTest(pin2_, pin1_, pin4_, pin3_)) { + return false; + } + } finally { + alloc_.freePinPair(pin1_); + alloc_.freePinPair(pin3_); + alloc_.freePeripheral(PeripheralType.UART); + } + Log.i("IOIOTortureTest", "Passed UartFlowTest on pins: " + pin1_ + ", " + + pin2_ + ", " + pin3_ + ", " + pin4_); + return true; + } + + private boolean runTest(int inPin, int outPin, int rtsPin, int ctsPin) + throws ConnectionLostException, InterruptedException { + if ((outPin == 9) || (rtsPin == 9)) { + // pin 9 doesn't support peripheral output + return true; + } + final int BYTE_COUNT = 2000; + final int SEED = 17; + FlowMode mode = modeMap_[modeCount_ & 0x3]; + modeCount_ += 1; + + Uart uart = ioio_.openUart(inPin, outPin, 115200, Uart.Parity.NONE, + Uart.StopBits.ONE, mode, rtsPin, ctsPin); + InputStream in = uart.getInputStream(); + OutputStream out = uart.getOutputStream(); + Random rand = new Random(SEED); + bytesVerified_ = 0; + Thread reader = new ReaderThread(in, SEED, BYTE_COUNT); + reader.start(); + try { + for (int i = 0; i < BYTE_COUNT; ++i) { + byte value = (byte) rand.nextInt(); + out.write(value); + } + reader.join(); + } catch (IOException e) { + try { + in.close(); + } catch (IOException e1) { + } + reader.interrupt(); + reader.join(); + throw new ConnectionLostException(e); + } finally { + uart.close(); + } + if (bytesVerified_ != BYTE_COUNT) { + Log.w("IOIOTortureTest", "Failed UartFlowTest input: " + inPin + + ", output: " + outPin + ", " + rtsPin + ", " + ctsPin + + ". Bytes passed: " + bytesVerified_); + return false; + } + return true; + } + + class ReaderThread extends Thread { + private InputStream in_; + private Random rand_; + private int count_; + + public ReaderThread(InputStream in, int seed, int count) { + in_ = in; + rand_ = new Random(seed); + count_ = count; + } + + @Override + public void run() { + super.run(); + try { + while (count_-- > 0) { + int expected = rand_.nextInt() & 0xFF; + int read = in_.read(); + if (read != expected) { + Log.e("IOIOTortureTest", "Expected: " + expected + " got: " + read); + return; + } else { + bytesVerified_++; + } + } + } catch (IOException e) { + } + } + } +}