Skip to content
Open
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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@
!.vscode/settings.json
__pycache__/
*.pyc

# IDE / Temporary files
.metadata/
.vscode/
build/
sdkconfig
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
"files.associations": {
"sdkconfig*": "properties"
}
},
"idf.currentSetup": "C:\\esp\\v6.1\\esp-idf"
}
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ if(NOT DEFINED ENV{IDF_PATH})
message(FATAL_ERROR "ESP-IDF is not active. Open an ESP-IDF terminal before building.")
endif()

# <<< أضف هذا السطر هنا ليقرأ المكونات من مجلد lib >>>
set(EXTRA_COMPONENT_DIRS "lib")

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp32_sensing_node)
project(esp32_sensing_node)
11 changes: 11 additions & 0 deletions Contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# GP API revision 10

This header is the single declaration reference for the assignments. It contains
types and function prototypes, not production implementations. Ahmed provides
the portable codec definitions; Rodaina uses that exact version for Blackpill TX.
Ali and Farah publish the shared header on Testing before developer branches.

Library ownership: joystick = Boody; uart_sender = Rodaina; gp_protocol and
gateway = Ahmed; command_map = Rabe3; motor_driver = Boda.
Application initialization, hardware callbacks, RTOS tasks and function calls
belong to the maintainers. Do not hard-code board pins or HAL handles in libraries.
100 changes: 100 additions & 0 deletions Contracts/gp_types.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#ifndef CUERT_GP_TYPES_H
#define CUERT_GP_TYPES_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define GP_API_REVISION 10u
#define GP_UART_VERSION 2u
#define GP_UART_FRAME_BYTES 14u
#define GP_CAN_COMMAND_ID 0x105u
#define GP_FLAG_VALID 0x01u
#define GP_FLAG_ARM 0x02u
#define GP_FLAG_DEADMAN 0x04u
typedef enum { GP_OK=0, GP_PENDING, GP_BAD_ARG,
GP_INVALID, GP_STALE, GP_IO_ERROR, GP_NO_SPACE } GpResult;
typedef struct {
uint16_t sequence, throttle_pm;
int16_t steering_pm;
uint8_t flags;
} TargetSample;
typedef struct {
uint16_t min[2], center[2], max[2], deadband[2];
} JoystickCalibration;
typedef bool (*AdcReadFn)(void *user, uint8_t axis,
uint16_t *raw);
typedef GpResult (*UartWriteFn)(void *user,
const uint8_t *bytes, size_t length);
typedef struct { UartWriteFn write; void *user; bool initialized;
} UartSender;
typedef struct { uint8_t bytes[GP_UART_FRAME_BYTES]; size_t used;
} UartRx;
typedef struct { uint16_t id; uint8_t dlc; uint8_t data[8];
} GpCanFrame;
typedef GpResult (*CanWriteFn)(void *user,
const GpCanFrame *frame);
typedef struct { CanWriteFn write; void *user;
uint32_t max_queue_ms; uint16_t last_sequence;
bool seen, initialized;
} Gateway;
typedef struct { int16_t throttle_duty_pm, steering_rate_pm;
} MotorOutput;
typedef struct {
uint16_t throttle_cap_pm, steering_cap_pm;
uint16_t throttle_slew_pm_s, steering_slew_pm_s;
uint32_t max_dt_ms;
} CommandMapConfig;
typedef struct { CommandMapConfig config; MotorOutput previous;
uint32_t throttle_remainder, steering_remainder;
bool initialized;
} CommandMap;
typedef struct { bool estop_ok, enabled; } MotorSafety;
typedef GpResult (*MotorWriteFn)(void *user,
const MotorOutput *output);
typedef void (*MotorOffFn)(void *user);
typedef struct {
MotorWriteFn write; MotorOffFn off; void *user;
uint16_t max_duty_pm; uint32_t max_step_hz;
uint16_t step_pulse_us, dir_setup_us, enable_setup_us;
uint32_t reversal_deadtime_ms;
} MotorDriverConfig;
typedef struct { MotorDriverConfig config; MotorOutput previous;
uint32_t zero_since_ms; int8_t last_steering_direction;
bool initialized;
} MotorDriver;

GpResult Joystick_ReadSample(AdcReadFn read, void *user,
const JoystickCalibration *cal, uint16_t sequence,
uint8_t request_flags, TargetSample *out);
GpResult UartSender_Init(UartSender *sender,
UartWriteFn write, void *user);
GpResult UartSender_Send(UartSender *sender,
const TargetSample *command);
void UartRx_Init(UartRx *rx);
GpResult UartRx_Feed(UartRx *rx, const uint8_t *bytes,
size_t length, size_t *consumed, TargetSample *out);
GpResult GP_EncodeUart(const TargetSample *command,
uint8_t *out, size_t capacity, size_t *written);
GpResult GP_DecodeUart(const uint8_t *bytes,
size_t length, TargetSample *out);
GpResult GP_EncodeCan(const TargetSample *command,
GpCanFrame *out);
GpResult GP_DecodeCan(const GpCanFrame *frame,
TargetSample *out);
GpResult Gateway_Init(Gateway *gateway, CanWriteFn write,
void *user, uint32_t max_queue_ms);
GpResult Gateway_Forward(Gateway *gateway,
const TargetSample *command, uint32_t queued_ms);
void Gateway_Reset(Gateway *gateway);
GpResult CommandMap_Init(CommandMap *map,
const CommandMapConfig *config);
GpResult CommandMap_Update(CommandMap *map,
const TargetSample *command, uint32_t dt_ms,
bool enabled, MotorOutput *out);
void CommandMap_Reset(CommandMap *map);
GpResult MotorDriver_Init(MotorDriver *driver,
const MotorDriverConfig *config);
GpResult MotorDriver_Apply(MotorDriver *driver,
const MotorOutput *request, const MotorSafety *safety,
uint32_t now_ms, MotorOutput *applied);
void MotorDriver_Stop(MotorDriver *driver);
#endif
18 changes: 18 additions & 0 deletions Contracts/verification.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef CUERT_VERIFICATION_H
#define CUERT_VERIFICATION_H
#include "gp_types.h"
typedef struct { char id[12], node[12], event[20];
uint32_t tick_ms; uint16_t sequence;
int32_t expected, actual; bool check_ok;
} VerificationEvidence;
typedef bool (*VerifyWriteFn)(void *user,
const char *line, size_t length);
typedef struct { bool (*read_fault)(void *user, bool *fault);
void (*write_led)(void *user, bool on); void *user;
} DiagnosticsLedArgs;
GpResult Verification_Init(VerifyWriteFn write, void *user);
bool Verification_Log(const VerificationEvidence *e);
uint32_t Verification_DroppedCount(void);
void VerificationSerialTask(void *unused);
void DiagnosticsLedTask(void *argument);
#endif
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# ESP32-Sensing-Node

CUERT ESP32 sensing firmware, using C and the native ESP-IDF CMake build system.
The starter logs a heartbeat once per second and does not configure sensor pins.
CUERT ESP32 firmware, using C and the native ESP-IDF CMake build system. The
application reads revision-10 command frames on UART1 and forwards validated
commands as standard CAN frames through the ESP32 TWAI controller.

## Hardware baseline

Expand All @@ -12,6 +13,11 @@ module's marking. The initial flash configuration uses a conservative 2 MB,
DIO, 40 MHz baseline. Change flash size in `idf.py menuconfig` after confirming
the module's actual capacity; 38-pin boards often have 4 MB.

UART1 uses GPIO17 (TX), GPIO16 (RX), and 115200 baud. TWAI uses GPIO21 (TX),
GPIO22 (RX), and 500 kbit/s. The ESP32 has no built-in CAN transceiver; connect
an external transceiver between the ESP32 and the CAN bus. Confirm pin wiring
and bus termination before connecting hardware.

## One-time Windows setup

1. Open this directory in VS Code.
Expand Down Expand Up @@ -96,8 +102,8 @@ ESP32's built-in ROM download bootloader over USB-to-UART, and writes the
bootloader, partition table, and application at their generated offsets.
An ST-Link is not required for normal USB flashing.

Expected output is `CUERT ESP32 sensing node started`, then a heartbeat each
second. Exit the monitor with Ctrl+]. VS Code also provides ESP-IDF commands
Expected output includes `CUERT ESP32 sensing node started`. Exit the monitor
with Ctrl+]. VS Code also provides ESP-IDF commands
for building, selecting a port, flashing using UART, and monitoring.

If no COM port appears, check the cable and the driver for the board's actual
Expand Down
5 changes: 5 additions & 0 deletions lib/gateway/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
idf_component_register(
SRCS "src/gateway.c"
INCLUDE_DIRS "include"
REQUIRES gp_protocol gp_common
)
23 changes: 23 additions & 0 deletions lib/gateway/include/gateway.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef GATEWAY_H
#define GATEWAY_H

/*
* ESP32-side UART stream parser and command-to-CAN forwarding logic.
*
* This component does not create RTOS tasks or configure UART/TWAI hardware.
* The application/maintainer owns peripheral setup, UART reads, CAN TX queues,
* and scheduling.
*/

#include <stddef.h>
#include <stdint.h>
#include "gp_protocol.h"

/*
* The callback must be nonblocking. It must copy the entire frame into a
* bounded, maintainer-owned TX queue before returning GP_OK.
*
* GP_PENDING means busy and nothing was accepted.
* GP_IO_ERROR means a permanent/driver error.
*/
#endif
Loading
Loading