Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions pstop_c/examples/client/client_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "transport/udp/udp_transport.h"
#include "pstop/device_id.h"
#include "pstop/os.h"
#include "pstop/machine_client_data.h"
#include "pstop/protocol_data.h"

udp_transport_data_t udp_transport;

Expand Down Expand Up @@ -50,7 +50,7 @@ read_msg(udp_transport_data_t *transport, pstop_os_env *env, pstop_msg_t *resp,
}

int
send_msg(udp_transport_data_t *transport, pstop_os_env *env, machine_client_data_t *machine, const device_id_t *uuid, uint8_t msg)
send_msg(udp_transport_data_t *transport, pstop_os_env *env, protocol_data_t *machine, const device_id_t *uuid, uint8_t msg)
{
uint8_t reqbytes[PSTOP_MESSAGE_SIZE];

Expand Down Expand Up @@ -83,15 +83,15 @@ send_msg(udp_transport_data_t *transport, pstop_os_env *env, machine_client_data
}

void
send_bond(udp_transport_data_t *transport, pstop_os_env *env, machine_client_data_t *machine, const device_id_t *uuid)
send_bond(udp_transport_data_t *transport, pstop_os_env *env, protocol_data_t *machine, const device_id_t *uuid)
{
if(send_msg(transport, env, machine, uuid, PSTOP_MESSAGE_BOND)) {
fprintf(stderr, "BOND Success\n");
}
}

void
send_ok(udp_transport_data_t *transport, pstop_os_env *env, machine_client_data_t *machine, const device_id_t *uuid, int is_ok)
send_ok(udp_transport_data_t *transport, pstop_os_env *env, protocol_data_t *machine, const device_id_t *uuid, int is_ok)
{
if(is_ok) {
if(send_msg(transport, env, machine, uuid, PSTOP_MESSAGE_OK)) {
Expand All @@ -106,7 +106,7 @@ send_ok(udp_transport_data_t *transport, pstop_os_env *env, machine_client_data_
}

void
send_unbond(udp_transport_data_t *transport, pstop_os_env *env, machine_client_data_t *machine, const device_id_t *uuid)
send_unbond(udp_transport_data_t *transport, pstop_os_env *env, protocol_data_t *machine, const device_id_t *uuid)
{
if(send_msg(transport, env, machine, uuid, PSTOP_MESSAGE_UNBOND)) {
fprintf(stderr, "UNBOND Success\n");
Expand Down Expand Up @@ -135,8 +135,8 @@ main(int argc, char *argv[])
return -1;
}

machine_client_data_t machine;
machine_client_init(&machine);
protocol_data_t machine;
protocol_data_init(&machine);

pstop_os_env env;
pstop_os_env_init(&env);
Expand All @@ -160,11 +160,11 @@ main(int argc, char *argv[])
fprintf(stderr, "uuid=%d\n", this_uuid.data[15]);
send_bond(&udp_transport, &env, &machine, &this_uuid);

sleep_ms(300);
sleep_ms(750);

for(int i = 0; i < 30; ++i) {
send_ok(&udp_transport, &env, &machine, &this_uuid, (i % 2));
sleep_ms(300);
sleep_ms(750);
}

send_unbond(&udp_transport, &env, &machine, &this_uuid);
Expand Down
7 changes: 6 additions & 1 deletion pstop_c/examples/machine/machine_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ int
robot_status(pstop_status_message_t status)
{
if(lastStatus != status) {
fprintf(stderr, "Robot Status = %d\n", (int)status);
if(status == PSTOP_STATUS_OK) {
fprintf(stderr, "Robot Status = OK\n");
}
else {
fprintf(stderr, "Robot Status = STOP\n");
}
lastStatus = status;
}

Expand Down
2 changes: 1 addition & 1 deletion pstop_c/pstop/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ find_package(unity REQUIRED)
add_library(pstop
src/pstop/checksum.c
src/pstop/device_id.c
src/pstop/machine_client_data.c
src/pstop/machine.c
src/pstop/os.c
src/pstop/protocol.c
src/pstop/protocol_data.c
src/pstop/pstop_application.c
src/pstop/pstop_client_data.c
src/pstop/pstop_msg.c
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-FileCopyrightText: 2026 Polymath Robotics, Inc.
// SPDX-License-Identifier: Apache-2.0

#ifndef PSTOP_MACHINE_CLIENT_DATA_H
#define PSTOP_MACHINE_CLIENT_DATA_H
#ifndef PSTOP_PROTOCOL_DATA_H
#define PSTOP_PROTOCOL_DATA_H

#include <stdint.h>

Expand All @@ -23,8 +23,8 @@ typedef struct {

uint32_t last_counter;

} machine_client_data_t;
} protocol_data_t;

void machine_client_init(machine_client_data_t *client);
void protocol_data_init(protocol_data_t *client);

#endif /* PSTOP_MACHINE_CLIENT_DATA_H */
#endif /* PSTOP_PROTOCOL_DATA_H */
14 changes: 2 additions & 12 deletions pstop_c/pstop/include/pstop/pstop_client_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "pstop/device_id.h"
#include "pstop/constants.h"
#include "pstop/protocol_data.h"

typedef enum {

Expand All @@ -24,18 +25,7 @@ typedef struct {

uint32_t local_client_id;

device_id_t client_id;

// last time we've heard from this client
uint64_t last_timestamp;

// how frequently we should hear from this client
uint64_t heartbeat_ms;

// the counter indicating each message we are sending
uint32_t msg_counter;

uint32_t last_counter;
protocol_data_t client_data;

// approx how far off is the client's clock from this clock
// compare the incoming pstop_msg.stamp to this clock.
Expand Down
43 changes: 29 additions & 14 deletions pstop_c/pstop/src/pstop/machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ init_new_client(pstop_application_t *application, pstop_client_data_t *client, c
{
uint64_t now = application->env.get_time_cb();

device_id_copy(&(client->client_id), &(msg->id));
client->last_timestamp = now;
client->heartbeat_ms = application->app_config.default_timeout_ms;
client->msg_counter = 0U;
client->last_counter = 0U;
device_id_copy(&(client->client_data.client_id), &(msg->id));
client->client_data.last_timestamp = now;
client->client_data.heartbeat_ms = application->app_config.default_timeout_ms;
client->client_data.msg_counter = 0U;
client->client_data.last_counter = 0U;

if(now >= msg->stamp) {
client->clock_drift = (int64_t)(now - msg->stamp);
Expand Down Expand Up @@ -224,7 +224,7 @@ machine_handle_message(pstop_machine_t *machine, const pstop_msg_t *req, pstop_m
}

uint64_t now = machine->application->env.get_time_cb();
client->last_timestamp = now;
client->client_data.last_timestamp = now;

switch(req->message) {
case PSTOP_MESSAGE_BOND:
Expand All @@ -241,6 +241,15 @@ machine_handle_message(pstop_machine_t *machine, const pstop_msg_t *req, pstop_m
return handle_stop_msg(machine, client, req, *resp);
}

static
void
machine_notify_hal(pstop_machine_t *machine, pstop_status_message_t status)
{
if(machine->application->status_cb != NULL) {
machine->application->status_cb(status);
}
}

static
pstop_error_t
machine_check_heartbeats(pstop_machine_t *machine)
Expand All @@ -258,22 +267,22 @@ machine_check_heartbeats(pstop_machine_t *machine)

// if for some reason now is in the past compared to the last heart beat
// then there's no need to check if we've heard from this client
if(now <= client->last_timestamp) {
if(now <= client->client_data.last_timestamp) {
continue;
}

uint64_t diff = now - client->last_timestamp;
uint64_t diff = now - client->client_data.last_timestamp;

// if we're still within the heartbeat timeout then this client is still
// good.
if(diff <= client->heartbeat_ms) {
if(diff <= client->client_data.heartbeat_ms) {
continue;
}

// problem! this client hasn't talked to us in a while
// if we're still within the window of missed heartbeats then we're OK

client->missed_heartbeats_counter = (uint16_t)(diff / client->heartbeat_ms);
client->missed_heartbeats_counter = (uint16_t)(diff / client->client_data.heartbeat_ms);
if(client->missed_heartbeats_counter >= machine->application->app_config.max_missed_heartbeats) {
// trigger a stop!
client->client_state = PSTOP_CLIENT_UNKNOWN;
Expand All @@ -287,6 +296,14 @@ machine_check_heartbeats(pstop_machine_t *machine)
return PSTOP_MISSED_HEARTBEATS;
}

if(machine->robot_state.robot_state == ROBOT_STATE_STOPPED) {
machine_notify_hal(machine, PSTOP_STATUS_STOP);
}
else {
machine_notify_hal(machine, PSTOP_STATUS_OK);

}

return PSTOP_OK;
}

Expand All @@ -303,7 +320,7 @@ machine_init(pstop_machine_t *machine, pstop_application_t *app, pstop_client_da

machine->robot_state.client_stop_id = 0U;
machine->robot_state.restart_state = ROBOT_RESTART_STATE_OK;
machine->robot_state.robot_state = ROBOT_STATE_OK;
machine->robot_state.robot_state = ROBOT_STATE_STOPPED;

pstop_clients_init(&(machine->pstops));
}
Expand All @@ -315,7 +332,5 @@ machine_stop_robot(pstop_machine_t *machine)
machine->robot_state.restart_state = ROBOT_RESTART_STATE_NEED_STOP;
machine->robot_state.client_stop_id = 0U;

if(machine->application->status_cb != NULL) {
machine->application->status_cb(PSTOP_STATUS_STOP);
}
machine_notify_hal(machine, PSTOP_STATUS_STOP);
}
16 changes: 8 additions & 8 deletions pstop_c/pstop/src/pstop/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ protocol_handle_message(pstop_machine_t *machine, const pstop_msg_t *req, pstop_

// if we've already seen this client, then validate the counter/timestamps
if(client != NULL) {
if(req->counter <= client->last_counter) {
if(req->counter <= client->client_data.last_counter) {
*resp = NULL;
return PSTOP_MSG_OUT_OF_ORDER;
}
if((req->counter - client->last_counter) > machine->application->app_config.max_lost_messages) {
if((req->counter - client->client_data.last_counter) > machine->application->app_config.max_lost_messages) {
*resp = NULL;
return PSTOP_MSG_LOST;
}
if(req->stamp <= client->last_timestamp) {
if(req->stamp <= client->client_data.last_timestamp) {
*resp = NULL;
return PSTOP_MSG_OUT_OF_ORDER;
}
if(req->received_counter != client->msg_counter) {
if(req->received_counter != client->client_data.msg_counter) {

}
}
Expand Down Expand Up @@ -79,10 +79,10 @@ protocol_handle_message(pstop_machine_t *machine, const pstop_msg_t *req, pstop_

// null client will happen on unbond
if(client != NULL) {
(*resp)->counter = client->msg_counter + 1U;
client->msg_counter++;
client->last_counter = req->counter;
client->last_timestamp = now;
(*resp)->counter = client->client_data.msg_counter + 1U;
client->client_data.msg_counter++;
client->client_data.last_counter = req->counter;
client->client_data.last_timestamp = now;
}

return PSTOP_OK;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// SPDX-FileCopyrightText: 2026 Polymath Robotics, Inc.
// SPDX-License-Identifier: Apache-2.0

#include "pstop/machine_client_data.h"
#include "pstop/protocol_data.h"

void
machine_client_init(machine_client_data_t *client)
protocol_data_init(protocol_data_t *client)
{
device_id_init(&(client->client_id));
client->last_timestamp = 0U;
Expand Down
8 changes: 2 additions & 6 deletions pstop_c/pstop/src/pstop/pstop_client_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ static uint32_t next_client_id = 0U;
void
pstop_client_init(pstop_client_data_t *client)
{
device_id_init(&(client->client_id));
client->last_timestamp = 0U;
client->heartbeat_ms = 0U;
client->msg_counter = 0U;
client->last_counter = 0U;
protocol_data_init(&(client->client_data));
client->clock_drift = 0U;
client->lost_message_counter = 0U;
client->missed_heartbeats_counter = 0U;
Expand Down Expand Up @@ -78,7 +74,7 @@ pstop_client_get(pstop_clients_t *clients, const device_id_t *client_id)
{
for(uint16_t i = 0U; i < clients->max_clients; ++i) {
if(clients->clients[i].client_state != PSTOP_CLIENT_UNKNOWN) {
if(device_id_cmp(&(clients->clients[i].client_id), client_id) == 0) {
if(device_id_cmp(&(clients->clients[i].client_data.client_id), client_id) == 0) {
return &(clients->clients[i]);
}
}
Expand Down
4 changes: 2 additions & 2 deletions pstop_c/pstop/test/src/pstop/machine_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ test_new_client_operator_allowed(void)

TEST_ASSERT_EQUAL(PSTOP_OK, machine.handle_machine_message_cb(&machine, &msg, &resp));
TEST_ASSERT_EQUAL(PSTOP_MESSAGE_BOND, resp->message);
TEST_ASSERT_EQUAL(101U, pstop_clients[0].last_timestamp);
TEST_ASSERT_EQUAL(60U, pstop_clients[0].heartbeat_ms);
TEST_ASSERT_EQUAL(101U, pstop_clients[0].client_data.last_timestamp);
TEST_ASSERT_EQUAL(60U, pstop_clients[0].client_data.heartbeat_ms);
}

static
Expand Down
14 changes: 7 additions & 7 deletions pstop_c/pstop/test/src/pstop/pstop_client_data_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ void
assert_empty_client(pstop_client_data_t *client)
{
for(int i = 0; i < DEVICE_ID_LENGTH; ++i) {
TEST_ASSERT_EQUAL(0U, client->client_id.data[i]);
TEST_ASSERT_EQUAL(0U, client->client_data.client_id.data[i]);
}
TEST_ASSERT_EQUAL(0U, client->last_timestamp);
TEST_ASSERT_EQUAL(0U, client->heartbeat_ms);
TEST_ASSERT_EQUAL(0U, client->msg_counter);
TEST_ASSERT_EQUAL(0U, client->client_data.last_timestamp);
TEST_ASSERT_EQUAL(0U, client->client_data.heartbeat_ms);
TEST_ASSERT_EQUAL(0U, client->client_data.msg_counter);
TEST_ASSERT_EQUAL(0U, client->clock_drift);
}

Expand Down Expand Up @@ -101,8 +101,8 @@ test_remove_client(void)
pstop_client_data_t *c1 = pstop_client_get_free_client(&clients);
pstop_client_data_t *c2 = pstop_client_get_free_client(&clients);

device_id_copy(&(c1->client_id), &c1_id);
device_id_copy(&(c2->client_id), &c2_id);
device_id_copy(&(c1->client_data.client_id), &c1_id);
device_id_copy(&(c2->client_data.client_id), &c2_id);

// remove first client and make sure second client was copied over
TEST_ASSERT_EQUAL(2U, pstop_client_num_active(&clients));
Expand All @@ -115,7 +115,7 @@ test_remove_client(void)
// verify that the other client is still available
c2 = pstop_client_get(&clients, &c2_id);
TEST_ASSERT_NOT_NULL(c2);
TEST_ASSERT_EQUAL(0, device_id_cmp(&c2_id, &(c2->client_id)));
TEST_ASSERT_EQUAL(0, device_id_cmp(&c2_id, &(c2->client_data.client_id)));

// now remove last client
pstop_client_deactivate(c2);
Expand Down
Loading