Syrus 4G allows application developers to create low energy (BLE) applications for their IoT projects. The version of BLE that Syrus 4G uses is 4.2.

Developers can interact with the Syrus 4 device through the following defined Bluetooth services and characteristics:

Service: Communication

  • UUID: 00000000-dc70-0080-dc70-a07ba85ee4d6
  • Description: All the communication Protocol is going here

Characteristic: S4GBT Main Console

  • UUID: 00000000-dc74-0180-dc74-a07ba85ee4d6
  • Description: Allows outside users to command the Syrus 4 with either Linux or apx-tool commands. Users will receive the response generated by these commands.
  • Functions: Allows write, and notification.

Characteristic: S4GBT Destination Point

  • UUID: 00000000-dc74-0280-dc74-a07ba85ee4d6
  • Description: Will act as a Bluetooth Destination Point where all events generated within Apex will be sent to the Bluetooth device that is using this characteristic.
  • Functions: Notifications

Characteristic: S4GBT User Application Console

  • UUID: 00000000-dc74-0380-dc74-a07ba85ee4d6
  • Description: Allows a "user developed application" that runs internally in Apex to communicate with a "user developed application" that runs externally in another device.
  • Functions: Allows write, read, and notification.

Security

Communication between the user and the S4GBT Main Console must be authenticated. The authentication process consists of using the corresponding apx-bt command with the last five digits of the IMEI for the default password. Users are recommended to change this default password immediately, the new password can be up to 30 characters long with only alphanumeric characters allowed.

Explanation

Advertising

By default Syrus 4 will go advertise for 5 minutes after it's turned on, when it does advertising it can be found with the name Syrus 4 BT xxxxx where xxxxx are the last five digits of the IMEI. The configuration of the advertising can be done with the apx-bt tool, for example:

$ sudo apx-bt advertising mode,flag,duration
mode,flag,durationdescription
modeEither 0 or 1 for disable and enable respectively.
flagTo get the desired on state flag, simply add the hex numbers from flag Number.
durationA value in seconds between 30 to 300 seconds. A number more than 300 will force advertising duration to be 600 which means advertising is continuous, meaning advertising will always be on. Default it continuous (600).
flag NumberNot addedAdded
0x001Local Random AddressLocal Public Address
0x002Non DiscoverableDiscoverable
0x004Non ConnectableConnectable
0x010Advertise Name OffAdvertise Name
0x020Advertise Tx Pwr OffAdvertise Tx Pwr
0x040No AppearanceAdvertise Appearance
0x100Peer Random AddressPeer Public Address

Note that the default flag Number used when this key is not defined is 0x0016 where a random local address is used that is discoverable and connectable, and exposes the device name

Services and Characteristics

The communication service contains three different characteristics:

S4GBT Main Console

  • Users must first authenticate the connection by sending apx-bt auth xxxxx where xxxxx is the security password. By default, the security password will be the last five digits of the IMEI.
  • Once secure connection is established, the user may proceed to send any apx-tool related command to the device. Furthermore, only a limited amount of BLE commands are allowed, refer to table below.
  • Users must have notifications enabled to receive immediate responses from the device.
  • Large messages, more than 20 bytes, will be broken into packets of 20 bytes and all will be received.
  • Employs a communication protocol where all messages received must be JSON format and contain the following keys: len, id, cmd, and crc.
  • Messages sent also use JSON format and contain the following keys: len, id, res, and crc.
Valid BLE CommandsDescription
apx-System tool commands
uname -aReturns linux information on the name of the device
dateReturns a date in ISOFORMAT

S4GBT Destination Point

  • Will act as a destination point that will send notifications to all of the devices connected, authenticated, and are subscribed to receive notifications.
  • Notifications are events that were generated, managed, and are ready to be dispatched.
  • By default all event messages are sent in JSON format.
  • If a different format is needed, the message must first go to a user created application that will translate that message to the desired format then send to the Bluetooth core application for notification to the connected devices.
  • The user created application must use the apx-bt send command to notify outside applications.

S4GBT User Application Console

  • Allows an over the air link between an internal user created application that runs within Apex and an external user created application.
  • This will allow an external application to send messages to the Syrus 4 through BLE and these messages are internally published to the channel bluetooth/user_apps_console/MESSAGE
  • The external application must be able to break the messages into packets of 20 bytes and send them to Syrus 4. Only applications that are authenticated and connected can use this
  • Messages received from an external application must include a header to let the Bluetooth core application know to which user internal application the message must go to
  • Messages coming from the user internal application must include a header to let the Bluetooth core application know to which device the message must go to
  • Internal user applications must subscribe to a Redis channel bluetooth/user_apps_console/path. Where path is the path given to the user application.
  • User external applications should handle some form of encryption to encrypt messages when communicating with user internal applications. This is due to messages being sent through public channels.
  • User external application must be able to break the messages into packets of 20 bytes and send them to Syrus 4.

Header: sample_terminal

# Sample download of an application and installation using syrus-apps-manager
$ wget https://server.com/applications/terminal_1.0.zip -O /data/downloads/terminal_1.0.zip
$ syrus-apps-manager install-app terminal /data/downloads/terminal_1.0.zip
$ syrus-apps-manager create-instance sample_terminal terminal 1.0
$ Syrus-apps-manager start sample_terminal 

Subscribe:

bluetooth/user_apps_console/sample_terminal

bluetooth/user_apps_console/incoming only when header is not present

Syrus 4 publishes a message when the external application subscribes itself for notifications

"PUBLISH" "bluetooth" "{\"address\":\"602C7E1A683E\",\"user_apps_console\":true}" 

"PUBLISH" "bluetooth" "{\"address\":\"602C7E1A683E\",\"events\":true}"

Security

Two commands will be used to handle the security for using the S4GBT Main Console. One for authenticating and another to change the password.

  • Any device that wishes to use the other characteristics must be authenticated.
  • The very first action a user must do before utilizing the S4GBT Main Console is to authenticate the connection.
  • If the connection is not authenticated within two minutes, then the user trying to use S4GBT Main Console will be disconnected. The user needs to constantly send a message within 2 min to the main console in order to maintain the connection alive.
  • Failing to authenticate three or more times will cause the user to be disconnected.
  • A user may use the correct command to change the password.

Tool Schema

Advertising

The following commands can be used to edit and view the key values related with Advertising.

$sudo apx-bt advertising

The above command will return all three elements corresponding to advertising, refer to advertising.

$sudo apx-bt advertising 1,0x16,200

The above command will take a string separated by commas where the first parameter is the mode where 0 means disabled and 1 means enabled. The second parameter is the flag for the type of advertising to do, refer to advertising. The third parameter is the duration for how long to keep advertising; this takes a number from 30 to 300 seconds and any number above 300 will declare the advertising to be in continuous mode where Syrus 4 will constantly keep advertising.

Services and Characteristics

A new command must be introduced so that messages can go to their corresponding characteristics.

$sudo apx-bt send characteristic message

The new command send will expect one of the characteristics that are already defined: events and u_console. The message is already a formatted message that is ready to be written or sent as a notification.

Security

To use the S4GBT Main Console, the user must authenticate the connection by sending the following command through the Bluetooth connection:

$sudo apx-bt auth 01234

Where 01234 are the last five digits of the IMEI.
The user may change this password by sending the command:

$sudo apx-bt change_auth 01234 passphrase

Where 01234 is the old password and passphrase is the new password to use. The passphrase can be up to 30 alphanumeric characters long.

Walkthrough

Detailed Explanation

The following section is a detailed explanation of the communication protocol used by each of the characteristics.

Using the BLE functions of the apx-bt tool, you can place the device in advertising mode so that it's discoverable and connectable for example.

$sudo apx-bt advertising 1,0x16,600

Using the following service UUID 00000000-dc70-0080-dc70-a07ba85ee4d6, an application developer can connect to the services and get the characteristics.

S4GBT Main Console

  • UUID: 00000000-dc74-0180-dc74-a07ba85ee4d6
  • Send authentication message in JSON format before sending any command
  • The JSON object must have the following keys:
    • len
      • Will contain a string representing a numerical value of characters of the entire message. The number must have leading zeros. The number of characters for this string must always be five characters. Max "99999".
      • Example: "len":"00071"
      • This key must be the first key in the message.
    • id
      • Will contain a number of ten digits long, this number will be the epoch when the message was created or sent.
      • Example: "id":1614876607
      • This key must be the second key in the message.
    • cmd
      • Will be the command the Syrus 4 should attempt to execute.
      • This command must be enclosed in double quotes.
      • The command send inside the double quotes can have spaces which will count towards the len.
      • Example: "cmd":"apx-bt auth 99733"
      • This key must be the third key in the message.
    • crc
      • Will be the CRC-16/ARC calculated from the cmd sent. This includes the double quotes.
      • This will be a number of exactly five characters long and the number is treated as a string with leading zeros when applicable.
      • Example: "crc":"42606"
      • This key must be the fourth key in the message.
      • This is the decimal representation of the number.
  • Note that the JSON message is minified, so a complete valid message will look like this:
`{"len":"00071","id":1614876607,"cmd":"apx-bt auth 99733","crc":"42606"}`
  • Message responses from the Syrus 4 device will also be formatted in JSON and will contain the following keys:
    • len
      • Same as the len for receiving messages.
    • id
      • The same id that was received.
    • res
      • Will be a JSON formatted response from the command that was executed. This could be a string enclosed in {} or " ".
      • Example: "res":"authenticated"
      • This key will be the third key in the message.
    • crc
      • Will be the CRC-16/ARC calculated from the res to be received. This includes double quotes or {}.
      • Same format as message received.
      • This key will be the fourth key in the message.
  • A complete valid response message will look like this:
`{"len":"00067","id":1614876607,"res":"authenticated","crc":"11272"}`
  • Messages received from the Syrus 4 will be broken into packets of 20 bytes, (int(len/20) + 1) packets. Meaning that there will be (int(len/20) + 1) notifications made to send the entire message.
  • To validate the message, notice how many opening and closing { } exist and the count must be equals between opening and closing. Also the len can be used to assure that the length of the entire message is correct. The id can be used to confirm that the response belongs to the cmd message sent. Finally, the crc can be checked to see that the res message was valid and no errors forming the entire message occurred.
  • Since messages sent and received have fixed key and value lengths; except cmd and res, the base length of messages will be 52 characters long. The additional length is the length of the entire cmd or res including { } or " ".

S4GBT Destination Point

  • UUID: 00000000-dc74-0280-dc74-a07ba85ee4d6
  • Authentication is required through the S4GBT Main Console characteristic before receiving notification messages from Syrus 4.
  • Must only allow subscription to notifications
  • All messages received from this characteristic will be JSON.

S4GBT User Application Console

  • Allows a user external application to communicate with a user created internal application that runs inside of the Syrus 4 device.
  • Anything written to this characteristic will be forwarded to the internal user application via Redis publishes.
  • Users can define their own communication protocol between internal and external applications if desired.
  • Any messages from the internal user application that need to go to the external application will be notified as is; meaning they are not edited or modified by Syrus 4.

Developer Notes

To properly distinguish between devices that provide custom services, Syrus 4 will provide the following service with its corresponding characteristics:

ServiceID: 00000000-dc70-0080-dc70-a07ba85ee4d6
ServiceName: Syrus Communication Service

UUID Characteristic: 00000000-dc74-0180-dc74-a07ba85ee4d6
Characteristic Name: S4GBT Main Console

UUID Characteristic: 00000000-dc74-0280-dc74-a07ba85ee4d6
Characteristic Name: S4GBT Destination Point

UUID Characteristic: 00000000-dc74-0380-dc74-a07ba85ee4d6
Characteristic Name: S4GBT User Application Console

  • Developers creating Interface Application can give the service and characteristics their correct name based on the UUID read.
  • BLE connection between an external device and Syrus 4 requires that the external device uses the S4GBT Main Console at least once every two minutes. If this is not done, then the external device will be disconnected from the Syrus 4.
  • Devices that are connected to Syrus 4 must be authenticated before using any of the characteristics offered. A device only has three chances to authenticate before being disconnected by Syrus 4.
  • The default password to authenticate a BLE connection is the last five digits of the Syrus 4 IMEI.
  • The authentication message needs to be the first message the developer’s application has to write to the Syrus 4 through the Main Console characteristic.
    • Authentication Message: {"len":"00071","id":1614876607,"cmd":"apx-bt auth 99733","crc":"42606"}. Where 99733 is the last five digits of the IMEI in this particular Syrus 4 example.
  • Developer’s application need to be subscribed to notifications from Main Console and expect the following message once authentication was successful:
    {"len":"00067","id":1614876607,"res":"authenticated","crc":"11272"}

Syrus Bluetooth Demo

The following code snippet puts it all together:

  • Calculation and verification of data integrity using CRC16.
  • Encoding and decoding of text for Bluetooth communication.
  • Construction and transmission of commands in a BLE-compliant format.
  • Establishing and maintaining a Bluetooth connection with the Syrus 4G.
  • Handling and processing incoming data from the device.
// helpers
// crc16/ARC Lookup table
// http://www.lammertbies.nl/comm/info/crc-calculation.html
const crctab16 = new Uint16Array([
	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
])
function crc16(data) {
	let crc = 0x0000;
	for (let b of data){
		crc = ((crc >> 8 & 0xFF) ^ crctab16[(crc ^ b.charCodeAt()) & 0xFF])
	}
	return crc
}
// encoder / decoder needed for parsing data
let encoder = new TextEncoder()
let decoder = new TextDecoder()
// msg builder
function build_command(cmd){
	let crc = crc16(`"${cmd}"`)
	let string = `{"len":"$$$$$","id":${parseInt(Date.now() / 1e3)},"cmd":"${cmd}","crc":"${crc}"}`
	let size = `${string.length}`
	let compiled = string.replace('$$$$$', `${"0".repeat(5 - size.length)}${size}`)
	return compiled
}
// split message into packets of max 20 characters and sends them to the charactersitic provided
async function send_message(characteristic, message, recursive=false){
	if (!recursive) console.log(`sending message`, message)
	let m = message.slice(0,20)
	let r = message.slice(20)
	console.log('sending partial', characteristic.uuid, m)
	await characteristic.writeValue(encoder.encode(m))
	if (r.length) return await send_message(characteristic, r, true)
}

// async function main (){
let IMEI = window.prompt(`syrus imei? (only last 5 required)`) || '94437'
let SERVICES = {
	"main": {
		"uuid": "00000000-dc70-0080-dc70-a07ba85ee4d6",
		"characteristics": {
			"main_console": "00000000-dc74-0180-dc74-a07ba85ee4d6",
			"user_console": "00000000-dc74-0380-dc74-a07ba85ee4d6",
			"dp": "00000000-dc74-0280-dc74-a07ba85ee4d6",
		}
	},
}
// select device on browser
let s4Device = await navigator.bluetooth.requestDevice({
	filters: [{
		namePrefix: 'Syrus 4G',
	}],
	optionalServices: [SERVICES.main.uuid]
})
// connect to the device
let server = await s4Device.gatt.connect()
// get service and characteristics
let service = await server.getPrimaryService(SERVICES.main.uuid)
let main_console = await service.getCharacteristic(SERVICES.main.characteristics.main_console)
let user_console = await service.getCharacteristic(SERVICES.main.characteristics.user_console)
let dp = await service.getCharacteristic(SERVICES.main.characteristics.dp)

// set callbacks for parsed messages
let CALLBACKS = {}
CALLBACKS[SERVICES.main.characteristics.main_console] = (message) => { console.log({"main_console": message}) }
CALLBACKS[SERVICES.main.characteristics.user_console] = (message) => { console.log({"user_console": message}) }
CALLBACKS[SERVICES.main.characteristics.dp] = (message) => { console.log({"dp": message}) }

// listen for characteristic value changes
let characteristics = [main_console, user_console, dp]
characteristics.forEach(async (characteristic) => {
	let temp = ""
	let len = 0
	let timeout = null
	characteristic.addEventListener(
		"characteristicvaluechanged",
		async (event) => {
			// allow 5 seconds for remaining messages to arrive, reset console in case messages are missing
			timeout = setTimeout(() => { temp = ""; len = 0 }, 5 * 1000)
			let partial = decoder.decode(event.target.value)
			temp += partial
			if (partial.startsWith(`{"len":"`)) {
				len = parseInt(partial.split(`{"len":"`)[1].split(`","`)[0])
			}
			if (len > 0 && temp.length == len) {
				console.log(`received response(${characteristic.uuid})`, temp);
				CALLBACKS[characteristic.uuid](JSON.parse(temp))
				temp = ""
				len = 0
				clearTimeout(timeout)
				return
			}
			console.log(`received partial(${characteristic.uuid})`, partial);
		},
	);
	await characteristic.startNotifications()
})
// authenticate with console service
let message = build_command(`apx-bt auth ${s4Device.name.slice(-5)}`)
await send_message(main_console, message)

// send other messages