From 2598da173988896f6b38b2945693b6fe331d768d Mon Sep 17 00:00:00 2001 From: k5jae Date: Sat, 2 Mar 2024 09:57:53 -0600 Subject: [PATCH 1/3] Added initial JSON Schema and test file for OpenRTX JSON CPS Format --- .../geographical-location.schema.json | 20 ++ openrtx_cps_json/openrtx-cps.schema.json | 336 ++++++++++++++++++ openrtx_cps_json/readme.md | 2 + openrtx_cps_json/test.json | 94 +++++ 4 files changed, 452 insertions(+) create mode 100644 openrtx_cps_json/geographical-location.schema.json create mode 100644 openrtx_cps_json/openrtx-cps.schema.json create mode 100644 openrtx_cps_json/readme.md create mode 100644 openrtx_cps_json/test.json diff --git a/openrtx_cps_json/geographical-location.schema.json b/openrtx_cps_json/geographical-location.schema.json new file mode 100644 index 0000000..b4e2a4d --- /dev/null +++ b/openrtx_cps_json/geographical-location.schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "geographical-location.schema.json", + "title": "Longitude and Latitude", + "description": "A geographical coordinate on a planet (most commonly Earth).", + "required": [ "latitude", "longitude" ], + "type": "object", + "properties": { + "latitude": { + "type": "number", + "minimum": -90, + "maximum": 90 + }, + "longitude": { + "type": "number", + "minimum": -180, + "maximum": 180 + } + } +} diff --git a/openrtx_cps_json/openrtx-cps.schema.json b/openrtx_cps_json/openrtx-cps.schema.json new file mode 100644 index 0000000..5f202fd --- /dev/null +++ b/openrtx_cps_json/openrtx-cps.schema.json @@ -0,0 +1,336 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "openrtx-cps.schema.json", + "title": "OpenRTXConfig", + "description": "The OpenRTX JSON config format", + "type": "object", + "properties": { + "version_number": { + "description": "Major, minor and bufgix version of the OBCF standard", + "type": "integer", + "minimum": 0, + "maximum": 2147483647 + }, + "author": { + "description": "User-provided author of the config", + "type": "string", + "maxLength": 32 + }, + "description": { + "description": "User-provided description of the config", + "type": "string", + "maxLength": 32 + }, + "timestamp": { + "description": "ISO 8601 timestamp of when the config was last edited", + "type": "string" + }, + "contact_count": { + "description": "Number of stored contacts", + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "channel_count": { + "description": "Number of stored channels", + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "contacts": { + "description": "Contacts", + "type": "array", + "items": { "$ref": "#/$defs/contact" }, + "minItems": 1, + "uniqueItems": true + }, + "channels": { + "description": "Channels", + "type": "array", + "items": { "$ref": "#/$defs/channel" }, + "minItems": 1, + "uniqueItems": true + } + }, + "required": [ + "description", "timestamp", "contact_count", + "channel_count", "contacts", "channels" + ], + "unevaluatedProperties": false, + + + "$defs": { + "contact": { + "description": "Contact", + "type": "object", + "properties": { + "name": { + "description": "Display name for the contact", + "type": "string", + "maxLength": 32 + }, + "mode": { + "description": "Mode the contact is used", + "enum": [ "None", "DMR", "M17" ] + } + }, + "required": [ "name", "mode" ], + "oneOf": [ + { + "properties": { + "mode": { "const": "M17" }, + "info": { + "description": "Mode-specific M17 contact info", + "$ref": "#/$defs/m17_contact_t" + } + }, + "required": [ "info" ] + }, + { + "properties": { + "mode": { "const": "DMR" }, + "info": { + "description": "Mode-specific DMR contact info", + "$ref": "#/$defs/dmr_contact_t" + } + }, + "required": [ "info" ] + }, + { + "properties": { + "mode": { + "enum": [ "None", "FM" ] + } + } + } + ], + "unevaluatedProperties": false + }, + "channel": { + "description": "Channel", + "type": "object", + "properties": { + "mode": { + "description": "Mode the channel is used", + "enum": [ "None", "FM", "DMR", "M17" ] + }, + "traits": { + "description": "Channel traits", + "type": "object", + "properties": { + "rx_only": { + "description": "RX-only channel", + "type": "boolean" + } + }, + "unevaluatedProperties": false + }, + "power": { + "description": "Transmit power, in mW", + "type": "integer", + "minimum": 0, + "maximum": 2147483647 + }, + "rx_frequency": { + "description": "RX frequency, in Hz", + "type": "integer", + "minimum": 0, + "maximum": 2147483647 + }, + "tx_frequency": { + "description": "TX frequency, in Hz", + "type": "integer", + "minimum": 0, + "maximum": 2147483647 + }, + "name": { + "description": "Display name for channel", + "type": "string", + "maxLength": 32 + }, + "description": { + "description": "Description of the channel", + "type": "string", + "maxLength": 32 + }, + "location": { + "description": "Transmitter location", + "$ref": "geographical-location.schema.json" + }, + "groups": { + "description": "Group tags to group related channels (banks)", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 0, + "uniqueItems": true + } + }, + "required": [ + "mode", "traits", "power", "rx_frequency", + "tx_frequency", "name", "description", "location" ], + "oneOf": [ + { + "properties": { + "mode": { "const": "FM" }, + "info": { + "description": "Mode-specific FM channel info", + "$ref": "#/$defs/fmInfo_t" + } + }, + "required": [ "info" ] + }, + { + "properties": { + "mode": { "const": "DMR" }, + "info": { + "description": "Mode-specific DMR channel info", + "$ref": "#/$defs/dmrInfo_t" + } + }, + "required": [ "info" ] + }, + { + "properties": { + "mode": { "const": "M17" }, + "info": { + "description": "Mode-specific M17 channel info", + "$ref": "#/$defs/m17Info_t" + } + }, + "required": [ "info" ] + }, + { + "properties": { + "mode": { + "enum": [ "None" ] + } + } + } + ], + "unevaluatedProperties": false + }, + "m17_contact_t": { + "description": "M17 Contact", + "type": "object", + "properties": { + "address": { + "description": "Callsign", + "type": "string", + "maxLength": 9 + } + }, + "required": [ "address" ] + }, + "dmr_contact_t": { + "description": "DMR Contact", + "type": "object", + "properties": { + "dmr_id": { + "description": "DMR ID", + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "dmr_type": { + "description": "DMR Type", + "enum": [ "Group", "Private", "All" ] + }, + "alert_tone": { + "description": "Alert Tone", + "type": "boolean" + } + }, + "required": [ "dmr_id", "dmr_type", "alert_tone" ] + }, + "fmInfo_t": { + "description": "Define analog-specific channel information such as tones", + "type": "object", + "properties": { + "bandwidth": { + "description": "bandwidth of RF in kHz", + "enum": [ 12.5, 25 ] + }, + "rx_tone_index": { + "description": "RX CTC/DCS tone index 0-49", + "type": "integer", + "minimum": 0, + "maximum": 49 + }, + "rx_tone_en": { + "description": "RX CTC/DCS tone enable", + "type": "boolean" + }, + "tx_tone_index": { + "description": "TX CTC/DCS tone index 0-49", + "type": "integer", + "minimum": 0, + "maximum": 49 + }, + "tx_tone_en": { + "description": "TX CTC/DCS tone enable", + "type": "boolean" + } + }, + "required": [ "bandwidth", "rx_tone_index", "rx_tone_en", "tx_tone_index", "tx_tone_en" ] + }, + "dmrInfo_t": { + "description": "Define all and only the information for DMR channels", + "type": "object", + "properties": { + "rx_color_code": { + "description": "Color code for RX squelch opening", + "type": "integer", + "minimum": 0, + "maximum": 15 + }, + "tx_color_code": { + "description": "Color code sent during transmission", + "type": "integer", + "minimum": 0, + "maximum": 15 + }, + "dmr_timeslot": { + "description": "MR timeslot, either 1 or 2", + "type": "integer", + "minimum": 1, + "maximum": 2 + } + }, + "required": [ "rx_color_code", "tx_color_code", "dmr_timeslot" ] + }, + "m17Info_t": { + "description": "Define all and only the information for M17 channels", + "type": "object", + "properties": { + "rx_can": { + "description": "Channel Access Number for RX", + "type": "integer", + "minimum": 0, + "maximum": 7 + }, + "tx_can": { + "description": "Channel Access Number for TX", + "type": "integer", + "minimum": 0, + "maximum": 7 + }, + "channel_mode": { + "description": "Channel operation mode", + "enum": [ "Voice", "Data", "VoiceData" ] + }, + "encryption_mode": { + "description": "Channel encryption mode", + "enum": [ "Plain", "Scrambler", "AES" ] + }, + "gps_mode": { + "description": "Channel gps mode", + "enum": [ "None", "GpsMeta" ] + } + }, + "required": [ "rx_can", "tx_can", "channel_mode", + "encryption_mode", "gps_mode" ] + } + } +} diff --git a/openrtx_cps_json/readme.md b/openrtx_cps_json/readme.md new file mode 100644 index 0000000..8a4bcd8 --- /dev/null +++ b/openrtx_cps_json/readme.md @@ -0,0 +1,2 @@ +# Execute validation as shown: +$ ajv validate --spec=draft2020 -s openrtx-cps.schema.json -r geographical-location.schema.json -d test.json diff --git a/openrtx_cps_json/test.json b/openrtx_cps_json/test.json new file mode 100644 index 0000000..98f2809 --- /dev/null +++ b/openrtx_cps_json/test.json @@ -0,0 +1,94 @@ +{ + "version_number": 11, + "author": "Jae, K5JAE", + "description": "My awesome repeater config", + "timestamp": "2024-01-23T18:25:43.511Z", + "contact_count": 2, + "channel_count": 3, + "contacts" : [ + { + "name": "Jae", + "mode": "M17", + "info" : { + "address": "K5JAE" + } + }, + { + "name": "George", + "mode": "DMR", + "info" : { + "dmr_id": 1234, + "dmr_type": "All", + "alert_tone": false + } + } + ], + "channels" : [ + { + "mode": "M17", + "traits": { + "rx_only": false + }, + "power": 1000, + "rx_frequency": 433475000, + "tx_frequency": 433475000, + "name": "Hotspot", + "description": "12345678901234567890123456789012", + "location": { + "latitude": -78.75, + "longitude": 20.4 + }, + "info" : { + "rx_can": 0, + "tx_can": 0, + "channel_mode": "Voice", + "encryption_mode": "Plain", + "gps_mode": "None" + }, + "groups": ["Dallas"] + }, + { + "mode": "FM", + "traits": { + "rx_only": false + }, + "power": 1000, + "rx_frequency": 433475000, + "tx_frequency": 433475000, + "name": "Hotspot", + "description": "12345678901234567890123456789012", + "location": { + "latitude": -78.75, + "longitude": 20.4 + }, + "info" : { + "bandwidth": 12.5, + "rx_tone_index": 5, + "rx_tone_en": false, + "tx_tone_index": 5, + "tx_tone_en": false + } + }, + { + "mode": "DMR", + "traits": { + "rx_only": false + }, + "power": 1000, + "rx_frequency": 433475000, + "tx_frequency": 433475000, + "name": "Hotspot", + "description": "12345678901234567890123456789012", + "location": { + "latitude": -78.75, + "longitude": 20.4 + }, + "info" : { + "rx_color_code": 0, + "tx_color_code": 0, + "dmr_timeslot": 1 + }, + "groups": ["Dallas"] + } + ] +} From f9217f4b0231984c9687c3f369a464978c4bd929 Mon Sep 17 00:00:00 2001 From: k5jae Date: Sat, 2 Mar 2024 10:10:55 -0600 Subject: [PATCH 2/3] Removed DMR alert_tone from contact and made location optional for channels. --- openrtx_cps_json/openrtx-cps.schema.json | 19 +++++++-------- openrtx_cps_json/test.json | 31 ++++++++++-------------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/openrtx_cps_json/openrtx-cps.schema.json b/openrtx_cps_json/openrtx-cps.schema.json index 5f202fd..8443eb4 100644 --- a/openrtx_cps_json/openrtx-cps.schema.json +++ b/openrtx_cps_json/openrtx-cps.schema.json @@ -161,15 +161,15 @@ "description": "Group tags to group related channels (banks)", "type": "array", "items": { - "type": "string" + "type": "string" }, "minItems": 0, "uniqueItems": true - } + } }, "required": [ "mode", "traits", "power", "rx_frequency", - "tx_frequency", "name", "description", "location" ], + "tx_frequency", "name", "description" ], "oneOf": [ { "properties": { @@ -221,7 +221,8 @@ "maxLength": 9 } }, - "required": [ "address" ] + "required": [ "address" ], + "unevaluatedProperties": false }, "dmr_contact_t": { "description": "DMR Contact", @@ -236,13 +237,10 @@ "dmr_type": { "description": "DMR Type", "enum": [ "Group", "Private", "All" ] - }, - "alert_tone": { - "description": "Alert Tone", - "type": "boolean" } }, - "required": [ "dmr_id", "dmr_type", "alert_tone" ] + "required": [ "dmr_id", "dmr_type" ], + "unevaluatedProperties": false }, "fmInfo_t": { "description": "Define analog-specific channel information such as tones", @@ -273,7 +271,8 @@ "type": "boolean" } }, - "required": [ "bandwidth", "rx_tone_index", "rx_tone_en", "tx_tone_index", "tx_tone_en" ] + "required": [ "bandwidth", "rx_tone_index", "rx_tone_en", "tx_tone_index", "tx_tone_en" ], + "unevaluatedProperties": false }, "dmrInfo_t": { "description": "Define all and only the information for DMR channels", diff --git a/openrtx_cps_json/test.json b/openrtx_cps_json/test.json index 98f2809..0e5a618 100644 --- a/openrtx_cps_json/test.json +++ b/openrtx_cps_json/test.json @@ -5,25 +5,24 @@ "timestamp": "2024-01-23T18:25:43.511Z", "contact_count": 2, "channel_count": 3, - "contacts" : [ + "contacts": [ { "name": "Jae", "mode": "M17", - "info" : { + "info": { "address": "K5JAE" } }, { "name": "George", "mode": "DMR", - "info" : { + "info": { "dmr_id": 1234, - "dmr_type": "All", - "alert_tone": false - } + "dmr_type": "All" + } } ], - "channels" : [ + "channels": [ { "mode": "M17", "traits": { @@ -38,14 +37,14 @@ "latitude": -78.75, "longitude": 20.4 }, - "info" : { + "info": { "rx_can": 0, "tx_can": 0, "channel_mode": "Voice", "encryption_mode": "Plain", "gps_mode": "None" }, - "groups": ["Dallas"] + "groups": [ "Dallas" ] }, { "mode": "FM", @@ -57,12 +56,8 @@ "tx_frequency": 433475000, "name": "Hotspot", "description": "12345678901234567890123456789012", - "location": { - "latitude": -78.75, - "longitude": 20.4 - }, - "info" : { - "bandwidth": 12.5, + "info": { + "bandwidth": 12.5, "rx_tone_index": 5, "rx_tone_en": false, "tx_tone_index": 5, @@ -78,17 +73,17 @@ "rx_frequency": 433475000, "tx_frequency": 433475000, "name": "Hotspot", - "description": "12345678901234567890123456789012", + "description": "Fancy MMDVM HS", "location": { "latitude": -78.75, "longitude": 20.4 }, - "info" : { + "info": { "rx_color_code": 0, "tx_color_code": 0, "dmr_timeslot": 1 }, - "groups": ["Dallas"] + "groups": [ "Dallas" ] } ] } From a25b3252587fd06ef1a1c845b3c12b982a826823 Mon Sep 17 00:00:00 2001 From: k5jae Date: Sat, 2 Mar 2024 10:37:33 -0600 Subject: [PATCH 3/3] Modified the way CTCSS tones are handled in the schema. Now the tones are directly in an enum which allows for validation of tones rather than an opaque index. --- openrtx_cps_json/openrtx-cps.schema.json | 28 ++++++++++++++---------- openrtx_cps_json/test.json | 4 ++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/openrtx_cps_json/openrtx-cps.schema.json b/openrtx_cps_json/openrtx-cps.schema.json index 8443eb4..512d59a 100644 --- a/openrtx_cps_json/openrtx-cps.schema.json +++ b/openrtx_cps_json/openrtx-cps.schema.json @@ -250,28 +250,24 @@ "description": "bandwidth of RF in kHz", "enum": [ 12.5, 25 ] }, - "rx_tone_index": { - "description": "RX CTC/DCS tone index 0-49", - "type": "integer", - "minimum": 0, - "maximum": 49 + "rx_ctcss_tone": { + "description": "RX CTCSS tone in Hz", + "$ref": "#/$defs/ctcss_tones" }, "rx_tone_en": { - "description": "RX CTC/DCS tone enable", + "description": "RX CTCSS tone enable", "type": "boolean" }, - "tx_tone_index": { - "description": "TX CTC/DCS tone index 0-49", - "type": "integer", - "minimum": 0, - "maximum": 49 + "tx_ctcss_tone": { + "description": "TX CTCSS tone in Hz", + "$ref": "#/$defs/ctcss_tones" }, "tx_tone_en": { "description": "TX CTC/DCS tone enable", "type": "boolean" } }, - "required": [ "bandwidth", "rx_tone_index", "rx_tone_en", "tx_tone_index", "tx_tone_en" ], + "required": [ "bandwidth", "rx_ctcss_tone", "rx_tone_en", "tx_ctcss_tone", "tx_tone_en" ], "unevaluatedProperties": false }, "dmrInfo_t": { @@ -330,6 +326,14 @@ }, "required": [ "rx_can", "tx_can", "channel_mode", "encryption_mode", "gps_mode" ] + }, + "ctcss_tones": { + "description": "CTCSS code frequency support is implemented as the 39 tones defined in ANSI/TIA-603-E-2016 1.3.5.2 plus 11 additional non-standard tones.", + "enum": [67.0, 69.3, 71.9, 74.4, 77.0, 79.7, 82.5, 85.4, 88.5, 91.5, + 94.8, 97.4, 100.0, 103.4, 107.2, 110.9, 114.8, 118.8, 123.0, 127.3, + 131.8, 136.5, 141.3, 146.2, 151.4, 156.7, 159.8, 162.2, 165.5, 167.9, + 171.3, 173.8, 177.3, 179.9, 183.5, 186.2, 189.9, 192.8, 196.6, 199.5, + 203.5, 206.5, 210.7, 218.1, 225.7, 229.1, 233.6, 241.8, 250.3, 254.1] } } } diff --git a/openrtx_cps_json/test.json b/openrtx_cps_json/test.json index 0e5a618..471a380 100644 --- a/openrtx_cps_json/test.json +++ b/openrtx_cps_json/test.json @@ -58,9 +58,9 @@ "description": "12345678901234567890123456789012", "info": { "bandwidth": 12.5, - "rx_tone_index": 5, + "rx_ctcss_tone": 77, "rx_tone_en": false, - "tx_tone_index": 5, + "tx_ctcss_tone": 123.0, "tx_tone_en": false } },