Add 3299 protocol support to interface2

This commit is contained in:
Andrew Kay 2021-11-06 13:32:39 -05:00
parent 14fd7485fe
commit cec0ab781a
25 changed files with 1419 additions and 24 deletions

View File

@ -28,6 +28,12 @@
#define COAX_ERROR_NOT_INITIALIZED -1024
enum class CoaxProtocol
{
_3270 = 0,
_3299 = 1
};
enum class CoaxParity
{
Odd = 0,
@ -39,13 +45,17 @@ class SPICoaxTransceiver;
class Coax
{
public:
Coax(SPICoaxTransceiver &spiCoaxTransceiver, CoaxParity parity,
volatile uint16_t *buffer, size_t bufferSize);
Coax(SPICoaxTransceiver &spiCoaxTransceiver, volatile uint16_t *buffer,
size_t bufferSize);
bool init();
void reset();
void setTXProtocol(CoaxProtocol protocol);
void setRXProtocol(CoaxProtocol protocol);
void setParity(CoaxParity parity);
int transmit(const uint16_t *buffer, size_t bufferCount);
int receive(uint16_t *buffer, size_t bufferSize, uint16_t timeout);
@ -53,6 +63,8 @@ public:
private:
SPICoaxTransceiver &_spiCoaxTransceiver;
CoaxProtocol _txProtocol;
CoaxProtocol _rxProtocol;
CoaxParity _parity;
bool _isInitialized;
@ -79,7 +91,9 @@ private:
#define COAX_REGISTER_CONTROL 0x2
#define COAX_REGISTER_CONTROL_LOOPBACK 0x01
#define COAX_REGISTER_CONTROL_TX_PROTOCOL 0x04
#define COAX_REGISTER_CONTROL_TX_PARITY 0x08
#define COAX_REGISTER_CONTROL_RX_PROTOCOL 0x20
#define COAX_REGISTER_CONTROL_RX_PARITY 0x40
#define COAX_REGISTER_DEVICE_ID 0xf
@ -100,7 +114,9 @@ public:
int receive(uint16_t *buffer, size_t bufferSize);
void setLoopback(bool loopback);
void setTXProtocol(CoaxProtocol protocol);
void setTXParity(CoaxParity parity);
void setRXProtocol(CoaxProtocol protocol);
void setRXParity(CoaxParity parity);
inline bool isTXComplete()

View File

@ -34,6 +34,8 @@
#define INFO_MESSAGE_BUFFER_SIZE 0x06
#define INFO_FEATURES 0x07
#define FEATURE_PROTOCOL_3299 0x10
#define TEST_SUPPORTED_TESTS 0x01
#define ERROR_INVALID_MESSAGE 1

View File

@ -21,10 +21,12 @@
#include "coax.h"
Coax::Coax(SPICoaxTransceiver &spiCoaxTransceiver, CoaxParity parity,
volatile uint16_t *buffer, size_t bufferSize) :
Coax::Coax(SPICoaxTransceiver &spiCoaxTransceiver, volatile uint16_t *buffer,
size_t bufferSize) :
_spiCoaxTransceiver(spiCoaxTransceiver),
_parity(parity),
_txProtocol(CoaxProtocol::_3270),
_rxProtocol(CoaxProtocol::_3270),
_parity(CoaxParity::Even),
_buffer(buffer),
_bufferSize(bufferSize)
{
@ -41,7 +43,10 @@ bool Coax::init()
return false;
}
_spiCoaxTransceiver.setTXProtocol(_txProtocol);
_spiCoaxTransceiver.setTXParity(_parity);
_spiCoaxTransceiver.setRXProtocol(_rxProtocol);
_spiCoaxTransceiver.setRXParity(_parity);
_isInitialized = true;
@ -59,10 +64,62 @@ void Coax::reset()
_spiCoaxTransceiver.reset();
_spiCoaxTransceiver.setTXProtocol(_txProtocol);
_spiCoaxTransceiver.setTXParity(_parity);
_spiCoaxTransceiver.setRXProtocol(_rxProtocol);
_spiCoaxTransceiver.setRXParity(_parity);
}
void Coax::setTXProtocol(CoaxProtocol protocol)
{
if (!_isInitialized) {
_txProtocol = protocol;
return;
}
if (_txProtocol == protocol) {
return;
}
_spiCoaxTransceiver.setTXProtocol(protocol);
_txProtocol = protocol;
}
void Coax::setRXProtocol(CoaxProtocol protocol)
{
if (!_isInitialized) {
_rxProtocol = protocol;
return;
}
if (_rxProtocol == protocol) {
return;
}
_spiCoaxTransceiver.setRXProtocol(protocol);
_rxProtocol = protocol;
}
void Coax::setParity(CoaxParity parity)
{
if (!_isInitialized) {
_parity = parity;
return;
}
if (_parity == parity) {
return;
}
_spiCoaxTransceiver.setTXParity(parity);
_spiCoaxTransceiver.setRXParity(parity);
_parity = parity;
}
int Coax::transmit(const uint16_t *buffer, size_t bufferCount)
{
if (!_isInitialized) {
@ -434,11 +491,21 @@ void SPICoaxTransceiver::setLoopback(bool loopback)
writeRegister(COAX_REGISTER_CONTROL, loopback ? COAX_REGISTER_CONTROL_LOOPBACK : 0, COAX_REGISTER_CONTROL_LOOPBACK);
}
void SPICoaxTransceiver::setTXProtocol(CoaxProtocol protocol)
{
writeRegister(COAX_REGISTER_CONTROL, protocol == CoaxProtocol::_3299 ? COAX_REGISTER_CONTROL_TX_PROTOCOL : 0, COAX_REGISTER_CONTROL_TX_PROTOCOL);
}
void SPICoaxTransceiver::setTXParity(CoaxParity parity)
{
writeRegister(COAX_REGISTER_CONTROL, parity == CoaxParity::Even ? COAX_REGISTER_CONTROL_TX_PARITY : 0, COAX_REGISTER_CONTROL_TX_PARITY);
}
void SPICoaxTransceiver::setRXProtocol(CoaxProtocol protocol)
{
writeRegister(COAX_REGISTER_CONTROL, protocol == CoaxProtocol::_3299 ? COAX_REGISTER_CONTROL_RX_PROTOCOL : 0, COAX_REGISTER_CONTROL_RX_PROTOCOL);
}
void SPICoaxTransceiver::setRXParity(CoaxParity parity)
{
writeRegister(COAX_REGISTER_CONTROL, parity == CoaxParity::Even ? COAX_REGISTER_CONTROL_RX_PARITY : 0, COAX_REGISTER_CONTROL_RX_PARITY);

View File

@ -46,6 +46,9 @@ Interface::Interface(Coax &coax, Indicators &indicators) :
_coax(coax),
_indicators(indicators)
{
_coax.setTXProtocol(CoaxProtocol::_3270);
_coax.setRXProtocol(CoaxProtocol::_3270);
_coax.setParity(CoaxParity::Even);
}
void Interface::handleMessage(uint8_t *buffer, size_t bufferCount)
@ -143,6 +146,12 @@ void Interface::handleTransmitReceive(uint8_t *buffer, size_t bufferCount)
}
}
if (transmitBuffer[0] & 0x8000) {
_coax.setTXProtocol(CoaxProtocol::_3299);
} else {
_coax.setTXProtocol(CoaxProtocol::_3270);
}
int transmitCount = _coax.transmit(transmitBuffer, transmitBufferCount);
if (transmitCount < 0) {
@ -214,8 +223,9 @@ void Interface::handleInfo(uint8_t *buffer, size_t bufferCount)
buffer[2] = INFO_HARDWARE_TYPE;
buffer[3] = INFO_FIRMWARE_VERSION;
buffer[4] = INFO_MESSAGE_BUFFER_SIZE;
buffer[5] = INFO_FEATURES;
MessageSender::send(buffer, 5);
MessageSender::send(buffer, 6);
} else if (query == INFO_HARDWARE_TYPE) {
buffer[0] = 0x01;
@ -238,6 +248,11 @@ void Interface::handleInfo(uint8_t *buffer, size_t bufferCount)
memcpy(buffer + 1, &size, sizeof(uint32_t));
MessageSender::send(buffer, 5);
} else if (query == INFO_FEATURES) {
buffer[0] = 0x01;
buffer[1] = FEATURE_PROTOCOL_3299;
MessageSender::send(buffer, 2);
} else {
sendErrorMessage(ERROR_INVALID_MESSAGE, "HANDLE_INFO_UNKNOWN_QUERY");
return;

View File

@ -45,7 +45,7 @@ SPICoaxTransceiver spiCoaxTransceiver;
volatile uint16_t coaxBuffer[COAX_BUFFER_SIZE];
Coax coax(spiCoaxTransceiver, CoaxParity::Even, coaxBuffer, COAX_BUFFER_SIZE);
Coax coax(spiCoaxTransceiver, coaxBuffer, COAX_BUFFER_SIZE);
volatile uint8_t messageBuffer[MESSAGE_BUFFER_SIZE];

View File

@ -24,6 +24,7 @@ module coax_buffered_rx (
input read_strobe,
output empty,
output full,
input protocol,
input parity
);
parameter CLOCKS_PER_BIT = 8;
@ -45,6 +46,7 @@ module coax_buffered_rx (
.error(coax_rx_error),
.data(coax_rx_data),
.strobe(coax_rx_strobe),
.protocol(protocol),
.parity(parity)
);

View File

@ -25,6 +25,7 @@ module coax_buffered_tx (
output empty,
output full,
output reg ready,
input protocol,
input parity
);
parameter CLOCKS_PER_BIT = 8;
@ -56,6 +57,7 @@ module coax_buffered_tx (
.data(coax_tx_data),
.strobe(coax_tx_strobe),
.ready(coax_tx_ready),
.protocol(protocol),
.parity(parity)
);

View File

@ -22,6 +22,7 @@ module coax_rx (
output reg error,
output reg [9:0] data,
output reg strobe = 0,
input protocol,
input parity
);
parameter CLOCKS_PER_BIT = 8;
@ -95,6 +96,8 @@ module coax_rx (
case (state)
STATE_IDLE:
begin
next_input_data = 10'b0;
if (ss_detector_strobe)
begin
// The start sequence ends with a code violation, so reset
@ -111,7 +114,7 @@ module coax_rx (
// differently and consider it part of the start sequence as
// it must be a 1 and we don't consider the receiver active
// until this has been detected.
next_bit_counter = 0;
next_bit_counter = (protocol == 1 ? 4 : 0);
if (rx != previous_rx && mid_bit_counter > CLOCKS_PER_HALF_BIT)
begin

View File

@ -22,6 +22,7 @@ module coax_tx (
input [9:0] data,
input strobe,
output ready,
input protocol,
input parity
);
parameter CLOCKS_PER_BIT = 8;
@ -48,6 +49,8 @@ module coax_tx (
reg next_tx;
reg first_word;
reg next_first_word;
reg end_sequence;
reg next_end_sequence;
@ -86,6 +89,7 @@ module coax_tx (
next_tx = 0;
next_first_word = first_word;
next_end_sequence = 0;
next_output_data = output_data;
@ -188,6 +192,7 @@ module coax_tx (
START_SEQUENCE_9:
begin
next_tx = 1;
next_first_word = 1;
if (last_clock)
next_state = SYNC_BIT;
@ -197,10 +202,21 @@ module coax_tx (
begin
next_tx = first_half ? 0 : 1;
next_bit_counter = 9;
if (last_clock)
begin
// First word is 6 bits in 3299 protocol mode.
if (protocol == 1 && first_word)
begin
next_output_data = { output_data[5:0], 4'b0 };
next_bit_counter = 5;
end
else
begin
next_bit_counter = 9;
end
next_state = DATA_BIT;
end
end
DATA_BIT:
@ -228,6 +244,8 @@ module coax_tx (
if (last_clock)
begin
next_first_word = 0;
if (output_data_full)
begin
next_state = SYNC_BIT;
@ -280,6 +298,7 @@ module coax_tx (
active <= (state != IDLE); // TODO: this causes active to remain high one additional clock cycle
tx <= next_tx;
first_word <= next_first_word;
end_sequence <= next_end_sequence;
output_data <= next_output_data;

View File

@ -36,6 +36,7 @@ module control (
input tx_empty,
input tx_full,
input tx_ready,
output tx_protocol,
output tx_parity,
// RX
@ -45,6 +46,7 @@ module control (
input [9:0] rx_data,
output reg rx_read_strobe,
input rx_empty,
output rx_protocol,
output rx_parity
);
parameter DEFAULT_CONTROL_REGISTER = 8'b01001000;
@ -342,6 +344,8 @@ module control (
assign loopback = control_register[0];
assign tx_protocol = control_register[2];
assign tx_parity = control_register[3];
assign rx_protocol = control_register[5];
assign rx_parity = control_register[6];
endmodule

View File

@ -98,6 +98,7 @@ module top (
wire tx_empty;
wire tx_full;
wire tx_ready;
wire tx_protocol;
wire tx_parity;
coax_buffered_tx #(
@ -115,6 +116,7 @@ module top (
.empty(tx_empty),
.full(tx_full),
.ready(tx_ready),
.protocol(tx_protocol),
.parity(tx_parity)
);
@ -125,6 +127,7 @@ module top (
wire [9:0] rx_data;
wire rx_read_strobe;
wire rx_empty;
wire rx_protocol;
wire rx_parity;
coax_buffered_rx #(
@ -139,6 +142,7 @@ module top (
.data(rx_data),
.read_strobe(rx_read_strobe),
.empty(rx_empty),
.protocol(rx_protocol),
.parity(rx_parity)
);
@ -184,6 +188,7 @@ module top (
.tx_empty(tx_empty),
.tx_full(tx_full),
.tx_ready(tx_ready),
.tx_protocol(tx_protocol),
.tx_parity(tx_parity),
.rx_reset(rx_reset),
@ -192,6 +197,7 @@ module top (
.rx_data(rx_data),
.rx_read_strobe(rx_read_strobe),
.rx_empty(rx_empty),
.rx_protocol(rx_protocol),
.rx_parity(rx_parity)
);

View File

@ -15,6 +15,7 @@ coax_tx_tb: coax_tx_tb.v $(RTL)/coax_tx.v $(RTL)/coax_tx_bit_timer.v
coax_rx_blanker_tb: coax_rx_blanker_tb.v $(RTL)/coax_rx_blanker.v
coax_tx_rx_frontend_tb: coax_tx_rx_frontend_tb.v $(RTL)/coax_tx_rx_frontend.v $(RTL)/coax_tx_distorter.v $(RTL)/coax_rx_blanker.v
control_tb: control_tb.v $(RTL)/control.v $(RTL)/coax_buffered_tx.v $(RTL)/coax_tx.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_buffer.v $(RTL)/third_party/*.v
tx_rx_loopback_tb: tx_rx_loopback_tb.v $(RTL)/coax_tx.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_rx.v $(RTL)/coax_rx_ss_detector.v
regression_memorex_tb: regression_memorex_tb.v $(RTL)/coax_rx.v $(RTL)/coax_rx_ss_detector.v
test: $(TESTS)

View File

@ -31,6 +31,7 @@ module coax_buffered_rx_tb;
.reset(reset),
.rx(rx),
.read_strobe(read_strobe),
.protocol(1'b0),
.parity(1'b1)
);

View File

@ -28,6 +28,7 @@ module coax_buffered_tx_tb;
.data(data),
.load_strobe(load_strobe),
.start_strobe(start_strobe),
.protocol(1'b0),
.parity(1'b1)
);

View File

@ -28,6 +28,7 @@ module coax_rx_tb;
.clk(clk),
.reset(reset),
.rx(rx),
.protocol(1'b0),
.parity(1'b1)
);

View File

@ -24,6 +24,7 @@ module coax_tx_tb;
.reset(reset),
.data(data),
.strobe(strobe),
.protocol(1'b0),
.parity(1'b1)
);

View File

@ -22,6 +22,7 @@ module regression_memorex_tb;
.clk(clk),
.reset(reset),
.rx(rx),
.protocol(1'b0),
.parity(1'b1)
);

View File

@ -0,0 +1,323 @@
`default_nettype none
`include "assert.v"
module tx_rx_loopback_tb;
reg clk = 0;
initial
begin
forever
begin
#1 clk <= ~clk;
end
end
reg reset = 0;
wire loopback;
wire tx_active;
reg [9:0] tx_data;
reg tx_strobe = 0;
wire tx_ready;
reg tx_protocol = 0;
reg tx_parity = 0;
wire rx_error;
wire [9:0] rx_data;
wire rx_strobe;
reg rx_protocol = 0;
reg rx_parity = 0;
coax_tx #(
.CLOCKS_PER_BIT(8)
) dut_tx (
.clk(clk),
.reset(reset),
.active(tx_active),
.tx(loopback),
.data(tx_data),
.strobe(tx_strobe),
.ready(tx_ready),
.protocol(tx_protocol),
.parity(tx_parity)
);
coax_rx #(
.CLOCKS_PER_BIT(8)
) dut_rx (
.clk(clk),
.reset(reset),
.rx(loopback),
.error(rx_error),
.data(rx_data),
.strobe(rx_strobe),
.protocol(rx_protocol),
.parity(rx_parity)
);
initial
begin
$dumpfile("tx_rx_loopback_tb.vcd");
$dumpvars(0, tx_rx_loopback_tb);
test_3270_protocol;
test_3299_protocol;
test_protocol_mismatch;
test_parity_mismatch;
$finish;
end
task test_3270_protocol;
begin
$display("START: test_3270_protocol");
tx_protocol = 0;
tx_parity = 1;
rx_protocol = 0;
rx_parity = 1;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
fork: test_3270_protocol_tx_rx_fork
begin
tx_data = 10'b0101110101;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
@(posedge tx_ready);
tx_data = 10'b1010001010;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
end
begin
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b0101110101, "RX data should be equal to TX data");
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b1010001010, "RX data should be equal to TX data");
disable test_3270_protocol_tx_rx_fork;
end
begin
#1000;
$display("[TIMEOUT] %m (%s:%0d)", `__FILE__, `__LINE__);
disable test_3270_protocol_tx_rx_fork;
end
join
#100;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
$display("END: test_3270_protocol");
end
endtask
task test_3299_protocol;
begin
$display("START: test_3299_protocol");
tx_protocol = 1;
tx_parity = 1;
rx_protocol = 1;
rx_parity = 1;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
fork: test_3299_protocol_tx_rx_fork
begin
tx_data = 10'b0000110001;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
@(posedge tx_ready);
tx_data = 10'b0101110101;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
@(posedge tx_ready);
tx_data = 10'b1010001010;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
end
begin
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b0000110001, "RX data should be equal to TX data");
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b0101110101, "RX data should be equal to TX data");
@(posedge rx_strobe);
`assert_equal(rx_data, 10'b1010001010, "RX data should be equal to TX data");
disable test_3299_protocol_tx_rx_fork;
end
begin
#1000;
$display("[TIMEOUT] %m (%s:%0d)", `__FILE__, `__LINE__);
disable test_3299_protocol_tx_rx_fork;
end
join
#100;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
$display("END: test_3299_protocol");
end
endtask
task test_protocol_mismatch;
begin
$display("START: test_protocol_mismatch");
tx_protocol = 1;
tx_parity = 1;
rx_protocol = 0;
rx_parity = 1;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
fork: test_protocol_mismatch_tx_rx_fork
begin
tx_data = 10'b0000110001;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
@(posedge tx_ready);
tx_data = 10'b0101110101;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
// Wait for TX to complete... we don't want to reset the RX
// to soon as it could be reactivated with the remaining
// transmission.
@(negedge tx_active);
disable test_protocol_mismatch_tx_rx_fork;
end
begin
#1000;
$display("[TIMEOUT] %m (%s:%0d)", `__FILE__, `__LINE__);
disable test_protocol_mismatch_tx_rx_fork;
end
join
// The exact error (parity or loss of mid-bit transition) may depend
// on the length of message and data.
`assert_high(rx_error, "RX error should be HIGH");
`assert_equal(rx_data, dut_rx.ERROR_LOSS_OF_MID_BIT_TRANSITION, "RX data should be ERROR_LOSS_OF_MID_BIT_TRANSITION");
#16;
dut_reset;
#100;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
$display("END: test_protocol_mismatch");
end
endtask
task test_parity_mismatch;
begin
$display("START: test_parity_mismatch");
tx_protocol = 0;
tx_parity = 1;
rx_protocol = 0;
rx_parity = 0;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
fork: test_parity_mismatch_tx_rx_fork
begin
tx_data = 10'b0101110101;
#2;
tx_strobe = 1;
#2;
tx_strobe = 0;
// Wait for TX to complete... we don't want to reset the RX
// to soon as it could be reactivated with the remaining
// transmission.
@(negedge tx_active);
disable test_parity_mismatch_tx_rx_fork;
end
begin
#1000;
$display("[TIMEOUT] %m (%s:%0d)", `__FILE__, `__LINE__);
disable test_parity_mismatch_tx_rx_fork;
end
join
`assert_high(rx_error, "RX error should be HIGH");
`assert_equal(rx_data, dut_rx.ERROR_PARITY, "RX data should be ERROR_PARITY");
#16;
dut_reset;
#100;
`assert_equal(dut_tx.state, dut_tx.IDLE, "state should be IDLE");
`assert_equal(dut_rx.state, dut_rx.STATE_IDLE, "state should be IDLE");
$display("END: test_parity_mismatch");
end
endtask
task dut_reset;
begin
reset = 1;
#2;
reset = 0;
end
endtask
endmodule

833
protocol/3299.svg Normal file
View File

@ -0,0 +1,833 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="800"
height="152"
viewBox="0 0 211.667 40.217"
version="1.1"
id="svg271"
sodipodi:docname="3299.svg"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview273"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="true"
inkscape:zoom="3.6928652"
inkscape:cx="535.49206"
inkscape:cy="112.10807"
inkscape:window-width="3834"
inkscape:window-height="2154"
inkscape:window-x="2560"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g269">
<inkscape:grid
type="xygrid"
id="grid1114"
units="px"
spacingx="0.26458375"
spacingy="0.26458553"
dotted="true"
empspacing="8" />
</sodipodi:namedview>
<defs
id="defs23">
<marker
overflow="visible"
id="g"
refX="0"
refY="0"
orient="auto">
<path
stroke-width=".4pt"
stroke="#999"
fill-rule="evenodd"
fill="#999"
d="M2.308 0l-3.46 2v-4z"
id="path2" />
</marker>
<marker
overflow="visible"
id="f"
refX="0"
refY="0"
orient="auto">
<path
stroke-width=".4pt"
stroke="#999"
fill-rule="evenodd"
fill="#999"
d="M-2.308 0l3.46-2v4z"
id="path5" />
</marker>
<marker
overflow="visible"
id="e"
refX="0"
refY="0"
orient="auto">
<path
stroke-width=".4pt"
stroke="#999"
fill-rule="evenodd"
fill="#999"
d="M2.308 0l-3.46 2v-4z"
id="path8" />
</marker>
<marker
overflow="visible"
id="d"
refX="0"
refY="0"
orient="auto">
<path
stroke-width=".4pt"
stroke="#999"
fill-rule="evenodd"
fill="#999"
d="M-2.308 0l3.46-2v4z"
id="path11" />
</marker>
<filter
color-interpolation-filters="sRGB"
height="1.0104658"
y="-0.0052328963"
width="1.0035491"
x="-0.0017745273"
id="b">
<feGaussianBlur
stdDeviation=".018"
id="feGaussianBlur14" />
</filter>
<filter
color-interpolation-filters="sRGB"
id="c"
x="-0.0014912155"
width="1.0029824"
y="-0.0020151678"
height="1.0040303">
<feGaussianBlur
stdDeviation=".018"
id="feGaussianBlur17" />
</filter>
<filter
color-interpolation-filters="sRGB"
height="1.0417323"
y="-0.020866141"
width="1.0376163"
x="-0.018808143"
id="a">
<feGaussianBlur
id="feGaussianBlur20" />
</filter>
<marker
overflow="visible"
id="e-1"
refX="0"
refY="0"
orient="auto">
<path
stroke-width="0.4pt"
stroke="#999999"
fill-rule="evenodd"
fill="#999999"
d="m 2.308,0 -3.46,2 v -4 z"
id="path8-7" />
</marker>
<filter
color-interpolation-filters="sRGB"
height="1.0090845"
y="-0.0045422457"
width="1.0011981"
x="-0.00059902789"
id="b-1">
<feGaussianBlur
stdDeviation=".018"
id="feGaussianBlur14-1" />
</filter>
</defs>
<path
d="M4.233 14.817H12.7v12.7H4.233z"
fill="#aef"
id="path25" />
<path
d="M12.7 14.817h8.467v12.7H12.7z"
fill="#d5f6ff"
id="path27" />
<path
d="M21.167 14.817h8.467v12.7h-8.467z"
fill="#aef"
id="path29" />
<path
d="M29.633 14.817H38.1v12.7h-8.467z"
fill="#d5f6ff"
id="path31" />
<path
d="M38.1 14.817h8.467v12.7H38.1z"
fill="#aef"
id="path33" />
<path
d="M46.567 14.817h8.467v12.7h-8.467z"
fill="#d5f6ff"
id="path35" />
<path
d="M55.033 14.817H63.5v12.7h-8.467z"
fill="#aef"
id="path37" />
<path
d="m 80.432843,14.81679 h 8.467006 v 12.7 h -8.467006 z"
fill="#d5f6ff"
id="path47" />
<path
d="m 88.899849,14.81679 h 8.467 v 12.7 h -8.467 z"
fill="#aaeeff"
id="path49" />
<path
d="m 97.365849,14.81679 h 8.467001 v 12.7 h -8.467001 z"
fill="#d5f6ff"
id="path51" />
<path
d="m 105.83285,14.81679 h 8.467 v 12.7 h -8.467 z"
fill="#aaeeff"
id="path53" />
<path
d="m 114.29985,14.81679 h 8.467 v 12.7 h -8.467 z"
fill="#d5f6ff"
id="path55" />
<path
d="m 122.76585,14.81679 h 8.467 v 12.7 h -8.467 z"
fill="#aaeeff"
id="path57" />
<path
d="m 131.23285,14.81679 h 8.467 v 12.7 h -8.467 z"
fill="#d5f6ff"
id="path59" />
<path
d="m 139.69985,14.81679 h 8.467 v 12.7 h -8.467 z"
fill="#aaeeff"
id="path61" />
<path
d="m 148.16585,14.81679 h 8.467 v 12.7 h -8.467 z"
fill="#d5f6ff"
id="path63" />
<path
d="m 156.63285,14.81679 h 8.467 v 12.7 h -8.467 z"
fill="#aaeeff"
id="path65" />
<path
d="m 63.499816,14.81679 h 8.467011 v 12.7 h -8.467011 z m 101.600034,0 h 8.467 v 12.7 h -8.467 z"
fill="#d5f6ff"
id="path67" />
<path
d="M2.117 14.817h2.117v12.7H2.117z"
fill="#ffd5e5"
id="path69" />
<path
d="m 207.43403,14.81679 h 2.117 v 12.7 h -2.117 z"
fill="#ffaacc"
id="path71" />
<path
d="m 71.965827,14.81679 h 8.467016 v 12.7 h -8.467016 z"
fill="#aaeeff"
id="path73" />
<g
filter="url(#a)"
id="g269">
<path
stroke-width="0.265"
stroke="#999999"
fill="none"
d="m 63.499816,34.92479 2.116,-3.175 h 4.234007 l 2.116004,3.175 -2.116004,3.175 h -4.234007 z"
id="path229" />
<path
stroke-width="0.265"
stroke="#999999"
fill="none"
d="M 4.233,10.583 V 2.117 M 12.7,10.583 V 2.117 m 50.799816,8.466421 V 2.1174212"
id="path75"
sodipodi:nodetypes="cccccc" />
<text
filter="url(#b)"
text-anchor="middle"
font-family="sans-serif"
font-size="10.667"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
x="11.469"
y="7.917"
transform="rotate(-90 7.523 1.868) scale(.26458)"
id="text81"><tspan
x="11.469"
y="7.917"
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
id="tspan77">Sync</tspan><tspan
x="11.469"
y="21.25"
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
id="tspan79">Bit</tspan></text>
<text
filter="url(#c)"
text-anchor="middle"
font-family="sans-serif"
font-size="10.667px"
font-weight="400"
transform="matrix(0,-0.26458,0.26458,0,64.945816,10.09279)"
y="7.9169998"
x="13.781"
style="line-height:1.25;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
id="text87"><tspan
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
y="7.9169998"
x="13.781"
id="tspan83">Parity</tspan><tspan
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
y="21.25"
x="13.781"
id="tspan85">Bit</tspan></text>
<text
filter="url(#b)"
font-family="sans-serif"
font-size="10.667px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="-0.70300001"
y="7.9169998"
transform="matrix(0.26458,0,0,0.26458,27.410186,5.141)"
id="text91"><tspan
x="-0.70300001"
y="7.9169998"
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan89">Address (6-bits)</tspan></text>
<path
marker-end="url(#e)"
stroke-width="0.265"
stroke="#999999"
fill="none"
d="M 50.799711,6.3500527 H 62.441474"
id="path95"
sodipodi:nodetypes="cc" />
<path
marker-end="url(#e-1)"
stroke-width="0.265"
stroke="#999999"
fill="none"
d="M 25.3995,6.3500527 H 13.757737"
id="path95-7"
sodipodi:nodetypes="cc"
style="marker-end:url(#e-1)" />
<path
stroke-width="0.265"
stroke="#999999"
fill="none"
d="M 71.965827,10.58279 V 2.1167897 M 80.432843,10.58279 V 2.1167897 M 165.09985,10.58279 V 2.1167897 m 8.466,8.4660003 V 2.1167897"
id="path97" />
<text
filter="url(#b)"
text-anchor="middle"
font-family="sans-serif"
font-size="10.667px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
x="11.469"
y="7.9169998"
transform="matrix(0,-0.26458,0.26458,0,73.387829,9.3897897)"
id="text103"><tspan
x="11.469"
y="7.9169998"
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
id="tspan99">Sync</tspan><tspan
x="11.469"
y="21.25"
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
id="tspan101">Bit</tspan></text>
<text
filter="url(#c)"
text-anchor="middle"
font-family="sans-serif"
font-size="10.667px"
font-weight="400"
transform="matrix(0,-0.26458,0.26458,0,166.54585,10.09279)"
y="7.9169998"
x="13.781"
style="line-height:1.25;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
id="text109"><tspan
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
y="7.9169998"
x="13.781"
id="tspan105">Parity</tspan><tspan
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center"
y="21.25"
x="13.781"
id="tspan107">Bit</tspan></text>
<text
filter="url(#b)"
font-family="sans-serif"
font-size="10.667px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="-0.70300001"
y="7.9169998"
transform="matrix(0.26458,0,0,0.26458,113.13485,5.1407897)"
id="text113"><tspan
x="-0.70300001"
y="7.9169998"
style="-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan111">Data (10-bits)</tspan></text>
<path
marker-start="url(#f)"
stroke-width="0.265"
stroke="#999999"
fill="none"
d="M 81.490845,6.3497897 H 111.12485"
id="path115" />
<path
marker-end="url(#g)"
stroke-width="0.265"
stroke="#999999"
fill="none"
d="m 134.40785,6.3497897 h 29.633"
id="path117" />
<path
stroke-width=".265"
stroke="#000"
fill="none"
d="M21.167 34.925l2.116-3.175h4.234l2.116 3.175-2.116 3.175h-4.234z"
id="path119" />
<text
transform="translate(0,-1.058)"
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="24.131001"
y="37.497002"
id="text123"><tspan
x="24.131001"
y="37.497002"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan121">1</tspan></text>
<path
stroke-width=".265"
stroke="#000"
fill="none"
d="M29.633 34.925l2.117-3.175h4.233l2.117 3.175-2.117 3.175H31.75z"
id="path125" />
<text
transform="translate(8.467,-1.058)"
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="24.131001"
y="37.497002"
id="text129"><tspan
x="24.131001"
y="37.497002"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan127">1</tspan></text>
<path
stroke-width=".265"
stroke="#000"
fill="none"
d="M38.1 34.925l2.117-3.175h4.233l2.117 3.175L44.45 38.1h-4.233z"
id="path131" />
<text
transform="translate(16.933 -1.058)"
stroke-width=".265"
font-family="monospace"
font-size="4.233"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="24.131"
y="37.497"
id="text135"><tspan
x="24.131"
y="37.497"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan133">0</tspan></text>
<path
stroke-width=".265"
stroke="#000"
fill="none"
d="M46.567 34.925l2.116-3.175h4.234l2.116 3.175-2.116 3.175h-4.234z"
id="path149" />
<text
transform="translate(25.4,-1.058)"
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
y="37.497002"
x="24.131001"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="text153"><tspan
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
y="37.497002"
x="24.131001"
id="tspan151">0</tspan></text>
<path
stroke-width=".265"
stroke="#000"
fill="none"
d="M55.033 34.925l2.117-3.175h4.233l2.117 3.175-2.117 3.175H57.15z"
id="path155" />
<text
transform="translate(33.867,-1.058)"
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="24.131001"
y="37.497002"
id="text159"><tspan
x="24.131001"
y="37.497002"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan157">0</tspan></text>
<path
stroke-width="0.265"
stroke="#000000"
fill="none"
d="m 88.899849,34.92479 2.116,-3.175 h 4.234 l 2.116,3.175 -2.116,3.175 h -4.234 z"
id="path167" />
<text
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
y="36.438793"
x="91.863678"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="text171"><tspan
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
y="36.438793"
x="91.863678"
id="tspan169">0</tspan></text>
<path
stroke-width="0.265"
stroke="#000000"
fill="none"
d="m 105.83285,34.92479 2.117,-3.175 h 4.233 l 2.117,3.175 -2.117,3.175 h -4.233 z"
id="path173" />
<text
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
y="36.438793"
x="108.79669"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="text177"><tspan
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
y="36.438793"
x="108.79669"
id="tspan175">0</tspan></text>
<path
stroke-width="0.265"
stroke="#000000"
fill="none"
d="m 131.23285,34.92479 2.117,-3.175 h 4.233 l 2.117,3.175 -2.117,3.175 h -4.233 z"
id="path179" />
<text
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
y="36.438793"
x="134.1967"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="text183"><tspan
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
y="36.438793"
x="134.1967"
id="tspan181">0</tspan></text>
<path
stroke-width="0.265"
stroke="#000000"
fill="none"
d="m 97.365849,34.92479 2.117,-3.175 h 4.233001 l 2.117,3.175 -2.117,3.175 h -4.233001 z"
id="path185" />
<text
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
y="36.438793"
x="100.33068"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="text189"><tspan
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
y="36.438793"
x="100.33068"
id="tspan187">1</tspan></text>
<path
stroke-width="0.265"
stroke="#000000"
fill="none"
d="m 148.16585,34.92479 2.117,-3.175 h 4.233 l 2.117,3.175 -2.117,3.175 h -4.233 z"
id="path191" />
<text
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
y="36.438793"
x="151.13069"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="text195"><tspan
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
y="36.438793"
x="151.13069"
id="tspan193">1</tspan></text>
<path
stroke-width="0.265"
stroke="#000000"
fill="none"
d="m 139.69985,34.92479 2.116,-3.175 h 4.234 l 2.116,3.175 -2.116,3.175 h -4.234 z"
id="path197" />
<text
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="142.6637"
y="36.438793"
id="text201"><tspan
x="142.6637"
y="36.438793"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan199">0</tspan></text>
<g
filter="url(#a)"
transform="translate(93.132849,-1.0582103)"
stroke-width="0.265"
id="g209">
<path
stroke="#000000"
fill="none"
d="m 21.167,35.983 2.116,-3.175 h 4.234 l 2.116,3.175 -2.116,3.175 h -4.234 z"
id="path203" />
<text
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="24.131001"
y="37.497002"
id="text207"><tspan
x="24.131001"
y="37.497002"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan205">0</tspan></text>
</g>
<path
stroke-width="0.265"
stroke="#000000"
fill="none"
d="m 122.76585,34.92479 2.117,-3.175 h 4.233 l 2.117,3.175 -2.117,3.175 h -4.233 z"
id="path211" />
<text
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="125.7307"
y="36.438793"
id="text215"><tspan
x="125.7307"
y="36.438793"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan213">0</tspan></text>
<path
stroke-width=".265"
stroke="#999"
fill="none"
d="M4.233 34.925L6.35 31.75h4.233l2.117 3.175-2.117 3.175H6.35z"
id="path217" />
<text
fill="#999"
transform="translate(-16.933 -1.058)"
stroke-width=".265"
font-family="monospace"
font-size="4.233"
font-weight="400"
y="37.497"
x="24.131"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="text221"><tspan
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
y="37.497"
x="24.131"
id="tspan219">1</tspan></text>
<path
stroke-width="0.265"
stroke="#999999"
fill="none"
d="m 71.965827,34.92479 2.117004,-3.175 h 4.233008 l 2.117004,3.175 -2.117004,3.175 h -4.233008 z"
id="path223" />
<text
fill="#999999"
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="74.930679"
y="36.438793"
id="text227"><tspan
x="74.930679"
y="36.438793"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan225">1</tspan></text>
<text
fill="#999999"
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="66.463692"
y="36.438793"
id="text233"><tspan
x="66.463692"
y="36.438793"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan231">0</tspan></text>
<path
stroke-width="0.265"
stroke="#999999"
fill="none"
d="m 165.09985,34.92479 2.116,-3.175 h 4.234 l 2.116,3.175 -2.116,3.175 h -4.234 z"
id="path235" />
<text
fill="#999999"
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
y="36.438793"
x="168.06369"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="text239"><tspan
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
y="36.438793"
x="168.06369"
id="tspan237">0</tspan></text>
<path
stroke-width=".265"
stroke="#000"
fill="none"
d="M12.7 34.925l2.117-3.175h4.233l2.117 3.175L19.05 38.1h-4.233z"
id="path241" />
<text
transform="translate(-8.467,-1.058)"
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
y="37.497002"
x="24.131001"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="text245"><tspan
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
y="37.497002"
x="24.131001"
id="tspan243">1</tspan></text>
<path
stroke-width="0.265"
stroke="#000000"
fill="none"
d="m 80.432843,34.92479 2.117004,-3.175 h 4.233002 l 2.117,3.175 -2.117,3.175 h -4.233002 z"
id="path253" />
<text
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="83.396683"
y="36.438793"
id="text257"><tspan
x="83.396683"
y="36.438793"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan255">1</tspan></text>
<path
stroke-width="0.265"
stroke="#000000"
fill="none"
d="m 156.63285,34.92479 2.117,-3.175 h 4.233 l 2.117,3.175 -2.117,3.175 h -4.233 z"
id="path259" />
<text
stroke-width="0.265"
font-family="monospace"
font-size="4.233px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
x="159.59669"
y="36.438793"
id="text263"><tspan
x="159.59669"
y="36.438793"
style="-inkscape-font-specification:'monospace, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal"
id="tspan261">0</tspan></text>
<path
stroke-width=".216"
stroke="#b3b3b3"
fill="none"
d="M12.7 11.642v2.116m8.467-2.116v2.116m8.466-2.116v2.116m8.467-2.116v2.116m8.467-2.116v2.116m8.466-2.116v2.116m8.467-2.116v2.116m8.467-2.116v2.116m8.466-2.116v2.116m8.467-2.116v2.116m8.467-2.116v2.116m8.466-2.116v2.116m8.467-2.116v2.116m8.467-2.116v2.116m8.466-2.116v2.116m8.467-2.116v2.116m8.467-2.116v2.116m8.466-2.116v2.116m8.467-2.116v2.116m8.467-2.116v2.116m8.466-2.116v2.116m8.467-2.116v2.116m8.467-2.116v2.116m8.466-2.116v2.116m-203.2-2.116v2.116M12.7 28.575v2.117m8.467-2.117v2.117m8.466-2.117v2.117m8.467-2.117v2.117m8.467-2.117v2.117m8.466-2.117v2.117m8.467-2.117v2.117m8.467-2.117v2.117m8.466-2.117v2.117m8.467-2.117v2.117m8.467-2.117v2.117m8.466-2.117v2.117m8.467-2.117v2.117m8.467-2.117v2.117m8.466-2.117v2.117m8.467-2.117v2.117m8.467-2.117v2.117m8.466-2.117v2.117m8.467-2.117v2.117m8.467-2.117v2.117m8.466-2.117v2.117m8.467-2.117v2.117m8.467-2.117v2.117m8.466-2.117v2.117m-203.2-2.117v2.117"
id="path265" />
<path
stroke-width="0.397"
stroke="#000000"
fill="none"
d="m 4.233,25.4 h 4.234 v -8.467 l 4.232395,4.74e-4 v 8.466737 h 4.233368 v -8.466737 h 4.233369 v 8.466737 h 4.233 l 3.68e-4,-8.466737 h 4.233368 v 8.466737 h 4.233369 v -8.466737 h 8.466737 v 8.466737 L 46.567,25.4 v 0 l -6.58e-4,2.11e-4 v -8.466737 h 4.233369 v 8.466737 h 4.233368 v -8.466737 h 4.233368 v 8.466737 h 4.233369 v -8.466737 l 4.233368,0 v 8.467 h 8.467 v -8.467 h 4.233 v 8.467 h 4.233 v -8.467 h 8.467 v 8.467 h 8.466996 v -8.467 h 8.466 v 8.467 h 4.234 v -8.467 h 4.233 v 8.467 h 4.233 v -8.467 h 4.234 v 8.467 h 4.233 v -8.467 h 4.233 v 8.467 h 4.234 v -8.467 h 4.233 v 8.467 h 8.467 v -8.467 h 4.233 v 0 h 4.233 v 8.467 h 4.234 v -8.467 h 4.233 v 8.467 h 4.233"
id="path267"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
<path
fill="#ececec"
d="m 173.56739,14.81687 33.86695,-8e-5 v 12.700105 l -33.86695,0 z"
id="path7340"
style="stroke-width:1"
sodipodi:nodetypes="ccccc" />
<text
filter="url(#b)"
font-family="sans-serif"
font-size="10.667px"
font-weight="400"
style="line-height:1.25;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;filter:url(#b-1)"
x="-0.70300001"
y="7.9169998"
transform="matrix(0.26458,0,0,0.26458,175.96136,18.086847)"
id="text113-5"><tspan
sodipodi:role="line"
x="-0.70300001"
y="7.9169998"
id="tspan11983">Additional words, if</tspan><tspan
sodipodi:role="line"
x="-0.70300001"
y="21.25075"
id="tspan13576">any</tspan></text>
<path
d="m 173.56807,34.925309 2.11601,-3.175006 29.63358,-3.9e-5 2.11701,3.175006 -2.11701,3.175046 -29.63358,0 z"
fill="none"
stroke="#999999"
stroke-width="0.265001"
stroke-dasharray="0.793749, 0.264583"
id="path16992"
sodipodi:nodetypes="ccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -54,18 +54,29 @@ calculation includes the sync bit. Words are transmitted most significant bit
![Diagram showing two 10-bit words within a 3270 protocol frame](data.svg)
### 3299 Variant
The 3299 variant of the protocol includes a 6-bit address word at the start
of each frame, specifying the multiplexer port the remainder of the frame
should be sent to.
![Diagram showing a 3299 protocol frame with 6-bit address word](3299.svg)
As with 10-bit words, the 6-bit address word starts with a sync bit and ends
with an even parity bit.
### Words
All communication is initiated by the controller when it sends a frame
containing a command word and optional data words. The attached device responds
with a frame containing one or more data words.
### Words
Except for the `POLL` command response, words are either:
* Command - encapsulates a single 8-bit command byte, sent from a controller
to an attached device
* Data - encapsulates a single 8-bit data byte
* Transmission Turnaround (TR/TA) - sent as an acknowledgment of a command
* Transmission Turnaround (TT/AR) - sent as an acknowledgment of a command
when there is no response data
| Bit | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |

View File

@ -1,5 +1,6 @@
from .__about__ import __version__
from .interface import InterfaceFeature
from .serial_interface import SerialInterface, open_serial_interface
from .protocol import (
@ -48,6 +49,8 @@ from .features import (
parse_features
)
from .multiplexer import get_device_address
from .exceptions import (
InterfaceError,
ReceiveError,

View File

@ -10,6 +10,9 @@ from .exceptions import ProtocolError
class Interface:
"""3270 coax interface."""
def __init__(self):
self.features = set()
def reset(self):
"""Reset the interface."""
raise NotImplementedError
@ -42,6 +45,11 @@ class Interface:
def _transmit_receive(self, outbound_frames, response_lengths, timeout):
raise NotImplementedError
class InterfaceFeature(Enum):
"""Interface feature."""
PROTOCOL_3299 = 0x10
class FrameFormat(Enum):
"""3270 coax frame format."""

View File

@ -0,0 +1,22 @@
"""
coax.multiplexer
~~~~~~~~~~~~~~~~
"""
PORT_MAP_3299 = [
# The 3299-2 port numbers appear to be LSB first
0b000000,
0b100000,
0b010000,
0b110000,
0b001000,
0b101000,
0b011000,
0b111000
]
def get_device_address(port):
if port < 0 or port > 7:
raise ValueError('Port must be between 0 and 7')
return PORT_MAP_3299[port]

View File

@ -11,7 +11,7 @@ from contextlib import contextmanager
from serial import Serial
from sliplib import SlipWrapper, ProtocolError
from .interface import Interface, FrameFormat
from .interface import Interface, InterfaceFeature, FrameFormat
from .protocol import pack_data_word
from .exceptions import InterfaceError, InterfaceTimeout, ReceiveError, ReceiveTimeout
@ -22,6 +22,8 @@ class SerialInterface(Interface):
if serial is None:
raise ValueError('Serial port is required')
super().__init__()
self.serial = serial
self.slip_serial = SlipSerial(self.serial)
@ -60,6 +62,13 @@ class SerialInterface(Interface):
else:
raise InterfaceError(f'Invalid reset response: {message}')
# Query features, if this is not a legacy firmware.
if not self.legacy_firmware_detected:
try:
self.features = self._get_features()
except InterfaceError:
pass
def enter_dfu_mode(self):
"""Enter device firmware upgrade mode."""
message = bytes([0xf2])
@ -71,18 +80,35 @@ class SerialInterface(Interface):
if message[0] != 0x01:
raise _convert_error(message)
def _transmit_receive(self, outbound_frames, response_lengths, timeout):
if any(address is not None for (address, _) in outbound_frames):
raise NotImplementedError('Interface does not support 3299 protocol')
def _get_features(self):
"""Get interface features."""
message = bytes([0xf0, 0x07])
self._write_message(message)
message = self._read_message()
if message[0] != 0x01:
return _convert_error(message)
known_feature_values = {feature.value for feature in InterfaceFeature}
features = {InterfaceFeature(value) for value in message[1:] if value in known_feature_values}
return features
def _transmit_receive(self, outbound_frames, response_lengths, timeout):
if len(response_lengths) != len(outbound_frames):
raise ValueError('Response lengths length must equal outbound frames length')
if any(address is not None for (address, _) in outbound_frames) and InterfaceFeature.PROTOCOL_3299 not in self.features:
raise NotImplementedError('Interface does not support 3299 protocol')
# Pack all messages before sending.
timeout_milliseconds = self._calculate_timeout_milliseconds(timeout)
messages = [_pack_transmit_receive_message(frame, response_length, timeout_milliseconds)
for ((_, frame), response_length) in zip(outbound_frames, response_lengths)]
messages = [_pack_transmit_receive_message(address, frame, response_length, timeout_milliseconds)
for ((address, frame), response_length) in zip(outbound_frames, response_lengths)]
responses = []
@ -158,7 +184,7 @@ def open_serial_interface(serial_port, reset=True):
yield interface
def _pack_transmit_receive_message(frame, response_length, timeout_milliseconds):
def _pack_transmit_receive_message(address, frame, response_length, timeout_milliseconds):
message = bytes([0x06])
repeat_count = 0
@ -197,6 +223,15 @@ def _pack_transmit_receive_message(frame, response_length, timeout_milliseconds)
for byte in frame[1]:
bytes_ += struct.pack('<H', pack_data_word(byte))
if address is not None:
if address < 0 or address > 63:
raise ValueError('Address must be between 0 and 63')
if repeat_count > 0:
repeat_offset += 1
bytes_ = struct.pack('<H', 0x8000 | address) + bytes_
message += struct.pack('>H', (repeat_offset << 15) | repeat_count)
message += bytes_
message += struct.pack('>HH', response_length, timeout_milliseconds)

View File

@ -5,7 +5,7 @@ import sliplib
import context
from coax.interface import FrameFormat
from coax.interface import InterfaceFeature, FrameFormat
from coax.serial_interface import SerialInterface
from coax.exceptions import InterfaceError, ReceiveTimeout
@ -25,7 +25,7 @@ class SerialInterfaceResetTestCase(unittest.TestCase):
self.interface.reset()
# Assert
self.interface._write_message.assert_called_with(bytes.fromhex('01'))
self.interface._write_message.assert_any_call(bytes.fromhex('01'))
def test_non_legacy_response_is_handled_correctly(self):
# Act
@ -191,9 +191,27 @@ class SerialInterfaceTransmitReceiveTestCase(unittest.TestCase):
# Assert
self.interface._write_message.assert_called_with(bytes.fromhex('06 00 00 ff 03 02 00 fe 03 00 01 01 f4'))
def test_addressed_frame(self):
def test_addressed_frame_with_3299_protocol_feature(self):
# Arrange
self.interface.features.add(InterfaceFeature.PROTOCOL_3299)
self.interface._read_message.return_value=bytes.fromhex('01 00 00')
# Act
responses = self.interface._transmit_receive([(0b111000, (FrameFormat.WORDS, [0b1111111111, 0b0000000000]))], [1], None)
# Assert
self.assertEqual(responses, [[0]])
self.interface._write_message.assert_called_with(bytes.fromhex('06 00 00 38 80 ff 03 00 00 00 01 00 00'))
def test_addressed_frame_with_no_3299_protocol_feature(self):
# Arrange
self.interface._read_message.return_value=bytes.fromhex('01 00 00')
# Act and assert
with self.assertRaises(NotImplementedError):
self.interface._transmit_receive([(0b111000, (FrameFormat.WORD_DATA, 0b1111111111, [0x00, 0xff]))], [1], 0.5)
self.interface._transmit_receive([(0b111000, (FrameFormat.WORDS, [0b1111111111, 0b0000000000]))], [1], None)
def test_multiple_frames(self):
# Arrange