275 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | ||
| <html>
 | ||
| <head>
 | ||
| <title>Ether Dream - Protocol</title>
 | ||
| <link rel="stylesheet" type="text/css" href="main.css" />
 | ||
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 | ||
| </head>
 | ||
| <body>
 | ||
|  <img src="etherdream.png" width="298" height="75" alt="ether dream">
 | ||
|  <div id="header"><a href="protocol.html">Ether Dream</a></div>
 | ||
|  <div id="content">
 | ||
|   <h1>Ether Dream - Protocol</h1>
 | ||
| <h2>Contents</h2>
 | ||
| 
 | ||
| <ul>
 | ||
| <li><a href="#intro">Introduction</a></li>
 | ||
| <li><a href="#stm">State Machines</a></li>
 | ||
| <li><a href="#status">Status Responses</a></li>
 | ||
| <li><a href="#broadcast">Broadcast</a></li>
 | ||
| <li><a href="#commands">Commands</a></li>
 | ||
| <li><a href="#responses">Responses</a></li>
 | ||
| </ul>
 | ||
| 
 | ||
| <h2 id="intro">Introduction</h2>
 | ||
| 
 | ||
| <p>
 | ||
|  Communication with the DAC happens over TCP on port 7765. The DAC will only
 | ||
|  communicate with one host at a time; another device that connects while the DAC
 | ||
|  has an established control connection will have its connection attempt rejected.
 | ||
| 
 | ||
|  If the host does not send anything to the device for one second, the device will close
 | ||
|  the TCP connection. <em>TODO: The 1-second timeout is not implemented, but will be
 | ||
|  in the future.</em>
 | ||
| </p>
 | ||
| <p>
 | ||
|  The DAC has a USB interface as well. This is used for firmware updates. <em>TODO:
 | ||
|  In the future, the USB interface may also emulate a standard USB CDC-ECM network
 | ||
|  device. This would allow the same communication protocol to be spoken over USB. In
 | ||
|  this mode, the DAC would choose a link-local IP address.</em>
 | ||
| </p>
 | ||
| <p>
 | ||
|  In this document, protocol messages are described as structs. Fields are packed
 | ||
|  together with no padding (<code>__attribute__((packed))</code> or <code>#pragma pack(1)</code>);
 | ||
|  standard C typedefs such as uint8_t, uint32_t, int32_t, etc. have
 | ||
|  their usual meanings, and multi-byte values are transmitted little-endian
 | ||
|  ("host" byte order on x86 and ARM): the most significant byte appears first.
 | ||
| </p>
 | ||
| 
 | ||
| <h2 id="stm">State Machines</h2>
 | ||
| 
 | ||
| <p> 
 | ||
|  There are three distinct state machines within the DAC: light engine, playback, and source. The light
 | ||
|  engine states are:
 | ||
| </p>
 | ||
| <ul>
 | ||
|  <li>0: Ready.</li>
 | ||
|  <li>1: Warmup. In the case where the DAC is also used for thermal control of laser apparatus,
 | ||
|      this is the state that is entered after power-up.</li>
 | ||
|  <li>2: Cooldown. Lasers are off but thermal control is still active.</li>
 | ||
|  <li>3: Emergency stop. An emergency stop has been triggered, either by an E-stop input on the DAC,
 | ||
|      an E-stop command over the network, or a fault such as over-temperature.</li>
 | ||
| </ul>
 | ||
| <p>
 | ||
|  <em class="todo">TODO: Since thermal control is not implemented yet, it is not defined how
 | ||
|  transitions to and from the "Warmup" and "Cooldown" states occur.</em>
 | ||
| </p>
 | ||
| <p>
 | ||
|  The DAC has one playback system, which buffers data and sends it to the analog output
 | ||
|  hardware at its current point rate. At any given time, the playback system is connected
 | ||
|  to a source. Usually, the source is the network streamer, which uses the protocol described
 | ||
|  in this document; however, other sources exist, such as a built-in abstract generator and
 | ||
|  file playback from SD card. The playback system is in one of the following states:
 | ||
| </p>
 | ||
| <ul>
 | ||
|  <li>0: Idle. This is the default state. No points may be added to the buffer. No output is
 | ||
|  generated; all analog outputs are at 0v, and the shutter is controlled by the data source.</li>
 | ||
|  <li>1: Prepared. The buffer will accept points. The output is the same as in the Idle state.</li>
 | ||
|  <li>2: Playing. Points are being sent to the output.</li>
 | ||
| </ul>
 | ||
| 
 | ||
| <h2 id="status">Status Responses</h2>
 | ||
| 
 | ||
| <p>Periodically, and as part of ACK packets, the DAC sends to the host information on its
 | ||
|    current playback status. The status struct is:</p>
 | ||
| 
 | ||
| <blockquote><pre>struct dac_status {
 | ||
|         uint8_t protocol;
 | ||
|         uint8_t light_engine_state;
 | ||
|         uint8_t playback_state;
 | ||
|         uint8_t source;
 | ||
|         uint16_t light_engine_flags;
 | ||
|         uint16_t playback_flags;
 | ||
|         uint16_t source_flags;
 | ||
|         uint16_t buffer_fullness;
 | ||
| 	uint32_t point_rate;
 | ||
| 	uint32_t point_count;
 | ||
| };</pre></blockquote>
 | ||
| <p>
 | ||
|  The light_engine_state field gives the current state of the light engine. If the light engine
 | ||
|  is Ready, light_engine_flags will be 0. Otherwise, bits in light_engine_flags will be set as follows:
 | ||
| </p>
 | ||
| <ul>
 | ||
|  <li>[0]: Emergency stop occurred due to E-Stop packet or invalid command.
 | ||
|  <li>[1]: Emergency stop occurred due to E-Stop input to projector.
 | ||
|  <li>[2]: Emergency stop input to projector is currently active.
 | ||
|  <li>[3]: Emergency stop occurred due to overtemperature condition.
 | ||
|  <li>[4]: Overtemperature condition is currently active.
 | ||
|  <li>[5]: Emergency stop occurred due to loss of Ethernet link.
 | ||
|  <li>[15:5]: Future use.
 | ||
| </ul>
 | ||
| <p>
 | ||
| <p>Similarly, playback_state gives the state of the playback system. The playback_flags field may
 | ||
|    be nonzero during normal operation. Its bits are defined as follows:</p>
 | ||
| <ul>
 | ||
|  <li>[0]: Shutter state: 0 = closed, 1 = open.
 | ||
|  <li>[1]: Underflow. 1 if the last stream ended with underflow, rather than a
 | ||
|      Stop command. Reset to zero by the Prepare command.
 | ||
|  <li>[2]: E-Stop. 1 if the last stream ended because the E-Stop state was entered.
 | ||
|      Reset to zero by the Prepare command.
 | ||
| </ul>
 | ||
| <p>
 | ||
|  The buffer_fullness field contains the number of points currently buffered.
 | ||
|  point_rate is the number of points per second for which the DAC is configured (if Prepared or
 | ||
|  Playing), or zero if the DAC is idle. point_count is the number of points that the DAC has
 | ||
|  actually emitted since it started playing (if Playing), or zero (if Prepared or Idle).
 | ||
| </p>
 | ||
| <p>
 | ||
|  The currently-selected data source is specified in the source field:
 | ||
| </p>
 | ||
| <ul>
 | ||
|  <li>0: Network streaming (the protocol defined in the rest of this document).
 | ||
|  <li>1: ILDA playback from SD card.
 | ||
|  <li>2: Internal abstract generator.
 | ||
| </ul>
 | ||
| 
 | ||
| <h2 id="broadcast">Broadcast</h2>
 | ||
| <p>
 | ||
|  Regardless of the data source being used, each DAC broadcasts a status/ID datagram over UDP to
 | ||
|  its local network's broadcast address once per second. This datagram is formed as follows:
 | ||
| </p>
 | ||
| <blockquote><pre>struct j4cDAC_broadcast {
 | ||
| 	uint8_t mac_address[6];
 | ||
| 	uint16_t hw_revision;
 | ||
| 	uint16_t sw_revision;
 | ||
| 	uint16_t buffer_capacity;
 | ||
| 	uint32_t max_point_rate;
 | ||
|         struct dac_status status;
 | ||
| };</pre></blockquote>
 | ||
| 
 | ||
| <h2 id="commands">Commands</h2>
 | ||
| 
 | ||
| <p>
 | ||
|  When a host first connects to the device, the device immediately sends it a status reply,
 | ||
|  as if the host had sent a ping packet (described later). The host sends to the device a
 | ||
|  series of commands. All commands receive a response from the DAC; responses are described
 | ||
|  after the list of commands. The commands are as follows:
 | ||
| </p>
 | ||
| 
 | ||
| <h3>Prepare Stream</h3>
 | ||
| <p>Single byte: 'p' (0x70)</p>
 | ||
| <p>This command causes the playback system to enter the Prepared state. The DAC resets its buffer to
 | ||
|    be empty and sets "point_count" to 0. This command may only be sent if the light engine is Ready
 | ||
|    and the playback system is Idle. If so, the DAC replies with ACK; otherwise, it replies with NAK - Invalid.</p> 
 | ||
| 
 | ||
| <h3>Begin Playback</h3>
 | ||
| <blockquote><pre>struct begin_command {
 | ||
| 	uint8_t command; /* 'b' (0x62) */
 | ||
|         uint16_t low_water_mark;
 | ||
| 	uint32_t point_rate;
 | ||
| };</pre></blockquote>
 | ||
| <p>This causes the DAC to begin producing output. point_rate is the number of points per second to be
 | ||
|    read from the buffer. If the playback system was Prepared and there was data in the buffer, then the
 | ||
|    DAC will reply with ACK; otherwise, it replies with NAK - Invalid.</p>
 | ||
| <p><span class="todo">TODO: The low_water_mark parameter is currently unused.</span></p>
 | ||
| 
 | ||
| <h3>Queue Rate Change</h3>
 | ||
| <blockquote><pre>struct queue_change_command {
 | ||
| 	uint8_t command; /* 'q' (0x74) */
 | ||
| 	uint32_t point_rate;
 | ||
| };</pre></blockquote>
 | ||
| <p>This adds a new point rate to the point rate buffer. Point rate changes are read out of the buffer when
 | ||
|    a point with an appropriate flag is played; see the Write Data command. If the DAC is not Prepared or
 | ||
|    Playing, it replies with NAK - Invalid. If the point rate buffer is full, it replies with NAK - Full.
 | ||
|    Otherwise, it replies with ACK.</p>
 | ||
| 
 | ||
| <h3>Write Data</h3>
 | ||
| <blockquote><pre>struct data_command {
 | ||
| 	uint8_t command; /* ‘d’ (0x64) */
 | ||
| 	uint16_t npoints;
 | ||
| 	struct dac_point data[];
 | ||
| };
 | ||
| struct dac_point {
 | ||
|         uint16_t control;
 | ||
|         int16_t x;
 | ||
|         int16_t y;
 | ||
| 	uint16_t r;
 | ||
| 	uint16_t g;
 | ||
| 	uint16_t b;
 | ||
| 	uint16_t i;
 | ||
| 	uint16_t u1;
 | ||
| 	uint16_t u2;
 | ||
| };</pre></blockquote>
 | ||
| <p>This provides data for the DAC to add to its buffer. The data values are full-scale (for instance,
 | ||
|    for color channels, 65535 is full output); the least-significant bits of each word will be ignored
 | ||
|    if the DAC’s resolution is less than 16 bits. The DAC will reply with ACK if the incoming packet
 | ||
|    can fully fit in its buffer, or NAK - Full if it cannot. It is valid for npoints to be zero; in
 | ||
|    this case, no point will be added to the buffer, but the packet will still be ACKed (as long as
 | ||
|    the DAC is Prepared or Playing.)</p>
 | ||
| <p>The "control" field has the following fields defined:</p>
 | ||
| <ul>
 | ||
| <li>[15]: Change point rate. If this bit is set, and there are any values in the point rate change
 | ||
|     buffer, then a new rate is read out of the buffer and set as the current playback rate. If the
 | ||
|     buffer is empty, the point rate is not changed.
 | ||
| <li>Other bits: reserved for future expansion to support extra TTL outputs, etc.
 | ||
| </ul>
 | ||
| 
 | ||
| <h3>Stop</h3>
 | ||
| <p>Single byte: 's' (0x73)</p>
 | ||
| <p>The stop command causes the DAC to immediately stop playing and return to the Idle state. It is
 | ||
|    ACKed if the DAC was Playing or Prepared; otherwise it is replied to with NAK - Invalid.</p>
 | ||
| 
 | ||
| <h3>Emergency Stop</h3>
 | ||
| <p>Single byte: 0x00 or 0xFF. (The DAC will recognize either one.)</p>
 | ||
| <p>The e-stop command causes the light engine to enter the E-Stop state, regardless
 | ||
|    of its previous state. It is always ACKed.</p>
 | ||
| <p>Any unrecognized command will also be trested as E-stop; however, software should not send
 | ||
|    undefined commands deliberately, since they may be defined in the future.</p>
 | ||
| 
 | ||
| <h3>Clear E-Stop</h3>
 | ||
| <p>Single byte: 'c' (0x63)</p>
 | ||
| <p>If the light engine was in E-Stop state due to an emergency stop command (either from a local
 | ||
|    stop condition or over the network), then this command resets it to be Ready. It is ACKed if the
 | ||
|    DAC was previously in E-Stop; otherwise it is replied to with a NAK - Invalid. If the condition
 | ||
|    that caused the emergency stop is still active (E-Stop input still asserted, temperature still
 | ||
|    out of bounds, etc.), then a NAK - Stop Condition is sent.</p>
 | ||
| 
 | ||
| <h3>Ping</h3>
 | ||
| <p>Single byte: '?' (0x3F)</p>
 | ||
| <p>The DAC will reply to this with an ACK packet. This serves as a keep-alive for the connection when
 | ||
|    the DAC is not actively streaming.</p>
 | ||
| 
 | ||
| <h2 id="responses">Responses</h2>
 | ||
| <p>Responses have one form:</p>
 | ||
| <blockquote><pre>struct dac_response {
 | ||
| 	uint8_t response;
 | ||
| 	uint8_t command;
 | ||
| 	struct status dac_status;
 | ||
| };</pre></blockquote>
 | ||
| <p>In the case of ACK/NAK responses, "command" echoes back the command to which the response is sent.
 | ||
|    (Commands are always sent in order, so this field exists for sanity-checking on the host side.) 
 | ||
|    The response field can be one of the following:</p>
 | ||
| <ul>
 | ||
| <li>ACK - 'a' (0x61) - The previous command was accepted.
 | ||
| <li>NAK - Full - 'F' (0x46) - The write command could not be performed because there was not
 | ||
|     enough buffer space when it was received.
 | ||
| <li>NAK - Invalid - 'I' (0x49) - The command contained an invalid command byte or parameters.
 | ||
| <li>NAK - Stop Condition - '!' (0x21) - An emergency-stop condition still exists.
 | ||
| </ul>
 | ||
| 
 | ||
|  </div>
 | ||
|  <div id="footer">
 | ||
|   © 2010-2021 Jacob Potter.
 | ||
|  </div>
 | ||
|  <div id="menu">
 | ||
|   <ul>
 | ||
|     <li><a href="../index.html">LJ doc</a></li>
 | ||
|     <li><a href="protocol.html">Protocol</a></li>
 | ||
|    <li><a href="userguide.html">V1 User Guide</a></li>
 | ||
|    <li><a href="manual.html">V1 Developer Manual</a></li>
 | ||
|    <li><a href="dmx.html">V1 DMX Board</a></li>
 | ||
|   </ul>
 | ||
|  </div>
 | ||
| </body>
 | ||
| </html>
 |