Flesh out protocol descriptions more
This commit is contained in:
parent
b686080af0
commit
8e304902a8
|
@ -1 +1,60 @@
|
||||||
# Audio control
|
# Audio control
|
||||||
|
|
||||||
|
- [`[synit]/protocols/schemas/audio.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/audio.prs)
|
||||||
|
|
||||||
|
The audio control protocol configures sound sources and sinks, for instance for call audio
|
||||||
|
control on a mobile phone. This protocol is still *experimental*, as configuration of audio
|
||||||
|
stacks is complex and I have only a few simple examples to work from thus far. As Synit is
|
||||||
|
ported to new systems (e.g. new mobile handsets, to desktop machines, and so on), this protocol
|
||||||
|
will be refined.
|
||||||
|
|
||||||
|
**Implementation.** The protocol is (as of October 2022) implemented entirely within the
|
||||||
|
SqueakPhone Smalltalk image, in class `AudioProfileDaemon`. The audio profile daemon has three
|
||||||
|
tasks: first, to track Linux input `HEADPHONE_INSERT` and `MICROPHONE_INSERT` events and state,
|
||||||
|
producing `HeadsetSpeakerPresent` and `HeadsetMicrophonePresent` assertions in response;
|
||||||
|
second, to track application state such as whether a call is in progress or not; and third, to
|
||||||
|
respond to changes in device and application state, along with changes in sink/source mapping
|
||||||
|
configuration, by using the external `amixer` program to enable and disable audio sinks and
|
||||||
|
sources. The schema definition file contains a few
|
||||||
|
[comments](https://git.syndicate-lang.org/synit/synit/src/commit/a2babb63d55743ce942562e7ccb9106fdb239cf4/protocols/schemas/audio.prs#L3-L17)
|
||||||
|
that give some of the flavour of the logic involved.
|
||||||
|
|
||||||
|
## Source/Sink mappings
|
||||||
|
|
||||||
|
Each different kind of device asserts `Mapping` records to connect abstract `Endpoint` names to
|
||||||
|
concrete ALSA device names.
|
||||||
|
|
||||||
|
```
|
||||||
|
Mapping = <alsa-mapping @abstract Endpoint @concrete string> .
|
||||||
|
Endpoint = <source @value Source> / <sink @value Sink> .
|
||||||
|
Sink = =speaker / =headset / =earpiece .
|
||||||
|
Source = =speakerphone / =headset / =handset .
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example.** When the Smalltalk code detects that it is running on a PinePhone, it asserts
|
||||||
|
|
||||||
|
- `<alsa-mapping <sink speaker> "Line Out">`
|
||||||
|
- `<alsa-mapping <sink headset> "Headphone">`
|
||||||
|
- `<alsa-mapping <sink earpiece> "Earpiece">`
|
||||||
|
- `<alsa-mapping <source speakerphone> "Mic1">`
|
||||||
|
- `<alsa-mapping <source handset> "Mic1">`
|
||||||
|
|
||||||
|
## Audio device state
|
||||||
|
|
||||||
|
The current daemon interprets low-level Linux input subsystem events, asserting
|
||||||
|
`HeadsetSpeakerPresent` and `HeadsetMicrophonePresent` when the relevant hardware is physically
|
||||||
|
attached to the system. These assertions are in turn used when selecting an audio profile to
|
||||||
|
enable.
|
||||||
|
|
||||||
|
```
|
||||||
|
HeadsetSpeakerPresent = <headset-speaker-present> .
|
||||||
|
HeadsetMicrophonePresent = <headset-microphone-present> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Relevant application state
|
||||||
|
|
||||||
|
The current daemon reacts to changes in
|
||||||
|
[`AlertSoundPlaying`](./soundEffects.md#AlertSoundPlaying),
|
||||||
|
[`PhoneRinging`](./telephony.md#PhoneRinging),
|
||||||
|
[`CallInProgress`](./telephony.md#CallInProgress), and
|
||||||
|
[`Speakerphone`](./telephony.md#Speakerphone) when selecting an audio profile to enable.
|
||||||
|
|
|
@ -1 +1,17 @@
|
||||||
# MIME type support
|
# MIME type support
|
||||||
|
|
||||||
|
- [`[synit]/protocols/schemas/mime.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/mime.prs)
|
||||||
|
|
||||||
|
Various protocols (e.g. the [sound effects](./soundEffects.md) protocols) rely on the
|
||||||
|
definition of a [MIME](https://en.wikipedia.org/wiki/MIME) `Value`, compatible with the
|
||||||
|
[suggested Preserves
|
||||||
|
convention](https://preserves.dev/conventions.html#mime-type-tagged-binary-data) for MIME
|
||||||
|
values.
|
||||||
|
|
||||||
|
The `type` is a symbol describing the MIME type, for example `application/octet-stream` or
|
||||||
|
`text/plain`. The `data` is the associated binary data, expected to be in the correct format
|
||||||
|
for the given `type`.
|
||||||
|
|
||||||
|
```
|
||||||
|
Value = <mime @type symbol @data bytes> .
|
||||||
|
```
|
||||||
|
|
|
@ -1 +1,118 @@
|
||||||
# Modem support
|
# Modem support
|
||||||
|
|
||||||
|
- [`[synit]/protocols/schemas/hayes.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/hayes.prs)
|
||||||
|
- [`[synit]/protocols/schemas/samsungGalaxyS7.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/samsungGalaxyS7.prs)
|
||||||
|
|
||||||
|
Each particular class of modem has internal protocols needed for controlling it. So far, Synit
|
||||||
|
is able to interact with generic Hayes-style ("AT-command") modems, as seen in the PinePhone,
|
||||||
|
as well as with the modem in the Samsung Galaxy S7.
|
||||||
|
|
||||||
|
Each modem's internal protocol is spoken across the modem's distinguished dataspace, a
|
||||||
|
reference to which is held in the modem's [`ModemPresent`](./telephony.md#ModemPresent)
|
||||||
|
assertion.
|
||||||
|
|
||||||
|
## Hayes-style ("AT-command") Modems
|
||||||
|
|
||||||
|
As of October 2022, this protocol is implemented entirely in the SqueakPhone Smalltalk image,
|
||||||
|
in class `HayesModemActor` and friends.
|
||||||
|
|
||||||
|
### Presence
|
||||||
|
|
||||||
|
Hayes-style modems announce their presence with a subtype of the general `ModemPresent`
|
||||||
|
assertion schema.
|
||||||
|
|
||||||
|
```
|
||||||
|
ModemPresent = <modem =hayes @devicePath string @dataspace #!InternalProtocol> .
|
||||||
|
```
|
||||||
|
|
||||||
|
(TODO: specify the `InternalProtocol` properly)
|
||||||
|
|
||||||
|
```
|
||||||
|
InternalProtocol = any .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unsolicited Result Codes
|
||||||
|
|
||||||
|
An `UnsolicitedResultCode` message is sent when the modem sends us a "URC", an Unsolicited
|
||||||
|
Result Code.
|
||||||
|
|
||||||
|
```
|
||||||
|
UnsolicitedResultCode = <unsolicited @result Result> .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Executing AT commands
|
||||||
|
|
||||||
|
Assert a `CommandRPC` record to request execution of an AT command string. The completion,
|
||||||
|
along with any responses, will be send to the `replyTo` entity reference. Alternatively, if no
|
||||||
|
completion notification or response is desired, send a `CommandEvent` message.
|
||||||
|
|
||||||
|
```
|
||||||
|
CommandRPC = <execute-command @commandText string @replyTo #!CommandResult> .
|
||||||
|
CommandEvent = <execute-command @commandText string> .
|
||||||
|
```
|
||||||
|
|
||||||
|
The result of a command execution is *asserted* as a `CommandResult` record to the `replyTo`
|
||||||
|
entity in the `CommandRPC`.
|
||||||
|
|
||||||
|
```
|
||||||
|
CommandResult = <command-result @commandText string @results [Result ...] @finalResult string> .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Responses and Unsolicited Results
|
||||||
|
|
||||||
|
The `Result` type appears in both `UnsolicitedResultCode` and `CommandResult` records.
|
||||||
|
|
||||||
|
```
|
||||||
|
Result = <result @text string @tag MaybeString @fields MaybeStrings> .
|
||||||
|
MaybeString = @present string / @absent #f .
|
||||||
|
MaybeStrings = @present [string ...] / @absent #f .
|
||||||
|
```
|
||||||
|
**Examples.**
|
||||||
|
- `<unsolicited <result "NO CARRIER" #f #f>>`
|
||||||
|
- `<unsolicited <result "+CRING: VOICE" "CRING" ["VOICE"]>>`
|
||||||
|
- `<unsolicited <result "+CLIP: \"+31655555555\",145,,,,0" "CLIP" ["+31655555555" "145" "" "" "" "0"]>>`
|
||||||
|
- `<unsolicited <result "^DSCI: 2,1,4,0,+31655555555,145" "DSCI" ["2" "1" "4" "0" "+31655555555" "145"]>>`
|
||||||
|
- `<unsolicited <result "+QIND: \"csq\",12,99" "QIND" ["csq" "12" "99"]>>`
|
||||||
|
|
||||||
|
## Samsung Galaxy S7
|
||||||
|
|
||||||
|
The Samsung Galaxy S7 was the first modem supported by Synit, but because of problems with the
|
||||||
|
relevant PostmarketOS kernel, support for it has languished a bit while development has
|
||||||
|
proceeded based around the PinePhone. As of October 2022, the Samsung modem support protocols
|
||||||
|
are implemented entirely in the SqueakPhone Smalltalk image, in class
|
||||||
|
`SamsungGalaxyS7ModemActor` and friends.
|
||||||
|
|
||||||
|
### Presence
|
||||||
|
|
||||||
|
The modem announces its presence with a subtype of the general `ModemPresent` assertion schema.
|
||||||
|
|
||||||
|
```
|
||||||
|
ModemPresent = <modem =samsung-galaxy-s7 @devicePath string @dataspace #!InternalProtocol> .
|
||||||
|
```
|
||||||
|
|
||||||
|
(TODO: specify the `InternalProtocol` properly)
|
||||||
|
|
||||||
|
```
|
||||||
|
InternalProtocol = any .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Low-level packet I/O
|
||||||
|
|
||||||
|
```
|
||||||
|
ModemPacket = @in <from-modem @packet any> / @out <to-modem @packet any> .
|
||||||
|
|
||||||
|
; The bodies are instances of SamsungFmtMessage and SamsungRfsMessage, respectively.
|
||||||
|
FmtPacket = <fmt @body #!any> .
|
||||||
|
RfsPacket = <rfs @body #!any> .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Executing commands
|
||||||
|
|
||||||
|
Analogous to AT command execution for Hayes-style modems.
|
||||||
|
|
||||||
|
```
|
||||||
|
; Assertion. Asks the modem to execute the given command.
|
||||||
|
CommandRPC = <execute-command @command FmtPacket @replyTo #!FmtPacket> .
|
||||||
|
; Message. Asks the modem to execute the given command, but not to send back the reply.
|
||||||
|
CommandEvent = <execute-command @command FmtPacket> .
|
||||||
|
```
|
||||||
|
|
|
@ -1 +1,195 @@
|
||||||
# Network core status and configuration
|
# Network core status and configuration
|
||||||
|
|
||||||
|
- [`[synit]/protocols/schemas/network.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/network.prs)
|
||||||
|
|
||||||
|
[interface monitor]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/usr/lib/synit/python/synit/daemon/interface_monitor.py
|
||||||
|
[wifi daemon]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/usr/lib/synit/python/synit/daemon/wifi_daemon.py
|
||||||
|
[network.pr]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/etc/syndicate/services/network.pr
|
||||||
|
[wifi.pr]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/etc/syndicate/services/wifi.pr
|
||||||
|
[modem.pr]: https://git.syndicate-lang.org/synit/synit/src/branch/main/packaging/packages/synit-config/files/etc/syndicate/services/modem.pr
|
||||||
|
|
||||||
|
The definitions in this protocol are used by the Synit daemons responsible for detecting and
|
||||||
|
responding to changes in the configuration of network devices.
|
||||||
|
|
||||||
|
**Implementation.** As of October 2022, this protocol is mostly implemented in
|
||||||
|
- the [interface monitor][],
|
||||||
|
- the [wifi daemon][], and
|
||||||
|
- the scripting around [network state changes][network.pr].
|
||||||
|
- the scripting around the [wifi subsystem][wifi.pr].
|
||||||
|
- the scripting around [mobile data][modem.pr].
|
||||||
|
|
||||||
|
## Network interface presence and state
|
||||||
|
|
||||||
|
The [interface monitor][] daemon uses the Linux netlink protocol to monitor changes in
|
||||||
|
interface presence and state. In response to netlink messages, it maintains an `Interface`
|
||||||
|
assertion for each network interface in the system.
|
||||||
|
|
||||||
|
```
|
||||||
|
Interface = <interface
|
||||||
|
@name string
|
||||||
|
@index int
|
||||||
|
@type InterfaceType
|
||||||
|
@administrativeState AdministrativeState
|
||||||
|
@operationalState OperationalState
|
||||||
|
@carrier CarrierState
|
||||||
|
@linkAddr string> .
|
||||||
|
```
|
||||||
|
|
||||||
|
The `InterfaceType` is synthesised by the interface monitor daemon based on somewhat ad-hoc
|
||||||
|
heuristics.
|
||||||
|
|
||||||
|
```
|
||||||
|
InterfaceType =
|
||||||
|
/ ; `lo` and friends
|
||||||
|
=loopback
|
||||||
|
/ ; `eth0`, bridges, anything that isn't loopback and isn't wireless
|
||||||
|
=normal
|
||||||
|
/ ; 'wlan0' and friends
|
||||||
|
=wireless
|
||||||
|
.
|
||||||
|
```
|
||||||
|
|
||||||
|
The `AdministrativeState` of an interface describes the state that the operator of the machine
|
||||||
|
wishes the interface to be in (according to the kernel).
|
||||||
|
|
||||||
|
```
|
||||||
|
AdministrativeState = =unknown / =down / =up .
|
||||||
|
```
|
||||||
|
|
||||||
|
The `OperationalState` and `CarrierState` taken together, by contrast, describe the *actual*
|
||||||
|
state of the interface.
|
||||||
|
|
||||||
|
```
|
||||||
|
OperationalState =
|
||||||
|
/ =unknown
|
||||||
|
/ =down
|
||||||
|
/ @lowerLayerDown =lower-layer-down
|
||||||
|
/ =testing
|
||||||
|
/ =dormant
|
||||||
|
/ =up
|
||||||
|
.
|
||||||
|
|
||||||
|
CarrierState =
|
||||||
|
/ @noCarrier =no-carrier
|
||||||
|
/ =carrier
|
||||||
|
.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Route presence and state
|
||||||
|
|
||||||
|
The [interface monitor][] daemon also listens for netlink messages describing network route
|
||||||
|
presence and state changes, maintaining a `Route` assertion for each route present.
|
||||||
|
|
||||||
|
```
|
||||||
|
Route = <route
|
||||||
|
@addressFamily AddressFamily
|
||||||
|
@destination RouteDestination
|
||||||
|
@priority int
|
||||||
|
@typeOfService int
|
||||||
|
@interfaceName RouteInterface
|
||||||
|
@gateway Gateway> .
|
||||||
|
|
||||||
|
AddressFamily = =ipv4 / =ipv6 / @other int .
|
||||||
|
RouteDestination = =default / @prefix <prefix @net string @bits int> .
|
||||||
|
RouteInterface = @name string / @none #f .
|
||||||
|
Gateway = @addr string / @none #f .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Default route presence
|
||||||
|
|
||||||
|
The [network.pr][] scripts respond to presence of `Route` records with a `default`
|
||||||
|
`destination` field by asserting a `DefaultRoute` record. Applications may use the presence or
|
||||||
|
absence of a `DefaultRoute` record to decide whether or not internet access is currently
|
||||||
|
present.
|
||||||
|
|
||||||
|
```
|
||||||
|
DefaultRoute = <default-route @addressFamily AddressFamily> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wi-fi associations
|
||||||
|
|
||||||
|
The [wifi.pr][] script starts an instance of the [wifi daemon][] and an instance of
|
||||||
|
[`wpa_supplicant`](https://w1.fi/cgit/hostap/tree/README) for each `Interface` of type
|
||||||
|
`wireless`. The wifi daemon speaks with the `wpa_supplicant` instance to do network scanning as
|
||||||
|
well as managing network attachments. It publishes a `WifiAssociation` for each active
|
||||||
|
connection to a wifi access point.
|
||||||
|
|
||||||
|
```
|
||||||
|
WifiAssociation = <wifi-association @interfaceName string @ssid string @state WifiAssociationState> .
|
||||||
|
WifiAssociationState = @inProgress =in-progress / =ready .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hotspots
|
||||||
|
|
||||||
|
In future, the software will use `HotspotState` assertions to publish the presence and state of
|
||||||
|
wifi hotspots hosted by the device.
|
||||||
|
|
||||||
|
```
|
||||||
|
HotspotState = <hotspot-state @interfaceName string @ssid string @stationCount int> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## AP scanning
|
||||||
|
|
||||||
|
In future, the software will assert `AvailableAccessPoint` with information it learns from
|
||||||
|
network scanning.
|
||||||
|
|
||||||
|
```
|
||||||
|
AvailableAccessPoint = <available-ap @interfaceName string @ssid string> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Network-related user settings
|
||||||
|
|
||||||
|
A number of user setting assertions control the network.
|
||||||
|
|
||||||
|
### Mobile Data
|
||||||
|
|
||||||
|
Asserting `MobileDataApn` and `MobileDataEnabled` causes the [modem.pr][] script to enable a
|
||||||
|
cellular data link.
|
||||||
|
|
||||||
|
```
|
||||||
|
MobileDataApn = <mobile-data-apn @apn string> .
|
||||||
|
MobileDataEnabled = <mobile-data-enabled> .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wifi network preferences
|
||||||
|
|
||||||
|
```
|
||||||
|
WifiAuthentication =
|
||||||
|
/ ; No authentication necessary: open network
|
||||||
|
=open
|
||||||
|
/ ; Pre-shared key (WPA2-PSK etc)
|
||||||
|
<psk @password string>
|
||||||
|
/ ; Other, not-yet-implemented
|
||||||
|
@other any
|
||||||
|
.
|
||||||
|
```
|
||||||
|
|
||||||
|
Each [wifi daemon][] responds to `SelectedWifiNetwork` assertions for its interface by trying
|
||||||
|
to connect to the named SSID using the provided credentials. The daemon asserts a
|
||||||
|
`WifiAssociation` in response.
|
||||||
|
|
||||||
|
```
|
||||||
|
SelectedWifiNetwork = <selected-wifi-network
|
||||||
|
@interfaceName string
|
||||||
|
@ssid string
|
||||||
|
@authentication WifiAuthentication> .
|
||||||
|
```
|
||||||
|
|
||||||
|
In future, user `Hotspot` assertions will cause setup of a wifi hotspot, hosted by the device.
|
||||||
|
|
||||||
|
```
|
||||||
|
Hotspot = <hotspot
|
||||||
|
@interfaceName string
|
||||||
|
@ssid string
|
||||||
|
@authentication WifiAuthentication> .
|
||||||
|
```
|
||||||
|
|
||||||
|
In future, `SavedWifiNetwork` assertions will hold records of previously-configured wifi
|
||||||
|
connection details.
|
||||||
|
|
||||||
|
```
|
||||||
|
SavedWifiNetwork = <saved-wifi-network
|
||||||
|
@ssid string
|
||||||
|
@authentication WifiAuthentication
|
||||||
|
@priority double> .
|
||||||
|
```
|
||||||
|
|
|
@ -1 +1,31 @@
|
||||||
# Sound effects
|
# Sound effects
|
||||||
|
|
||||||
|
- [`[synit]/protocols/schemas/soundEffects.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/soundEffects.prs)
|
||||||
|
|
||||||
|
From time to time, it makes sense for the device to use sound to communicate with the user.
|
||||||
|
|
||||||
|
**Implementation.** As of October 2022, the implementation resides within classes
|
||||||
|
`RingToneDaemon` and `SoundEffectsDaemon` in the SqueakPhone Smalltalk image.
|
||||||
|
|
||||||
|
## Continuous sounds
|
||||||
|
|
||||||
|
Continuous sounds such as a user's ringtone may be produced by asserting `ContinuousSound` with
|
||||||
|
an appropriately-type-tagged sound file (such as an mp3 file) as `data`. In response, the sound
|
||||||
|
effects daemon play the file in a loop and will assert `ContinuousSoundPlaying`.
|
||||||
|
|
||||||
|
```
|
||||||
|
ContinuousSound = <continuous-sound @data mime.Value> .
|
||||||
|
ContinuousSoundPlaying = <continuous-sound-playing> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## <span id="AlertSoundPlaying"></span>Alert sounds
|
||||||
|
|
||||||
|
One-off sound effects such as the notification of a received SMS may be produced by sending an
|
||||||
|
`AlertSound` message with an appropriately-type-tagged sound file (such as an mp3 file) as
|
||||||
|
`data`. In response, the sound effects daemon will play the file once and will assert
|
||||||
|
`AlertSoundPlaying` until the playback is complete.
|
||||||
|
|
||||||
|
```
|
||||||
|
AlertSound = <alert-sound @data mime.Value> .
|
||||||
|
AlertSoundPlaying = <alert-sound-playing> .
|
||||||
|
```
|
||||||
|
|
|
@ -1 +1,159 @@
|
||||||
# Telephony (call and SMS) support
|
# Telephony (call and SMS) support
|
||||||
|
|
||||||
|
- [`[synit]/protocols/schemas/telephony.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/telephony.prs)
|
||||||
|
|
||||||
|
The telephony protocol defines record and message types for non-modem-hardware-specific
|
||||||
|
telephony interactions.
|
||||||
|
|
||||||
|
**Implementation.** The protocol is (as of October 2022) implemented entirely within the
|
||||||
|
SqueakPhone Smalltalk image, in class `CallManager`, `HayesModemActor`,
|
||||||
|
`SamsungGalaxyS7ModemActor`, and so on.
|
||||||
|
|
||||||
|
## <span id="ModemPresent"></span>Available modem devices
|
||||||
|
|
||||||
|
A `ModemPresent` record is asserted for each modem available to the telephony subsystem. The
|
||||||
|
`type` field can, for example, be the symbol `hayes` for a Hayes modem, `samsung-galaxy-s7` for
|
||||||
|
a Samsung Galaxy S7, and so on. Each modem variant speaks a [variant-specific
|
||||||
|
protocol](./modem.md) across the `dataspace` reference in the `ModemPresent` record. Finally,
|
||||||
|
the `devicePath` is a Linux device path representative of the modem, for example
|
||||||
|
`/dev/umts_boot0` or `/dev/EG25.AT`.
|
||||||
|
|
||||||
|
```
|
||||||
|
ModemPresent = <modem @type symbol @devicePath string @dataspace #!any> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Telephony addresses (telephone numbers)
|
||||||
|
|
||||||
|
An `Address` represents a phone number. The `numberType` selects the numbering plan; the
|
||||||
|
`number` is the actual address. Numbering plans are complex! The GSM specifications are the
|
||||||
|
place to go for details. In general, using `international` with numbers like `+31 6 ...` is the
|
||||||
|
best way forward.
|
||||||
|
|
||||||
|
```
|
||||||
|
Address = <address @numberType NumberType @number string> .
|
||||||
|
NumberType = =unknown / =international / =national / =gsm0338 .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ongoing calls
|
||||||
|
|
||||||
|
An `ActiveCall` assertion describes an active, ongoing call.
|
||||||
|
|
||||||
|
The `callId` is a modem-specific call identification number. (TODO: if two modems are active,
|
||||||
|
their `callId`s may clash.) The `direction` is `mo` for calls placed by the local phone
|
||||||
|
endpoint, i.e. those dialed by the local user, and `mt` for calls placed by a remote phone,
|
||||||
|
i.e. incoming calls, those answered by the local user. The `type` field describes whether the
|
||||||
|
call is for voice or data; usually, this will be `voice`, but `data` is reported by some modems
|
||||||
|
when using mobile data connections. As you might imagine, `fax`-type calls are uncommon. The
|
||||||
|
`peer` field describes the other phone's network address (phone number). Finally, `state`
|
||||||
|
describes the state of the call.
|
||||||
|
|
||||||
|
```
|
||||||
|
ActiveCall = <call-state @callId CallId @direction CallDirection @type CallType @peer Address @state CallState> .
|
||||||
|
CallId = int .
|
||||||
|
CallDirection = =mo / =mt .
|
||||||
|
CallType = =voice / =data / =fax .
|
||||||
|
CallState = =hold / =original / =connect / =incoming / =waiting / =end / =alerting .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Answering an incoming call
|
||||||
|
|
||||||
|
When an `ActiveCall` record is asserted by the modem, if it has direction `mt` and state
|
||||||
|
`incoming`, the system should let the user choose to answer the call (or ignore it, etc.). If
|
||||||
|
the user chooses to answer, an `AnswerCall` message tells the modem to do the necessary. The
|
||||||
|
`callId` is the same value as in the `ActiveCall` assertion.
|
||||||
|
|
||||||
|
```
|
||||||
|
; Message. Triggers call answering.
|
||||||
|
AnswerCall = <answer-call @callId int> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rejecting and/or disconnecting a call
|
||||||
|
|
||||||
|
Sending a `DisconnectCall` message causes the modem to release an active call, either without
|
||||||
|
answering it (rejection) or while it is established (disconnection). The `callId` is taken from
|
||||||
|
the `ActiveCall` assertion, or is the symbol `all` to request disconnection of all active
|
||||||
|
calls. The `cause` field describes the release reason; it should usually be `normal`, but
|
||||||
|
`busy` or `callRejected` may also be appropriate.
|
||||||
|
|
||||||
|
```
|
||||||
|
DisconnectCall = <disconnect-call @callId CallIdSelector @cause ReleaseCause> .
|
||||||
|
CallIdSelector = @specificCall int / @allCalls =all .
|
||||||
|
ReleaseCause =
|
||||||
|
/ =unassignedNumber
|
||||||
|
/ =normal
|
||||||
|
/ =busy
|
||||||
|
/ =noUserResponding
|
||||||
|
/ =callRejected
|
||||||
|
/ =destinationOutOfOrder
|
||||||
|
/ =normalUnspecified
|
||||||
|
/ =incompatibleDestination
|
||||||
|
.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Placing an outbound call
|
||||||
|
|
||||||
|
Sending a `PlaceCall` message causes the matching modem (named by its `devicePath`, which
|
||||||
|
should match a `ModemPresent` assertion) to place an outbound call to the named `peer` (a phone
|
||||||
|
number).
|
||||||
|
|
||||||
|
```
|
||||||
|
; Message. Starts an outgoing call.
|
||||||
|
PlaceCall = <place-call @devicePath string @peer Address> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## <span id="CallInProgress"></span>Whole-device call state
|
||||||
|
|
||||||
|
Many applications don't care about precise details of individual calls, but only whether or not
|
||||||
|
some ongoing call is active (alerting, connected, ringing etc.). Those applications may monitor
|
||||||
|
the `CallInProgress` assertion.
|
||||||
|
|
||||||
|
```
|
||||||
|
CallInProgress = <call-in-progress> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## <span id="PhoneRinging"></span>Whole-device ringing state
|
||||||
|
|
||||||
|
A `PhoneRinging` assertion means that an incoming call is signalling the user, asking for a
|
||||||
|
decision about whether to answer, reject, or ignore the call.
|
||||||
|
|
||||||
|
```
|
||||||
|
PhoneRinging = <phone-ringing> .
|
||||||
|
```
|
||||||
|
|
||||||
|
A `PeerRinging` assertion means that, during the establishment phase of an outgoing call, the
|
||||||
|
remote party's phone should be ringing.
|
||||||
|
|
||||||
|
```
|
||||||
|
PeerRinging = <peer-ringing> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## SMS deliveries and transmissions
|
||||||
|
|
||||||
|
An `SmsDelivery` message indicates that an incoming SMS message has been received. The `smsc`
|
||||||
|
is the message relay server that forwarded the message on to us; this is usually some carrier-
|
||||||
|
and even plan-specific address, see the GSM specifications for details. The `peer` is the
|
||||||
|
sender's phone number. The `timestamp` describes the time associated with the SMS, and the
|
||||||
|
`body` is the message itself.
|
||||||
|
|
||||||
|
```
|
||||||
|
SmsDelivery = <sms-delivery @smsc Address @peer Address @timestamp time.Stamp @body string> .
|
||||||
|
```
|
||||||
|
|
||||||
|
To send an SMS message, assert an `SmsTransmission` record with the correct `smsc`, the
|
||||||
|
`peer`'s destination phone number, and the `body` of the message to send. The `continuation`
|
||||||
|
field should be a reference to an entity that expects the `ok` symbol as a message when the
|
||||||
|
transmission has been processed by the modem.
|
||||||
|
|
||||||
|
```
|
||||||
|
; Assertion. An outgoing SMS should be transmitted.
|
||||||
|
SmsTransmission = <sms-transmission @smsc Address @peer Address @body string @continuation #!=ok > .
|
||||||
|
```
|
||||||
|
|
||||||
|
## <span id="Speakerphone"></span>Speakerphone mode
|
||||||
|
|
||||||
|
The user may choose to assert a `Speakerphone` record in order to request that the local audio
|
||||||
|
hardware switch profile to speakerphone mode during a call.
|
||||||
|
|
||||||
|
```
|
||||||
|
Speakerphone = <speakerphone> .
|
||||||
|
```
|
||||||
|
|
|
@ -1 +1,21 @@
|
||||||
# Time stamps
|
# Time stamps
|
||||||
|
|
||||||
|
- [`[synit]/protocols/schemas/time.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/time.prs)
|
||||||
|
|
||||||
|
Various protocols rely on the definition of a time stamp type, `Stamp`, compatible with the
|
||||||
|
[suggested Preserves convention](https://preserves.dev/conventions.html#dates-and-times) for
|
||||||
|
dates and times.
|
||||||
|
|
||||||
|
```
|
||||||
|
Stamp = <rfc3339 @value string> .
|
||||||
|
```
|
||||||
|
|
||||||
|
From the Preserves convention document:
|
||||||
|
|
||||||
|
> Dates, times, moments, and timestamps can be represented with a Record with label `rfc3339`
|
||||||
|
> having a single field, a `String`, which MUST conform to one of the `full-date`,
|
||||||
|
> `partial-time`, `full-time`, or `date-time` productions of
|
||||||
|
> [section 5.6 of RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6).
|
||||||
|
> (In `date-time`, “T” and
|
||||||
|
> “Z” MUST be upper-case and “T” MUST be used; a space separating the `full-date` and
|
||||||
|
> `full-time` MUST NOT be used.)
|
||||||
|
|
|
@ -1 +1,204 @@
|
||||||
# User interface definitions and interaction
|
# User interface definitions and interaction
|
||||||
|
|
||||||
|
- [`[synit]/protocols/schemas/ui.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/ui.prs)
|
||||||
|
|
||||||
|
The user interface protocol is perhaps the most subject-to-change part of the whole system. It
|
||||||
|
is a client-server protocol, similar in spirit to X-Windows, where *clients* request display
|
||||||
|
and input services from a *server*, to which is attached a display and input devices.
|
||||||
|
|
||||||
|
At present, it is a simple system with a fixed set of widget types, a TeX-inspired box-and-glue
|
||||||
|
layout model, and a very limited set of event types. In future, a
|
||||||
|
NeWS/Display-PostScript-inspired model could dovetail very nicely with the capability and
|
||||||
|
dataspace features of Syndicate.
|
||||||
|
|
||||||
|
**Implementation.** The SqueakPhone Smalltalk image includes the initial implementation of the
|
||||||
|
protocol, in classes `WidgetDaemon`, `WidgetBuilder`, `WidgetWindow`, and so on.
|
||||||
|
|
||||||
|
## Creating a window
|
||||||
|
|
||||||
|
A client *observes* `Window` assertions with an `id` of its choice. The server notices the
|
||||||
|
client's interest, and in response, creates a fresh dataspace for configuration and interaction
|
||||||
|
relating to the new window, and asserts a `Window` record mapping the `id` to the new `space`.
|
||||||
|
|
||||||
|
```
|
||||||
|
Window = <window @id WidgetId @space #!any> .
|
||||||
|
WidgetId = any .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuring a window
|
||||||
|
|
||||||
|
Within the dataspace referred to by a `Window` assertion—henceforth the *window dataspace*—the
|
||||||
|
client may assert `WindowCloseable` to add a close button to the window decoration, and may
|
||||||
|
assert `WindowTitle` to give the window a name.
|
||||||
|
|
||||||
|
```
|
||||||
|
WindowCloseable = <window-closeable> .
|
||||||
|
WindowTitle = <window-title @title string> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating widget trees
|
||||||
|
|
||||||
|
The client may place `Widget` assertions within the window dataspace to create new widgets
|
||||||
|
within the window. The window is hidden until the first `Widget` is asserted.
|
||||||
|
|
||||||
|
`Root` and `Parent` assertions connect new widgets to the overall window layout tree. A `Root`
|
||||||
|
assertion places the widget directly in the containing window, while a `Parent` assertion marks
|
||||||
|
a widget as child of another widget. In both cases, the `order` sort key is used when multiple
|
||||||
|
children are present within a container that supports widget ordering.
|
||||||
|
|
||||||
|
```
|
||||||
|
Widget = <widget @id WidgetId @type WidgetType> .
|
||||||
|
|
||||||
|
Parent = <parent @id WidgetId @parentId WidgetId @order SortKey> .
|
||||||
|
Root = <root @id WidgetId @order SortKey> .
|
||||||
|
|
||||||
|
SortKey = @double double / @string string .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Widget Types
|
||||||
|
|
||||||
|
Widgets acting as containers for other widgets may be of either `column` or `row` type. Leaf
|
||||||
|
widgets may be `blank` (for spacing/padding/layout), `text` (a label or editable field), a
|
||||||
|
`slider`, an `image`, or a [FontAwesome](https://fontawesome.com/) `icon`.
|
||||||
|
|
||||||
|
```
|
||||||
|
WidgetType = NodeType / LeafType .
|
||||||
|
NodeType = =column / =row .
|
||||||
|
LeafType = =blank / =text / =slider / =image / =icon .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuring widgets
|
||||||
|
|
||||||
|
Widgets have *attributes* attached to them. An attribute is a pair of a symbol `key` and a
|
||||||
|
`value` (of `key`-specific type) attached to a particular widget. Most attribute keys are
|
||||||
|
expected to have either zero or one `Attribute` records for any given widget, but the
|
||||||
|
Syndicated Actor Model naturally supports *multiple* values for a given attribute, and some
|
||||||
|
attribute keys take advantage of this. See [below](#attribute-keys) for more on the available
|
||||||
|
attribute keys.
|
||||||
|
|
||||||
|
```
|
||||||
|
Attribute = <attribute @id WidgetId @key symbol @value any> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Events and Widget State
|
||||||
|
|
||||||
|
Widgets marked with the [`interactive` attribute](#interactive) generate events in response to
|
||||||
|
user interaction.
|
||||||
|
|
||||||
|
Clients can observe `Touch` assertions to receive information about when the user has a finger
|
||||||
|
touching the displayed widget on a touchscreen. The assertion for a given widget will appear
|
||||||
|
when the touch starts, and disappear when the touch ends. Multiple touches, uniquely
|
||||||
|
identified, may be active simultaneously.
|
||||||
|
|
||||||
|
```
|
||||||
|
Touch = <touch @widget WidgetId @touchId any> .
|
||||||
|
```
|
||||||
|
|
||||||
|
Clients can observe `Click` messages to receive information about when the user removes a
|
||||||
|
touching finger from a widget while the finger is within the widget's bounds.
|
||||||
|
|
||||||
|
```
|
||||||
|
Click = <click @widget WidgetId> .
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, whether a widget is marked interactive or not, the UI server actor asserts `State`
|
||||||
|
assertions containing facts about a given widget's state. For example, a text widget asserts a
|
||||||
|
`State` assertion with the symbol `text` as its `key` and a string as its `value`; a slider
|
||||||
|
asserts a `value`-keyed `State`; and a scrollable widget asserts a `visible-scroll-range`-keyed
|
||||||
|
`State` with a `VisibleScrollRange` value.
|
||||||
|
|
||||||
|
```
|
||||||
|
State = <state @widget WidgetId @key any @value any> .
|
||||||
|
|
||||||
|
VisibleScrollRange =
|
||||||
|
/ =none
|
||||||
|
/ @visibleScrollRange <visible-scroll-range
|
||||||
|
<min @minId WidgetId @minSortKey SortKey>
|
||||||
|
<max @maxId WidgetId @maxSortKey SortKey>>
|
||||||
|
.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Accessing widget instances
|
||||||
|
|
||||||
|
Within the current implementation, access to the raw
|
||||||
|
[Morphic](http://wiki.squeak.org/squeak/morphic) object representing the widget can be gained
|
||||||
|
by monitoring `WidgetInstance` assertions. (This is not a sustainable technique, and it will be
|
||||||
|
replaced in future by an entity-reference-based system.)
|
||||||
|
|
||||||
|
```
|
||||||
|
WidgetInstance = <widget-instance @id WidgetId @instance #!any> .
|
||||||
|
```
|
||||||
|
|
||||||
|
## <span id="attribute-keys"></span>Widget Attributes
|
||||||
|
|
||||||
|
### General attributes
|
||||||
|
|
||||||
|
interactive - boolean - ?
|
||||||
|
name - string - morphic name for the widget
|
||||||
|
|
||||||
|
### Color and style
|
||||||
|
|
||||||
|
The `Color` type describes an RGBA color value where the components are `double`s in the range
|
||||||
|
`0.0` to `1.0` (inclusive).
|
||||||
|
|
||||||
|
```
|
||||||
|
Color = <rgba @red double @green double @blue double @alpha double> .
|
||||||
|
```
|
||||||
|
|
||||||
|
#### backgroundColor: Color
|
||||||
|
|
||||||
|
Sets the background color of the widget.
|
||||||
|
|
||||||
|
#### foregroundColor: Color
|
||||||
|
|
||||||
|
Text color in a label or editable field; icon color for FontAwesome icons.
|
||||||
|
|
||||||
|
#### cornerStyle: `square` or `rounded`
|
||||||
|
|
||||||
|
Sets the widget's corner style. Defaults to `square`.
|
||||||
|
|
||||||
|
#### cornerRadius: number
|
||||||
|
|
||||||
|
Sets the widget's corner radius (where `cornerStyle` is `rounded`), measured in points.
|
||||||
|
|
||||||
|
#### fontSize: number
|
||||||
|
|
||||||
|
Sets the font size, measured in points.
|
||||||
|
|
||||||
|
#### icon: symbol
|
||||||
|
|
||||||
|
Sets the FontAwesome icon name for icons.
|
||||||
|
|
||||||
|
#### icon-style: symbol
|
||||||
|
|
||||||
|
Sets the FontAwesome icon style name for icons.
|
||||||
|
|
||||||
|
### Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
; Box-and-glue layout
|
||||||
|
Fill = @fixed double / <fill @weight int @rank int> .
|
||||||
|
Sizing = <sizing @ideal double @stretch Fill @shrink Fill> .
|
||||||
|
BoxSize = <box-size @horizontal Sizing @vertical Sizing> .
|
||||||
|
```
|
||||||
|
|
||||||
|
padding - BoxSize - layout padding
|
||||||
|
size - BoxSize
|
||||||
|
spacing - BoxSize
|
||||||
|
|
||||||
|
### Sliders
|
||||||
|
|
||||||
|
max - number
|
||||||
|
min - number
|
||||||
|
orientation - `vertical` or `horizontal` - for sliders
|
||||||
|
value - number - slider value
|
||||||
|
|
||||||
|
### Text fields (labels and editable fields)
|
||||||
|
|
||||||
|
readOnly - boolean - set to false to turn a label into an editable field
|
||||||
|
value - string - label or editable field contents
|
||||||
|
|
||||||
|
### Column and row attributes
|
||||||
|
|
||||||
|
cells - integer - number of cells per row (column) of the layout matrix - if none, just one row (column) exists
|
||||||
|
scrollable - boolean
|
||||||
|
|
|
@ -1 +1,18 @@
|
||||||
# User settings
|
# User settings
|
||||||
|
|
||||||
|
- [`[synit]/protocols/schemas/userSettings.prs`](https://git.syndicate-lang.org/synit/synit/src/branch/main/protocols/schemas/userSettings.prs)
|
||||||
|
|
||||||
|
```
|
||||||
|
version 1 .
|
||||||
|
|
||||||
|
; Assertion.
|
||||||
|
CommandRPC = <user-settings-command @action Action @reply #!CommandReply> .
|
||||||
|
; Message.
|
||||||
|
CommandEvent = <user-settings-command @action Action> .
|
||||||
|
|
||||||
|
CommandReply = =done .
|
||||||
|
Action = <assert @item any> / <retract @item any> .
|
||||||
|
|
||||||
|
; Assertion.
|
||||||
|
Value = <user-setting @item any> .
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue