diff --git a/Cargo.toml b/Cargo.toml index ebaa5b25..18ef5d86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ members = [ "samples/managed_subscribe", "samples/mixed", "samples/property", - "samples/seat_massager", + # "samples/seat_massager", "samples/streaming", "samples/tutorial" ] @@ -38,9 +38,9 @@ members = [ [workspace.dependencies] async-std = "^1.5" bytes = "1.4.0" -config = "0.13.3" +config = "0.14.0" dyn-clone = "1.0.14" -env_logger= "0.10.0" +env_logger= "0.11.2" futures = "0.3.28" futures-core = "0.3.4" futures-util = "0.3.28" @@ -56,13 +56,13 @@ paho-mqtt = "0.12" parking_lot = "0.12.1" prost = "0.12" prost-types = "0.12" -regex = " 1.9.3" -sdl2 = "0.35.2" +regex = " 1.10.3" +sdl2 = "0.34.0" serde = "1.0.160" serde_derive = "1.0.163" serde_json = "^1.0" -strum = "0.25" -strum_macros = "0.25.1" +strum = "0.26.1" +strum_macros = "0.26.1" tokio = "1.29.1" tokio-console-subscriber = { version = "0.2.0", package = "console-subscriber" } tokio-stream = "0.1.14" diff --git a/README.md b/README.md index 1f8e0d5b..36a5f1de 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ sudo apt install -y libsdl2-dev You will need to install dotnet-sdk for the dtdl-tools crate. This can be done by executing: ```shell -sudo apt install -y dotnet-sdk-7.0 +sudo apt install -y dotnet-sdk-8.0 ``` ### Install MQTT Broker diff --git a/digital-twin-model/dtdl/dtmi/sdv/airbag_seat_massager-1.json b/digital-twin-model/dtdl/dtmi/sdv/airbag_seat_massager-1.json new file mode 100644 index 00000000..43574653 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/airbag_seat_massager-1.json @@ -0,0 +1,116 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:airbag_seat_massager;1", + "description": "Airbag Seat Massager Interface", + "extends": "dtmi:sdv:seat_massager;1", + "contents": [ + { + "@type": "Command", + "@id": "dtmi:sdv:airbag_seat_massager:store_sequence;1", + "name": "store_sequence", + "request": { + "name": "request", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "sequence", + "schema": "dtmi:sdv:massage_sequence;1" + } + ] + } + }, + "response": { + "name": "response", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "status", + "schema": "dtmi:sdv:airbag_seat_massager:status;1" + } + ] + } + } + }, + { + "@type": "Command", + "@id": "dtmi:sdv:airbag_seat_massager:perform_step;1", + "name": "perfom_step", + "request": { + "name": "request", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "sequence", + "schema": "dtmi:sdv:massage_sequence;1" + } + ] + } + }, + "response": { + "name": "response", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "status", + "schema": "dtmi:sdv:airbag_seat_massager:status;1" + } + ] + } + } + } + ], + "schemas": [ + { + "@id": "dtmi:sdv:airbag_seat_massager:status;1", + "@type": "Object", + "fields": [ + { + "name": "code", + "schema": "integer" + }, + { + "name": "message", + "schema": "string" + } + ] + }, + { + "@id": "dtmi:sdv:massage_sequence;1", + "@type": "Array", + "elementSchema": "dtmi:sdv:massage_step;1" + }, + { + "@id": "dtmi:sdv:massage_step;1", + "@type": "Array", + "elementSchema": "dtmi:sdv:airbag_adjustments;1" + }, + { + "@id": "dtmi:sdv:airbag_adjustments;1", + "@type": "Array", + "elementSchema": "dtmi:sdv:airbag_adjustment;1" + }, + { + "@id": "dtmi:sdv:airbag_adjustment;1", + "@type": "Object", + "fields": [ + { + "name": "airbag_identifier", + "schema": "integer" + }, + { + "name": "inflation_level", + "schema": "integer" + }, + { + "name": "duration", + "schema": "duration" + } + ] + } + ] +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/basic_airbag_seat_massager-1.json b/digital-twin-model/dtdl/dtmi/sdv/basic_airbag_seat_massager-1.json new file mode 100644 index 00000000..83e08328 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/basic_airbag_seat_massager-1.json @@ -0,0 +1,7 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:basic_airbag_seat_massager;1", + "description": "Basic Airbag Seat Massager Interface", + "extends": "dtmi:sdv:airbag_seat_massager;1" +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/cabin-1.json b/digital-twin-model/dtdl/dtmi/sdv/cabin-1.json new file mode 100644 index 00000000..3ae3d164 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/cabin-1.json @@ -0,0 +1,62 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:cabin;1", + "description": "Cabin Interface", + "contents": [ + { + "@type": "Relationship", + "@id": "dtmi:sdv:cabin:has_infotainment;1", + "target": "dtmi:sdv:infotainment;1", + "name": "has_infotainment", + "maxMultiplicity": 1 + }, + { + "@type": "Relationship", + "@id": "dtmi:sdv:cabin:has_hvac;1", + "target": "dtmi:sdv:hvac;1", + "name": "has_hvac", + "maxMultiplicity": 1 + }, + { + "@type": "Relationship", + "@id": "dtmi:sdv:cabin:has_seat;1", + "name": "has_seat", + "target": "dtmi:sdv:seat;1", + "properties": [ + { + "@type": "Property", + "@id": "dtmi:sdv:seat:seat_row;1", + "name": "seat_row", + "schema": "integer" + }, + { + "@type": "Property", + "@id": "dtmi:sdv:Seat:seat_position;1", + "name": "seat_position", + "schema": { + "@type": "Enum", + "valueSchema": "string", + "enumValues": [ + { + "name": "left", + "displayName": "left", + "enumValue": "left" + }, + { + "name": "center", + "displayName": "center", + "enumValue": "center" + }, + { + "name": "right", + "displayName": "right", + "enumValue": "right" + } + ] + } + } + ] + } + ] +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/camera-1.json b/digital-twin-model/dtdl/dtmi/sdv/camera-1.json new file mode 100644 index 00000000..5236d1b6 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/camera-1.json @@ -0,0 +1,31 @@ +{ + "@context": "dtmi:dtdl:context;3", + "@type": "Interface", + "@id": "dtmi:sdv:camera;1", + "description": "Cabin camera.", + "contents": [ + { + "@type": "Property", + "@id": "dtmi:sdv:camera:feed;1", + "name": "Feed", + "description": "The camera feed inside of the cabin.", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "media_type", + "schema": "string" + }, + { + "name": "media_content", + "description": "An array of bytes (represented by integers here).", + "schema": { + "@type": "Array", + "elementSchema": "integer" + } + } + ] + } + } + ] +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/hmi-1.json b/digital-twin-model/dtdl/dtmi/sdv/hmi-1.json new file mode 100644 index 00000000..d36f652c --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/hmi-1.json @@ -0,0 +1,21 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:hmi;1", + "description": "The Human Machine Interface.", + "contents": [ + { + "@type": "Command", + "@id": "dtmi:sdv:hmi:show_notification;1", + "name": "show_notification", + "description": "Show a notification on the HMI.", + "request": { + "@id": "dtmi:sdv:hmi:show_notification:request;1", + "name": "notification", + "displayName": "Notification", + "description": "The notification to show on the HMI.", + "schema": "string" + } + } + ] +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/hvac-1.json b/digital-twin-model/dtdl/dtmi/sdv/hvac-1.json new file mode 100644 index 00000000..b3dfcd20 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/hvac-1.json @@ -0,0 +1,22 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:hvac;1", + "description": "Heat, Ventilation and Air Conditioning", + "contents": [ + { + "@type": "Property", + "@id": "dtmi:sdv:hvac:ambient_air_temperature;1", + "name": "ambient_air_temperature", + "description": "The immediate surroundings' air temperature (in Fahrenheit).", + "schema": "integer" + }, + { + "@type": "Property", + "@id": "dtmi:sdv:hvac:is_air_conditioning_active;1", + "name": "is_air_conditioning_active", + "description": "Is air conditioning active?", + "schema": "boolean" + } + ] +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/infotainment-1.json b/digital-twin-model/dtdl/dtmi/sdv/infotainment-1.json new file mode 100644 index 00000000..2087c304 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/infotainment-1.json @@ -0,0 +1,15 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:infotainment;1", + "description": "Infotainment Interface", + "contents": [ + { + "@type": "Relationship", + "@id": "dtmi:sdv:infotainment:has_hmi;1", + "target": "dtmi:sdv:hmi;1", + "name": "has_hmi", + "maxMultiplicity": 1 + } + ] +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/obd-1.json b/digital-twin-model/dtdl/dtmi/sdv/obd-1.json new file mode 100644 index 00000000..de669d23 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/obd-1.json @@ -0,0 +1,15 @@ +{ + "@context": "dtmi:dtdl:context;3", + "@type": "Interface", + "@id": "dtmi:sdv:obd;1", + "description": "On-board Diagnostics Interface", + "contents": [ + { + "@type": "Property", + "@id": "dtmi:sdv:obd:hybri_bBattery_remaining;1", + "name": "hybrid_battery_remaining", + "description": "The remaining hybrid battery life.", + "schema": "integer" + } + ] +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/premium_airbag_seat_massager-1.json b/digital-twin-model/dtdl/dtmi/sdv/premium_airbag_seat_massager-1.json new file mode 100644 index 00000000..723405a8 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/premium_airbag_seat_massager-1.json @@ -0,0 +1,7 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:premium_airbag_seat_massager;1", + "description": "Premium Airbag Seat Massager Interface", + "extends": "dtmi:sdv:airbag_seat_massager;1" +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/seat-1.json b/digital-twin-model/dtdl/dtmi/sdv/seat-1.json new file mode 100644 index 00000000..1e4deac1 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/seat-1.json @@ -0,0 +1,6 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:seat;1", + "description": "Seat Interface" +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/seat_massager-1.json b/digital-twin-model/dtdl/dtmi/sdv/seat_massager-1.json new file mode 100644 index 00000000..bf74a5f6 --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/seat_massager-1.json @@ -0,0 +1,110 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:seat_massager;1", + "description": "Seat Massager Interface", + "contents": [ + { + "@type": "Property", + "name": "sequence_names", + "@id": "dtmi:sdv:seat_massager:sequence_names;1", + "description": "The name of each of the stored sequences.", + "schema": { + "@type": "Array", + "elementSchema": "string" + } + }, + { + "@type": "Command", + "name": "load_sequence", + "request": { + "name": "request", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "sequence_name", + "schema": "string" + } + ] + } + }, + "response": { + "name": "response", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "status", + "schema": "dtmi:sdv:seatmassager:status;1" + } + ] + } + } + }, + { + "@type": "Command", + "name": "pause", + "response": { + "name": "response", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "status", + "schema": "dtmi:sdv:seatmassager:status;1" + } + ] + } + } + }, + { + "@type": "Command", + "name": "play", + "response": { + "name": "response", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "status", + "schema": "dtmi:sdv:seatmassager:status;1" + } + ] + } + } + }, + { + "@type": "Command", + "name": "reset", + "response": { + "name": "response", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "status", + "schema": "dtmi:sdv:seatmassager:status;1" + } + ] + } + } + } + ], + "schemas": [ + { + "@id": "dtmi:sdv:seatmassager:status;1", + "@type": "Object", + "fields": [ + { + "name": "code", + "schema": "integer" + }, + { + "name": "message", + "schema": "string" + } + ] + } + ] +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/seat_with_massager-1.json b/digital-twin-model/dtdl/dtmi/sdv/seat_with_massager-1.json new file mode 100644 index 00000000..9849b0ee --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/seat_with_massager-1.json @@ -0,0 +1,16 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:seat_with_massager;1", + "description": "Seat with Massager Interface", + "extends": "dtmi:sdv:seat;1", + "contents": [ + { + "@type": "Relationship", + "@id": "dtmi:sdv:seat_with_massager:has_seat_massager;1", + "target": "dtmi:sdv:seatmassager;1", + "name": "has_seat_massager", + "maxMultiplicity": 1 + } + ] +} diff --git a/digital-twin-model/dtdl/dtmi/sdv/vehicle-1.json b/digital-twin-model/dtdl/dtmi/sdv/vehicle-1.json new file mode 100644 index 00000000..36a3c01f --- /dev/null +++ b/digital-twin-model/dtdl/dtmi/sdv/vehicle-1.json @@ -0,0 +1,32 @@ +{ + "@context": ["dtmi:dtdl:context;3"], + "@type": "Interface", + "@id": "dtmi:sdv:vehicle;1", + "description": "Vehicle Interface", + "contents": [ + { + "@type": "Property", + "@id": "dtmi:sdv:vehicle:vehicle_identification;1", + "name": "vehicle_identification", + "description": "Vehicle Identification", + "schema": { + "@type": "Object", + "fields": [ + { + "@id": "dtmi:sdv:vehicle:vehicle_identification:vin;1", + "name": "vin", + "description": "Vehicle Identification Number", + "schema": "string" + } + ] + } + }, + { + "@type": "Relationship", + "@id": "dtmi:sdv:vehicle:has_cabin;1", + "target": "dtmi:sdv:cabin;1", + "name": "has_cabin", + "maxMultiplicity": 1 + } + ] +} diff --git a/digital-twin-model/dtdl/v3/spec/sdv/airbag_seat_massager.json b/digital-twin-model/dtdl/v3/spec/sdv/airbag_seat_massager.json deleted file mode 100644 index be2478bb..00000000 --- a/digital-twin-model/dtdl/v3/spec/sdv/airbag_seat_massager.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "@context": ["dtmi:dtdl:context;3"], - "@type": "Interface", - "@id": "dtmi:sdv:AirbagSeatMassager;1", - "description": "Airbag Seat Massager", - "contents": [ - { - "@type": "Property", - "@id": "dtmi:sdv:AirbagSeatMassager:MassageAirbags;1", - "name": "MassageAirbags", - "description": "The inflation level (0..100) for each massage airbag.", - "schema": { - "@type": "Array", - "elementSchema": "integer" - } - } - ] - } -] diff --git a/digital-twin-model/dtdl/v3/spec/sdv/camera.json b/digital-twin-model/dtdl/v3/spec/sdv/camera.json deleted file mode 100644 index e4ac45ea..00000000 --- a/digital-twin-model/dtdl/v3/spec/sdv/camera.json +++ /dev/null @@ -1,33 +0,0 @@ -[ - { - "@context": "dtmi:dtdl:context;3", - "@type": "Interface", - "@id": "dtmi:sdv:Camera;1", - "description": "Cabin camera.", - "contents": [ - { - "@type": "Property", - "@id": "dtmi:sdv:Camera:Feed;1", - "name": "Feed", - "description": "The camera feed inside of the cabin.", - "schema": { - "@type": "Object", - "fields": [ - { - "name": "MediaType", - "schema": "string" - }, - { - "name": "MediaContent", - "description": "An array of bytes (represented by integers here).", - "schema": { - "@type": "Array", - "elementSchema": "integer" - } - } - ] - } - } - ] - } -] diff --git a/digital-twin-model/dtdl/v3/spec/sdv/hmi.json b/digital-twin-model/dtdl/v3/spec/sdv/hmi.json deleted file mode 100644 index 8d025274..00000000 --- a/digital-twin-model/dtdl/v3/spec/sdv/hmi.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "@context": ["dtmi:dtdl:context;3"], - "@type": "Interface", - "@id": "dtmi:sdv:HMI;1", - "description": "The Human Machine Interface.", - "contents": [ - { - "@type": "Command", - "@id": "dtmi:sdv:HMI:ShowNotification;1", - "name": "ShowNotification", - "description": "Show a notification on the HMI.", - "request": { - "@id": "dtmi:sdv:HMI:ShowNotification:request;1", - "name": "Notification", - "displayName": "Notification", - "description": "The notification to show on the HMI.", - "schema": "string" - } - } - ] - } -] diff --git a/digital-twin-model/dtdl/v3/spec/sdv/hvac.json b/digital-twin-model/dtdl/v3/spec/sdv/hvac.json deleted file mode 100644 index 14075f02..00000000 --- a/digital-twin-model/dtdl/v3/spec/sdv/hvac.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "@context": ["dtmi:dtdl:context;3"], - "@type": "Interface", - "@id": "dtmi:sdv:HVAC;1", - "description": "Heat, Ventilation and Air Conditioning", - "contents": [ - { - "@type": "Property", - "@id": "dtmi:sdv:HVAC:AmbientAirTemperature;1", - "name": "AmbientAirTemperature", - "description": "The immediate surroundings' air temperature (in Fahrenheit).", - "schema": "integer" - }, - { - "@type": "Property", - "@id": "dtmi:sdv:HVAC:IsAirConditioningActive;1", - "name": "IsAirConditioningActive", - "description": "Is air conditioning active?", - "schema": "boolean" - } - ] - } -] diff --git a/digital-twin-model/dtdl/v3/spec/sdv/obd.json b/digital-twin-model/dtdl/v3/spec/sdv/obd.json deleted file mode 100644 index 9453a419..00000000 --- a/digital-twin-model/dtdl/v3/spec/sdv/obd.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "@context": ["dtmi:dtdl:context;3"], - "@type": "Interface", - "@id": "dtmi:sdv:OBD;1", - "description": "On-board Diagnostics Interface", - "contents": [ - { - "@type": "Property", - "@id": "dtmi:sdv:OBD:HybridBatteryRemaining;1", - "name": "HybridBatteryRemaining", - "description": "The remaining hybrid battery life.", - "schema": "integer" - } - ] - } -] diff --git a/digital-twin-model/src/sdv_v1.rs b/digital-twin-model/src/sdv_v1.rs index 996deb5a..c46cb3ce 100644 --- a/digital-twin-model/src/sdv_v1.rs +++ b/digital-twin-model/src/sdv_v1.rs @@ -4,15 +4,6 @@ // Note: In the future this code should be generated from a DTDL spec. -pub mod airbag_seat_massager { - pub mod massage_airbags { - pub const ID: &str = "dtmi:sdv:AirbagSeatMassager:MassageAirbags;1"; - pub const NAME: &str = "MassageAirbags"; - pub const DESCRIPTION: &str = "The inflation level (0..100) for each massage airbag."; - pub type TYPE = Vec; - } -} - #[allow(dead_code)] pub mod camera { pub mod feed { @@ -46,25 +37,79 @@ pub mod hmi { pub mod hvac { pub mod ambient_air_temperature { - pub const ID: &str = "dtmi:sdv:HVAC:AmbientAirTemperature;1"; - pub const NAME: &str = "AmbientAirTemperature"; + pub const ID: &str = "dtmi:sdv:hvac:ambient_air_temperature;1"; + pub const NAME: &str = "ambient_air_temperature"; pub const DESCRIPTION: &str = "The immediate surroundings air temperature (in Fahrenheit)."; pub type TYPE = i32; } pub mod is_air_conditioning_active { - pub const ID: &str = "dtmi:sdv:HVAC:IsAirConditioningActive;1"; - pub const NAME: &str = "IsAirConditioningActive"; + pub const ID: &str = "dtmi:sdv:HVAC:is_air_conditioning_active;1"; + pub const NAME: &str = "is_air_conditioning_active"; pub const DESCRIPTION: &str = "Is air conditioning active?"; pub type TYPE = bool; } } pub mod obd { + pub const ID: &str = "dtmi:sdv:obd;1"; + pub const DESCRIPTION: &str = "On-board Diagnostics Interface"; pub mod hybrid_battery_remaining { - pub const ID: &str = "dtmi:sdv:OBD:HybridBatteryRemaining;1"; - pub const NAME: &str = "HybridBatteryRemaining"; + pub const ID: &str = "dtmi:sdv:obd:hybrid_battery_remaining;1"; + pub const NAME: &str = "hybrid_battery_remaining"; pub const DESCRIPTION: &str = "The remaining hybrid battery life."; pub type TYPE = i32; } } + +pub mod seat_massager { + pub const ID: &str = "dtmi:sdv:seatmassager;1"; + pub const DESCRIPTION: &str = "Seat Massager Interface"; + pub mod massage_airbags { + pub const ID: &str = "dtmi:sdv:massage_seat:sequence_names;1"; + pub const NAME: &str = "sequence_names"; + pub const DESCRIPTION: &str = "The name of each of the stored sequences."; + pub type TYPE = Vec; + } +} + +pub mod basic_airbag_seat_massager { + pub const ID: &str = "dtmi:sdv:basic_airbag_seat_massager;1"; + pub const DESCRIPTION: &str = "Basic Airbag Seat Massager Interface"; +} + +pub mod premium_airbag_seat_massager { + pub const ID: &str = "dtmi:sdv:premium_airbag_seat_massager;1"; + pub const DESCRIPTION: &str = "Premium Airbag Seat Massager Interface"; +} + +pub mod airbag_seat_massager { + pub const ID: &str = "dtmi:sdv:airbag_seat_massager;1"; + pub const DESCRIPTION: &str = "Airbag Seat Massager Interface"; +} + +pub mod seat { + pub const ID: &str = "dtmi:sdv:seat;1"; + pub const DESCRIPTION: &str = "Seat Interface"; +} + +pub mod cabin { + pub const ID: &str = "dtmi:sdv:cabin;1"; + pub const DESCRIPTION: &str = "Cabin Interface"; +} + +pub mod vehicle { + pub const ID: &str = "dtmi:sdv:vehcile;1"; + pub const DESCRIPTION: &str = "Vehicle Interface"; + pub mod vehicle_identification { + pub const ID: &str = "dtmi:sdv:vehicle:vehicle_identification;1"; + pub const NAME: &str = "vehicle_identification"; + pub const DESCRIPTION: &str = "Vehicle Identification"; + pub mod vin { + pub const ID: &str = "dtmi:sdv:vehicle:vehicle_identification:vin;1"; + pub const NAME: &str = "vin"; + pub const DESCRIPTION: &str = "Vehicle Identification Number"; + pub type TYPE = String; + } + } +} \ No newline at end of file diff --git a/dtdl-tools/src/dtdl-validator/DtdlValidator.cs b/dtdl-tools/src/dtdl-validator/DtdlValidator.cs index 19f50d4e..778e8dcd 100644 --- a/dtdl-tools/src/dtdl-validator/DtdlValidator.cs +++ b/dtdl-tools/src/dtdl-validator/DtdlValidator.cs @@ -4,6 +4,8 @@ using DTDLParser; using DTDLParser.Models; +using Azure; +using Azure.IoT.ModelsRepository; using System; using System.Collections.Generic; using System.CommandLine; @@ -20,6 +22,13 @@ class Program private const int EXIT_SUCCESS = 0; private const int EXIT_FAILURE = 1; + static string ConvertToDTMI(string filepath, string dirpath, string extension) + { + string relativepath = filepath.Substring(dirpath.Length + 1, filepath.Length - dirpath.Length - extension.Length - 2); + string dtmi = relativepath.Replace('/', ':').Replace('-', ';'); // .ToLower(); + return dtmi; + } + /// /// This method validates all of the DTDL files with the provided extension that are located /// under the provided directory. @@ -46,17 +55,29 @@ static int ValidateDtdl(DirectoryInfo directory, String extension) return EXIT_FAILURE; } - var parser = new ModelParser(); + var dmrClient = new ModelsRepositoryClient(new Uri(directory.FullName)); + + var parser = new ModelParser(new ParsingOptions() + { + DtmiResolverAsync = dmrClient.ParserDtmiResolverAsync + }); bool failureOccured = false; foreach (var file in files) { try - { - var dtdl = File.ReadAllText(file); - parser.ParseAsync(dtdl).GetAwaiter().GetResult(); + { + string dtmi = ConvertToDTMI(file, directory.FullName, extension); + Console.WriteLine("DTMI = {0}", dtmi); + + // var dtdl = File.ReadAllText(file); + // parser.ParseAsync(dtdl).GetAwaiter().GetResult(); + var model = dmrClient.GetModelAsync(dtmi).GetAwaiter().GetResult(); + Console.WriteLine("For {0} the model cardinality is {1}", dtmi, model.Content.Count); + // Console.WriteLine("Content = {0}", model.Content[dtmi]); + var dictParsed = parser.ParseAsync(model.Content[dtmi]).GetAwaiter().GetResult(); Console.WriteLine($"{file} - ok"); - } + } catch (ParsingException ex) { Console.WriteLine($"{file} - failed"); @@ -65,6 +86,18 @@ static int ValidateDtdl(DirectoryInfo directory, String extension) } failureOccured = true; } + catch (ResolutionException ex) + { + Console.WriteLine($"{file} - failed"); + Console.WriteLine($" {ex.ToString()}"); + failureOccured = true; + } + catch (Exception ex) + { + Console.WriteLine($"{file} - failed"); + Console.WriteLine($" {ex.ToString()}"); + failureOccured = true; + } } if (failureOccured) diff --git a/dtdl-tools/src/dtdl-validator/ModelsRepositoryClientExtensions.cs b/dtdl-tools/src/dtdl-validator/ModelsRepositoryClientExtensions.cs new file mode 100644 index 00000000..359cd503 --- /dev/null +++ b/dtdl-tools/src/dtdl-validator/ModelsRepositoryClientExtensions.cs @@ -0,0 +1,21 @@ + +using Azure.IoT.ModelsRepository; +using DTDLParser; +using System.Runtime.CompilerServices; + +internal static class ModelsRepositoryClientExtensions +{ + public static async IAsyncEnumerable ParserDtmiResolverAsync( + this ModelsRepositoryClient client, IReadOnlyCollection dtmis, + [EnumeratorCancellation] CancellationToken ct = default) + { + Console.WriteLine("HERE"); + foreach (var dtmi in dtmis.Select(s => s.AbsoluteUri)) + { + Console.WriteLine($"DTMI >>> {dtmi}"); + var result = await client.GetModelAsync(dtmi, ModelDependencyResolution.Disabled, ct); + Console.WriteLine("DTMI <<<"); + yield return result.Content[dtmi]; + } + } +} \ No newline at end of file diff --git a/dtdl-tools/src/dtdl-validator/dtdl-validator.csproj b/dtdl-tools/src/dtdl-validator/dtdl-validator.csproj index f7aa0b82..44d6779d 100644 --- a/dtdl-tools/src/dtdl-validator/dtdl-validator.csproj +++ b/dtdl-tools/src/dtdl-validator/dtdl-validator.csproj @@ -3,12 +3,15 @@ Exe - net7.0 + net8.0 + enable + enable + diff --git a/dtdl-tools/src/lib.rs b/dtdl-tools/src/lib.rs index 3e1d2b90..3af290ae 100644 --- a/dtdl-tools/src/lib.rs +++ b/dtdl-tools/src/lib.rs @@ -15,7 +15,7 @@ mod dtdl_tools_tests { const OUT_DIR: &str = env!("OUT_DIR"); const DTDL_VALIDATOR_FILENAME: &str = "dtdl-validator"; - const DTDL_VALIDATOR_BIN_DIR: &str = "Debug/net7.0"; + const DTDL_VALIDATOR_BIN_DIR: &str = "Debug/net8.0"; const DTDL_VALIDATOR_EXT_OPTION: &str = "-e"; /// Validate DTDL files. @@ -27,7 +27,7 @@ mod dtdl_tools_tests { let dtdl_validator_command_path = Path::new(OUT_DIR).join(DTDL_VALIDATOR_BIN_DIR).join(DTDL_VALIDATOR_FILENAME); - println!("dtdl_validator_command_path = '{:?}", dtdl_validator_command_path); + println!("dtdl_validator_command_path = {:?}", dtdl_validator_command_path); let dtdl_validator_output = Command::new(dtdl_validator_command_path) .arg(directory) diff --git a/samples/interfaces/sample_grpc/v2/digital_twin_common.proto b/samples/interfaces/sample_grpc/v2/digital_twin_common.proto new file mode 100644 index 00000000..f9ba04b3 --- /dev/null +++ b/samples/interfaces/sample_grpc/v2/digital_twin_common.proto @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +syntax = "proto3"; + +package sample_grpc.v2.digital_twin_common; + +message Status { + int32 code = 1; + string message = 2; +} diff --git a/samples/interfaces/sample_grpc/v2/digital_twin_consumer.proto b/samples/interfaces/sample_grpc/v2/digital_twin_consumer.proto new file mode 100644 index 00000000..b60c0181 --- /dev/null +++ b/samples/interfaces/sample_grpc/v2/digital_twin_consumer.proto @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +syntax = "proto3"; + +import "digital_twin_common.proto"; + +package sample_grpc.v2.digital_twin_consumer; + +service DigitalTwinConsumer { + rpc Publish (PublishRequest) returns (PublishResponse); + rpc Respond (RespondRequest) returns (RespondResponse); +} + +message PublishRequest { + string entity_id = 1; + string value = 2; +} + +message PublishResponse { +} + +message RespondRequest { + string entity_id = 1; + string response_id = 2; + string payload = 3; +} + +message RespondResponse { +} \ No newline at end of file diff --git a/samples/interfaces/sample_grpc/v2/digital_twin_provider.proto b/samples/interfaces/sample_grpc/v2/digital_twin_provider.proto new file mode 100644 index 00000000..927d26fb --- /dev/null +++ b/samples/interfaces/sample_grpc/v2/digital_twin_provider.proto @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +syntax = "proto3"; + +import "digital_twin_common.proto"; + +package sample_grpc.v2.digital_twin_provider; + +service DigitalTwinProvider { + rpc Get (GetRequest) returns (GetResponse); + rpc Set (SetRequest) returns (SetResponse); + rpc Invoke (InvokeRequest) returns (InvokeResponse); +} + +message GetRequest { + string entity_id = 1; + string consumer_uri = 2; +} + +message GetResponse { + sample_grpc.v2.digital_twin_common.Status status = 1; +} + +message SetRequest { + string entity_id = 1; + string value = 2; +} + +message SetResponse { + sample_grpc.v2.digital_twin_common.Status status = 1; +} + +message InvokeRequest { + string entity_id = 1; + string consumer_uri = 2; + string response_id = 3; + string payload = 4; +} + +message InvokeResponse { + sample_grpc.v2.digital_twin_common.Status status = 1; +} \ No newline at end of file diff --git a/samples/protobuf_data_access/build.rs b/samples/protobuf_data_access/build.rs index cf214dbd..a2a0f8d0 100644 --- a/samples/protobuf_data_access/build.rs +++ b/samples/protobuf_data_access/build.rs @@ -5,6 +5,9 @@ fn main() -> Result<(), Box> { tonic_build::compile_protos("../interfaces/sample_grpc/v1/digital_twin_consumer.proto")?; tonic_build::compile_protos("../interfaces/sample_grpc/v1/digital_twin_provider.proto")?; + tonic_build::compile_protos("../interfaces/sample_grpc/v2/digital_twin_common.proto")?; + tonic_build::compile_protos("../interfaces/sample_grpc/v2/digital_twin_consumer.proto")?; + tonic_build::compile_protos("../interfaces/sample_grpc/v2/digital_twin_provider.proto")?; tonic_build::configure() .message_attribute("EndpointInfo", "#[derive(serde::Deserialize, serde::Serialize)]") .message_attribute("EntityAccessInfo", "#[derive(serde::Deserialize, serde::Serialize)]") diff --git a/samples/protobuf_data_access/src/lib.rs b/samples/protobuf_data_access/src/lib.rs index 30208109..0744cff5 100644 --- a/samples/protobuf_data_access/src/lib.rs +++ b/samples/protobuf_data_access/src/lib.rs @@ -26,6 +26,7 @@ pub mod chariott { } } + pub mod sample_grpc { pub mod v1 { pub mod digital_twin_consumer { @@ -36,6 +37,19 @@ pub mod sample_grpc { tonic::include_proto!("digital_twin_provider"); } } + pub mod v2 { + pub mod digital_twin_common { + tonic::include_proto!("sample_grpc.v2.digital_twin_common"); + } + + pub mod digital_twin_consumer { + tonic::include_proto!("sample_grpc.v2.digital_twin_consumer"); + } + + pub mod digital_twin_provider { + tonic::include_proto!("sample_grpc.v2.digital_twin_provider"); + } + } } pub mod tutorial_grpc {