Smoothie Accessory Protocol Notes

  • the protocol is based on master/slave relationship
  • the master always initiates comms and slaves have irq lines to get the master's attention
    • the exception to this is UART where the slave sends '\0' on a timer to assert an irq
      • this irq timer should be stopped when the master begins to send a command and restarted after the reply (assuming it was not a Clear IRQ command)
  • slaves should assert an irq at boot once ready to accept commands
  • all Commands from the master receive a Reply from the slave, even if it is just to say OK with no data
  • the protocol allows for describing messages of great length but this is limited by the practicality of buffer sizes. For now all simple (not relayed or queued) binary commands should keep their command data under 16byte. I plan to use 32byte buffers in early implementations and this needs to allow room for relaying queued messages to downstream devices. This will help enforce a level of economy in the core protocol. Later this cap can be raised.

Hardware Protocols

UART:

  • bus: VCC GND
  • unq: TX RX [DTR] [CTS]
  • doesn't need a dedicated irq pin since the slave can speak at will and can spam '\0' at the master with a delay as an irq

I2C:

  • bus: VCC GND SCL SDA
  • unq: IRQ
  • self-arbitrates (master can 'hang-up')

SPI:

  • bus: VCC GND SCK MISO MOSI
  • unq: SSEL IRQ
  • very fast and reliable

Software Protocol

Command Message Structure

  <Virtual Address 8bit><Command Type 8bit><Data Length 1-4byte><Command Data ...><Checksum 8bit>
   <Virtual Address>:
    -different from i2c address, a single i2c slave (or any other protocol slave) 
      may have up to 255 distinct virtual devices to communicate with. some may
      be parts of the slave, others may actually be unique downstream devices and
      the accessory will be expected to pass the message along
    -the virtual address 0x00 always refers to the module manager of the accessory 
      being spoken to, the other 255 addresses are available for use by modules
   <Command Type>:
    -Everything should be possible using Command Types 0x00 through 0x03, i.e. all other
      commands only really exist for convenience or to save bandwidth
    -Types 0x00 - 0x1F are reserved for system commands
    -Types 0x20 - 0x7F are reserved for core protocol commands
    -Types 0x80 - 0xFF provide 128 addresses for module-specific protocol commands
    -Command Type List:
      0x00: Nop
      0x01: Resend Last Reply
      0x02: Clear IRQ
      0x10: Write system data: <System Memory Address 1byte><Data 0+byte>
      0x11: Read system data: <System Memory Address 1byte>
      0x12: Enable
      0x13: Disable
      0x14: Pause
      0x15: Resume
      0x16: Text Mode
      0x17: Binary Mode
      0x20: Write data: <Shared Memory Address 1-4byte><Data 0+byte>
      0x21: Read data: <Shared Memory Address 1-4byte>
      0x22: Queue Command: <Delta 1-4byte><Command Type 1byte><Command Data ...>
      <Delta>:
       - the time offset from the previous command expressed in ticks as specified
        in the Virtual Device's System Memory at which to execute the command
       - 0 means the command is meant to be executed simultaneously or immediately after
        the previous command
       - in each byte, a high order bit of 0 means this is the last address 
        byte and the lower 7 bits hold the address data
       - if the high order bit is 1 it means another address byte follows, it's 7
        data bits will be 7 bits higher order than the previous byte's data
       - up to 4 bytes can be sent this way, allowing a max of 28bits data
      0x80-0xFF: Module Specific Commands
      <Shared Memory Address>:
       - in each byte, a high order bit of 0 means this is the last address 
        byte and the lower 7 bits hold the address data
       - if the high order bit is 1 it means another address byte follows, it's 7
        data bits will be 7 bits higher order than the previous byte's data
       - up to 4 bytes can be sent this way, allowing 28bits (256MB) of memory to 
        be addressed per virtual device. (this actually (in theory) would allow a
        single accessory to address up to nearly 64GB of data. That by 127 accessories
        would give Smoothie the ability to address up to almost 8 phemptobytes through one device! )
   <Data Length>:
    -the number of bytes in <Data> not including the <Virtual Address>, <Command Type>, <Data Length> or <Checksum>
    - in each byte, a high order bit of 0 means this is the last address 
     byte and the lower 7 bits hold the address data
    - if the high order bit is 1 it means another address byte follows and
     the following byte's 7 data bits will be 7 bits higher order than 
     this byte's data
    - up to 4 bytes can be sent this way, allowing a max of 28bits of data
    - the 4th byte's 7th bit is always 0
   <Command Data>:
    -command data can be of variable length depending on the specific 
      <Command Type> used
    -if the <Command Type> can itself have variable data length, the command should
      provide a way of determining the expected data length as early as possible
   <Checksum>:
    -the last block of all protocol messages
    -includes all message blocks except <Checksum> itself starting with <Virtual Address>

Reply Message Structure

  <Status 8bit><Data Length 1-4byte><Data 0+byte><Checksum 8bit>
   <Status>:
    -Status List:
      0x00: OK!
       - Everything is tickety-boo and the reply data should be as expected. If there
        was less data than expected or all bytes after a point are '\0' then the message will 
        be truncated, this will be apparent in the <Data Length> field.
      0x10: Checksum Error.
      0x11: Length Error. 
       - command had more or less bytes than expected.
       - only applies to I2C (and maybe SPI)
      0x12: Timeout Error. Did not receive as many bytes as expected within the timeout 
       period. Command was ignored.
       - only applies to UART (and maybe SPI)
   <Data Length>:
    - same as in command messages
   <Data>:
    -the reply data which may be different than expected depending on <Status>
   <Checksum>:
    -last block of reply
    -includes all blocks in the reply except the <Checksum> starting from the <Status> byte

Memory Maps

Virtual Device 0x00 (Module Manager) Memory Map

  0x0000  Magic Number (128bit read only)
   - this identifies the device as a compatible accessory and must always contain the magic value
   - "SMOOTHIEWAREMINI"
  0x0010  Creator ID (128bit read only)
   - this field identifies the device manufacturer, similar to VID in plug and play
   - using 16byte uuid for these fields allows anyone to generate their own unique numbers
    with no need for a central tracking system
  0x0020  Device Type ID (128bit read only)
   - this field uniquely identifies the device type, like the PID in plug and play
  0x0030  Device Serial (128bit read only)
   - this field holds a device serial that should actually be unique
  0x0040  *** (196byte)
  0x0100  Upstream UART Config
  0x0200  Upstream SPI Config
  0x0300  Upsteram I2C Config

System Memory Map

  - System Memory Maps are 128bytes
  - every virtual device has it's own System Memory Map for configuration and basic control
  - this leaves each virtual device's main memory map free, preventing conflicts with existing memory maps
  0x00    Module ID (128bit read only)
   - this field contains a unique identifier for the running module
   - Virtual Device 0x00 (Module Manager) has a Module ID of 0x0000 0000 0000 0000
  0x10    Status Flags (32bit read only)
     0b0  starting
     0b1  disabling
     0b2  pausing
     0b3  resuming
     *** 28bits free
  0x14    State Flags (16bit)
     0b0  disabled
       - when disabled the device will only process System Command Types 0x00 through 0x1F
       - it will continue to run (assuming it's not paused), but will only complete 
        commands that have already been received.
     0b1  paused
       - when paused the device will 'stop', the meaning of which depends on what the 
        device in question actually does. It will however continue to accept all
        commands as normal (assuming it's enabled).
     *** 14bits free
     1b0  binary mode
       - if false then 'text mode' is used, which requires any binary commands to be 
        prefixed with a '\0'
     *** 15bits fre
  0x16    IRQ Flags (16bit)
     0b0  irq system enabled
     0b1  config irq enabled
     0b2  queue empty irq enabled
     0b3  queue full irq enabled
     *** 3bits free
     0b7  module irq enabled
     1b0  connect irq asserted
     1b1  config irq asserted
     1b2  queue empty irq asserted
     1b3  queue full irq asserted
     *** 3bits free
     1b7  module irq asserted
  0x18    Virtual Address (1byte)
   - reading this value may be a little pointless, but by writing you will change 
    the address being used
   - after changing the Virtual Address the next command sent to the virtual device 
      will need to use the new address
   - the Virtual Address of Virtual Device 0x00 (Module Manager) cannot be changed
  0x19    Command Buffers (1byte)
      b0  command bitsize (4bit)
       - this value describes the maximum length command
        the accessory is capable of receiving in bits
       - Current plan is for the default to be 5, which means a 32byte buffer
       - value must be from 4 to 28, though this is also limited by available 
        h/w resources like ram
      b4  queue bitsize (4bit)
       - this is the size of the command queue in bits. Currently shooting for a
        default of 4, which would let the queue hold up to 16 commands.
  0x1A    Queue Time Division (2bytes)
      b15 timing (1bit)
       - if 0 then the low 15 bits represent ticks per sync/beat  
       - if 1 then b8-b14 are frames per second, and b0-b7 are ticks per frame
      b0  sync divisor (15bit)
      b8  timecode frame divisor (7bit)
      b0  timecode tick divisor (8bit)
    B0b6
    B0b7  timing
    B1    delta ticks per frame
  0x1C    Queue State (4byte)
   - holds the number of commands currently in the queue