Skip to content

Commit e88da74

Browse files
moved threadx helpers to embedded base
1 parent dc01762 commit e88da74

9 files changed

Lines changed: 259 additions & 69 deletions

File tree

threadX/inc/threadX_utils.h

Lines changed: 0 additions & 11 deletions
This file was deleted.

threadX/inc/u_debug.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
#ifndef __U_DEBUG_H
3+
#define __U_DEBUG_H
4+
5+
#include <string.h>
6+
#include <stdio.h>
7+
#include "tx_api.h"
8+
#include "stm32h5xx_hal.h"
9+
10+
/* General-purpose status macros. */
11+
#define U_SUCCESS 0
12+
#define U_ERROR 1
13+
#define U_QUEUE_EMPTY 2
14+
15+
/* Debugging Macros */
16+
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) /* Gets the name of the file. */
17+
#define U_DEBUG /* Comment out to enable/disable debugging. */
18+
#ifdef U_DEBUG
19+
#define DEBUG_PRINTLN(message, ...) printf("[%s/%s()] " message "\n", __FILENAME__, __func__, ##__VA_ARGS__) /* Prints an error message in the format: "[file_name.c/function()] {message}"*/
20+
#else
21+
#define DEBUG_PRINTLN(message, ...) /* If debugging is turned off, macro doesn't need to expand to anything. */
22+
#endif
23+
24+
/**
25+
* @brief Checks if a function is successful when called. DEBUG_PRINTLNs an error message if it fails.
26+
* @param function_call The function to call.
27+
* @param success The function's success code/macro (e.g., U_SUCCESS, TX_SUCCESS, etc.).
28+
*
29+
* @note This macro intentionally doesn't support custom error messages, for the sake of readability. If an error is complex enough to
30+
* require a custom message, the error should probably be checked manually and DEBUG_PRINTLN() called directly.
31+
*/
32+
#define CATCH_ERROR(function_call, success) do { \
33+
int _function_status = (function_call); \
34+
if (_function_status != success) { \
35+
DEBUG_PRINTLN("CATCH_ERROR(): Function failed: %s (Status: %d)", #function_call, _function_status); \
36+
return _function_status; \
37+
} \
38+
} while(0)
39+
40+
/* Converts a ThreadX status macro to a printable string. */
41+
/* This function is intended to be used with DEBUG_PRINTLN(), and shouldn't really ever be used outside of debugging purposes. */
42+
/* (these macros are defined in tx_api.h) */
43+
const char* tx_status_toString(UINT status);
44+
45+
/* Converts a STM32 HAL status macro to a printable string. */
46+
/* This function is intended to be used with DEBUG_PRINTLN(), and shouldn't really ever be used outside of debugging purposes. */
47+
/* (these macros are defined in stm32h5xx_hal_def.h) */
48+
const char* hal_status_toString(HAL_StatusTypeDef status);
49+
50+
#endif

threadX/inc/u_general.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
21
#ifndef __U_GENERAL_H
32
#define __U_GENERAL_H
43

5-
#include <string.h>
6-
#include <stdio.h>
7-
/* This file (and u_general.c) contain miscellaneous macros, functions, and configuration settings that can be used throughout the project. */
4+
#include "tx_port.h"
85

9-
/* General-purpose status macros. */
10-
#define U_SUCCESS 0
11-
#define U_ERROR 1
12-
#define U_QUEUE_EMPTY 2
6+
/* Time and tick conversions */
7+
#define MS_TO_TICKS(ms) (((ms) * TX_TIMER_TICKS_PER_SECOND + 999) / 1000)
8+
#define TICKS_TO_MS(ticks) ((ticks) * 1000 / TX_TIMER_TICKS_PER_SECOND)
139

1410
#endif

threadX/inc/u_queues.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#ifndef __U_QUEUES_H
2+
#define __U_QUEUES_H
3+
4+
#include "tx_api.h"
5+
#include "u_debug.h"
6+
#include <stdint.h>
7+
8+
/*
9+
* Basically just a wrapper for ThreadX stuff. Lets you create/configure queues.
10+
*
11+
* Author: Blake Jackson
12+
*/
13+
14+
/* Queue Config Macros */
15+
#define QUEUE_WAIT_TIME TX_NO_WAIT
16+
17+
typedef struct {
18+
19+
/* PUBLIC: Queue Configuration Settings */
20+
/* Set these when defining an instance of this struct. */
21+
const CHAR *name; /* Name of the queue */
22+
const UINT message_size; /* Size of each message in the queue, in bytes. */
23+
const UINT capacity; /* Maximum number of messages in the queue */
24+
25+
/* PRIVATE: Internal implementation - DO NOT ACCESS DIRECTLY */
26+
/* (should only be accessed by functions in u_queues.c) */
27+
TX_QUEUE _TX_QUEUE; /* Queue instance. */
28+
size_t _bytes; /* Size of each queue message, in bytes. */
29+
size_t _words; /* Size of each queue message, in 32-bit words. */
30+
} queue_t;
31+
32+
33+
/* API */
34+
uint8_t create_queue(TX_BYTE_POOL *byte_pool, queue_t *queue);
35+
uint8_t queue_send(queue_t *queue, void *message); // Sends a message to the specified queue.
36+
uint8_t queue_receive(queue_t *queue, void *message); // Receives a message from the specified queue
37+
38+
#endif

threadX/inc/u_threads.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
#include <stdint.h>
33
#include <stdio.h>
44

5-
/* Initializes all threads. Called from app_threadx.c */
6-
uint8_t threads_init(TX_BYTE_POOL *byte_pool);
7-
85
typedef struct {
96
/* PUBLIC: Thread Configuration Settings */
107
/* Set these when defining an instance of this struct. */
@@ -21,4 +18,6 @@ typedef struct {
2118
/* PRIVATE: Internal implementation - DO NOT ACCESS DIRECTLY */
2219
/* (should only be accessed by functions in u_threads.c) */
2320
TX_THREAD _TX_THREAD;
24-
} thread_t;
21+
} thread_t;
22+
23+
uint8_t create_thread(TX_BYTE_POOL *byte_pool, thread_t *thread);

threadX/src/threadX_utils.c

Lines changed: 0 additions & 46 deletions
This file was deleted.

threadX/src/u_debug.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "u_debug.h"
2+
#include <stdio.h>
3+
4+
const char* tx_status_toString(UINT status) {
5+
switch(status) {
6+
case TX_SUCCESS: return "TX_SUCCESS";
7+
case TX_DELETED: return "TX_DELETED";
8+
case TX_POOL_ERROR: return "TX_POOL_ERROR";
9+
case TX_PTR_ERROR: return "TX_PTR_ERROR";
10+
case TX_WAIT_ERROR: return "TX_WAIT_ERROR";
11+
case TX_SIZE_ERROR: return "TX_SIZE_ERROR";
12+
case TX_GROUP_ERROR: return "TX_GROUP_ERROR";
13+
case TX_NO_EVENTS: return "TX_NO_EVENTS";
14+
case TX_OPTION_ERROR: return "TX_OPTION_ERROR";
15+
case TX_QUEUE_ERROR: return "TX_QUEUE_ERROR";
16+
case TX_QUEUE_EMPTY: return "TX_QUEUE_EMPTY";
17+
case TX_QUEUE_FULL: return "TX_QUEUE_FULL";
18+
case TX_SEMAPHORE_ERROR: return "TX_SEMAPHORE_ERROR";
19+
case TX_NO_INSTANCE: return "TX_NO_INSTANCE";
20+
case TX_THREAD_ERROR: return "TX_THREAD_ERROR";
21+
case TX_PRIORITY_ERROR: return "TX_PRIORITY_ERROR";
22+
case TX_NO_MEMORY: return "TX_NO_MEMORY"; // Same as TX_START_ERROR
23+
case TX_DELETE_ERROR: return "TX_DELETE_ERROR";
24+
case TX_RESUME_ERROR: return "TX_RESUME_ERROR";
25+
case TX_CALLER_ERROR: return "TX_CALLER_ERROR";
26+
case TX_SUSPEND_ERROR: return "TX_SUSPEND_ERROR";
27+
case TX_TIMER_ERROR: return "TX_TIMER_ERROR";
28+
case TX_TICK_ERROR: return "TX_TICK_ERROR";
29+
case TX_ACTIVATE_ERROR: return "TX_ACTIVATE_ERROR";
30+
case TX_THRESH_ERROR: return "TX_THRESH_ERROR";
31+
case TX_SUSPEND_LIFTED: return "TX_SUSPEND_LIFTED";
32+
case TX_WAIT_ABORTED: return "TX_WAIT_ABORTED";
33+
case TX_WAIT_ABORT_ERROR: return "TX_WAIT_ABORT_ERROR";
34+
case TX_MUTEX_ERROR: return "TX_MUTEX_ERROR";
35+
case TX_NOT_AVAILABLE: return "TX_NOT_AVAILABLE";
36+
case TX_NOT_OWNED: return "TX_NOT_OWNED";
37+
case TX_INHERIT_ERROR: return "TX_INHERIT_ERROR";
38+
case TX_NOT_DONE: return "TX_NOT_DONE";
39+
case TX_CEILING_EXCEEDED: return "TX_CEILING_EXCEEDED";
40+
case TX_INVALID_CEILING: return "TX_INVALID_CEILING";
41+
case TX_FEATURE_NOT_ENABLED: return "TX_FEATURE_NOT_ENABLED";
42+
default: return "UNKNOWN_STATUS";
43+
}
44+
}
45+
46+
const char* hal_status_toString(HAL_StatusTypeDef status) {
47+
switch(status) {
48+
case HAL_OK: return "HAL_OK";
49+
case HAL_ERROR: return "HAL_ERROR";
50+
case HAL_BUSY: return "HAL_BUSY";
51+
case HAL_TIMEOUT: return "HAL_TIMEOUT";
52+
default: return "UNKNOWN_STATUS";
53+
}
54+
}

threadX/src/u_queues.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
2+
#include "u_queues.h"
3+
4+
uint8_t create_queue(TX_BYTE_POOL *byte_pool, queue_t *queue) {
5+
uint8_t status;
6+
void *pointer;
7+
8+
/* Calculate message size in 32-bit words (round up), and then validate it. */
9+
/* According to the Azure RTOS ThreadX Docs, "message sizes range from 1 32-bit word to 16 32-bit words". */
10+
/* Basically, queue messages have to be a multiple of 4 bytes? Kinda weird but this should handle it. */
11+
UINT message_size_words = (queue->message_size + 3) / 4;
12+
if (message_size_words < 1 || message_size_words > 16) {
13+
DEBUG_PRINTLN("ERROR: Invalid message size %d bytes (must be 1-64 bytes). Queue: %s", queue->message_size, queue->name);
14+
return U_ERROR;
15+
}
16+
17+
/* Store metadata */
18+
queue->_bytes = queue->message_size;
19+
queue->_words = message_size_words;
20+
21+
/* Calculate total queue size in bytes. */
22+
int queue_size_bytes = message_size_words * 4 * queue->capacity;
23+
24+
/* Allocate the stack for the queue. */
25+
status = tx_byte_allocate(byte_pool, (VOID**) &pointer, queue_size_bytes, TX_NO_WAIT);
26+
if(status != TX_SUCCESS) {
27+
DEBUG_PRINTLN("ERROR: Failed to allocate memory before creating queue (Status: %d/%s, Queue: %s).", status, tx_status_toString(status), queue->name);
28+
return U_ERROR;
29+
}
30+
31+
/* Create the queue */
32+
status = tx_queue_create(&queue->_TX_QUEUE, (CHAR*)queue->name, message_size_words, pointer, queue_size_bytes);
33+
if (status != TX_SUCCESS) {
34+
DEBUG_PRINTLN("ERROR: Failed to create queue (Status: %d/%s, Queue: %s).", status, tx_status_toString(status), queue->name);
35+
tx_byte_release(pointer); // Free allocated memory if queue creation fails
36+
return U_ERROR;
37+
}
38+
39+
return U_SUCCESS;
40+
41+
}
42+
43+
uint8_t queue_send(queue_t *queue, void *message) {
44+
UINT status;
45+
46+
/* Create a buffer. */
47+
uint32_t buffer[queue->_words]; // Max size is 16 words (64 bytes).
48+
memset(buffer, 0, sizeof(buffer)); // Initialize buffer to zero
49+
50+
/* Copy message into the buffer. The buffer is what actually gets sent to the queue. */
51+
memcpy(buffer, message, queue->_bytes);
52+
53+
/* Send message (buffer) to the queue. */
54+
status = tx_queue_send(&queue->_TX_QUEUE, buffer, QUEUE_WAIT_TIME);
55+
if(status != TX_SUCCESS) {
56+
DEBUG_PRINTLN("ERROR: Failed to send message to queue (Status: %d/%s, Queue: %s).", status, tx_status_toString(status), queue->_TX_QUEUE.tx_queue_name);
57+
return U_ERROR;
58+
}
59+
60+
return U_SUCCESS;
61+
}
62+
63+
uint8_t queue_receive(queue_t *queue, void *message) {
64+
UINT status;
65+
66+
/* Create a buffer */
67+
uint32_t buffer[queue->_words]; // Max size is 16 words (64 bytes).
68+
memset(buffer, 0, sizeof(buffer)); // Initialize buffer to zero
69+
70+
/* Receive message from the queue. */
71+
status = tx_queue_receive(&queue->_TX_QUEUE, buffer, QUEUE_WAIT_TIME);
72+
if(status == TX_QUEUE_EMPTY) {
73+
return U_QUEUE_EMPTY;
74+
}
75+
76+
if((status != TX_SUCCESS)) {
77+
DEBUG_PRINTLN("ERROR: Failed to receive message from queue (Status: %d/%s, Queue: %s).", status, tx_status_toString(status), queue->_TX_QUEUE.tx_queue_name);
78+
return U_ERROR;
79+
}
80+
81+
/* Copy the data from the buffer into the message pointer. Using memcpy() here prevents memory overflow. */
82+
memcpy(message, buffer, queue->_bytes);
83+
84+
return U_SUCCESS;
85+
}

threadX/src/u_threads.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
#include "u_threads.h"
3+
#include "u_debug.h"
4+
5+
uint8_t create_thread(TX_BYTE_POOL *byte_pool, thread_t *thread) {
6+
CHAR *pointer;
7+
uint8_t status;
8+
9+
/* Allocate the stack for the thread. */
10+
status = tx_byte_allocate(byte_pool, (VOID**) &pointer, thread->size, TX_NO_WAIT);
11+
if(status != TX_SUCCESS) {
12+
DEBUG_PRINTLN("ERROR: Failed to allocate stack before creating thread (Status: %d/%s, Thread: %s).", status, tx_status_toString(status), thread->name);
13+
return U_ERROR;
14+
}
15+
16+
/* Create the thread. */
17+
status = tx_thread_create(&thread->_TX_THREAD, (CHAR*)thread->name, thread->function, thread->thread_input, pointer, thread->size, thread->priority, thread->threshold, thread->time_slice, thread->auto_start);
18+
if(status != TX_SUCCESS) {
19+
DEBUG_PRINTLN("ERROR: Failed to create thread (Status: %d/%s, Thread: %s).", status, tx_status_toString(status), thread->name);
20+
tx_byte_release(pointer); // Free allocated memory if thread creation fails
21+
return U_ERROR;
22+
}
23+
24+
return U_SUCCESS;
25+
}

0 commit comments

Comments
 (0)