In revision 13, the temporary message was added.
Revisions previous to 9 of this documentation incorrectly indicated that Terminated Event Schedule Packets and Unterminated Event Schedule Packets used 8-byte integers, and not 4-byte integers.
Each Display Driver will have its own Scheduler. Everything which wishes to schedule a sequence will do so with the scheduler. This means that nothing will talk directly to the Display Driver, only to the Scheduler.
(The scheduler's relation to the Display Driver is an implementation detail — it can be integrated into the Display Driver for performance or be a separate program which connects to it as a client for simplicity. Neither choice will affect anything in this specification.)
There are several different types of schedules that one might want to set:
This requires a mildly complex scheduling protocol, but it should cover every concievable method of scheduling a sequence that a human being is likely to want. It will give the full power of schedulers like the one in Microsoft® Outlook®, which is generally held to be sufficient for human endeavors. In some cases it will actually give more power than that.
There will be an override sequence which, if set, overrides anything else in this scheduler and displays continuously until the override sequence is changed or cleared.
Each schedule will have an assigned priority. At any given time, the highest priority message which is scheduled for that time will display. Priorities are indicated by a priority number which ranges from 1-100 with 1 being the highest priority.
Time-based (synchronous) schedules will have a default priority of 70. Data event triggered (asynchronous) schedules will have a default priority of 40.
There will be a temporary message which, if set, displays in preference to the default message but otherwise comes below all other scheduled messages. The temporary message comes with a timeout, after which the message board will revert to the default message. The temporary message is intended purely for use in ITS systems which frequently update what message is supposed to be displaying.
There will also be a default sequence which will be set at all times in case there is no scheduled sequence which should be playing.
There are fundamentally two different types of time-based schedules. The first is a Singleton schedule, which occurs only between two distinct points in the history of the world. (For example, from July 3, 2004 at 5:04pm through November 9th, 2005 at 4:15am.) The other is a Recurrant Schedule, which occurs repetatively according to some pattern. (For example, fridays in October and November from 9pm-9am.)
Recurrant schedules have a great deal of flexibility; as a result they also have a number of constraints to simplify implementation. However, these constraints are generally just limitations to sensible uses of recurrant schedules.
A recurrant schedule can indicate repetition along any of months, days of the month, days of weeks, weekdays of the month (2nd tuesday, etc.), hours, and minutes. The restrictions are that no parallel cycles may be simultaneously scheduled within the same recurrant schedule. E.g. Day of the month and weekday may not both be specified in a single recurrant schedule. Similarly, day of the month and weekday of the month is forbidden, day of week and weekday of month, etc.
Temporary messages are inteded only for use in ITS systems, and so their features are geared for that use. Temporary message schedules are not written to disk, so if the power is lost the unit will come up displaying the default message if it would otherwise have displayed the temporary message. Temporary messages come with a timeout, after which the unit reverts to its default schedule (unless overriden by a higher priority schedule, of course). The purpose of the timeout is to allow for an "out of communication" message, so that a unit will not display messages reflecting old conditions during communication loss. Temporary messages also require the specification of a library to avoid all possible confusion, since this is no more onerous for a machine than not doing it is.
Temporary messages may not be embeded in any other message. If someone wants a message to only display for (e.g.) 15 minutes at some future date, they can use a terminated schedule to achieve that effect.
Certain types of schedules may be embedded within other types. A recurrant schedule may be embedded within a singleton schedule, so that the recurrance only happens between the singleton's start and stop dates. Also, asynchronous events may be embedded either in a singleton or recurrant schedule, so that they'll only trigger a sequence during the scheduled dates and times.
Schedules with different priorities will be permitted to conflict. Schedules with the same priority, however, will not be permitted to conflict, and it is the responsibility of the Scheduler to verify that they do not. For time-based schedules, this means that no two time-based schedules may overlap. (Note: if a recurrant schedule displays on MWF, a one-time schedule for a thursday would be fine, but Thu-Sat would not be (because of the conflict on friday). Similarly, two recurrant schedules, one for MWF the other for TThu would not conflict.)
The asynchronous layer is more complex. Asynchronous schedules for different event IDs must have different priorities. Schedules for the same event ID may be at the same priority, provided that they are for different event values. Of course, event-based schedules may conflict if they are embedded in time-based schedules which do not conflict.
The default sequence may be set either immediately, on some future date, or by an event. This allows one to switch defaults messages after Christmas, or when the temperature goes below some predetermined value, etc. Once the default sequence is set, it remains the default sequence until it is replaced.
The override sequence can be set at any time, and takes priority over all other messages in the scheduler. (Indeed, the scheduler is free to shut down its normal scheduling loop while there's an override sequence.) The override sequence is cleared by setting an override sequence with the title "" (that is, a zero-length title).
Sequences will be scheduled by title. This means that when the Scheduler is going to send a sequence to its Display Driver, it fetches the appropriate sequence from the Librarian. This is designed to allow one to make modifications to a sequence without having to reschedule it.
(Note: Since it is a requirement of the controller's Librarian that only one sequence with a given title can be stored at a time, there cannot be any conflicts about which sequence to display.)
(Note: the generation and notification of events is covered in the Data Sources specification.)
(Note: The above means that in order to schedule a sequence, it must first be inserted into the controller's sequence library.)
(Note: Because more than one Display Driver (and hence Scheduler) might be present on a controller, it is the responsibility of a program which wants to remove a sequence from the controller's library to ensure that it is not in use by the scheduler. As a result, if the Scheduler tries to send a sequence to the Display Controller which does not exist in the library, it should just discontinue the attempt (possibly notifying the user) but otherwise continue as normal and should not remove the sequence from its schedule (if it is a recurrant schedule).)
In order to support low-bandwidth applications, it is necessary for notifications of the changes to the currently displaying message to be able to exclude changes which happen too frequently on a consistent basis. Right now, that means radar, but in general any sort of message change on frequent events could be problematic, and so we introduce the category of frequently changing messages. Prior to now, the way to find out what a sign was displaying was to ask the Display Driver, however it does not have the information necessary to distinguish between changes to due frequent events and other changes, so it is now necessary to use the scheduler for this purpose.
In order to accomplish this, there are two packets added. The first is the Displaying Notification Request Packet, which subscribes the listener to notifications and can include a flag to indicate that we are not interested in frequently changing events.
Temporary messages do not count as frequently changing events, even though they probably will be in practice, because an ITS system will need to know about them and further an ITS system is not a low-bandwidth application.
The Scheduler Protocol is a variable-length packet based protocol which is initiated by a versioning handshake.
As a design decision, instead of assigning a scheduled sequence some sort of unique identifier, a scheduled sequence is always referred to by an appropriate schedule packet. While this does increase the bandwidth used, it should not do so significantly (scheduling should not be a high-volume activity, and the difference between the full packet and a unique ID is likely only about 30 or 40 bytes anyway). By doing this, we gain the assurance that there cannot be a mistake about what schedule is being referred to; by using full information, it is not possible for there to be a synchronization error if two people are concurrently trying to modify the schedule, nor can there be any problems with incomplete transactions which are thought to be complete, etc.
Each Scheduler will find an available port to listen on and publish this information with the Information Daemon in the category "scheduler". For convenience, however, the first scheduler is on port 40701, and subsequence schedulers are on consecutive ports.
Note: Unless otherwise specified, all multi-byte integeral types are in network order (i.e. they're big-endian).
Added the override schedule.
Added the Default Seqeuence Query Packet so that a remote application can query the current default sequence.
The protocol handshake works according to the Solartech Protocol Handshake & Authentication specification. The current protocol version is 3.
Once the handshake has been completed, the protocol is then an asynchronous protocol where either side may send any packet at any time, though most client packets will require an immediate response from the Scheduler.
In order to schedule a sequence, the client sends one of:
The Scheduler then confirms that the sequence was scheduled as requested by sending back an appropriate schedule packet. If the sequence is not valid (e.g. if it conflicts with another schedule), the Scheduler will reply with an Invalid Schedule Packet.
To cancel a scheduled event, the client sends a Cancellation Packet. The Scheduler then sends back an appropriate Cancellation packet as confirmation.
When a client wants a complete listing of all scheduled sequences, it sends a Schedule Information Request Packet. The Scheduler responds with a Scheduler Information Packet.
The following are the packets used in this protocol:
Note: the data type "String" denotes a Java string; i.e. an unsigned short followed by that many bytes of UTF-8 data.
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 0 | Packet Type |
8 | long integer | The date that the sequence should be loaded, specified in epoch seconds GMT. | |
8 | long integer | The date that the sequence should be removed, specified in epoch seconds GMT. | |
1 | unsigned byte | Priority | |
variable | schedule packet | Any schedule packet, including a cancellation packet, may be embedded here. | |
Notes: While theoretically any schedule packet could be embedded, it would be redundant to embed a time-based singleton packet (terminated or not), and is thus not permitted. If a Sequence Packet is embedded, this sets the sequence for the Time-based layer while this schedule is active. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 1 | Packet Type |
8 | long integer | The date that the sequence should be loaded, specified in epoch seconds GMT. | |
variable | schedule packet | Any schedule packet, including a cancellation packet, may be embedded here. | |
Notes: While theoretically any schedule packet could be embedded, it would be redundant to embed a time-based singleton packet (terminated or not), and is thus not permitted. If a Sequence Packet is embedded, the sequence becomes the default sequence. (It doesn't make any sense for an unterminated packet to have a priority, since the unterminated packet only embeds a schedule or a default sequence.) |
Byte Count | Data Type | Value | Description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | unsigned byte | 2 | Packet Type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | unsigned byte | A bitfield with flags for which of the date bitfields are significant:
Only those bitfields which are significant are included in this packet. Insignificant bitfields are considered to have every bit set and thus they only need to be included if there is some restriction desired. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | unsigned short | The month bitfield. The bitmasks are:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4 | unsigned integer | The day-of-month bitfield. The field corresponds to a mask of 1 << dayOfMonth, where dayOfMonth starts at 0. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4 | bitfield | The weekday-of-month bitfield. The mask is as follows:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | unsigned byte | The day-of-week bitfield. The bitmasks are:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4 | integer | The hour bitfield. If Hour is the hour of the day in 24 hour notation, then each hour's mask corresponds to (1 << Hour) (since 24 hour time runs from 00:00 to 23:59) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8 | long integer | The minute bitfield. The mask for each minute corresponds to 1 << Minute. Minute ranges from 0-59. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | unsigned byte | Priority | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
variable | schedule packet | Any schedule packet, including a cancellation packet, may be embedded here. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Notes: While theoretically any schedule packet could be embedded, it would be redundant to embed a time-based packet (recurrant or singleton, terminated or not), and is thus not permitted. If a Sequence Packet is embedded, while this schedule is active the embeded sequence becomes the displayed sequence for this priority level. |
Byte Count | Data Type | Value | Description | ||||||
1 | unsigned byte | 10 | Packet Type | ||||||
1 | byte | Cycle type:
|
|||||||
4 | integer | Recurrence data. The use of this field depends on the type of recurrence. In daily recurrence, it's not used. For weekly recurrence, it's a bitfield where the seven least significant bits are used to indicated Sunday through Saturday. For monthly, it's a number indicating which weekday of the month (0-6, 1st Sunday - 1st Saturday, 7-13, 2nd Sunday - 2nd Saturday, etc.). | |||||||
1 | byte | 0-23 | Start Hour | ||||||
1 | byte | 0-59 | Start Minute | ||||||
1 | byte | 0-23 | Stop Hour | ||||||
1 | byte | 0-59 | Stop Minute | ||||||
1 | unsigned byte | Priority | |||||||
variable | schedule packet | Any suitable schedule packet may be embedded here. | |||||||
Notes: While theoretically any schedule packet could be embedded, it would be redundant to embed a time-based packet (recurrant or singleton, terminated or not), and is thus not permitted. If a Sequence Packet is embedded, while this schedule is active the embedded sequence becomes the displayed sequence for this priority level. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 3 | Packet Type |
2-65,537 | String | The Source ID. | |
4 | integer | The minimum value of the source event for which this sequence should be displayed. (inclusive) | |
4 | integer | The maximum value of the source event for which this sequence should be displayed. (inclusive) | |
4 | integer | The duration of the event sequence, specified in milliseconds. After this time the currently scheduled sequence should be restored. (note: 4 bytes allows a maximum duration of 49 days 17 hours 2 minutes) | |
1 | unsigned byte | Priority | |
variable | Sequence Packet | The sequence to display. | |
Notes: It doesn't make sense to set a schedule based on an event only for a period of time. A schedule is either in the scheduler or not at all. Getting a schedule to be in the scheduler for a period of time can be better handled by properly creating the embeded schedule and setting it with an unterminated event. Thus only sequences may be set from terminated events. The embeded sequence becomes the current sequence for the asynchronous layer while this event is active. If another terminated event is triggered while this event is running, this event is prematurely terminated and the new event becomes the current event. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 4 | Packet Type |
2-65,537 | String | The Source ID. | |
4 | integer | The minimum value of the source event for which this sequence should be displayed. (inclusive) | |
4 | integer | The maximum value of the source event for which this sequence should be displayed. (inclusive) | |
variable | schedule packet | Any schedule packet, including a cancellation packet, may be embedded here. | |
Notes: When an unterminated event is triggered, the embedded packet is treated as if it was just sent by a client. Thus all embedded packets behave as if they were sent on their own. (In particular, an embedded sequence would set the default sequence.) (It doesn't make any sense for an unterminated packet to have a priority, since the unterminated packet only embeds a schedule or a default sequence.) |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 5 | Packet Type |
variable | schedule packet | A packet corresponding to the schedule to cancel is embedded in this packet. All values must match exactly for that schedule to be canceled. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 6 | Packet Type |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 7 | Packet Type |
4 | unsigned integer | (count) The number of schedules in this scheduler. | |
variable | Schedule Packet[count] | The schedule packets representing all of the schedules in this scheduler |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 8 | Packet Type |
2-65,537 | String | The sequence's title. | |
Notes: When sent alone, this packet sets the default sequence. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 9 | Packet Type |
2-65537 | String | The error string. This string explains why the requested schedule is invalid. | |
variable | schedule packet | Any schedule packet, including a cancellation packet, may be embedded here. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 11 | Packet Type |
1 | Unsigned Byte | On/off (1==on, 0==off). |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 12 | Packet Type |
2-65,537 | Java UTF-8 String | The sequence's title. | |
Notes: This is a version 2 packet When sent alone, this packet sets the override sequence. Please note that an empty (zero-length) string as the sequence title clears the override sequence. If the override sequence packet specifies the same sequence as is currently the override sequence, the scheduler must reload the sequence (i.e. fetch it from the library again). |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 13 | Packet Type |
Notes: This is a version 2 packet The scheduler will send an Override Sequence Packet in response. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 14 | Packet Type |
Notes: This is a version 3 packet The scheduler will send an Sequence Packet in response. |
Byte Count | Data Type | Value | Description | ||||
1 | unsigned byte | 15 | Packet Type | ||||
1 | bitfield | Flags:
|
|||||
Notes: This is a version 11 packet. Turns on displaying notifications. If the Notify of Current Message flag is set, a Displaying Notification Packet is immediately sent out. Right now, the only Frequent Event is radar, but in the future this might be dynamically calculated so that frequently used switch closures are automatically rate-limited. |
Byte Count | Data Type | Value | Description | ||||||||||||
1 | unsigned byte | 16 | Packet Type | ||||||||||||
1 | bitfield |
|
|||||||||||||
1 | unsigned byte | Intern Message Number | |||||||||||||
variable | String | (optional) the title of the message being displayed | |||||||||||||
Notes: This is a version 11 packet. The Caused by Frequent Event flag is 1 if a frequent event such as Radar is the reason for this message change (either to or from the frequent event message) The Intern Included Message flag indicates whether a message included. If 1, the message is included and should be associated with the intern number; if 0 the last message defined for that intern number is the currently playing message. |
Byte Count | Data Type | Value | Description |
1 | unsigned byte | 17 | Packet Type |
1 | unsigned byte | Flags | |
2-65537 | jstring | Temporary message title | |
2-65537 | jstring | Library | |
2 | unsigned short | Temporary Message Duration (in seconds) | |
Notes: This is a version 18 packet. |