The Information Daemon is a master daemon which aggregates all information necessary to connect to and use the components on the sign. It's also secondarily responsible for getting and setting system-wide properties like the time, the photocell levels, etc.
It provides a generic interface whereby components can register themselves into a category (e.g. "scheduler", "display"), indicate how to connect to them, and provide a description of what it is that they do. The Information Daemon also provides a generic interface so that clients can query it to find out what categories it has, how many of each, and ask for the descriptions of each component.
Components will provide a persistant ID so that notes may be associated with them in the Information Daemon. This is intended for use to help distinguish components. For example, if there are two Display Drivers, one might plug them in, figure out which is which, and then make the notes "Facing West Bound" and "Facing East Bound" to indicate that the first is facing the west-bound lanes and the other is facing the east-bound lanes.
Because notes will be used in interfaces to help users identify which component is which, notes should be as brief as possible. They should not be briefer than possible, however. For example, "West" doesn't tell you whether the sign is facing west, or whether it's facing people heading west, or whether it's on the west side of a north-south road (and thus facing north so that people who are south-bound can read it).
Also, every sign has a category "unit" with a component "This Unit". Its URL is blank and its description is the controller's serial number. Its main purpose is to provide a place to store notes describing where the message board is and what it's supposed to be doing there.
It is the responsibility of the Information Daemon to store the user notes for every component persistantly.
This protocol is used both to register components and to query information about them.
The Information Daemon will listen for connections using this protocol on port 40001.
Note: all category names will be forced to lowercase.
Note: unless otherwise specified, all multi-byte integral types are in network-order (i.e. big-endian).
The protocol handshake works according to the Solartech Protocol Handshake & Authentication specification. The current protocol version is 3.
After the version handshake, the protocol is asynchronous, though some packets require a response.
Components are expected to remain connected to the Information Daemon to indicate that they are still active. If a component ever drops its connection, every component that it registered over that connection is automatically de-registered. Note: the de-registration of a component does not cause the deletion of the note associated with its Component ID.
Version 8 of this protocol (that is, the first version carried over the single port protocol, adds the Compact Configuration Packet and the Compact Configuration Query Packet, which allow the querying of certain configuration data in a much more compact (i.e. bandwidth-efficient) form.
Note: unless otherwise specified, multi-byte integral types are network ordered (i.e. big-endian). Further, the data type String is defined as an unsigned short indicating length, followed by that many bytes of UTF-8 data.
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 0 | Packet Type |
2-65,537 | String | Category | |
2-65,537 | String | Component ID. This must be unique within a category, but does not need to be unqiue accross categories. It must be persistant accross sessions, boot-ups, etc. | |
2-65,537 | String | URL (see SolarTech URL Protocols) | |
2-65,537 | String | Description. This should be a human-readable description of what the component is and what it does. | |
2-65,537 | String | User Notes. These are whatever user-defined notes were set for this ID in this category. | |
Notes: When this is sent to the Information Daemon, it registers a component. When it is sent by the Information Daemon, it gives the information about that registered component. The major distinction between the description and the notes is that the component automatically generates the description whereas the user creates the notes. For example a Display Driver would say that it's a Display Driver and might mention its resolution, bit-depth, refresh rate, etc. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 1 | Packet Type |
Notes: This packet is used to request a Category List Packet |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 2 | Packet Type |
2 | unsigned short | (count) The number of categories in this packet. | |
variable | String[count] | The categories. | |
Notes: |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 3 | Packet Type |
2-65,537 | String | The category to get the list for. | |
Notes: This packet prompts the Information Daemon to send a Component List Packet>. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 4 | Packet Type |
2-65,537 | String | The category that this listing is for. | |
2 | unsigned short | (count) the number of component IDs in this list. | |
variable | String[count] | The component IDs for this category | |
Notes: |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 5 | Packet Type |
2-65,537 | String | The category. | |
2-65,537 | String | The component ID. | |
Notes: This requests that the Information Daemon send a Component Information packet. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 6 | Packet Type |
2-65,537 | String | The category. | |
2-65,537 | String | The component ID. | |
Notes: This packet causes the indicated component to be de-registered. If it is the last component in its category, that category is de-registered as well. (For components which have only registered a single component over their connection, it would be simpler to just terminate the connection without sending this packet.) |
Byte Count | Data Type | Value | Description | ||||||||||
1 | unsigned byte | 7 | Packet Type | ||||||||||
1 | byte | Error code:
|
|||||||||||
2-65,537 | String | A human-readable error string explaining what caused the error. | |||||||||||
Notes: Every error type should have the human-readable explanation, even if there does exist an error code for it. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 8 | Packet Type |
2-65,537 | String | Category | |
2-65,537 | String | Component ID | |
2-65,537 | String | Notes | |
Notes: If there are already notes present for this component, this packet overrites them. To erase the notes for just one component, the client should send this packet with a blank Notes field. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 9 | Packet Type |
2-65,537 | String | Category | |
Notes: This clears the notes on every component in the specified category. It is meant for limited system re-initialization (if a substantial, but not complete, part of the system is changed). |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 10 | Packet Type |
Notes: This causes the notes on every component in every category to be cleared, including the note on the "This Unit" component. This packet is only meant to be used for system re-initialization. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 11 | Packet Type |
Notes: |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 12 | Packet Type |
8 | long long | Time | |
2-65,537 | String | Time Zone | |
Notes: Time is the standard unix offset (in seconds) from January 1st, 1970, and is assumed to be in UTC. Time Zone is specified in the standard-ish java and unix format common to /etc/timezone. (These formats are actually defined in classpath's java/util/TimeZone.java file.) |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 13 | Packet Type |
Notes: |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 14 | Packet Type |
2 | unsigned short | Minimum Reading | |
2 | unsigned short | Maximum Reading | |
Notes: Photocell readings are 12-bit numbers in the range 0-4096. The typical limits are 500-3500. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 15 | Packet Type |
1 | unsigned byte | Solar panel orientation. 1 means the vertical, cleaning orientation. 0 means the horizontal, solar collecting orientation. | |
Notes: |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 16 | Packet Type |
Notes: Requests a font list, i.e. the contents of /usr/share/fonts/fontList.txt |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 17 | Packet Type |
2 | unsigned short | [count] Font list size (in bytes) | |
[count] | bytes | the font list | |
Notes: The font list is simple the contents of /usr/share/fonts/fontList.txt -- it's up to the client to parse this into something meaningful, or understand what the filenames of the fonts mean. When sent to the Information Daemon, the ID writes out /usr/share/fonts/fontList.txt with the contents in this packet and sends this packet back as confirmation. The unit must be rebooted before the new font list will take effect. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 18 | Packet Type |
2 | unsigned int | Secret length (in bytes) | |
0-65,535 | byte | The secret to use for all communications challenge/response authentication. | |
Notes: This is a version 2 packet. When the information daemon receives this packet, it will respond with this packet as confirmation that the new secret was stored. The unit must be rebooted before the new secret will take effect. |
Byte Count | Data Type | Value | Description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | unsigned byte | 19 | Packet Type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2-65,537 | String | Setting ID. See notes. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | unsigned byte | Query. 0 if the packet is querying the value, 1 if it is setting the value. If it's a query packet, the string should be empty, but must in any event be properly read and discarded. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2-65,537 | String | Value | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This packet only exists in version 2 and onward of this protocol. Notes:This packet allows the information daemon to set a value on the server side. It is the primary interface for dealing with the various settings which need to be changed (typically by being written to a file). The format of the data inside of the UTF-8 string is specific to each ID. Some of the fields are read-only. Read-only versus Read-Write is indicated in the ID table below. For read-only fields, the query packet field is ignored and all packets are treated as get packets. The setting IDs are as follows:
|
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 20 | Packet Type |
Notes: Causes the information daemon to respond with a Fonts Digest Packet. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 21 | Packet Type |
16 | MD5 Hash | UID for the current font data. | |
Notes: Note: the MD5 hash should be treated simply as a UID, and not used to check font integrity. There are no guarantees made as to exactly what is hashed or in what order, only that when any of the font data changes, this UID will as well. UIDs are not guaranteed to be consistent between machines. The only guarantee made is that if the font data on this unit changes, so will the UID (with high probability; there do exist different data sets with the same MD5 hash, after all). |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 22 | Packet Type |
Notes: This is a version 2 packet. Causes the information daemon to send a Fonts Description Packet. |
Byte Count | Data Type | Value | Description | ||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | unsigned byte | 23 | Packet Type | ||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | unsigned short | count | The number of fonts in the system | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Followed by count blocks of the form: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||
Notes: This is a version 2 packet. The MD5 checksum was added in version 3 of this protocol. The checksum should not be used for data integrity, but merely considered a UID to detect changes. The Flags field was added in version 14 of this protocol. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 24 | Packet Type |
2-65537 | Java String | The name of the font to get. | |
Notes: |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 25 | Packet Type |
2-65537 | Java String | The name of the font | |
4 | unsigned integer | size | The size (in bytes) of the embeded font |
[size] | Font | The font is embded in this packet. | |
Notes: The size indicated in the second field of this packet should be the size of the font on-disk. Ideally, it will be taken from the on-disk representation of the font. When sent from the information daemon to the client, this packet indicates what font is being used. When sent from the client to the Information Daemon, it defines a new font in the system. (In order to give that font an NTCIP number, consult the command packet.) |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 26 | Packet Type |
Notes: This is a version 2 packet When the information daemon gets this packet, it causes the watchdog timer to reboot the controller. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 27 | Packet Type |
1 | unsigned byte | 1 indicates the desire to receive notification, 0 the desire to not | |
Notes: This is a version 2 packet When the information daemon gets this packet, it sends notifications of changes to variables where were made through configuration packets sent to the information daemon. In general, it is not possible for the Information Daemon to know when the value of a configuration variable changes, since many of them are computed by asking a sub-system for the current state of a value (e.g. software version, last raw battery reading, whether the radar gun was configurable, etc.). It is possible, however, for the Information Daemon to pass on information when it gets a configuration packet, and that's what this packet registers interest in. Therefore, before using this packet, make sure that the configuration variable that you're interested in will only change through configuration packets send to the Information Daemon. A good rule of thumb is that variables marked RW will be passed on when modified, and variables marked RO must be queried every time a fresh value is desired. |
Byte Count | Data Type | Value | Description | ||||||||||||||||||||||||||
1 | unsigned byte | 28 | Packet Type | ||||||||||||||||||||||||||
1 | unsigned byte | action:
|
|||||||||||||||||||||||||||
2-65535 | Java String | the full path to the file name | |||||||||||||||||||||||||||
4 | unsigned integer | len | the number of bytes in the data payload | ||||||||||||||||||||||||||
len | bytes | the data payload. the meaning of this is dependent on the value of the action | |||||||||||||||||||||||||||
Notes: This is a version 2 packet the file must specify an absolute path, and contain no relative directories (/./ or /../). Attempts to retrieve a file which doesn't exist will have the same result as retrieving an empty file; that is, the InformationDaemon will respond with a file management put for the file with a data length of 0. Creating a directory responds with a directory creation packet on success, or an error packet on failure. NOTE: the info daemon only supports directory creation as of TRAFIX-1.9.17.1-inhouse12. Error values will have the file name set; the type of error is not encoded, unfortunately. Appending to a file appends to the end of the specified file. It is primarily meant for uploading a large file in chunks over an unreliable connection. Appending is not supported before TRAFIX-2.6.0-inhouse5. |
Byte Count | Data Type | Value | Description | ||||||||||
1 | unsigned byte | 29 | Packet Type | ||||||||||
2-65,537 | String | Command ID. Valid commands are:
|
|||||||||||
4 | unsigned int | Request ID | |||||||||||
2-65,537 | String | Parameter/Return Value. See notes. | |||||||||||
Notes: This is a version 3 packet Unlike configuration variables, these packets explicity cause the controller to take some sort of action. When a Command Packet is sent to the Information Daemon, the Information Daemon takes it as a command, and the second string in the packet is an a parameter to the command ("" for no parameter). The Information Daemon will respond to a command with this packet. When this packet is sent from the Information Daemon, the first string will be the same, and the second string is a return value ("" if there is no return value). The request ID field is set by the client and used by the Information Daemon in its response. It is up to the client to generate the request ID, if the client wants to use this field. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 30 | Packet Type |
Notes: This is a version 3 packet. Like the Fonts Description Request Packet, except it requests all of the fonts on the system which have NTCIP numbers. Causes the information daemon to send a Fonts Description Packet. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 31 | Packet Type |
1 | unsigned byte | count | |
count | unsigned bytes | the configuration IDs as specified in the Compact Configuration IDs table | |
Notes: |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 32 | Packet Type |
1 | unsigned byte | count | |
count | unsigned bytes | the configuration IDs as specified in the Compact Configuration IDs table | |
variable | the data payload for the IDs, in the order specified in the ID block | ||
Notes: |
ID | Configuration Variable | Byte Count | Encoding | ||||
0 | Battery Voltage | 2 | unsigned short (centi-volts) | ||||
1 | Raw Photocell Reading | 2 | short (raw value) | ||||
2 | Uptime | 4 | unsigned int (# of seconds) | ||||
3 | Current Runtime | 4 | unsigned int (# of hours) | ||||
4 | Lifetime Runtime | 4 | unsigned int (# of hours) | ||||
5 | Projected Runtime | 4 | signed int (# of minutes) | ||||
6 | Temperature | 1 | signed byte (degrees Fahrenheit - 60, i.e. add 60 to recover original value) | ||||
7 | Radar Gun Is Configurable | 1 | unsigned byte (0=no,1=yes) | ||||
8 | "Radar Gun Units" | 1 | unsigned byte (0=mph,1=kph) | ||||
9 | NTCIP Interface Control | 1 | unsigned byte (0=disabled,1=on,2=off) | ||||
10 | NTCIP Interface Status | 1 | unsigned byte (0=inactive,1=active) | ||||
11 | Module Row Count | 1 | unsigned byte | ||||
12 | Modules Per Row | 1 | unsigned byte | ||||
13 | Module Type | 1 | unsigned byte (same meaning as in DisplayController) | ||||
14 | Location | 10 | 2 signed ints, latitude then longitude, in microdegrees, 0xffffffff = no fix. Then 1 IEEE half-precision float giving the uncertainty in kilometers. There is no timestamp because this is only for transmitting the currently known position. | ||||
15 | Compass Reading | 2 | short (deci-degrees, 0xffff for no heading) | ||||
16 | Power Saving Mode | 1 | unsigned byte (0="off", 1="true" (i.e. auto), 2="on" (i.e. force), 3="very on", 4="max") | ||||
17 | Adaptive Blanking Level | 1 | signed byte | ||||
18 | Current Photocell Limits | 4 | 2 unsigned shorts (lower limit, then upper limit) | ||||
19 | Flashing Beacons | 1 | unsigned byte (0=off, 1=on) | ||||
20 | Power Source | 1 | unsigned byte (0xff=battery,0xfe=solar, other=acLine in volts, i.e. 121 = AC Line at 121V, 223 = AC Line at 223V) | ||||
21 | Librarian Revision | 4 | unsigned integer | ||||
22 | SolarNet Unit ID | 6 | The digits encoded as numbers (and therefore into the bottom nibble of each byte) | ||||
23 | MB_TYPE | 1 | The Message board type, encoded as follows:
|
||||
24 | |||||||
25 | |||||||
26 | |||||||
27 | |||||||
28 | |||||||
29 | |||||||
30 | |||||||
31 | |||||||
32 | |||||||
253 | [0,1,2,3,4,5,6,7,10,14,15,17,18,19,20] | 42 | the indicated ID values, in order | ||||
254 | [0-20] | 48 | the indicated ID values, in order |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 33 | Packet Type |
4 | unsigned int | count | the amount of data to follow |
count | bytes | The log data | |
Notes: The log data is gzip'd UTF-8 data (no gzip headers). |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 34 | Packet Type |
1 | unsigned byte | Data Stream indicator, bitfield, 0x01 == battery volts, 0x02 == battery watts, 0x04 == solar volts, 0x08 == solar watts | |
2 | unsigned short | limit | a limit on the number of entries in each data stream to return |
1 | unsigned byte | coalesce | The number of entries to coalesce into one (1 for no coalesce, which means each entry represents 15 minutes, 4 means each entry represents 1 hour) |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 35 | Packet Type |
1 | unsigned byte | Data Stream indicator, bitfield, 0x01 == battery volts, 0x02 == battery watts, 0x04 == solar volts, 0x08 == solar watts | |
1 | unsigned byte | coalesce | The number of entries coalesced into one (1 for no coalesce, which means each entry represents 15 minutes, 4 means each entry represents 1 hour, etc.) |
2 | unsigned short | count | The number of entries in each data stream |
2*count*[# of data streams] | unsigned short | the data streams | |
Notes: The data is encoded linearly, first battery volts, then battery watts, then solar volts, then solar watts. If any of those are not in the indicator bitfield, they are omitted from the data stream. count is the number of entries of any individual data type, not the total count (except in the degenerate case where there is only one data type in the packet). Units: volts are reported in millivolts, watts in centiwatts. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 36 | Packet Type |
Notes: |
Byte Count | Data Type | Value | Description | ||||
1 | unsigned byte | 37 | Packet Type | ||||
2 | unsigned short | battery volts (millivolts) | |||||
2 | unsigned short | current usage (milliamps) | |||||
2 | unsigned short | solar volts (millivots) | |||||
2 | unsigned short | solar amps (milliamps) | |||||
2 | unsigned short | battery charging current (milliamps) (protocol version >= 17) | |||||
1 | unsigned shortbitfield | Flags. (protocol version >= 17)
|
|||||
Notes: The battery charging current and flag fields are only present in the packet as of protocol version >= 17. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 41 | Packet Type |
1 |
| Query. 1 == query, 0 == response |
|
Notes: Used to find out if the other side is still able to respond (mostly as a verification that the connection hasn't been dropped). Either side should immediately respond to a query with a response. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 39 | Packet Type |
1 | unsigned byte | 0 | Request type, 0 == default. |
8 | signed long | Request date. The time in epoch milliseconds that the records should cover (from then to the present) | |
Notes: The client sends a Sensor Log Packet back in response. This is a protocol version 11 packet. |
Byte Count | Data Type | Value | Description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | unsigned byte | 40 | Packet Type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | unsigned byte | 0 | Answer type. Corresponds to the request type in the request packet. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4 | signed int | size | compressed data count | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size | compressed data | z-lib (Java's "deflate" compression format) compressed data of the following form:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Notes: This is a protocol version 11 packet |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 41 | Packet Type |
4 | unsigned int | The correct time in epoch seconds - 1,400,000,000 (since we don't need to represent time in the past) | |
Notes: This is used to allow the unit to correct its clock gradually, like how adjtime() does it. We don't measure transmission deltas because they're generally smaller than the resolution we really care about, and we don't have the bandwidth to do this correctly. This is a protocol version 11 packet. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 42 | Packet Type |
4 | unsigned int | The date to send historical readings from (epoch seconds - 1,400,000,000) | |
Notes: This is a protocol version 11 packet. |
Byte Count | Data Type | Value | Description | ||||||
1 | unsigned byte | 43 | Packet Type | ||||||
1 | unsigned byte | count | |||||||
count*6 | Reading | count readings. Readings are of the form:
|
|||||||
Notes: This is a protocol version 11 packet. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 44 | Packet Type |
1 | Type selector. high bit indicates query. If Type Selector & 0x80 == 0x80, then this is a query, otherwise it's a response. Lower bits are reserved for future data selection. | ||
4 | int | byte_countthe number of bytes in the data payload. This field only exists if this is not a query packet | |
byte_count | gzip data | the binary data, gzip compressed, This field only exists if this is not a query packet | |
Notes: |