🚚 Rename websocket_message to messages

This commit is contained in:
Rune Harlyk
2026-01-03 17:00:33 +01:00
committed by nikguin04
parent c4b1ae8335
commit 775ca78a10
33 changed files with 144 additions and 176 deletions
+2 -4
View File
@@ -19,7 +19,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: 'recursive' submodules: "recursive"
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: | path: |
@@ -34,13 +34,11 @@ jobs:
- name: Install PlatformIO Core - name: Install PlatformIO Core
run: pip install --upgrade platformio run: pip install --upgrade platformio
- name: Install Python dependencies for nanopb - name: Install Python dependencies for nanopb
run: pip install protobuf grpcio-tools run: pip install protobuf grpcio-tools
- name: Build Protocol Buffers (nanopb) - name: Build Protocol Buffers (nanopb)
run: python ./submodules/nanopb/generator/nanopb_generator.py -I "./platform_shared/" -D esp32/src/platform_shared ./platform_shared/websocket_message.proto ./platform_shared/rest_message.proto run: python ./submodules/nanopb/generator/nanopb_generator.py -I "./platform_shared/" -D esp32/src/platform_shared ./platform_shared/message.proto
- name: Build PlatformIO Project - name: Build PlatformIO Project
run: pio run run: pio run
+5 -6
View File
@@ -2,10 +2,9 @@ name: Proto Build
on: on:
push: push:
branches: [ master, protobuf-playground ] branches: [master, protobuf-playground]
pull_request: pull_request:
branches: [ master, protobuf-playground ] branches: [master, protobuf-playground]
jobs: jobs:
build: build:
@@ -20,7 +19,7 @@ jobs:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: 'recursive' submodules: "recursive"
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@@ -31,7 +30,7 @@ jobs:
run: pip install protobuf grpcio-tools run: pip install protobuf grpcio-tools
- name: Build Protocol Buffers (nanopb) - name: Build Protocol Buffers (nanopb)
run: python ./submodules/nanopb/generator/nanopb_generator.py -I "./platform_shared/" -D esp32/src/platform_shared ./platform_shared/websocket_message.proto ./platform_shared/rest_message.proto run: python ./submodules/nanopb/generator/nanopb_generator.py -I "./platform_shared/" -D esp32/src/platform_shared ./platform_shared/message.proto
- name: Setup Protocol Buffers compiler - name: Setup Protocol Buffers compiler
uses: arduino/setup-protoc@v3 uses: arduino/setup-protoc@v3
@@ -57,4 +56,4 @@ jobs:
- name: Build Protocol Buffers (Typescript) - name: Build Protocol Buffers (Typescript)
run: pnpm proto run: pnpm proto
working-directory: ./app working-directory: ./app
+1 -1
View File
@@ -17,7 +17,7 @@ const pluginPath =
path.join(projectRoot, 'node_modules', '.bin', 'protoc-gen-ts_proto.cmd') path.join(projectRoot, 'node_modules', '.bin', 'protoc-gen-ts_proto.cmd')
: path.join(projectRoot, 'node_modules', '.bin', 'protoc-gen-ts_proto') : path.join(projectRoot, 'node_modules', '.bin', 'protoc-gen-ts_proto')
const protoFiles = ['websocket_message.proto', 'rest_message.proto'] const protoFiles = ['message.proto']
const tsProtoOpts = ['useExactTypes=false', 'outputExtensions=true', 'outputSchema=true'].join(',') const tsProtoOpts = ['useExactTypes=false', 'outputExtensions=true', 'outputSchema=true'].join(',')
+1 -1
View File
@@ -37,7 +37,7 @@
import { radToDeg } from 'three/src/math/MathUtils.js' import { radToDeg } from 'three/src/math/MathUtils.js'
import type { URDFRobot } from 'urdf-loader' import type { URDFRobot } from 'urdf-loader'
import { get } from 'svelte/store' import { get } from 'svelte/store'
import { AnglesData, KinematicData, ModesEnum } from '$lib/platform_shared/websocket_message' import { AnglesData, KinematicData, ModesEnum } from '$lib/platform_shared/message'
interface Props { interface Props {
defaultColor?: string | null defaultColor?: string | null
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { ModeData, ModesEnum } from '$lib/platform_shared/websocket_message' import { ModeData, ModesEnum } from '$lib/platform_shared/message'
import { mode } from '$lib/stores' import { mode } from '$lib/stores'
const deactivate = async () => { const deactivate = async () => {
+1 -1
View File
@@ -1,7 +1,7 @@
import { get } from 'svelte/store' import { get } from 'svelte/store'
import type { body_state_t } from './kinematic' import type { body_state_t } from './kinematic'
import { currentKinematic } from './stores/featureFlags' import { currentKinematic } from './stores/featureFlags'
import { HumanInputData, WalkGaits } from './platform_shared/websocket_message' import { HumanInputData, WalkGaits } from './platform_shared/message'
export interface gait_state_t { export interface gait_state_t {
step_height: number step_height: number
+1 -1
View File
@@ -1,4 +1,4 @@
import { AnalyticsData } from '$lib/platform_shared/websocket_message' import { AnalyticsData } from '$lib/platform_shared/message'
import { writable } from 'svelte/store' import { writable } from 'svelte/store'
const analytics_data: AnalyticsData[] = [] const analytics_data: AnalyticsData[] = []
+1 -1
View File
@@ -1,5 +1,5 @@
import { writable } from 'svelte/store' import { writable } from 'svelte/store'
import { IMUData } from '$lib/platform_shared/websocket_message' import { IMUData } from '$lib/platform_shared/message'
const imu_data: IMUData[] = [] const imu_data: IMUData[] = []
const maxIMUData = 100 const maxIMUData = 100
+1 -1
View File
@@ -6,7 +6,7 @@ import {
ModesEnum, ModesEnum,
WalkGaitData, WalkGaitData,
WalkGaits WalkGaits
} from '$lib/platform_shared/websocket_message' } from '$lib/platform_shared/message'
import { persistentStore } from '$lib/utilities/svelte-utilities' import { persistentStore } from '$lib/utilities/svelte-utilities'
import { writable, type Writable } from 'svelte/store' import { writable, type Writable } from 'svelte/store'
+1 -1
View File
@@ -1,4 +1,4 @@
import { AnglesData } from '$lib/platform_shared/websocket_message' import { AnglesData } from '$lib/platform_shared/message'
import { writable, type Writable } from 'svelte/store' import { writable, type Writable } from 'svelte/store'
export const servoAnglesOut: Writable<AnglesData> = writable( export const servoAnglesOut: Writable<AnglesData> = writable(
+34 -34
View File
@@ -1,12 +1,12 @@
import { writable } from 'svelte/store' import { writable } from 'svelte/store'
import { import {
WebsocketMessage, Message,
CorrelationRequest, CorrelationRequest,
CorrelationResponse, CorrelationResponse,
protoMetadata as websocket_md, protoMetadata,
type MessageFns type MessageFns
} from '$lib/platform_shared/websocket_message' } from '$lib/platform_shared/message'
import * as WebsocketMessages from '$lib/platform_shared/websocket_message' import * as Messages from '$lib/platform_shared/message'
export const MESSAGE_TYPE_TO_KEY = new Map<MessageFns<unknown>, string>() export const MESSAGE_TYPE_TO_KEY = new Map<MessageFns<unknown>, string>()
export const MESSAGE_TYPE_TO_TAG = new Map<MessageFns<unknown>, number>() export const MESSAGE_TYPE_TO_TAG = new Map<MessageFns<unknown>, number>()
@@ -20,14 +20,14 @@ type PendingRequest = {
timeoutId: ReturnType<typeof setTimeout> timeoutId: ReturnType<typeof setTimeout>
} }
const websocketMessageType = websocket_md.fileDescriptor.messageType?.find( const MessageType = protoMetadata.fileDescriptor.messageType?.find(
(msg: { name: string }) => msg.name === 'WebsocketMessage' (msg: { name: string }) => msg.name === 'Message'
) )
if (websocketMessageType?.field) { if (MessageType?.field) {
for (const field of websocketMessageType.field) { for (const field of MessageType.field) {
if (field.typeName) { if (field.typeName) {
const messageFns = websocket_md.references[field.typeName] const messageFns = protoMetadata.references[field.typeName]
if (messageFns && field.jsonName && field.number) { if (messageFns && field.jsonName && field.number) {
MESSAGE_TYPE_TO_KEY.set(messageFns, field.jsonName) MESSAGE_TYPE_TO_KEY.set(messageFns, field.jsonName)
MESSAGE_TYPE_TO_TAG.set(messageFns, field.number) MESSAGE_TYPE_TO_TAG.set(messageFns, field.number)
@@ -38,21 +38,21 @@ if (websocketMessageType?.field) {
} }
} }
function get_name_from_messagetype<T>(event_type: MessageFns<T>): string { function getNameFromMessageType<T>(event_type: MessageFns<T>): string {
const event = MESSAGE_TYPE_TO_KEY.get(event_type as MessageFns<unknown>) const event = MESSAGE_TYPE_TO_KEY.get(event_type as MessageFns<unknown>)
if (!event) { if (!event) {
throw new Error( throw new Error(
"Event type not found in 'WebsocketMessage'. The MessageFns you passed doesn't correspond to any WebsocketMessage field." "Event type not found in 'Message'. The MessageFns you passed doesn't correspond to any Message field."
) )
} }
return event return event
} }
function get_tag_from_messagetype<T>(event_type: MessageFns<T>): number { function getTagFromMessageType<T>(event_type: MessageFns<T>): number {
const fieldNumber = MESSAGE_TYPE_TO_TAG.get(event_type as MessageFns<unknown>) const fieldNumber = MESSAGE_TYPE_TO_TAG.get(event_type as MessageFns<unknown>)
if (fieldNumber === undefined) { if (fieldNumber === undefined) {
throw new Error( throw new Error(
"Tag not found in 'WebsocketMessage'. The MessageFns you passed doesn't correspond to any WebsocketMessage field." "Tag not found in 'Message'. The MessageFns you passed doesn't correspond to any Message field."
) )
} }
return fieldNumber return fieldNumber
@@ -60,10 +60,10 @@ function get_tag_from_messagetype<T>(event_type: MessageFns<T>): number {
type SocketEvent = 'open' | 'close' | 'error' | 'message' | 'unresponsive' type SocketEvent = 'open' | 'close' | 'error' | 'message' | 'unresponsive'
type TaggedSocketMessage = { tag: number; msg: WebsocketMessage } type TaggedMessage = { tag: number; msg: Message }
export const decodeMessage = (data: ArrayBuffer): TaggedSocketMessage => { export const decodeMessage = (data: ArrayBuffer): TaggedMessage => {
const decoded = WebsocketMessage.decode(new Uint8Array(data)) const decoded = Message.decode(new Uint8Array(data))
const values = Object.entries(decoded).filter(([, value]) => value !== undefined) const values = Object.entries(decoded).filter(([, value]) => value !== undefined)
if (values.length != 1) { if (values.length != 1) {
throw new Error('Message included either 0 or more than 1 data point') throw new Error('Message included either 0 or more than 1 data point')
@@ -76,8 +76,8 @@ export const decodeMessage = (data: ArrayBuffer): TaggedSocketMessage => {
return { tag: tag, msg: decoded } return { tag: tag, msg: decoded }
} }
export const encodeMessage = (data: WebsocketMessage): Uint8Array<ArrayBuffer> => { export const encodeMessage = (data: Message): Uint8Array<ArrayBuffer> => {
const encoded = WebsocketMessage.encode(data).finish() const encoded = Message.encode(data).finish()
return encoded return encoded
} }
@@ -158,7 +158,7 @@ function createWebSocket() {
} }
function unsubscribe<MT>(event_type: MessageFns<MT>, listener: (data: MT) => void) { function unsubscribe<MT>(event_type: MessageFns<MT>, listener: (data: MT) => void) {
const tag = get_tag_from_messagetype(event_type) const tag = getTagFromMessageType(event_type)
const message_listeners_totag = message_listeners.get(tag) const message_listeners_totag = message_listeners.get(tag)
if (!message_listeners_totag) return if (!message_listeners_totag) return
@@ -182,43 +182,43 @@ function createWebSocket() {
function sendEvent<T>(event: MessageFns<T>, data: T) { function sendEvent<T>(event: MessageFns<T>, data: T) {
if (!ws || ws.readyState !== WebSocket.OPEN) return if (!ws || ws.readyState !== WebSocket.OPEN) return
const type = get_name_from_messagetype(event) const type = getNameFromMessageType(event)
const wsm = WebsocketMessage.create() as Record<string, unknown> const wsm = Message.create() as Record<string, unknown>
wsm[type] = data wsm[type] = data
send(wsm as WebsocketMessage) send(wsm as Message)
} }
function unsubscribeToMessageFromServer<T>(event_type: MessageFns<T>) { function unsubscribeToMessageFromServer<T>(event_type: MessageFns<T>) {
if (!ws || ws.readyState !== WebSocket.OPEN) return if (!ws || ws.readyState !== WebSocket.OPEN) return
const unsub_msg = WebsocketMessages.UnsubscribeNotification.create({ const unsub_msg = Messages.UnsubscribeNotification.create({
tag: get_tag_from_messagetype(event_type) tag: getTagFromMessageType(event_type)
}) })
send(WebsocketMessage.create({ unsubNotif: unsub_msg })) send(Message.create({ unsubNotif: unsub_msg }))
} }
function subscribeToEvent<T>(event_type: MessageFns<T>) { function subscribeToEvent<T>(event_type: MessageFns<T>) {
if (!ws || ws.readyState !== WebSocket.OPEN) return if (!ws || ws.readyState !== WebSocket.OPEN) return
const sub_msg = WebsocketMessages.SubscribeNotification.create({ const sub_msg = Messages.SubscribeNotification.create({
tag: get_tag_from_messagetype(event_type) tag: getTagFromMessageType(event_type)
}) })
send(WebsocketMessage.create({ subNotif: sub_msg })) send(Message.create({ subNotif: sub_msg }))
} }
function resubscribeAll() { function resubscribeAll() {
for (const tag of message_listeners.keys()) { for (const tag of message_listeners.keys()) {
const sub_msg = WebsocketMessages.SubscribeNotification.create({ tag }) const sub_msg = Messages.SubscribeNotification.create({ tag })
send(WebsocketMessage.create({ subNotif: sub_msg })) send(Message.create({ subNotif: sub_msg }))
} }
} }
function send(data: WebsocketMessage) { function send(data: Message) {
if (!ws || ws.readyState !== WebSocket.OPEN) return if (!ws || ws.readyState !== WebSocket.OPEN) return
const encoded = encodeMessage(data) const encoded = encodeMessage(data)
ws.send(encoded) ws.send(encoded)
} }
function ping() { function ping() {
send(WebsocketMessage.create({ pingmsg: {} })) send(Message.create({ pingmsg: {} }))
} }
function sendRequest( function sendRequest(
@@ -235,7 +235,7 @@ function createWebSocket() {
pending_requests.set(correlationId, { resolve, reject, timeoutId }) pending_requests.set(correlationId, { resolve, reject, timeoutId })
const request = CorrelationRequest.create({ correlationId, ...data }) const request = CorrelationRequest.create({ correlationId, ...data })
send(WebsocketMessage.create({ correlationRequest: request })) send(Message.create({ correlationRequest: request }))
} }
function flushQueuedRequests() { function flushQueuedRequests() {
@@ -250,7 +250,7 @@ function createWebSocket() {
sendEvent, sendEvent,
init, init,
on: <MT>(event_type: MessageFns<MT>, listener: (data: MT) => void): (() => void) => { on: <MT>(event_type: MessageFns<MT>, listener: (data: MT) => void): (() => void) => {
const tag = get_tag_from_messagetype(event_type) const tag = getTagFromMessageType(event_type)
let message_listeners_totag = message_listeners.get(tag) let message_listeners_totag = message_listeners.get(tag)
if (!message_listeners_totag) { if (!message_listeners_totag) {
+1 -1
View File
@@ -1,4 +1,4 @@
import { DownloadOTAData, RSSIData } from '$lib/platform_shared/websocket_message' import { DownloadOTAData, RSSIData } from '$lib/platform_shared/message'
import { writable } from 'svelte/store' import { writable } from 'svelte/store'
type telemetry_data_type = { type telemetry_data_type = {
+2 -2
View File
@@ -32,7 +32,7 @@
RSSIData, RSSIData,
SonarData, SonarData,
WalkGaitData WalkGaitData
} from '$lib/platform_shared/websocket_message' } from '$lib/platform_shared/message'
import { Throttler } from '$lib/utilities' import { Throttler } from '$lib/utilities'
interface Props { interface Props {
@@ -82,7 +82,7 @@
servoAngles.set(data) servoAngles.set(data)
}), }),
socket.on(PingMsg, data => { socket.on(PingMsg, data => {
console.log("Ping received!") console.log('Ping received!')
}) })
] ]
) )
+1 -1
View File
@@ -5,7 +5,7 @@
import { onMount } from 'svelte' import { onMount } from 'svelte'
import { mpu, socket } from '$lib/stores' import { mpu, socket } from '$lib/stores'
import { imu } from '$lib/stores/imu' import { imu } from '$lib/stores/imu'
import { IMUData } from '$lib/platform_shared/websocket_message' import { IMUData } from '$lib/platform_shared/message'
let layout = $derived($views.find(v => v.name === $selectedView)!) let layout = $derived($views.find(v => v.name === $selectedView)!)
+1 -6
View File
@@ -14,12 +14,7 @@
import { VerticalSlider } from '$lib/components/input' import { VerticalSlider } from '$lib/components/input'
import { gamepadAxes, gamepadButtonsEdges, hasGamepad } from '$lib/stores/gamepad' import { gamepadAxes, gamepadButtonsEdges, hasGamepad } from '$lib/stores/gamepad'
import { notifications } from '$lib/components/toasts/notifications' import { notifications } from '$lib/components/toasts/notifications'
import { import { ModeData, ModesEnum, WalkGaitData, WalkGaits } from '$lib/platform_shared/message'
ModeData,
ModesEnum,
WalkGaitData,
WalkGaits
} from '$lib/platform_shared/websocket_message'
let left: nipplejs.JoystickManager let left: nipplejs.JoystickManager
let right: nipplejs.JoystickManager let right: nipplejs.JoystickManager
+1 -1
View File
@@ -4,7 +4,7 @@
import { socket } from '$lib/stores' import { socket } from '$lib/stores'
import { Connection } from '$lib/components/icons' import { Connection } from '$lib/components/icons'
import I2CSetting from './i2cSetting.svelte' import I2CSetting from './i2cSetting.svelte'
import type { I2CDevice } from '$lib/platform_shared/websocket_message' import type { I2CDevice } from '$lib/platform_shared/message'
let active_devices: I2CDevice[] = $state([]) let active_devices: I2CDevice[] = $state([])
let isLoading = $state(false) let isLoading = $state(false)
@@ -7,7 +7,7 @@
import { import {
PeripheralSettingsData, PeripheralSettingsData,
PeripheralSettingsDataRequest PeripheralSettingsDataRequest
} from '$lib/platform_shared/websocket_message' } from '$lib/platform_shared/message'
let settings: PeripheralSettingsData | null = $state(null) let settings: PeripheralSettingsData | null = $state(null)
let isEditing = $state(false) let isEditing = $state(false)
+1 -1
View File
@@ -9,7 +9,7 @@
import { useFeatureFlags } from '$lib/stores/featureFlags' import { useFeatureFlags } from '$lib/stores/featureFlags'
import { Rotate3d } from '$lib/components/icons' import { Rotate3d } from '$lib/components/icons'
import { type IMUCalibrateData, IMUData } from '$lib/platform_shared/websocket_message' import { type IMUCalibrateData, IMUData } from '$lib/platform_shared/message'
Chart.register(...registerables) Chart.register(...registerables)
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { ServoPWMData, ServoStateData } from '$lib/platform_shared/websocket_message' import { ServoPWMData, ServoStateData } from '$lib/platform_shared/message'
import { socket } from '$lib/stores' import { socket } from '$lib/stores'
import { Throttler } from '$lib/utilities' import { Throttler } from '$lib/utilities'
+23 -11
View File
@@ -3,7 +3,13 @@
import { socket } from '$lib/stores' import { socket } from '$lib/stores'
//import { IMUReport, IMUType } from '$lib/platform_shared/example'; //import { IMUReport, IMUType } from '$lib/platform_shared/example';
import { AnglesData, WebsocketMessage, IMUData, CorrelationRequest, CorrelationResponse } from '$lib/platform_shared/websocket_message' import {
AnglesData,
Message,
IMUData,
CorrelationRequest,
CorrelationResponse
} from '$lib/platform_shared/message'
// const imu_report: IMUReport = {type: IMUType.IMU_ACCEL, xVal: 4} // const imu_report: IMUReport = {type: IMUType.IMU_ACCEL, xVal: 4}
// const writer = IMUReport.encode(imu_report); // const writer = IMUReport.encode(imu_report);
@@ -13,20 +19,20 @@
// .map((b) => b.toString(16).padStart(2, '0')) // .map((b) => b.toString(16).padStart(2, '0'))
// .join(' '); // .join(' ');
// const wmd: WebsocketMessage = { imu: {temp: 0, x: 0, y: 0, z: 1}, angles: {angles: [2]}} // const wmd: Message = { imu: {temp: 0, x: 0, y: 0, z: 1}, angles: {angles: [2]}}
// const wmd: WebsocketMessage = { imu: {temp: 0, x: 0, y: 0, z: 0} } // const wmd: Message = { imu: {temp: 0, x: 0, y: 0, z: 0} }
// const wmd: WebsocketMessage = { rssi: { rssi: 16 } } // const wmd: Message = { rssi: { rssi: 16 } }
// const wmd: WebsocketMessage = { imu: {temp: 1, x: 2, y: 4, z: 5} } // const wmd: Message = { imu: {temp: 1, x: 2, y: 4, z: 5} }
// const wmd: WebsocketMessage = { angles: {angles: [1,2,3,4]} } // const wmd: Message = { angles: {angles: [1,2,3,4]} }
const wmd: WebsocketMessage = { pongmsg: {} } const wmd: Message = { pongmsg: {} }
const writer = WebsocketMessage.encode(wmd) const writer = Message.encode(wmd)
const bytes = writer.finish() const bytes = writer.finish()
// Convert bytes to hex // Convert bytes to hex
const hex = Array.from(bytes) const hex = Array.from(bytes)
.map(b => b.toString(16).padStart(2, '0')) .map(b => b.toString(16).padStart(2, '0'))
.join(' ') .join(' ')
// const decodedmsg: WebsocketMessage = WebsocketMessage.decode(bytes); // const decodedmsg: Message = Message.decode(bytes);
// const objects = Object.entries(decodedmsg) // const objects = Object.entries(decodedmsg)
// console.log(Object.keys(AnglesData.create())[0] ) // console.log(Object.keys(AnglesData.create())[0] )
@@ -48,11 +54,17 @@
// console.log(data) // console.log(data)
} }
onMount(() => { onMount(() => {
socket.on(CorrelationResponse, (data) => { socket.on(CorrelationResponse, data => {
console.log(data) console.log(data)
}) })
socket.onEvent('open', () => { socket.onEvent('open', () => {
socket.sendEvent(CorrelationRequest, CorrelationRequest.create({correlationId: 69, featuresDataRequest: { sonarTest: true }})) socket.sendEvent(
CorrelationRequest,
CorrelationRequest.create({
correlationId: 69,
featuresDataRequest: { sonarTest: true }
})
)
}) })
return socket.on(IMUData, handleData) return socket.on(IMUData, handleData)
@@ -31,7 +31,7 @@
} from '$lib/components/icons' } from '$lib/components/icons'
import StatusItem from '$lib/components/StatusItem.svelte' import StatusItem from '$lib/components/StatusItem.svelte'
import ActionButton from './ActionButton.svelte' import ActionButton from './ActionButton.svelte'
import { AnalyticsData, type SystemInformation } from '$lib/platform_shared/websocket_message' import { AnalyticsData, type SystemInformation } from '$lib/platform_shared/message'
const features = useFeatureFlags() const features = useFeatureFlags()
+1 -1
View File
@@ -33,7 +33,7 @@
Edit Edit
} from '$lib/components/icons' } from '$lib/components/icons'
import StatusItem from '$lib/components/StatusItem.svelte' import StatusItem from '$lib/components/StatusItem.svelte'
import { KnownNetworkItem } from '$lib/platform_shared/websocket_message' import { KnownNetworkItem } from '$lib/platform_shared/message'
import { WifiSettings, type WifiStatus } from '$lib/platform_shared/rest_message' import { WifiSettings, type WifiStatus } from '$lib/platform_shared/rest_message'
let networkEditable: KnownNetworkItem = $state(KnownNetworkItem.create()) let networkEditable: KnownNetworkItem = $state(KnownNetworkItem.create())
+13 -22
View File
@@ -1,20 +1,15 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest' import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { WebSocketServer } from 'ws' import { WebSocketServer } from 'ws'
import { decodeMessage, MESSAGE_KEY_TO_TAG, socket } from '../../src/lib/stores/socket' import { decodeMessage, MESSAGE_KEY_TO_TAG, socket } from '../../src/lib/stores/socket'
import { import { IMUData, PingMsg, PongMsg, Message } from '../../src/lib/platform_shared/message'
IMUData,
PingMsg,
PongMsg,
WebsocketMessage
} from '../../src/lib/platform_shared/websocket_message'
// Helper function to create encoded WebSocket messages // Helper function to create encoded WebSocket messages
function createEncodedMessage(messageType: 'imu' | 'rssi' | 'mode', data: unknown): Uint8Array { function createEncodedMessage(messageType: 'imu' | 'rssi' | 'mode', data: unknown): Uint8Array {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const message: any = {} const message: any = {}
message[messageType] = data message[messageType] = data
const wsMessage = WebsocketMessage.create(message) const wsMessage = Message.create(message)
return WebsocketMessage.encode(wsMessage).finish() return Message.encode(wsMessage).finish()
} }
describe.sequential('WebSocket Integration Tests', () => { describe.sequential('WebSocket Integration Tests', () => {
@@ -130,7 +125,7 @@ describe.sequential('WebSocket Integration Tests', () => {
try { try {
// Decode the protobuf message // Decode the protobuf message
const decoded = WebsocketMessage.decode(new Uint8Array(data)) const decoded = Message.decode(new Uint8Array(data))
// console.log('Server: Decoded message:', JSON.stringify(decoded, null, 2)) // console.log('Server: Decoded message:', JSON.stringify(decoded, null, 2))
// Only resolve if we got actual IMU data // Only resolve if we got actual IMU data
@@ -193,9 +188,9 @@ describe.sequential('WebSocket Integration Tests', () => {
setTimeout(() => { setTimeout(() => {
console.log('Client: Sending invalid message type...') console.log('Client: Sending invalid message type...')
// Send any invalid message type // Send any invalid message type
const wsm = WebsocketMessage.create() const wsm = Message.create()
try { try {
socket.sendEvent(WebsocketMessage as any, wsm) socket.sendEvent(Message as any, wsm)
clearTimeout(timeout) clearTimeout(timeout)
reject(new Error('Expected sendEvent to throw, but it did not')) reject(new Error('Expected sendEvent to throw, but it did not'))
} catch (e) { } catch (e) {
@@ -208,7 +203,7 @@ describe.sequential('WebSocket Integration Tests', () => {
}) })
}) })
describe('WebsocketMessage Protobuf Encoding/Decoding', () => { describe('Message Protobuf Encoding/Decoding', () => {
it('should encode and decode IMU data correctly', () => { it('should encode and decode IMU data correctly', () => {
const imuData = IMUData.create({ const imuData = IMUData.create({
x: 3.25, x: 3.25,
@@ -233,21 +228,17 @@ describe('WebsocketMessage Protobuf Encoding/Decoding', () => {
}) })
it('should encode and decode two empty types correctly', () => { it('should encode and decode two empty types correctly', () => {
const encoded_ping = WebsocketMessage.encode( const encoded_ping = Message.encode(Message.create({ pingmsg: PingMsg.create() })).finish()
WebsocketMessage.create({ pingmsg: PingMsg.create() })
).finish()
const decoded_ping = decodeMessage(encoded_ping.buffer) const decoded_ping = decodeMessage(encoded_ping.buffer)
expect(decoded_ping.tag).toBe(MESSAGE_KEY_TO_TAG.get('pingmsg')) expect(decoded_ping.tag).toBe(MESSAGE_KEY_TO_TAG.get('pingmsg'))
const encoded_pong = WebsocketMessage.encode( const encoded_pong = Message.encode(Message.create({ pongmsg: PongMsg.create() })).finish()
WebsocketMessage.create({ pongmsg: PongMsg.create() })
).finish()
const decoded_pong = decodeMessage(encoded_pong.buffer) const decoded_pong = decodeMessage(encoded_pong.buffer)
expect(decoded_pong.tag).toBe(MESSAGE_KEY_TO_TAG.get('pongmsg')) expect(decoded_pong.tag).toBe(MESSAGE_KEY_TO_TAG.get('pongmsg'))
}) })
it('should encode and decode complete WebsocketMessage', () => { it('should encode and decode complete Message', () => {
const original = WebsocketMessage.create({ const original = Message.create({
imu: IMUData.create({ imu: IMUData.create({
x: 3.25, x: 3.25,
y: 2.5, y: 2.5,
@@ -259,8 +250,8 @@ describe('WebsocketMessage Protobuf Encoding/Decoding', () => {
}) })
}) })
const encoded = WebsocketMessage.encode(original).finish() const encoded = Message.encode(original).finish()
const decoded = WebsocketMessage.decode(encoded) const decoded = Message.decode(encoded)
expect(decoded.imu).toBeDefined() expect(decoded.imu).toBeDefined()
expect(decoded.imu?.x).toBe(3.25) expect(decoded.imu?.x).toBe(3.25)
+4 -4
View File
@@ -42,7 +42,7 @@ class CommAdapterBase {
MessageTraits<T>::assign(msg_, data); MessageTraits<T>::assign(msg_, data);
pb_ostream_t stream = pb_ostream_from_buffer(buffer_, sizeof(buffer_)); pb_ostream_t stream = pb_ostream_from_buffer(buffer_, sizeof(buffer_));
if (!pb_encode(&stream, socket_message_WebsocketMessage_fields, &msg_)) { if (!pb_encode(&stream, socket_message_Message_fields, &msg_)) {
return; return;
} }
@@ -86,10 +86,10 @@ class CommAdapterBase {
void sendPong(int cid) { void sendPong(int cid) {
uint8_t pongBuffer[16]; uint8_t pongBuffer[16];
msg_.which_message = socket_message_WebsocketMessage_pongmsg_tag; msg_.which_message = socket_message_Message_pongmsg_tag;
msg_.message.pongmsg = socket_message_PongMsg_init_zero; msg_.message.pongmsg = socket_message_PongMsg_init_zero;
pb_ostream_t stream = pb_ostream_from_buffer(pongBuffer, sizeof(pongBuffer)); pb_ostream_t stream = pb_ostream_from_buffer(pongBuffer, sizeof(pongBuffer));
if (pb_encode(&stream, socket_message_WebsocketMessage_fields, &msg_)) { if (pb_encode(&stream, socket_message_Message_fields, &msg_)) {
send(pongBuffer, stream.bytes_written, cid); send(pongBuffer, stream.bytes_written, cid);
} }
} }
@@ -97,7 +97,7 @@ class CommAdapterBase {
SemaphoreHandle_t mutex_; SemaphoreHandle_t mutex_;
std::map<int32_t, std::list<int>> client_subscriptions_; std::map<int32_t, std::list<int>> client_subscriptions_;
ProtoDecoder decoder_; ProtoDecoder decoder_;
socket_message_WebsocketMessage msg_ = socket_message_WebsocketMessage_init_zero; socket_message_Message msg_ = socket_message_Message_init_zero;
uint8_t buffer_[PROTO_BUFFER_SIZE]; uint8_t buffer_[PROTO_BUFFER_SIZE];
private: private:
+16 -17
View File
@@ -2,7 +2,7 @@
#include <pb_encode.h> #include <pb_encode.h>
#include <pb_decode.h> #include <pb_decode.h>
#include <platform_shared/websocket_message.pb.h> #include <platform_shared/message.pb.h>
#include <functional> #include <functional>
#include <map> #include <map>
@@ -11,16 +11,16 @@
template <typename T> template <typename T>
struct MessageTraits; struct MessageTraits;
#define DEFINE_MESSAGE_TRAITS(DataType, field) \ #define DEFINE_MESSAGE_TRAITS(DataType, field) \
template <> \ template <> \
struct MessageTraits<socket_message_##DataType> { \ struct MessageTraits<socket_message_##DataType> { \
static constexpr pb_size_t tag = socket_message_WebsocketMessage_##field##_tag; \ static constexpr pb_size_t tag = socket_message_Message_##field##_tag; \
static void assign(socket_message_WebsocketMessage& msg, const socket_message_##DataType& data) { \ static void assign(socket_message_Message& msg, const socket_message_##DataType& data) { \
msg.message.field = data; \ msg.message.field = data; \
} \ } \
static const socket_message_##DataType& access(const socket_message_WebsocketMessage& msg) { \ static const socket_message_##DataType& access(const socket_message_Message& msg) { \
return msg.message.field; \ return msg.message.field; \
} \ } \
}; };
DEFINE_MESSAGE_TRAITS(IMUData, imu) DEFINE_MESSAGE_TRAITS(IMUData, imu)
@@ -42,7 +42,6 @@ DEFINE_MESSAGE_TRAITS(ServoStateData, servo_state)
DEFINE_MESSAGE_TRAITS(CorrelationRequest, correlation_request) DEFINE_MESSAGE_TRAITS(CorrelationRequest, correlation_request)
DEFINE_MESSAGE_TRAITS(CorrelationResponse, correlation_response) DEFINE_MESSAGE_TRAITS(CorrelationResponse, correlation_response)
#undef DEFINE_MESSAGE_TRAITS #undef DEFINE_MESSAGE_TRAITS
class ProtoDecoder { class ProtoDecoder {
@@ -65,20 +64,20 @@ class ProtoDecoder {
bool decode(const uint8_t* data, size_t len, int clientId) { bool decode(const uint8_t* data, size_t len, int clientId) {
pb_istream_t stream = pb_istream_from_buffer(data, len); pb_istream_t stream = pb_istream_from_buffer(data, len);
if (!pb_decode(&stream, socket_message_WebsocketMessage_fields, &msg_)) { if (!pb_decode(&stream, socket_message_Message_fields, &msg_)) {
return false; return false;
} }
switch (msg_.which_message) { switch (msg_.which_message) {
case socket_message_WebsocketMessage_sub_notif_tag: case socket_message_Message_sub_notif_tag:
if (subscribeHandler_) subscribeHandler_(msg_.message.sub_notif.tag, clientId); if (subscribeHandler_) subscribeHandler_(msg_.message.sub_notif.tag, clientId);
return true; return true;
case socket_message_WebsocketMessage_unsub_notif_tag: case socket_message_Message_unsub_notif_tag:
if (unsubscribeHandler_) unsubscribeHandler_(msg_.message.unsub_notif.tag, clientId); if (unsubscribeHandler_) unsubscribeHandler_(msg_.message.unsub_notif.tag, clientId);
return true; return true;
case socket_message_WebsocketMessage_pingmsg_tag: case socket_message_Message_pingmsg_tag:
if (pingHandler_) pingHandler_(clientId); if (pingHandler_) pingHandler_(clientId);
return true; return true;
@@ -94,7 +93,7 @@ class ProtoDecoder {
} }
private: private:
socket_message_WebsocketMessage msg_ = socket_message_WebsocketMessage_init_zero; socket_message_Message msg_ = socket_message_Message_init_zero;
SubscribeHandler subscribeHandler_; SubscribeHandler subscribeHandler_;
UnsubscribeHandler unsubscribeHandler_; UnsubscribeHandler unsubscribeHandler_;
PingHandler pingHandler_; PingHandler pingHandler_;
+1 -1
View File
@@ -3,7 +3,7 @@
#include <WiFi.h> #include <WiFi.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <PsychicHttp.h> #include <PsychicHttp.h>
#include "platform_shared/websocket_message.pb.h" #include "platform_shared/message.pb.h"
#define FT_ENABLED(feature) feature #define FT_ENABLED(feature) feature
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
#include <platform_shared/websocket_message.pb.h> #include <platform_shared/message.pb.h>
struct CommandMsg { struct CommandMsg {
float lx, ly, rx, ry, h, s, s1; float lx, ly, rx, ry, h, s, s1;
+1 -1
View File
@@ -8,7 +8,7 @@
#include <features.h> #include <features.h>
#include <settings/peripherals_settings.h> #include <settings/peripherals_settings.h>
#include <template/stateful_endpoint.h> #include <template/stateful_endpoint.h>
#include <platform_shared/websocket_message.pb.h> #include <platform_shared/message.pb.h>
#include <list> #include <list>
#include <SPI.h> #include <SPI.h>
+1 -4
View File
@@ -16,10 +16,7 @@ def compile_nanopb():
output_dir.mkdir(parents=True, exist_ok=True) output_dir.mkdir(parents=True, exist_ok=True)
proto_files = [ proto_files = [proto_dir / "message.proto"]
proto_dir / "websocket_message.proto",
proto_dir / "rest_message.proto"
]
print(f"Compiling protobuf files with nanopb...") print(f"Compiling protobuf files with nanopb...")
print(f" Proto dir: {proto_dir}") print(f" Proto dir: {proto_dir}")
@@ -1,9 +1,8 @@
syntax = "proto3"; syntax = "proto3";
package socket_message; package socket_message;
// Partial data types
message Vector { float x = 1; float y = 2; } message Vector { float x = 1; float y = 2; }
message I2CDevice { int32 address = 1; string part_number = 2; string name = 3; } message I2CDevice { int32 address = 1; string part_number = 2; string name = 3; }
message PinConfig { int32 pin = 1; string mode = 2; string type = 3; string role = 4; } message PinConfig { int32 pin = 1; string mode = 2; string type = 3; string role = 4; }
@@ -39,8 +38,6 @@ message FeaturesDataResponse {
message FeaturesDataRequest { } message FeaturesDataRequest { }
message CorrelationRequest { message CorrelationRequest {
uint32 correlation_id = 1; uint32 correlation_id = 1;
oneof request { oneof request {
@@ -49,6 +46,7 @@ message CorrelationRequest {
IMUCalibrateExecute imu_calibrate_execute = 30; IMUCalibrateExecute imu_calibrate_execute = 30;
} }
} }
message CorrelationResponse { message CorrelationResponse {
uint32 correlation_id = 1; uint32 correlation_id = 1;
uint32 status_code = 2; uint32 status_code = 2;
@@ -67,6 +65,7 @@ enum ModesEnum {
STAND = 4; STAND = 4;
WALK = 5; WALK = 5;
} }
message StaticSystemInformation { message StaticSystemInformation {
string esp_platform = 1; string esp_platform = 1;
string firmware_version = 2; string firmware_version = 2;
@@ -83,10 +82,12 @@ message StaticSystemInformation {
string cpu_reset_reason = 13; string cpu_reset_reason = 13;
} }
message IMUCalibrateData { bool success = 1; } message IMUCalibrateData { bool success = 1; }
message IMUCalibrateExecute {} message IMUCalibrateExecute {}
message ModeData { ModesEnum mode = 1; } message ModeData { ModesEnum mode = 1; }
message ControllerInputData { message ControllerInputData {
Vector left = 1; Vector left = 1;
Vector right = 2; Vector right = 2;
@@ -94,6 +95,7 @@ message ControllerInputData {
float speed = 4; float speed = 4;
float s1 = 5; float s1 = 5;
} }
message AnalyticsData { message AnalyticsData {
int32 max_alloc_heap = 1; int32 max_alloc_heap = 1;
int32 psram_size = 2; int32 psram_size = 2;
@@ -114,32 +116,46 @@ message ServoPWMData {
int32 servo_id = 1; int32 servo_id = 1;
uint32 servo_pwm = 2; uint32 servo_pwm = 2;
} }
message ServoStateData { message ServoStateData {
bool active = 1; bool active = 1;
} }
message AnglesData { repeated int32 angles = 1; } message AnglesData { repeated int32 angles = 1; }
message I2CScanData { repeated I2CDevice devices = 1; } message I2CScanData { repeated I2CDevice devices = 1; }
message I2CScanDataRequest {} message I2CScanDataRequest {}
message PeripheralSettingsData { int32 sda = 1; int32 scl = 2; int32 frequency = 3; repeated PinConfig pins = 4; } message PeripheralSettingsData { int32 sda = 1; int32 scl = 2; int32 frequency = 3; repeated PinConfig pins = 4; }
message PeripheralSettingsDataRequest {} message PeripheralSettingsDataRequest {}
message WifiSettingsData { string hostname = 1; bool priority_rssi = 2; repeated KnownNetworkItem wifi_networks = 3; } message WifiSettingsData { string hostname = 1; bool priority_rssi = 2; repeated KnownNetworkItem wifi_networks = 3; }
message RSSIData { int32 rssi = 1; } message RSSIData { int32 rssi = 1; }
message DownloadOTAData { string status = 1; int32 progress = 2; string error = 3; } message DownloadOTAData { string status = 1; int32 progress = 2; string error = 3; }
message SonarData { string dummy_field = 1; } message SonarData { string dummy_field = 1; }
message HumanInputData { message HumanInputData {
Vector left = 10; Vector right = 11; float height = 20; float speed = 21; float s1 = 22; Vector left = 10; Vector right = 11; float height = 20; float speed = 21; float s1 = 22;
} }
message SystemInformation { message SystemInformation {
AnalyticsData analytics_data = 1; StaticSystemInformation static_system_information = 2; AnalyticsData analytics_data = 1; StaticSystemInformation static_system_information = 2;
} }
enum WalkGaits { enum WalkGaits {
TROT = 0; TROT = 0;
CRAWL = 1; CRAWL = 1;
} }
message WalkGaitData { message WalkGaitData {
WalkGaits gait = 1; WalkGaits gait = 1;
} }
message KinematicData { message KinematicData {
float omega = 1; float omega = 1;
float phi = 2; float phi = 2;
@@ -150,15 +166,15 @@ message KinematicData {
} }
message SubscribeNotification { int32 tag = 1; } message SubscribeNotification { int32 tag = 1; }
message UnsubscribeNotification {int32 tag = 1; } message UnsubscribeNotification {int32 tag = 1; }
message PingMsg {} message PingMsg {}
message PongMsg {} message PongMsg {}
// WebSocket message wrapper // WebSocket message wrapper
// Only ONE field will be set at a time (oneof ensures this) message Message {
message WebsocketMessage {
oneof message { oneof message {
CorrelationRequest correlation_request = 10; CorrelationRequest correlation_request = 10;
CorrelationResponse correlation_response = 11; CorrelationResponse correlation_response = 11;
-12
View File
@@ -1,12 +0,0 @@
rest_message.WifiStatus.local_ip max_size:16
rest_message.WifiStatus.mac_address max_size:18
rest_message.WifiStatus.ssid max_size:33
rest_message.WifiStatus.bssid max_size:18
rest_message.WifiStatus.subnet_mask max_size:16
rest_message.WifiStatus.gateway_ip max_size:16
rest_message.WifiStatus.dns_ip_1 max_size:16
rest_message.WifiStatus.dns_ip_2 max_size:16
rest_message.WifiSettings.hostname max_size:32
rest_message.WifiSettings.wifi_networks max_count:8
-27
View File
@@ -1,27 +0,0 @@
syntax = "proto3";
import "websocket_message.proto";
// Note: This is most likely a "temporary" proto that will be redone, as these endpoints are static for the esp32, which means we are forced to use WiFi for communication
package rest_message;
message WifiStatus {
int32 status = 1;
string local_ip = 2;
string mac_address = 3;
float rssi = 4;
string ssid = 5;
string bssid = 6;
uint32 channel = 7;
string subnet_mask = 8;
string gateway_ip = 9;
string dns_ip_1 = 10;
optional string dns_ip_2 = 11;
}
message WifiSettings {
string hostname = 1;
bool priority_rssi = 2;
repeated socket_message.KnownNetworkItem wifi_networks = 3;
}