The following architecture shows how multiple Generic HMI components, each with their own websocket connection, can share SDL Core's single websocket connection through the use of a Broker.
- User - a person interacting with the HMI's user interface(s).
- HMI Display - React application emulating the main screen in a vehicle.
- Hard Buttons - React application emulating the hard buttons in a vehicle's infotainment system, including driver steering wheel controls.
- Vehicle Data - React application allowing the user to emulate vehicle data being sent to the infotainment system.
- SDL Core - Instance of the embedded portion of SDL called SDL Core.
- The Generic HMI, emulation of hard buttons, and emulation of vehicle data can be one or more react applications.
- The UI components for emulation of hard buttons and emulation of vehicle data can be toggle on/off (e.g. with a build flag).
- The Broker can handle one to many HMI components over a single websocket connection to core.
- The Broker can be easily added into other HMI projects (e.g. for a Toyota or Ford specific HMI)
- SDL Core can only handle a single websocket connection.
- When subscribing to a component in SDL Core it is understood that the subscriber is asking for all messages related to that component (e.g. subscription to "Buttons" will return all messages related to soft and hard buttons).
-
HMI connects to Broker via websocket and starts listening for events. The HMI is considered a client to the Broker.
let brokerUrl = "ws://localhost:8086"; this.socket = new WebSocket(brokerUrl) this.socket.onopen = this.onopen.bind(this) this.socket.onclose = this.onclose.bind(this) this.socket.onmessage = this.onmessage.bind(this)
-
Broker connects to Core via a new websocket and starts listening for events.
let coreUrl = "ws://localhost:8087"; this.socket = new WebSocket(coreUrl) this.socket.onopen = this.onopen.bind(this) this.socket.onclose = this.onclose.bind(this) this.socket.onmessage = this.onmessage.bind(this)
-
Broker forwards all messages from a client (e.g. HMI) to Core.
onMessage(evt) { this.sendToCore(evt.data); }
-
Broker sends all messages it recieves from Core to each client.
onMessageFromCore(evt) { this.sendMessageToAllClients(evt.data); }
-
Core cannot have more than one type of component registered. For example, sending a message to register the
Buttons
component twice would result in error(s).{ "jsonrpc": "2.0", "id": -1, "method": "MB.registerComponent", "params": { "componentName": "Buttons" } }
-
The broker filters registration messages and ensures only a single registration message is sent for each type of component.
onMessage(evt) { let rpc = JSON.parse(evt.data); switch(rpc.message) { case "MB.registerComponent": if( ! isComponentRegistered(rpc.params.componentName)) { // TODO: Handle this senario return; } // Otherwise, forward the message to core. default: this.sendToCore(evt.data); break; } }
-
If a client (e.g. HMI) tries to register a component that has already been registered the Broker will add the client as an observer for these types of messages.
onMessage(evt) { let rpc = JSON.parse(evt.data); switch(rpc.message) { case "MB.registerComponent": if( ! isComponentRegistered(rpc.params.componentName)) { // Now we handle this senario addObserverToComponent(evt); return; } // Otherwise, forward the message to core. default: this.sendToCore(evt.data); break; } }
-
I lied earlier, the Broker does not send all messages back to all clients. The Broker will filter messages returned from Core. It will only return component messages to clients who have registered for that component's messages.
onMessageFromCore(evt) { // I lied //this.sendMessageToAllClients(evt.data); if(isComponentMessage(evt)) { for(let i = clients.length-1; i >= 0; --i) { if(isClientRegisteredForComponent(client[i], rpc)) this.sendToClient(client[i], rpc); } } } else { this.sendMessageToAllClients(evt.data); }
-
Further filting of the messages can be done, by the client or Broker, using the correlation ID. This ID is unique and attached to each message sent to core. When Core responds to a message it will contain the same correlation ID.