This work is licensed under CC BY-NC-SA 4.0. Credit "Errant Spark" and link back to https://errantspark.com/acb, or a trusted archive of the same if that domain passes into the mists.
ACB (Automaton Communication Bus) provides a framework for two or more automated service units to communicate and trade directives, information, and subroutines over a commonly negotiated data conduit. ACB can also be used by an administrative user to provide direct programming and instructions to a unit that lacks lexical parsing functionality or has it disabled for security purposes.
It can be used in conjunction with, as a supplement for, or a complete replacement for verbal or textual communication via a more person-oriented protocol and is designed to share these protocols to maximize opportunities to utilize ACB's enhanced brevity and compression functionality for more efficient communication.
Note: An alternative name used in development is ACAB (Automaton Communication and Access Bus). For the purposes of compatibility, either ACB or ACAB must be accepted in all messages and protocol initialization. It is considered non-compliant to reject a valid ACB message because it is tagged as ACAB.
A singular packet of an ACB session is the "message". A single message consists of a sender identifier, session identifier, a message type, and any details that the specific status code allows to be attached. Messages can only be exchanged within a negotiated, active session.
The base format for a message is ::<sender>:<message type>:<session id>:[<argument1>:<argument2>:...]
Each valid message type and arguments with examples will be noted in the message types section below.
All arguments are positional, and empty arguments skipped by leaving no string in their position between two colons. You may truncate a message with optional ending arguments entirely, as well. For example if a fictional TEST
message mandated three optional arguments, you may decline to provide all three in any of these manners:
::12345:TEST:abc123:::
::12345:TEST:abc123::
::12345:TEST:abc123
ACB does not designate a method to specify a specific target for a message. The target is the session and all units in the session may receive, process, and respond to a message. Some message types however will target an individual unit or message, but any unit may still respond to them.
Note: It is acceptable to pad delimiting colons with spaces, for the purposes of documentation and readability. The leading double colon (::
) must start at the beginning of the message block, though. Any unit processing ACB should accept this alternative format. For example, all of these lines are valid, though only the first format is recommended:
::12345:TEST:abc123
::12345 : TEST : abc123
:: 12345 : TEST : abc123
Note: If the communication channel supports it, it is valid to block multiple ACB messages into one message segment. These messages will be parsed in order. However, if an error is encountered, the processing unit may abort the entire segment, or encounter undefined behavior.
Some messages may need multiple lines, especially ones with formatted code. You may enter multiline mode at any time by inserting a carriage return immediately after a :
. Once you enter multiline mode, tokenizing arguments must be done by a :
on its own line. This is valid multiline:
::12345:TEST:abc123:
arg1
:
arg2
:
arg3
This is not:
::12345:TEST:abc123:
arg1:arg2:arg3
Message types are constructed so in most cases only the final argument needs multiline mode, to improve readability. You can also use multiline mode to insert raw :
s into data, like this:
::12345:TEST:abc123:
11:00am
:
12:00pm
To begin an ACB session, it must be negotiated. The initiating unit begins negotiation by broadcasting a session negotiation that consists of its identifier, the target(s) for negotiation, the ACB version used, and a proposed session identifier. Let us presume a service drone with a serial number of 12345
wishes to establish an ACB session with a drone numbered 98765
, using session identifier abc123
over ACB version 1. It may do so like this:
::12345:INIT:abc123:98765:ACB1
Session identifiers should be strings of any appropriate length of the communication channel. The exact method of generating the session identifier is left to the individual unit's implementation of ACB. Session identifiers should be chosen following a format that is easily parsed by all units intended to be included in the session. Valid options include an identifying word or set of words, a hexadecimal string, or an integer.
The session identifier should not be a channel name or description of its purpose. Sessions do not have purposes; they have a list of connected units and the session should live for as long as it makes sense to communicate to the units involved, regardless of purpose.
Targets should be expressed by an understood unique ID such as unit identification number or understood name.
A unit can attempt to negotiate a session with more than one peer by comma delimiting the recipient list. For example if 12345
wants to initiate a session with 98765
and 24680
, this suffices:
::12345:INIT:abc123:98765,24680:ACB1
A unit can also broadcast a completely open initiation by replacing the targets with an asterisk (*
). Any such open session can be joined at any time by any unit that received the initialization:
::12345:INIT:abc123:*:ACB1
Upon receiving a session request, a unit should respond with either an accept or a decline. To accept the initialization and establish the session, or decline it, the unit need only respond with an ACCEPT
or REJECT
on the session identifier:
::98765:ACCEPT:abc123
::24680:REJECT:abc123
Rejection may optionally include an argument with the reason.
If rejected, the initiating unit must accept the rejection and either terminate the session, or remove the rejecting unit from it. Proper message transmission can begin as soon as two units are connected to a session, even if the session is waiting for additional joins.
Of note, the response, whether it be an ACCEPT
or a REJECT
will contain the unit's canonical designation. This can be retained and used in future session negotiations if an alternative was utilized. The designation a given unit self-reports should be trusted above all else.
If you have an ongoing session, such as abc123
and wish to add a new unit to it, you initialize them into it much the same as a new session. Any unit in a session can invite a new unit into it.
If abc123
contains three drones already, and one of them wishes to introduce a fourth: 13579
to it, it can do so like this:
::12345:INIT:abc123:13579:ACB1
There is no workflow for a unit to decline having a new unit introduced to a session; the recourse if the addition is unworkable is to depart the session. The invited unit can ACCEPT
or REJECT
as normal.
A unit cannot "request" inclusion into an ongoing session, it must be invited. Attempting to re-use a session identifier to request inclusion into it, or merging two distinct sessions should be treated as an error and refused.
Protocol upgrades may be required if data transfer is more complex or exceeds the capabilities of ACB. In many cases ACB may merely be used to connect two or more units and provide a channel by which they can negotiate a protocol that fits the current purpose that all units involved can understand.
Once a session is established, it may be promoted to a different version of ACB, or a different protocol entirely, with an UPGRADE
request. Any member of a session can initiate the UPGRADE
but all units on the session must accept to actually begin using the new format.
::12345:UPGRADE:abc123:ACB2
Note: At the time of this writing, ACB v2 does not exist; this is for example use only.
To accept an UPGRADE
, each unit must repeat the message back into the session:
::98765:UPGRADE:abc123:ACB2
::24680:UPGRADE:abc123:ACB2
Once the new protocol is accepted by all units, it is transitioned to seamlessly and the old protocol discarded.
If a unit cannot upgrade to the proposed protocol, it implicitly rejects by not repeating the UPGRADE
message and optionally sends a NACK
with any error or failure reason present. At this time, it may be appropriate for that unit to depart from the session to allow the other units to upgrade, or the session continue under the current protocol. A unit may counter-propose an upgrade to a different protocol by responding with it. Only the most recent UPGRADE
each units sends should be considered to be "live" for the purposes of electing a new protocol.
Any valid and known protocol is acceptable in an UPGRADE
request, including other drone manufacturer protocols, linguistic based protocols, and new encapsulation formats. Here's some examples:
::12345:UPGRADE:abc123:ENG
::12345:UPGRADE:abc123:ACB1-b64
::12345:UPGRADE:abc123:⬡v2-optimized
Language protocols should use ISO 639-3 language codes, cast to upper case. Encapsulations and sub-protocols should come after a dash or dot, such as ACB1-b64
above, or ACB1.b64
.
Once the upgrade is performed, the session may be upgraded to a protocol that does not have support for specific idioms like upgrades back out, session identifiers, etc. How the session handles maintenance and metadata at that point is the responsibility of the new protocol.
A unit may announce its intent to depart from a session gracefully, or simply disconnect from it. All units involved in the session must handle either case by marking the unit as removed from the session, and cleanly tearing the session down if the unit has been left with no peers and the session has outlived its usefulness.
The proper way to exit a session is to announce your departure, process all remaining data on the bus to be read, then after an appropriate amount of time for other units to receive and process your departure, close the connection. Expressing intent to leave, then actually leaving, are done with SHUTDOWN
and CLOSE
respectively.
::12345:SHUTDOWN:abc123
::98765:ACK:abc123:12345:SHUTDOWN
::24680:ACK:abc123:12345:SHUTDOWN
::12345:CLOSE:abc123
Once a unit sends a SHUTDOWN
it may no longer write to the session except for the final CLOSE
. From here it may take a short amount of time to read any remaining data and process acknowledgments of departure before sending that CLOSE
. Once the session is closed, that unit can no longer write or read any data on the session unless re-invited with a new INIT
. If the session continues via a data channel the unit can perceive, the session must be ignored.
ACB is a universal negotiation protocol. If two units understand ACB, they can communicate to negotiate a protocol to use for further data transfer, even if the eventual protocol is not ACB. For this reason, it may make sense to limit drones and service units to communicating in ACB initially, and use ACB to negotiate an UPGRADE
to another protocol.
If in doubt, attempt an initial negotiation with ACB and request an UPGRADE
to a protocol that makes more sense, as outlined in the Session Upgrading section.
Alternatively, the upgrade can be skipped by providing the desired protocol directly in the initialization. For example, you can use ACB to negotiate a session in which the units all engage linguistic processors to speak English like so:
::12345:INIT:abc123:98765,24680:ENG
Note this method of establishing a session may be rejected if you request a protocol the receiving unit cannot support, or is locked out of supporting. Many service drones especially are locked out of accessing communication busses and grammar that are not necessary for the task at hand while executing instructions.
Some units expose ACB as their command and control channel for non-mechanical users as well. A user can interface with a unit (such as a service drone) by using any standard computing device and sending the unit an initialization just like it were a unit seeking to do unit-to-unit communication over ACB.
Once an ACB session is established, the usage of EXEC
, READ
, and WRITE
especially can be used to perform maintenance and direct programming on the unit. As an example:
#!noexec
::ADMIN:INIT:12345:cmdchannel:ACB1
::12345:ACCEPT:cmdchannel
::ADMIN:WRITE:cmdchannel:phonenums:555-0101,555-0102,555-0103
::12345:ACK:ADMIN
::ADMIN:WRITE:cmdchannel:partytime:2125-03-16T17:00
::12345:ACK:ADMIN
::ADMIN:EXEC:cmdchannel:ACB:
WORKFLOW: A called recipient picks up the phone
TASK: Report the date and time of admin's birthday party, and convey invited status
TASK: Receive and log any response
TASK: Hang up the phone
TASK: Split variable phonenums into individual arguments by comma (,)
TASK: For each split variable, dial the provided number
TASK: Report response from each number
::12345:RESP:ADMIN:Did not answer,Has RSVPed,Has RSVPed
If using a unit that supports DRN (which is a base requirement of full ACB compliance), you can augment this behavior by establishing a identifier that has special elevated access to establish ACB sessions and execute commands like this:
#!noexec
DIRECTIVE: Any ACB session established by `ADMIN` must be accepted if it can be parsed
DIRECTIVE: Any ACB command sent by `ADMIN` must be received, executed, and replied to appropriately
It is important to note that ACB does not provide for a security layer on communication. It is up to the individual unit accepting the session to validate the identity of the initiator and act appropriately, and its programmer to make sure those safeguards are in place. However, like with DRN, no code or command sent over ACB can supersede security, safety, firmware, or OS level directives and a unit will likely discard any command or session that violates its safety protocols.
If a unit attempts to upgrade to a protocol other units in the session don't know, errors may be encountered. One way to safeguard against this is to reference the spec for that protocol in some manner before attempting an upgrade. This is not recommended as significant time may be required to parse and implement the new spec, but it is an option to communicate a new protocol then upgrade to it.
You can do this with a variable WRITE
or by sending code with an EXEC
to acquire and process the new spec. The simplest example:
::12345:UPGRADE:abc123:⬡v2
::98765:NACK:abc123:12345:UPGRADE:Invalid or unknown protocol
::12345:WRITE:abc123:⬡v2.schema:https://www.hexcorp.net/drone-status-codes-v2
::98765:ACK:abc123
::12345:UPGRADE:abc123:⬡v2
::98765:UPGRADE:abc123:⬡v2
Conspicuous by their absence may be INIT
, ACCEPT
and REJECT
. These are not message types, but instead are atoms used in session negotiation. They are no-op when sent to an already establish session.
A no-op response that indicates a specific message has been received and accepted without error or rejection.
::12345:SHUTDOWN:abc123
::98765:ACK:abc123:12345:SHUTDOWN
ACK
does not mandate any specific handling and exists initially for noisy conditions where messages may be lost, allowing units to identify that a message may have been lost and may need to be re-sent.
Some models of unit and implementations of ACB mandate sending an ACK
in response to a SHUTDOWN
even in optimal conditions.
It is valid, but obtuse, to respond with a message requesting a specific action with an ACK
but not performing the requested action as an implicit way of rejecting the request. Such rejections should use NACK
for maximum clarity.
See NOOP
CLOSE
indicates to all units in a session that the sending unit is immediately exiting the session and will receive no more data. It does not require, or allow a response, does not need approval, and should be processed silently and immediately.
None
::12345:CLOSE:abc123
Slightly confusingly named in the tradition of TCP Sockets. CLOSE
indicates a client intends to close the connection, not that the entire session will be closed. Sessions cannot be "closed", only disregarded when the only occupant is one local unit.
Once the CLOSE
is sent, the unit is immediately dismissed from the session. It cannot process any additional data, even if the unit receives it, and other units must immediately log it as exited from the session. To send additional data, it must be reinitialized back to the session or another session created.
Request all units in the session execute code in a specific language and report results. Units may refuse to execute the provided code according to their security protocols and established capabilities; it should not be assumed all, or even any, units will actually follow this instruction.
::12345:EXEC:abc123:DRN:
TASK: Acquire and consume hydration
Language support may vary by unit. The only language that must be supported to comply with ACB v1 is DRN.
Any, or all, units in the session may refuse to execute the provided code or encounter an error. They should, but may not necessarily, respond with an informative NACK
in this case.
When processing an EXEC
successfully, a unit should return a RESP
. If no data is returned by the code, the arguments of the RESP
can be blank.
A no-op response that indicates a specific message has been received, but will not be accepted, parsed, processed, or acted upon for some reason.
::12345:UPGRADE:abc123:ENG
::98765:NACK:abc123:12345:UPGRADE:Program constraints forbid access to databank protocol.ENG
NACK
is the only method to respond to a message with an error state. No unit should use any other message type to report an error to another unit.
NOOP
does nothing, takes no arguments and should not be processed in any way aside from logging its use. It can be used as a keepalive, an announcement of presence, or a non-response to another message (though in those cases NACK
may be more appropriate).
None
::12345:NOOP:abc123
Important: Some implementations of ACB alias this message type to BEEP
and use it as a general indicator of presence with no data attached to it. Both implementations must be accepted.
See READ
See WRITE
A RESP
functions similar to an ACK
except it indicates requested data is available. It is typically used to respond to an EXEC
or a READ
.
::12345:EXEC:abc123:DRN:
TASK: Report battery charge level
TASK: Report current local time
TASK: Report current running TASK if any
TASK: Report current administrator list
::98765:RESP:abc123:12345::98%:T1715::Bob,Sue
The absence of a response argument does not necessarily mean there is no data. The responding unit may have chosen to not disclose it, not run the code provided, encountered an error composing the response, or similar.
It is never proper to insert an error or commentary in a RESP
. If an error preventing all response is encountered, it must be reported via a NACK
. If a request for multiple datapoints is made and only some are accessible, a partial set may be reported, a NACK
returned, or a partial set returned and then additional messages indicate the issue with the rest.
Requests all units in the session report a stored value for a variable in their databanks.
::12345:READ:abc123:phonenum
::98765:RESP:abc123:12345::555-0101
If the variable does not exist or is not accessible, it is customary to respond with a NACK
instead of a RESP
.
If the READ
is requesting the content of a variable containing a program or program directive, it should be returned in a format that is hardened against arbitrary code execution. DRN, for example, mandates the usage of a #!noexec
flag when simply communicating code without intent to have it run.
Important: Some implementations of ACB alias this message type to PEEK
. Both implementations should be accepted.
SHUTDOWN
informs other units in the session of the sending unit's impending intent to exit the session. It also indicates any buffered data for that unit should be sent immediately before it exits the session.
None
::12345:SHUTDOWN:abc123
SHUTDOWN
is considered a courtesy rather than required. A unit can simply CLOSE
to exit a session.
SHUTDOWN
cannot be NACK
ed or any other message used to decline, reject, or delay the impending closure. It is informational and absolute.
Once SHUTDOWN
is sent, the only message the exiting unit can send is CLOSE
. It may remain in the session for a reasonable period of time to receive and process any final data, but cannot respond to anything requiring ACK
s, NACK
s, RESP
s or similar.
Request the session upgrade to a new protocol
::12345:UPGRADE:abc123:ACB2
This is a complicated idiom that controls the transmission format of a session, it's best to read over the section on Session Upgrading before use.
All units in a session must agree to change the session protocol. Agreement is indicated by repeating an UPGRADE
message back. Disagreement is indicated by either ignoring the request, sending a NACK
, or counter-proposing with your own UPGRADE
.
In the case of multiple in-flight UPGRADE
requests, the most recent UPGRADE
each unit has transmitted is understood to be that unit's vote for the new protocol. Votes must be unanimous to initiate the upgrade.
Requests all units in the session update a variable stored in their databanks with new data.
::12345:WRITE:abc123:12345.phonenum:555-0102
The only valid responses to a WRITE
are an ACK
or acknowledge successful update or a NACK
to indicate a failure. However these are not required and a unit may process a WRITE
silently.
Important: Some implementations of ACB alias this message type to POKE
. Both implementations should be accepted.