Skip to content

Commit 2026836

Browse files
authored
Merge pull request #99 from stanford-ssi/working-command-processing
Command Processing
2 parents 8be2042 + 0a6f89a commit 2026836

6 files changed

Lines changed: 170 additions & 193 deletions

File tree

src/slate/slate.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,15 @@ typedef struct samwise_slate
6262
/*
6363
* Command switch
6464
*/
65-
queue_t task1_data; // queues of this kind will exist for each task called
66-
// from radio com
67-
queue_t task2_data;
65+
queue_t payload_command_data;
6866

6967
uint8_t struct_buffer[MAX_DATASTRUCTURE_SIZE];
7068

7169
uint16_t num_uploaded_bytes;
7270
uint16_t packet_buffer_index;
7371
uint16_t last_place_on_packet;
7472
uint8_t uploading_command_id;
73+
uint8_t number_commands_processed;
7574

7675
/*
7776
* Radio

src/tasks/command/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
add_library(command_task command_task.c)
1+
add_library(command_task command_task.c command_parser.c)
22

33
# Specify targets to link compiled binaries
44
target_link_libraries(command_task PUBLIC slate common error rfm9x hardware_spi)

src/tasks/command/command_parser.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @author Thomas Haile
3+
* @date 2025-05-24
4+
*
5+
* Command parsing implementation
6+
*/
7+
8+
#include "command_parser.h"
9+
#include "macros.h"
10+
11+
/// @brief Parse packet and dispatch command to appropriate queue
12+
void dispatch_command(slate_t *slate, packet_t *packet)
13+
{
14+
slate->number_commands_processed++;
15+
16+
Command command_id = (Command)packet->data[0];
17+
LOG_INFO("Command ID Received: %i", command_id);
18+
19+
switch (command_id)
20+
{
21+
case NO_OP:
22+
{
23+
LOG_INFO("Number of Commands Executed: %d",
24+
slate->number_commands_processed);
25+
break;
26+
}
27+
28+
case PAYLOAD_EXEC:
29+
{
30+
PAYLOAD_COMMAND_DATA task;
31+
strlcpy(task.serialized_command, (char *)&packet->data[1],
32+
sizeof(task.serialized_command));
33+
34+
queue_try_add(&slate->payload_command_data, &task);
35+
36+
LOG_INFO("Payload: %s", task.serialized_command);
37+
break;
38+
}
39+
40+
/* Toggle Commands */
41+
// TODO: ADD HERE
42+
43+
default:
44+
LOG_ERROR("Unknown command ID: %i", command_id);
45+
break;
46+
}
47+
}

src/tasks/command/command_parser.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @author Thomas Haile
3+
* @date 2025-05-24
4+
*
5+
* Command parsing and data structure definitions
6+
*/
7+
8+
#pragma once
9+
10+
#include "packet.h"
11+
#include "slate.h"
12+
#include <stdbool.h>
13+
#include <stdint.h>
14+
#include <string.h>
15+
16+
typedef enum
17+
{
18+
NO_OP,
19+
PAYLOAD_EXEC
20+
// add more commands here as needed
21+
} Command;
22+
23+
// Packet configuration
24+
#define COMMAND_MNEMONIC_SIZE 1 // number of bytes used to identify command
25+
26+
/**
27+
* Command data structures
28+
*
29+
* How to add new command:
30+
* 1. Define command ID
31+
* 2. Define data structure (e.g., typedef struct { ... } TASK3_DATA;)
32+
* 3. Add queue initialization in command_task_init()
33+
* 4. Add case in dispatch_command()
34+
*/
35+
36+
typedef struct
37+
{
38+
char serialized_command[sizeof(((packet_t *)0)->data) -
39+
COMMAND_MNEMONIC_SIZE];
40+
} PAYLOAD_COMMAND_DATA;
41+
42+
void dispatch_command(slate_t *slate, packet_t *packet);

src/tasks/command/command_task.c

Lines changed: 60 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,60 @@
1-
/**
2-
* @author Sasha Luchyn + Michael Dalva
3-
* @date 2024-09-11
4-
*
5-
* Task to parse incoming bitstream and allocate data for according tasks
6-
*/
7-
8-
/* How to add new command (using an example of some task1")
9-
1. add a mnemonic code for the command
10-
eg: #define COMMAND1_ID 1
11-
12-
2. create or choose an existing data structure for this command. Define it in
13-
the packet.h file. eg: struct TASK1_DATA_STRUCT_FORMAT
14-
15-
3. create a queue in the slate.h file
16-
eg: queue_t task1_data;
17-
18-
4. create a struct for a new command
19-
eg: struct TASK1_DATA_STRUCT_FORMAT current_data_holder_task1;
20-
21-
5. initialize queue in the command_switch_task_init
22-
eg: queue_init(&slate->task1_data, sizeof(current_data_holder_task1),
23-
TASK1_QUEUE_LENGTH);
24-
25-
*note the TASK1_QUEUE_LENGTH is the length of the queu, in other words
26-
how many calls for that command can be queued simultaniously*
27-
28-
29-
6. add a case to the switch case in command_switch_dispatch
30-
eg:
31-
case COMMAND1_ID:{
32-
struct TASK1_DATA_STRUCT_FORMAT task;
33-
uint16_t task_size = sizeof(task);
34-
parse_packets_as_command(slate, task_size, COMMAND1_ID,
35-
&slate->task1_data); }break;
36-
37-
38-
7. All set! (hopefully)
39-
*/
40-
41-
#include "command_task.h"
42-
#include "macros.h"
43-
#include "packet.h"
44-
#include "pico/stdlib.h"
45-
#include "slate.h"
46-
47-
const int RADIO_PACKETS_OUT_MAX_LENGTH = 64; // max radio queue length
48-
const int COMMAND_MNEMONIC_BYTE_SIZE =
49-
1; // how many bytes are used to identify the command
50-
const int TASK1_QUEUE_LENGTH = 32; // max queue length for task 1
51-
52-
#define PACKET_BYTE_LENGTH 251 // in bytes TODO check?/ get from driver mod?
53-
#define STOP_BYTE \
54-
255 // stop byte is added on the last transmission of the packet (everything
55-
// afterwards is disregarded in that packet)
56-
#define COMMAND1_ID 1
57-
#define COMMAND2_ID 2
58-
59-
// in the end, we should replace these with just the size of the structs for
60-
// each command, that way we don't need to create random structs just to get the
61-
// size.
62-
TASK1_DATA current_data_holder_task1;
63-
TASK2_DATA current_data_holder_task2;
64-
65-
/// @brief Initialize the command switch task
66-
/// @param slate Address of the slate
67-
void command_task_init(slate_t *slate)
68-
{
69-
// initialize queue for radio input data,TODO: assumed to be initialized in
70-
// the radio module and comment out when merging
71-
queue_init(&slate->rx_queue, PACKET_BYTE_LENGTH * sizeof(uint8_t),
72-
RADIO_PACKETS_OUT_MAX_LENGTH);
73-
74-
// Initialize queues for storing processed commands
75-
queue_init(&slate->task1_data, sizeof(current_data_holder_task1),
76-
TASK1_QUEUE_LENGTH);
77-
queue_init(&slate->task2_data, sizeof(current_data_holder_task2),
78-
TASK1_QUEUE_LENGTH);
79-
80-
slate->num_uploaded_bytes =
81-
0; // Number of bytes currently uploaded to buffer
82-
slate->packet_buffer_index = 0; // Index of the position in payload buffer
83-
slate->uploading_command_id = 0; // number of command that is currently
84-
// being uploaded (0 if nothing uploading)
85-
}
86-
87-
/// @brief
88-
/// @param slate
89-
void command_task_dispatch(slate_t *slate)
90-
{
91-
int number_of_commands_to_process = 1;
92-
for (int i = 0; i < number_of_commands_to_process; i++)
93-
{
94-
95-
// This packet will store what is currently up next in the radio receive
96-
// queue
97-
packet_t packet;
98-
99-
// Peek at the upcoming item in the radio receive queue
100-
bool successful_peek = queue_try_remove(&slate->rx_queue, &packet);
101-
102-
if (successful_peek)
103-
{
104-
if (!is_packet_authenticated(&packet, slate->reboot_counter))
105-
{
106-
// Packet is not authenticated, drop it
107-
LOG_ERROR("Packet authentication failed. Dropping packet.");
108-
continue;
109-
}
110-
111-
/**
112-
* Update the command ID depending on if it was previously
113-
* uploading. If previously not loading (command id == 0) then reset
114-
* the task byte size.
115-
*/
116-
uint8_t command_id = packet.data[0];
117-
LOG_INFO("Command ID Recieved: %i", command_id);
118-
119-
/**
120-
* Pass specific structs and taks queues appropriate for each
121-
* command
122-
*/
123-
switch (command_id)
124-
{
125-
// COMMAND_ID NEED TO START FROM 1 BECAUSE 0 IS BEING USED AS
126-
// THE "NOT UPLOADING" INDEX
127-
case COMMAND1_ID:
128-
{
129-
TASK1_DATA task;
130-
memcpy(&task, packet.data + 1, sizeof(task));
131-
queue_try_add(&slate->task1_data, &task);
132-
LOG_INFO("struct 1: %i, %i", task);
133-
}
134-
break;
135-
case COMMAND2_ID:
136-
{
137-
TASK2_DATA task;
138-
memcpy(&task, packet.data + 1, sizeof(task));
139-
queue_try_add(&slate->task2_data, &task);
140-
LOG_INFO("struct 2: %i, %i", task.number, task.yes_no);
141-
}
142-
break;
143-
default:
144-
break;
145-
}
146-
}
147-
}
148-
}
149-
150-
sched_task_t command_task = {.name = "command",
151-
.dispatch_period_ms = 100,
152-
.task_init = &command_task_init,
153-
.task_dispatch = &command_task_dispatch,
154-
/* Set to an actual value on init */
155-
.next_dispatch = 0};
1+
/**
2+
* @author Thomas Haile
3+
* @date 2025-05-24
4+
*
5+
* Task management for command processing
6+
*/
7+
8+
#include "command_task.h"
9+
#include "command_parser.h"
10+
#include "macros.h"
11+
#include "pico/stdlib.h"
12+
#include "slate.h"
13+
14+
#define PACKET_BYTE_LENGTH 251 // in bytes TODO check?/ get from driver mod?
15+
16+
const int RADIO_PACKETS_OUT_MAX_LENGTH = 64;
17+
const int PAYLOAD_DATA_CAPACITY = 32;
18+
19+
/// @brief Initialize the command switch task
20+
/// @param slate Slate
21+
void command_task_init(slate_t *slate)
22+
{
23+
// Initialize queue for radio input data
24+
queue_init(&slate->rx_queue, PACKET_BYTE_LENGTH * sizeof(uint8_t),
25+
RADIO_PACKETS_OUT_MAX_LENGTH);
26+
27+
// Initialize queues for storing processed commands
28+
queue_init(&slate->payload_command_data, sizeof(PAYLOAD_COMMAND_DATA),
29+
PAYLOAD_DATA_CAPACITY);
30+
31+
slate->num_uploaded_bytes = 0;
32+
slate->packet_buffer_index = 0;
33+
slate->uploading_command_id = 0;
34+
slate->number_commands_processed = 0;
35+
}
36+
37+
/// @brief Process incoming radio packets and dispatch commands
38+
void command_task_dispatch(slate_t *slate)
39+
{
40+
packet_t packet;
41+
42+
// Process one packet per dispatch cycle
43+
if (queue_try_remove(&slate->rx_queue, &packet))
44+
{
45+
if (!is_packet_authenticated(&packet, slate->reboot_counter))
46+
{
47+
LOG_ERROR("Packet authentication failed. Dropping packet.");
48+
return;
49+
}
50+
51+
// Parse and process the command
52+
dispatch_command(slate, &packet);
53+
}
54+
}
55+
56+
sched_task_t command_task = {.name = "command",
57+
.dispatch_period_ms = 100,
58+
.task_init = &command_task_init,
59+
.task_dispatch = &command_task_dispatch,
60+
.next_dispatch = 0};

src/tasks/command/command_task.h

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,18 @@
1-
/**
2-
* @author Sasha Luchyn
3-
* @date 2024-09-11
4-
*/
5-
6-
#pragma once
7-
8-
#include <string.h>
9-
10-
#include "slate.h"
11-
#include "state_machine.h"
12-
#include "typedefs.h"
13-
14-
void command_task_init(slate_t *slate);
15-
void command_task_dispatch(slate_t *slate);
16-
17-
extern sched_task_t command_task;
18-
19-
/*
20-
21-
Here is where we will define all of the structs that hold arguments for calling
22-
certain tasks.
23-
24-
*/
25-
typedef struct
26-
{
27-
28-
} TASK1_DATA;
29-
30-
typedef struct
31-
{
32-
bool yes_no;
33-
uint16_t number;
34-
} TASK2_DATA;
1+
2+
/**
3+
* @author Thomas Haile
4+
* @date 2025-05-24
5+
*
6+
* Task management for command processing
7+
*/
8+
9+
#pragma once
10+
11+
#include "slate.h"
12+
#include "state_machine.h"
13+
#include "typedefs.h"
14+
15+
void command_task_init(slate_t *slate);
16+
void command_task_dispatch(slate_t *slate);
17+
18+
extern sched_task_t command_task;

0 commit comments

Comments
 (0)