From 2c0dd5ea355a91d6ae42a3c9236f981792a59211 Mon Sep 17 00:00:00 2001 From: Sirblobfish Date: Sat, 1 Nov 2014 16:05:22 -0700 Subject: [PATCH] Implement sensor value updates and add those structs to yaml (Removes yaml comments?) --- .../common_defs/radio_protocol_ng.yaml | 227 ++++-------------- controller/src/radio_config.c | 71 +++++- 2 files changed, 115 insertions(+), 183 deletions(-) diff --git a/angel-player/src/chrome/content/common_defs/radio_protocol_ng.yaml b/angel-player/src/chrome/content/common_defs/radio_protocol_ng.yaml index 92caed22..d1c6611d 100644 --- a/angel-player/src/chrome/content/common_defs/radio_protocol_ng.yaml +++ b/angel-player/src/chrome/content/common_defs/radio_protocol_ng.yaml @@ -14,53 +14,15 @@ repr: unsigned kind: alien size: 8 +- name: float + repr: floating + kind: alien + size: 4 + + + + -# Radio needs to transmit the following: - -# Robot Host -# --------------------------------------------------- -# Telemetry → -# Control signals ← -# Code ← -# Bulk state → -# Debug <-> -# Sensor probing <-> - - - -# NDL3 ports: -# NDL3_UBJSON_PORT -# Reliable, structured UBJSON data -# Usage: -# Debug -# NDL3_STRING_PORT -# Reliable, unstructured data -# Usage: -# stdout -# stdin? -# NDL3_CODE_PORT -# Reliable, structured binary data -# Usage: -# Code -# Bulk state? -# NDL3_CONFIG_PORT -# Reliable, structured binary data -# Usage: -# start/stop VM -# patch? -# device probing -# NDL3_FAST_PORT -# Unreliable, structured UBJSON data -# Usage: -# Telemetry -# Controls - - - - -# UBJSON (reliable) port: -# const TYPE_MEMOIZE_CLEAR 0x00 -# const TYPE_MEMOIZE_STRING 0x01 - name: TYPE_MEMOIZE_CLEAR kind: const value: 0x00 @@ -68,23 +30,11 @@ kind: const value: 0x01 -# [ -# 123, // type -# { // Only for TYPE_MEMOIZE_STRING -# 123: “str” // Memoize the string “str” with id 123 -# … -# } -# ] -# String port: -# Raw, unencapsulated strings for stdin/stdout -# Code port: -# #define ID_SEND_CODE_BLOB 0x00 - name: ID_SEND_CODE_BLOB kind: const value: 0x00 -# #define ID_GET_TRACE_BLOB 0x01 - name: ID_GET_TRACE_BLOB kind: const value: 0x01 @@ -98,57 +48,49 @@ type: uint32_t - name: data type: uint8_t[] -# struct code_port (packed) { -# uint8_t id -# uint32_t len -# uint8_t[] data -# } - -# Config port: -# #define ID_START_VM + - name: ID_START_VM kind: const value: 0x00 -# #define ID_STOP_VM - name: ID_STOP_VM kind: const value: 0x01 -# #define ID_LOAD_MAIN_THREAD 0x02 - name: ID_LOAD_MAIN_THREAD kind: const value: 0x02 -# #define ID_CONTROL_UNFREEZE 0x10 - name: ID_CONTROL_UNFREEZE kind: const value: 0x10 -# #define ID_CONTROL_STOP 0x11 - name: ID_CONTROL_STOP kind: const value: 0x11 -# #define ID_CONTROL_UNPOWERED 0x12 - name: ID_CONTROL_UNPOWERED kind: const value: 0x12 -# #define ID_CONTROL_SET_AUTON 0x13 - name: ID_CONTROL_SET_AUTON kind: const value: 0x13 -# #define ID_CONTROL_SET_TELEOP 0x14 - name: ID_CONTROL_SET_TELEOP kind: const value: 0x14 -# #define ID_DEVICE_GET_LIST 0x20 - name: ID_DEVICE_GET_LIST kind: const value: 0x20 -# #define ID_DEVICE_READ_DESCRIPTOR 0x21 - name: ID_DEVICE_READ_DESCRIPTOR kind: const value: 0x21 -# #define ID_DEVICE_ENABLE_BLINK 0x22 - name: ID_DEVICE_ENABLE_BLINK kind: const value: 0x22 + name: ID_DEVICE_START_UPDATES + kind: const + value: 0x23 + name: ID_DEVICE_STOP_UPDATES + kind: const + value: 0x24 + name: ID_DEVICE_VALUE_UPDATE + kind: const + value: 0x23 - name: device_list_t kind: struct @@ -157,7 +99,7 @@ - name: count type: uint32_t - name: dids - type: uint16_t[] + type: uint64_t[] - name: device_read_descriptor_req_t kind: struct @@ -170,10 +112,6 @@ - name: len type: uint16_t -- name: LENGTH_AT_LEAST_ONE - kind: const - value: 0x01 - - name: device_read_descriptor_resp_t kind: struct packed: true @@ -181,7 +119,18 @@ - name: did type: uint64_t - name: data - type: uint8_t[LENGTH_AT_LEAST_ONE] + type: uint8_t[1] + +- name: device_value_update + kind: struct + packed: true + slots: + - name: timestamp + type: uint32_t + - name: count + type: uint32_t + - name: devices + type: device_value[] - name: device_blink_t kind: struct @@ -192,6 +141,24 @@ - name: blink_on type: uint8_t +- name: channel_value + kind: struct + packed: true + slots: + - name: value + type: float + +- name: device_value + kind: struct + packed: true + slots: + - name: did + type: uint64_t + - name: count + type: uint32_t + - name: values + type: channel_value[] + - name: config_port_data kind: union slots: @@ -206,7 +173,6 @@ - name: nothing type: uint8_t - - name: config_port kind: struct packed: true @@ -215,31 +181,8 @@ type: uint8_t - name: data type: config_port_data -# struct config_port (packed) { -# uint8_t id -# union { -# struct device_list { -# uint32_t count -# uint64_t[] dids -# } -# struct device_read_descriptor_req { -# uint64_t did -# uint16_t start -# uint16_t len -# } -# struct device_read_descriptor_resp { -# uint8_t[] data -# } -# struct device_blink { -# uint8_t blink_on -# uint64_t did -# } -# } -# } - -# Fast port: -# const TYPE_JOY_DATA 0x00 -# const TYPE_TELEM_DATA 0x01 + + - name: TYPE_JOY_DATA kind: const value: 0x00 @@ -247,18 +190,6 @@ kind: const value: 0x01 -# [ -# nnn, // type -# { -# 123: [1,0,1,…] // Telemetry or joystick, can be repeated -# } // 123 = memoized string -# // array = samples (for telemetry) -# // channel (for joystick) -# ] - - - - @@ -272,48 +203,7 @@ -# More detailed brain dumps: -# Notes on UBJSON -# UBJSON is only available to Lua. Any state that needs to be available to C cannot be sent via UBJSON (easily). Any data from UBJSON can be condidered “untrusted” (not resistant against tampering from within studencode) -# String memoization -# The purpose of string memoization is to reduce the number of bytes that need to be sent repeatedly. For example, suppose there was a string “joy0-analog” that needed to be sent in every joystick packet. This takes up 11 bytes in every telemetry packet that conveys no additional information after the first time. String memoization solves this by having the host send a unique number and the string to the controller once at the beginning. The string will then be replaced by this number, which will usually take only 1 byte. -# The host can memoize strings sent to the controller. The controller can also send back a TYPE_MEMOIZE_STRING back to the host for e.g. telemetry. IDs may overlap between the two. -# TYPE_MEMOIZE_CLEAR clears both directions -# String port -# This port is directly mapped to stdio. No encapsulation -# printf() from robot appears here -# data written to this port should be made available via scanf, etc. -# Code/trace -# Code is always host-->robot -# Trace is always robot-->host -# Code is not run immediately. Running the code is controlled by the config port. -# How to trigger trace is TBD -# Config -# The majority of host “controlling” the robot happens here. This includes field control logic. -# VM state control -# The host can completely stop execution of any studentcode by sending a stop command. This tears down the VM and frees all of the associated state. -# Start will cause a VM to be created. Standard libraries will be loaded but no studentcode will be. -# Load main thread is used to load the studentcode. The studentcode must have been sent earlier using the code port. -# Replacing the studentcode should work. This needs to be worked out on the runtime dide. Loading studentcode when there is already a studentcode should tear down the student-controlled parts of the VM without rebooting the entire VM. -# Patching will be controlled here. Exact behavior TBD. -# Field control logic -# Field control logic is here (rather than e.g. a UBJSON port) so that it is impossible for students to cheat it. -# There are three stop/run states (unfreeze, stop, unpowered) because of corner-cases with e.g. servos. There are extensive notes on this elsewhere. -# Autonomous and teleop are needed by the C code to block access to the joystick (PiER never did this). It will also be exposed to Lua -# Smartdevice logic -# Smartdevices will be enumerated by the firmware at TBD time. The host can request a list of devices using the get list command. This will return a list of smart device UUIDs. -# The firmware will automatically handle bw allocation and most of the details of communicating with devices. The UI needs to handle human-readable descriptors and binding devices to meaningful names. -# The UI can get descriptions of the devices by reading the descriptor information. See smartdevice spec. -# In order to help identify devices that are already mounted on the robot, the UI can command the LED on the smartdevice to blink. -# Joystick -# Joystick packets contain a number of channels that each contain a number of values. Each individual value can be referred to as - -# For the Xbox 360 joystick, there would be 2 channels: button, analog with 11 and 8 values -# Multiple joysticks can be sent in the same packet -# Telemetry -# Telemetry contains channels that can contain 1 or more samples -# Behavior very similar to joysticks -# Telemetry is batched up and sent at intervals @@ -327,18 +217,3 @@ -# Sample exchanges (PC <--> robot); -# config port: 0x01 → (stop VM, reset (almost) all state) -# config port: 0x20 → (get device list) -# config port: ← 0x20 0x01 0x00 0x00 0x00 0xAA 0xBB 0xCC 0xDD 0xEE 0xFF 0x00 0x01 -# config port: 0x21 [0xAA … 0x01] 0x00 0x00 0x02 0x00 → (read descriptor length) -# config port: ← 0x21 0x55 0x00 -# config port: 0x21 [0xAA … 0x01] 0x00 0x00 0x55 0x00 → (read entire descriptor) -# config port: ← 0x21 … -# config port: 0x00 → (start VM) -# code port: 0x00 0x23 0x01 0xXX 0xXX … → (buffer code) -# config port: 0x02 → (load code into main thread) -# ubjson reliable: [1, {0: “joy0-analog”, 1: “joy0-button”}] → (memoize string) -# config port: 0x10 → (unfreeze) -# ubjson fast: [0, 0: [1,1,0.5, …], 1: [true, false, …]] → (joystick) -# ... diff --git a/controller/src/radio_config.c b/controller/src/radio_config.c index c5a19765..aec96e19 100644 --- a/controller/src/radio_config.c +++ b/controller/src/radio_config.c @@ -54,8 +54,7 @@ void receiveConfigPort(config_port *port, size_t len) { } config_port *getDeviceList() { - config_port *port = pvPortMalloc(sizeof(uint8_t) + sizeof(uint32_t) - + SMART_ID_LEN*numSensors); + config_port *port = pvPortMalloc( sizeof(uint8_t) + sizeof(uint32_t) + SMART_ID_LEN*numSensors); port->id = ID_DEVICE_GET_LIST; port->data.device_list.count = numSensors; for (int i = 0; i < numSensors; i++) { @@ -68,11 +67,48 @@ config_port *getDeviceList() { return port; } +config_port *getValueUpdate() { + uint8_t total_number_of_channels = 0; + for(i=0;ichannels) + } + config_port *port = pvPortMalloc( sizeof(uint8_t) + sizeof(TickType_t) +sizeof(uint32_t) + numSensors*SMART_ID_LEN + numSensors*sizeof(uint8_t) + total_number_of_channels*sizeof(uint64_t)); //TODO(sirblobfish): uint64_t is probably not the correct size for sensor values + port->id = ID_DEVICE_VALUE_UPDATE; + port->data.device_value_update.timestamp = xTaskGetTickCount(); + port->data.device_value_update.count = numSensors; + for (int i = 0; i < numSensors; i++) { + uint64_t temp = 0; + for (int j = SMART_ID_LEN-1; j > 0; j--) { + temp = ((temp << 8) | sensorArr[i]->id[j]); + } + port->data.device_value_update.devices[i].did = temp; + port->data.device_value_update.devices[i].count = sensorArr[i]->channelsNum; + for (int k = 0; k < port->sensorArr[i]->channelsNum; k++){ + ss_get_value(sensorArr[i]->channels[k], port->data.device_value_update.devices[i].values[k], sensorArr[i]->channels[k].outgoingLen); + } + return port; + static portTASK_FUNCTION_PROTO(radioConfigTask, pvParameters) { (void) pvParameters; + int send_messages_toggle = 0; + TickType_t time_offset = 100; + TickType_t next_time_stamp=0; + TickType_t wait_time = portMAX_DELAY; + while (1) { ConfigMessage msg; - while (xQueueReceive(configMessageQueue, &msg, portMAX_DELAY) == pdTRUE) { + if (send_messages_toggle == 1){ + current_time_stamp = xTaskGetTickCount(); + time_difference = current_time_stamp - next_time_stamp; + if (time_difference > offset) //if time_difference (unsigned) is negative, hence, super big + { + wait_time = next_time_stamp - current_time_stamp; + next_time_stamp = current_time_stamp + time_offset; + } + else {wait_time = 1} //Just a really small wait time so that the signal can be sent almost immediately + } + } + while (xQueueReceive(configMessageQueue, &msg, wait_time) == pdTRUE) { switch (msg.port->id) { // TODO(vdonato): Implement the rest case ID_START_VM: break; @@ -96,20 +132,41 @@ static portTASK_FUNCTION_PROTO(radioConfigTask, pvParameters) { setGameMode(RuntimeModeTeleop); break; case ID_DEVICE_GET_LIST: { - config_port *deviceList = getDeviceList(); - size_t size = sizeof(uint8_t) + sizeof(uint32_t) + - SMART_ID_LEN*numSensors; - radioPushConfig(deviceList, size); + if(send_messages_toggle == 1){ + config_port *deviceList = getDeviceList(); + size_t size = sizeof(uint8_t) + sizeof(uint32_t) + + SMART_ID_LEN*numSensors; + radioPushConfig(deviceList, size); + } } break; case ID_DEVICE_READ_DESCRIPTOR: break; case ID_DEVICE_ENABLE_BLINK: break; + + case ID_DEVICE_START_UPDATES: + send_messages_toggle = 1 + initial_time_stamp = xTaskGetTickCount() + break; + case ID_DEVICE_STOP_UPDATES: + send_messages_toggle = 0 + break; + case ID_DEVICE_VALUE_UPDATE: { + config_port *device_value_update = getValueUpdate(); + size_t value_size = sizeof(device_value_update); + radioPushConfig(device_value_update, value_size); + } + break; + default: + config_port *device_value_update = getValueUpdate(); + size_t value_size = sizeof(device_value_update); + radioPushConfig(device_value_update, value_size); break; } vPortFree(msg.port); } } } +