***************************************************************************************************************************

  Communication Protocol SpiNNaker <-> generic external Hardware connected to TUM IO Board                        28.7.2014

***************************************************************************************************************************

General remarks about the IO Board:

                all UART interfaces in this document are "logic" UARTs numbered from 0 to 4 counter-clockwise on the physical board

                        all UARTs by default are configured to 4mbps, 8N1, full handshaking RTS/CTS

                        UARTs 1+2 can support 8mbps or 10.5mbps for specific projects' demands

                                         ,-------------------------.    top view

                                         |    UART4*       *UART3  |    (asterisks indicate pin1 of port)

                                         |   (debug)               |

                    ,--------------------’                         |

                    | *                                            |

                    | S L      .------.       .------.             |

                    | p i      | CPLD |       |  uC  |     *UART2  |

                    | i n      `------’       `------’             |

                    | n k                                          |

                    `--------------------.                         |

                                         |                         |

                                         |    *UART0       *UART1  |

                                         `-------------------------’

                UART port 4 (last port counterclockwise) is debug port; can be connected to PC (FTDI adapter) to monitor operation

                                                can be used to stream out (visualize) spiNNaker data for debug

                                                can generate arbitrary "spinnaker packets" to go into the system

                UART ports 0..3 are available for external hardware;

                                                up to 4 retinas can be connected to any one (or multiple) of UART ports 0..3

                                                specific hardware (e.g. SpomniBot, BallBalancer) requires the use of a particular UART port

***************************************************************************************************************************

***************************************************************************************************************************

- SpiNNaker -> external Hardware

***************************************************************************************************************************

   

   The SpiNNaker IO board (currently) only reacts to MultiCast (MC) packets.

   

   Every MC packet received by the IO board (from SpiNNaker) is "valid" - i.e. the board interprets every incoming packet.

   Key top 21 bits are ignored (sender address according to SpiNNaker notation: 8bit x, 8bit y, 5bit coreID)

   

   Key bottom 11 bits "iiiiiiifddd":

                                7 bits for command id (0-127), 1 bit for payload-format (0-1), 3 bits for dimension (0-7)

        the (optional) payload contains an additional value:

                format == 0 --> payload 32bit (signed) int

                format == 1 --> payload for replies(!) encoded in S16.15

                                        - to convert to integer: (value*maximum_value)>>15

                                        - to convert to boolean: (value & 0xA000)

      id=127: Board Configuration

                dim=0: payload top 21 bits: set new master ID for package transmission IO-Board --> SpiNNaker

                                default master key: ((254<<24) | (255<<16) | (248<<8))  =  0xFEFFF800

                                (overwrites possibly set individual retina keys!)

                dim=1: configure board hardware for a particular project

                                        (such as baud rates on UART ports, enable/disable handshaking, use I2C instead of UART,
                              interpret received data correctly, ...)

                                PL=0: reset to default (all ports at 4mbps, full handshaking active)

                                PL=1: PushBot project (uart0,1,3 at 4mbps, uart2 at 8mbps, full handshaking active)

                                PL=2: SpomniBot project (robot at UART0, eDVS at UART1..3; full handshaking active)

                                PL=3: BallBalancer - lower baud rates for UART0 & UART1, no RTS/CTS

                                PL=4: Myorobotics project - UART2 configured as CAN controller (1MBit, requires additional hardware)

                                PL=5..: open for future projects

***************************************************************************************************************************

***************************************************************************************************************************

  Project specific keys:

***************************************************************************************************************************

***************************************************************************************************************************

***************************************************************************************************************************

  - eDVS4337 (retina)  id 0..31 is for retina

                id bits 2..0 (7..0) encode function

                id bits 4..3 (+24/+16/+8/+0) encode retina ID (which UART port on interface board); up to 4 retinas

***************************************************************************************************************************

        id=0: Retina eDVS4337 Event Streaming and Reset

            dim=0: disable retina event streaming ("E-")

            dim=1: enable retina event streaming ("E+"), payload specifies data format

                  PL bits 31..29: timestamp:    0: no timestamp

                                                1: delta-timestamps from sensor; (global) absolute 4 bytes timestamp (in us) provided in packet payload

                                                2: 2 bytes time-stamp 0..65536us == 65ms - timestamp provided in packet payload

                                                3: 3 bytes time-stamp 0..16777216us == 16.7s - timestamp provided in packet payload

                                                4: 4 bytes time-stamp 0..4294967296us == 71 minutes - timestamp provided in packet payload

                                                5..7: unused

                                                                (note that activating timestamps enforces event address encoding in keys, see PL bit 28..26 below)

                  PL bits 28..26: event-encoding in payload vs. event-encoding in key (with possible downsampling):

                                                0: all events transmitted as payload with fixed retina key (use “no timestamp” mode in bits 31..29)

                                                1: events encoded in lower 15 bits (1p +7x +7y) of key
                                               2: events encoded in lower 13 bits (1p +6x +6y) of key (downsampling:2 -> 64x64 pixel)

                                                3: events encoded in lower 11 bits (1p +5x +5y) of key (downsampling:4 -> 32x32 pixel)

                                                4: events encoded in lower  9 bits (1p +4x +4y) of key (downsampling:8 -> 16x16 pixel)

                                                5..7: unused

            dim=2: payload specifies retina events "sending key" (default is the IO board's key + "retina offset" 0..3)
                          note: this key is only for events, not for sensor data!

            dim=3: payload set internal timer/counter for timestamps (on eDVS and on interface board); without payload set to 0

            dim=4: handle master/slave time synchronization

                  PL = 0: use internal counter, no external synchronization (default)

                  PL = 1: set slave (reset internal timer, connect to external source)

                  PL = 2: set master, clock not started

                  PL = 4: set master, clock active

            dim=5: set Bias values

                  PL bits 31..28: bias ID (0..11)

                  PL bits 23..0:  bias Value (0..16777215)

            dim=6: unused

            dim=7: Reset eDVS4337 retina

      id=1: Request on-board sensor data: https://wiki.lsr.ei.tum.de/nst/documentation/edvs-4337

            dim=0: sensor reporting off (bitfield 31..0, no payload -> all sensors off)

            dim=1: poll multiple sensors once (bitfield 31..0 request multiple sensors simultaneously)

            dim=2: poll individual sensor continuously (specify separately for each sensor)

                        payload bits 31..27: sensor ID (31..0)

                        payload bits 26..0: sensor polling interval (time in ms)

                   the "f" (format) flag allows reply in “binary/decimal” (0) or “S16.15” (1)

      id=2: PWM Motor Output

            dim=0: payload 0/1: disable/enable motor driver

            dim=1: payload = PWM total period duration (in microseconds)

            dim=4: payload = PWM signal for motor 0 (raw motor output, permanent)

            dim=5: payload = PWM signal for motor 1 (raw motor output, permanent)

            dim=6: payload = PWM signal for motor 0 (raw motor output, leaking towards zero)

            dim=7: payload = PWM signal for motor 1 (raw motor output, leaking towards zero)

      id=3: PWM pin Output Duration

            dim=0: payload = timer A total period (in microseconds)

            dim=2: payload = timer B total period (in microseconds)

            dim=4: payload = timer C total period (in microseconds)

      id=4: PWM pin output ratio

            dim=0: payload = timer A, channel 0 active period (in microseconds)

            dim=1: payload = timer A, channel 1 active period (in microseconds)

            dim=2: payload = timer B, channel 0 active period (in microseconds)

            dim=3: payload = timer B, channel 1 active period (in microseconds)

            dim=4: payload = timer C, channel 0 active period (in microseconds)

            dim=5: payload = timer C, channel 1 active period (in microseconds)

      id=5: Digital IO Signals:

            dim=0: query state of IO lines (will trigger a reply, documented below)

            dim=1: set output pattern to payload (6 bits)

            dim=2: add payload (logic or(PL)) to current output

            dim=3: remove payload (logic and(not(PL))) from current output

            dim=4: set payload pins to high impedance (6 bits)

      id=6-7:  unused

      retina id-offset +0 / +8 / +16 / +24:    select UART 0..3 port for retina

***************************************************************************************************************************

  - PushBot connected to UART0/1/2/3

   The PushBot is controlled by a retina, so id=4..5 are from the retina above, id=32..39 are specific to the robot

***************************************************************************************************************************

      id=4/12/20/28: Laser/Speaker/LED

            dim=0: total period for laser (in microseconds)                                (part of the eDVS4337 key-space above)

            dim=2: total period for speaker (in microseconds)

            dim=4: total period for top-LED (in microseconds)

      id=5/13/21/29: Laser/Speaker/LED

            dim=0: Laser active time (in microseconds)                                (part of the eDVS4337 key-space above)

            dim=2: Speaker active time (in microseconds)           (typically 1/2 value of id4:dim2 to set 50% duty cycle)

            dim=4: LED back active time (in microseconds)

            dim=5: LED front active time (in microseconds)

      id=32/33/34/35: Track (Motor) Velocity Control:

            dim=0: payload = signal for motor 0 (desired velocity, permanent)

            dim=1: payload = signal for motor 1 (desired velocity, permanent)

            dim=2: payload = signal for motor 0 (desired velocity leaking towards zero)

            dim=3: payload = signal for motor 1 (desired velocity leaking towards zero)

      id=36: Speaker

            dimension bit 0 -> select tone or melody (0=beep; 1=melody)

            dimension bit 2..1 -> select robot/UART port 0..3

                   payload: for tone: specify frequency in Hertz

                   payload: for melody: select melody

      id=37: LED/Laser (at 50% duty cycle)

            dimension bit 0 -> select LED or laser (0=led; 1=laser)

            dimension bit 2..1 -> select robot/UART port 0..3

                   payload: specify frequency in milli-Hertz

      id=38..39:  unused

***************************************************************************************************************************

  - SpomniBot connect to UART0 (in fact any Munich OmniWheel robot)

    id 40..47 are specific for OmniBot

***************************************************************************************************************************

      id=40: PWM (direct) motor wheel output

            dim=0..2:  payload = PWM signal for motor 0..2 (raw motor output, permanent)

            dim=4..6:  payload = PWM signal for motor 0..2 (raw motor output, leaking towards zero)

            dim=7:     payload = PWM total period duration (in microseconds)

      id=41: Motor Wheel Velocity Control:

            dim=0..2: payload = signal for motor 0..2 (desired velocity, permanent)

            dim=4..6: payload = signal for motor 0..2 (desired velocity leaking towards zero)

            dim=7: emergency stop (all three wheels)

      id=42: Motor Abstract Driving Commands (desired velocities in robots coordinate frame)

            dim=0: payload = desired velocity in frontal direction, forward is positive

            dim=1: payload = desired velocity in lateral (sideways) direction, right is positive

            dim=2: payload = desired velocity in rotation (counter-clockwise is positive)

            dim=4..6: same with leaking velocities towards zero

            dim=7: emergency stop (all three wheels)

      id=43: Robot Control and Beeper

            (dim=0: payload==0 -> enable direct motor mode (id=40)                OUTDATED, the robot changes automatically)

            (       payload!=0 -> enable velocity control mode (id=41/42), default active     OUTDATED)

            dim=6: single beep

            dim=7: double beep (that's all the robot can do...)

      id=44: Request on-board Sensor Data:

            dim=0: sensors reporting off

            dim=1: poll sensors once (payload format below)

            dim=2: poll sensor continuously (payload format below, only bits 0..7 supported)

                    payload = bit pattern to activate sensors (bits 7..0), according to specs on web page:

                        https://wiki.lsr.ei.tum.de/nst/documentation/omnirob

                    the "f" (format) flag indicates if the reply should be sent in binary/decimal or S16.15

            dim=3: reporting frequency in Hz, default 25Hz (robot mainloop frequency 125Hz; only integer-fractions available)

      id=45..47:  unused

***************************************************************************************************************************

  - BallBalancer (Motors connected to UART0 and UART1)

    id 48..51 are specific for Ball Balancer

***************************************************************************************************************************

      id=48: Set Servo Motor Position

            dim=0: payload angle x (parallel to left side when looking "diagonal" into balancer)

            dim=1: payload angle y (parallel to right side when looking "diagonal" into balancer)

            dim=7: turn off motors (free plate to allow "hand motion")

      id=49: Request/Read Sensory Data (here we need some explanation about the board's reply)

            dim=0: sensors reporting off

            dim=1: poll sensors once (payload format below)

            dim=2: poll sensor continuously (payload format below)

                    payload = bit pattern to activate sensors

                      bit(0): angle X+Y

                      bit(1): velocity X+Y

                      bit(2): current X+Y

            dim=3: reporting period in ms, default 1000ms (1Hz)

      id=50..51:  unused

***************************************************************************************************************************

  - LaserMirror (connected to UART0)

    id 52..55 are specific for LaserMirror

***************************************************************************************************************************

      id=52: Set Pan/Tilt Angle for Laser Mirror

            dim=0: payload angle x (horizontal)

            dim=1: payload angle y (vertical)

            dim=2: payload velocity x (horizontal)

            dim=3: payload velocity y (vertical)

            dim=4: laser power (payload: on/off)

      id=53..56:  unused

***************************************************************************************************************************

- Myorobotics project (using additional CAN transceiver on UART2)

    id 56..63 are specific for Myorobotics

Register and use up to 8 different motors, 8 different motor monitors and 8 different joint sensors in individual

tables for each type. Register each motor and its corresponding motor monitor to the same single index (use id=56).

Register each agonistic and its corresponding antagonistic muscle to consecutive indices, which allows quasi-simultaneous

control with a single command (id=58).

***************************************************************************************************************************

      id=56: Register Motor and Corresponding Monitor

            dim=0..7: specifies index at which to register the motor/monitor pair

                      payload: CAN ID of monitor << 16  (bits 31..16) | CAN ID of motor (bits 15..0)

      id=57: Set Motor PWM signal

            dim=0..7: specifies index of the registered target motor

                      payload: PWM signal (range -4000..4000), int32

      id=58: Simultaneously Set Motor PWM signals for 2 Motors at (<dim>) and ((<dim>+1)%8)

            dim=0..7: specifies index of the first registered target motor

                      payload: (int16 PWM value1 << 16) | (int16 PWM value2)     (range -4000..4000)

                               value1 (high bytes) is sent to motor #<dim>

                               value2 (low bytes)  is sent to motor #(<dim>+1)

      id=59: Set/Request Motor Monitor Data Streams (continuous, int32)

            dim=0..7: specifies the index of the registered monitor

                      payload: bit pattern to activate sensor streams

                               bit 3..0: displacement (+8), current (+4), encoder Position (+2), omega (+1)

 

      id=60: Register Joint (Angle) Sensor and Request Continuous Data Stream (int32)

            dim=0..7: specifies index at which to register the sensor

                      payload: CAN ID of the sensor (set to 0 to deregister/mute this stream)

      id=61..63 currently not used

***************************************************************************************************************************

  - other (future) hardware

        id ..126 are free

***************************************************************************************************************************

  to come

***************************************************************************************************************************

***************************************************************************************************************************

- external Hardware -> SpiNNaker

***************************************************************************************************************************

The IOBoard does not "by itself" send packets; it only generates replies after queries.

The IOBoard uses the "Master-ID" for the top 21 bits of key (possibly different for retinas); set with key id=127

default master key = 0xFEFFF800

The key space for the 11 lower bits (10:0) needs to be re-designed (differs from sending keys),

as we need to represent a large number of individual responses for some commands (does not fit within dim space),

but for most keys we need no reply at all.

The payload format is specified by the earlier "request" command; will be memorized for an individual id/dimension

***************************************************************************************************************************

        Key bottom 11 bits "iiiidddddss":

                                4 bits for sensor/command id (0-15), 5 bits for dimension (0-31), 2 bits for "sub-dimension” (0-3)

***************************************************************************************************************************

        id=0:                retina event streaming (sub-dimension specify retina 0..3);

                                payload contains event encoded as p0000000.0yyyyyyy.00000000.0xxxxxxx

                                (for future larger retinas the "0"s can be used to extend range in x and y respectively)

        id=1/2/3/4:        retina request on-board sensor data

                                dim=0..31 - type of sensory data (e.g. Gyro)

                                ss =0..3  - sensory axis (e.g. Gyro_rateX)

                                payload contains sensory data either "plain" or S16.15 as requested

        id=5:                return digital IO signals, (sub-dimension specify retina 0..3)

***************************************************************************************************************************

        id=8:                PushBot specific replies (none yet)

                                dim[4..3]= 28/24/20/16 UART/PushBot-ID (3..0)

                                dim[2..0]= unused (0..3)

                                ss       = unused (0..3)

***************************************************************************************************************************

        id=9:                SpomniBot specific replies, on-board sensor data:

                                dim=0..31 - type of sensory data (e.g. Gyro)

                                ss =0..3  - sensory axis (e.g. Gyro_rateX)

                                payload contains sensory data either "plain" or S16.15 as requested

***************************************************************************************************************************

        id=10:                BallBalancer request/read-back current angle

                                dim=0..31 - type of data (angle, velocity, current, ...)

                                ss =0..1  - direction X or Y

***************************************************************************************************************************

        id=11:                Laser Mirror (none yet)

***************************************************************************************************************************

      id=12: Myorobotics Motor Monitor and Sensor Data

                        dim specifies the data source:

                            dim bit 3:     source flag: motor monitor (cleared), sensor (set)

                            dim bits 2..0: index (0..7) of data source

                        subdimension specifies type of sensory data (only relevant for motor monitor)

                            3: displacement, 2: current, 1: encoder Position, 0: omega

                        payload contains data in int32 format

***************************************************************************************************************************

***************************************************************************************************************************

        id=13..15:        free