.. _controller: Controller ========== The controller's purpose is to interface an ONI hardware system with the host computer. It aggregates and routes device data and provides transparent access to all devices, independently of their physical location. The host also contains a common clock that is used to timestamp data from all devices, independently of their origin hub. Communication between the controller and the host computer shall occur over four abstract communication channels: #. **Read**: Read-only, high-bandwidth stream of device output samples from controller to host. #. **Write**: Write-only, high-bandwidth stream of device input samples from host to controller. #. **Signal**: Read-only stream of short-messages and asynchronous hardware events from controller to host. #. **Configuration**: Bidirectional, addressed access to device registers. API access to all these channels is blocking, i.e.: an API call that accesses any channel will not return until the requested transaction on that channel is complete. Concurrent access to a single channel by different threads is NOT permitted. However, channels are independent and concurrent access to *different* channels MUST be permitted. A stream transaction is defined as a blocking read or write of a set number of bytes, while a register transaction is defined as a single register read or write cycle to an individual address. The required characteristics of these channels are described in the following sections. A complete understanding of their use during software development requires an understanding of the :ref:`oni-api`. .. _data-rd-chan: Read Channel ------------ - **Word size** : 32 bits - **Channel type** : Stream - **Direction** : Read The *read* channel provides high bandwidth communication from the controller to the host computer. Data from the read stream of all devices that support it is aggregated and multiplexed by the controller and sent to the host through this channel. Data should be pushed to this channel as quickly as possible. It is the responsibility of the host computer to read data from the stream quickly enough to keep up with data production by the controller. Therefore, it is highly recommended that an ONI system implements some kind of internal buffering to ameliorate the effects of uneven reading times caused by computer operating systems or other software limitations. .. _frame: Data Frames ~~~~~~~~~~~ Data from the read channel is packed in frames. Each frame is a timestamped `type-length-value-encoded `__ structure that contains data from a single device :ref:`sample `. The frame format is: :: uint64 Common_Timestamp uint32 Device_Address uint32 Sample_Size var Sample Where - ``Common_Timestamp``: A counter common to all devices generated by the controller common acquisition clock. - ``Device_Address``: The address of the device producing the data, as featured on the :ref:`device table `. - ``Sample_Size``: The full size of the sample, and must be equal to the ``Read_Sample_Size`` field of the :ref:`device descriptor `. - ``Sample``: The complete data sample as described on the :ref:`device sample format ` section. .. _data-wr-chan: Write Channel ------------- - **Word size** : 32 bits - **Channel type** : Stream - **Direction** : Write The *write* channel provides high bandwidth communication from the host computer to the controller, and is used to send data to the devices. Data is sent with a :ref:`frame ` format identical to the one used for read, but without the ``Common_Timestamp`` field. It is the responsibility of the controller to accept frames at any rate the computer might be sending them. Currently, there is no defined mechanism to inform the host of any possible dropped frame on the write channel, although this can be included in an implementation so long as it does not invalidate any other ONI requirements. .. _sig-chan: Signal channel -------------- - **Word size** : 8 bits - **Channel type** : Stream - **Direction** : Read The *signal* channel provides a way for the controller to inform the host of configuration results, which may be provided with a significant delay. Additionally, it is the channel over which the controller sends the device table to the host following a system reset. Signal data MUST be framed into packets using Consistent Overhead Byte Stuffing (`COBS `__). Within this scheme, packets are delimited using 0's and always have the following format: :: ... | PACKET_FLAG, data0, data1, ..., data_k | ... where ``PACKET_FLAG`` is 32-bit unsigned integer with a single unique bit setting, ``|`` represents a packet delimiter (in this case, 0), “``,``” are for visual clarity and are not actually in the data stream, and ``...`` represents other packets. This stream can be read and ignored until a desired packet is received. Reading this stream shall block if no data is available, which allows asynchronous configuration acknowledgment. Valid ``PACKET_FLAG``\ s are: ============ ========== ===================================== Flag Value Description ============ ========== ===================================== NULLSIG 0x00000001 Null signal, ignored by host CONFIGWACK 0x00000002 Configuration write-acknowledgment CONFIGWNACK 0x00000004 Configuration no-write-acknowledgment CONFIGRACK 0x00000008 Configuration read-acknowledgment CONFIGRNACK 0x00000010 Configuration no-read-acknowledgment DEVICETABACK 0x00000020 Device table start acknowledgment DEVICEINST 0x00000040 Device descriptor instance ============ ========== ===================================== Following a hardware reset, the signal channel is used to provide the :ref:`device table ` to the host using the following packet sequence: :: ... | DEVICETABACK, uint32 num_devices | DEVICEINST, uint32 dev_addr_0, device_descriptor dev_0 | DEVICEINST, uint32 dev_addr_1, device_descriptor dev_1 | ... | DEVICEINST, uint32 dev_addr_n, device_descriptor dev_n | ... Where ``dev_addr_n`` is the full address of each device as described in the :ref:`device table ` section and ``dev_n`` is a :ref:`device descriptor `. In addition to providing the device table following reset, the signal channel is also used to asynchronously acknowledge register access via the :ref:`configuration channel `. Following a device register read or write, an CONFIGWACK, CONFIGWNACK, CONFIGRACK, or CONFIGRNACK signal is pushed onto the signal stream by the controller to indicate the validity of the transaction. For instance, on a successful register read: :: ... | CONFIGRACK | ... .. _conf-chan: Configuration Channel --------------------- - **Word size** : 32 bits - **Channel type** : Register - **Direction** : Read-Write The *configuration* channel supports addressed access to a set of configuration registers. There are two classes of registers handled by the configuration channel: the first set of registers encapsulates a generic device register programming interface. The remaining registers are for global controller control and configuration and provide access to acquisition parameters and state control. The interface must use 32-bit values and, at least, 24-bit addressing. The required register map is as follows: ========== ========================= ================== Address Name Type ========== ========================= ================== 0x00000000 Device Address Register interface 0x00000001 Register Address Register interface 0x00000002 Register Value Register interface 0x00000003 Read/Write Register interface 0x00000004 Trigger Register interface 0x00000005 Running Global 0x00000006 Reset Global 0x00000007 System Clock Global 0x00000008 Acquisition Clock Global 0x00000009 Reset Acquisition Counter Global 0x0000000A Hardware Address Global ========== ========================= ================== Device Register Programming Interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The device programming interface allows transparent access to each device's :ref:`register map `. It defines a general purpose bus that hides the specifics of any particular implementation. It is composed of the following configuration channel registers: - ``Device Address``: The fully qualified address of a device as enumerated in the :ref:`device table ` and to which communication will be directed as described below. - ``Register Address``: The address of the register within the :ref:`register map ` of the device located at ``Device Address`` that will be written to or read from. - ``Register Value``: Value to be written to or read from and that corresponds to the register ``Register Address`` of device located at ``Device Address``. - ``Read/Write``: A flag indicating if a read or write should be performed. 0 indicates read operation. A value > 0 indicates write operation. - ``Trigger``: Set > 0 to trigger either register read or write operation depending on the state of ``Read/Write``. If ``Read/Write`` is 0, a read is performed. In this case, after a successful operation, ``Register Value`` is updated with value stored in the register at ``Register Address`` on the device at ``Device Address``. If ``Read/Write`` is 1, ``Register Value`` is written to register at ``Register Address`` on the device at ``Device Address``. The ``Trigger`` register is always set low by the controller following transmission even if it is not successful or does not make sense given the supplied register address and/or value. Appropriate values of ``Register Address`` and ``Register Value`` are determined by: - Looking at a device's data sheet if the device is an integrated circuit and using :ref:`raw registers `. - Examining the :ref:`ONI Device Datasheet ` for :ref:`managed registers `. Register Read Sequence ^^^^^^^^^^^^^^^^^^^^^^ When a host requests a device register *read*, the following following sequence must be performed: 1. Check the value of ``Trigger``. - If it is 0, the procedure can proceed. - Else, the hardware is busy with a previous transaction and a new one cannot be issued. 2. The target device is selected by writing its address, as featured on the device map, into ``Device Address`` on the controller. 3. The desired register address within the device register map is written into ``Register Address`` on the controller. 4. The ``Read/Write`` register on the controller is set to 0x00. 5. The ``Trigger`` register on the controller is set to 0x01, triggering configuration transmission. 1. (Controller) A register read is routed by the controller to the appropriate device. 2. (Controller) ``Trigger`` is set to 0x00 once the operation finishes. 3. (Controller) ``CONFIGRACK`` is pushed into the signal stream if the operation was successful, ``CONFIGRNACK`` is pushed if it failed. 6. The signal stream must be pumped until either ``CONFIGRACK`` or ``CONFIGRNACK`` is received indicating that controller has either: - Completed reading the specified device register and copied its value to the ``Register Value`` register. - Failed to read the register in which case the value of ``Register Value`` contains invalid data. 7. If operation was successful, the ``Register Value`` can be read. Register Write Sequence ^^^^^^^^^^^^^^^^^^^^^^^ When a host requests a device register *write*, the following following sequence must be performed: 1. Check the value of ``Trigger``. - If it is 0, the procedure can proceed. - Else, the hardware is busy with a previous transaction and a new one cannot be issued. 2. The target device is selected by writing its address, as featured on the device map, into ``Device Address`` on the controller 3. The desired register address within the device register map is written into ``Register Address`` on the controller. 4. The ``Read/Write`` register on the controller is set to 0x01. 5. The ``Trigger`` register on the controller is set to 0x01, triggering configuration transmission. 1. (Controller) A register write is routed by the controller to the appropriate device. 2. (Controller) ``Trigger`` is set to 0x00 once the operation finishes. 3. (Controller) ``CONFIGWACK`` is pushed into the signal stream if the operation was successful, ``CONFIGWNACK`` is pushed if it failed. 6. The signal stream must be pumped until either ``CONFIGWACK`` or ``CONFIGWNACK`` is received indicating that the controller has either: - Successfully completed writing the specified device register. - Failed to write the register. Following successful or unsuccessful device register read or write, the appropriate ACK or NACK packets *must* be passed to the :ref:`signal channel ` by the controller. If they are not, the register read and write calls will block indefinitely. Global Acquisition Registers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following global acquisition registers provide information about, and control over, the entire acquisition system: - ``Running``: Set to > 0 to run the system clock and produce data. Set to 0 to stop the system clock and therefore stop data flow. Results in no other configuration changes. - ``Reset``: Set to > 0 to trigger a hardware reset and send a fresh device map to the host. Devices are reset but their managed registers might remain unchanged, depending on their configuration (See the :ref:`Device registers ` section for more information). Set to 0 by the controller upon entering the reset state. - ``System Clock``: A read-only register specifying the master hardware clock frequency in Hz. This is the clock used by the controller to perform data transmission. - ``Acquisition Clock``: A read-only register specifying the system common clock frequency in Hz. This clock is used to generate an acquisition counter that timestamps data from all the devices. The ``Common_Timestamp`` in the read :ref:`frame ` header is incremented at this frequency. - ``Reset Acquisition Counter``: This register is used to reset the counter generating the ``Common_Timestamp`` used in the :ref:`device frames `. A value of 1 will reset the counter to 0 without affecting the ``Running`` state. A value of 2 will reset the counter and, at the same time, set ``Running`` to 1, starting data production. - ``Hardware Address``: This is used for systems that allow multiple controllers with a link between them to synchronize their ``Common_Timestamps``. When resetting the acquisition counter through the ``Reset acquisition counter`` on a device with a ``Hardware Address`` of 0, this command will be sent through an external link to all non-zero devices, synchronizing the counters. Multiple controller support or hardware-based timestamp synchronization through dedicated links are optional features of an ONI system.