initial commit

This commit is contained in:
2026-01-27 20:45:47 +01:00
commit 1e5eb44ca9
53 changed files with 11048 additions and 0 deletions

12
src/flash.lds Normal file
View File

@@ -0,0 +1,12 @@
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
INCLUDE memory_map.ld
REGION_ALIAS("REGION_TEXT", flash);
REGION_ALIAS("REGION_RODATA", flash);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
INCLUDE sections.ld

7
src/memory_map.ld Normal file
View File

@@ -0,0 +1,7 @@
MEMORY
{
ram (wxa!ri) : ORIGIN = 0x00000000, LENGTH = 128K
rom (rxai!w) : ORIGIN = 0x10080000, LENGTH = 8k
flash (rxai!w) : ORIGIN = 0x20000000, LENGTH = 16M
dram (wxa!ri) : ORIGIN = 0x40000000, LENGTH = 2048M
}

12
src/ram.lds Normal file
View File

@@ -0,0 +1,12 @@
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
INCLUDE memory_map.ld
REGION_ALIAS("REGION_TEXT", ram);
REGION_ALIAS("REGION_RODATA", ram);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
INCLUDE sections.ld

12
src/rom.lds Normal file
View File

@@ -0,0 +1,12 @@
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
INCLUDE memory_map.ld
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_RODATA", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
INCLUDE sections.ld

184
src/sections.ld Normal file
View File

@@ -0,0 +1,184 @@
PHDRS
{
flash PT_LOAD;
ram_init PT_LOAD;
tls PT_TLS;
ram PT_NULL;
dram PT_NULL;
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 2K;
__stack_segment_size = DEFINED(__stack_segment_size) ? __stack_segment_size : __stack_size;
.init ORIGIN(REGION_TEXT) :
{
KEEP (*(.text.init.enter))
KEEP (*(.text.init.*))
KEEP (*(.text.init))
KEEP (*(SORT_NONE(.init)))
KEEP (*(.text.libgloss.start))
} >REGION_TEXT AT>REGION_TEXT :flash
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >REGION_TEXT AT>REGION_TEXT :flash
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} >REGION_TEXT AT>REGION_TEXT :flash
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >REGION_RODATA AT>REGION_RODATA :flash
.srodata :
{
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >REGION_RODATA AT>REGION_RODATA :flash
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >REGION_RODATA AT>REGION_RODATA :flash
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >REGION_RODATA AT>REGION_RODATA :flash
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >REGION_RODATA AT>REGION_RODATA :flash
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >REGION_RODATA AT>REGION_RODATA :flash
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >REGION_RODATA AT>REGION_RODATA :flash
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >REGION_RODATA AT>REGION_RODATA :flash
.data : ALIGN(4)
{
__DATA_BEGIN__ = .;
*(.data .data.*)
*(.gnu.linkonce.d.*)
__SDATA_BEGIN__ = .;
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
} >REGION_DATA AT>REGION_RODATA :ram_init
.tdata : ALIGN(8) {
PROVIDE( __tls_base = . );
*(.tdata .tdata.* .gnu.linkonce.td.*)
} >REGION_DATA AT>REGION_RODATA :tls :ram_init
PROVIDE( __data_source = LOADADDR(.data) );
PROVIDE( __data_start = ADDR(.data) );
PROVIDE( __data_end = ADDR(.tdata) + SIZEOF(.tdata) );
PROVIDE( __tdata_source = LOADADDR(.tdata) );
PROVIDE( __tdata_size = SIZEOF(.tdata) );
.tbss : ALIGN(8) {
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon .tcommon.*)
PROVIDE( __tls_end = . );
} >REGION_DATA AT>REGION_DATA :tls :ram
PROVIDE( __tbss_size = SIZEOF(.tbss) );
PROVIDE( __tls_size = __tls_end - __tls_base );
.tbss_space : ALIGN(8) {
. = . + __tbss_size;
} >REGION_DATA :ram
.bss :
{
__BSS_BEGIN__ = .;
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__BSS_END__ = .;
} >REGION_BSS AT>REGION_BSS :ram
PROVIDE( __bss_start = ADDR(.tbss) );
PROVIDE( __bss_end = ADDR(.bss) + SIZEOF(.bss) );
__global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800));
PROVIDE( _end = . );
PROVIDE( end = . );
.stack ORIGIN(ram) + LENGTH(ram) - __stack_segment_size :
{
PROVIDE( _heap_end = . );
. = __stack_segment_size;
PROVIDE( _sp = . );
} >REGION_BSS AT>REGION_BSS :ram
PROVIDE( tohost = . );
PROVIDE( fromhost = . + 8 );
}

337
src/tcp_demo/main.c Normal file
View File

@@ -0,0 +1,337 @@
/* This is a small demo of the high-performance NetX Duo TCP/IP stack.
This program demonstrates ICMPv6 protocols Neighbor Discovery and
Stateless Address Configuration for IPv6, ARP for IPv4, and
TCP packet sending and receiving with a simulated Ethernet driver. */
#include "nx_api.h"
#include "tx_api.h"
#include <stdio.h>
#define DEMO_STACK_SIZE 2048
#define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
#define PACKET_SIZE 1536
#define POOL_SIZE ((sizeof(NX_PACKET) + PACKET_SIZE) * 8)
#define NX_DISABLE_IPV6
/* Define the ThreadX and NetX object control blocks... */
TX_THREAD thread_0;
TX_THREAD thread_1;
NX_PACKET_POOL pool_0;
NX_IP ip_0;
NX_IP ip_1;
NX_TCP_SOCKET client_socket;
NX_TCP_SOCKET server_socket;
UCHAR pool_buffer[POOL_SIZE];
/* Define the counters used in the demo application... */
ULONG thread_0_counter;
ULONG thread_1_counter;
ULONG error_counter;
/* Define thread prototypes. */
void thread_0_entry(ULONG thread_input);
void thread_1_entry(ULONG thread_input);
void thread_1_connect_received(NX_TCP_SOCKET* server_socket, UINT port);
void thread_1_disconnect_received(NX_TCP_SOCKET* server_socket);
void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT* driver_req);
void _nx_mnrs_network_driver(struct NX_IP_DRIVER_STRUCT* driver_req);
#define NETWORK_DRIVER _nx_mnrs_network_driver
// alternative the ram driver can be used
// #define NETWORK_DRIVER _nx_ram_network_driver
/* Define main entry point. */
int main() {
/* Enter the ThreadX kernel. */
tx_kernel_enter();
}
/* Define what the initial system looks like. */
void tx_application_define(void* first_unused_memory) {
CHAR* pointer;
UINT status;
puts("Setting up application");
/* Setup the working pointer. */
pointer = (CHAR*)first_unused_memory;
/* Create the main thread. */
tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, pointer, DEMO_STACK_SIZE, 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE;
/* Create the main thread. */
tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, pointer, DEMO_STACK_SIZE, 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
pointer = pointer + DEMO_STACK_SIZE;
/* Initialize the NetX system. */
nx_system_initialize();
/* Create a packet pool. */
status = nx_packet_pool_create(&pool_0, "packet_pool0", PACKET_SIZE, pool_buffer, POOL_SIZE);
if(status) {
error_counter++;
}
/* Create an IP instance. */
status = nx_ip_create(&ip_0, "eth0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, NETWORK_DRIVER, pointer, 2048, 1);
pointer = pointer + 2048;
/* Create another IP instance. */
status += nx_ip_create(&ip_1, "eth1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, NETWORK_DRIVER, pointer, 2048, 1);
pointer = pointer + 2048;
if(status) {
error_counter++;
}
/* Enable ARP and supply ARP cache memory for IP Instance 0. */
status = nx_arp_enable(&ip_0, (void*)pointer, 1024);
pointer = pointer + 1024;
/* Enable ARP and supply ARP cache memory for IP Instance 1. */
status += nx_arp_enable(&ip_1, (void*)pointer, 1024);
pointer = pointer + 1024;
/* Check ARP enable status. */
if(status) {
error_counter++;
}
/* Enable ICMP */
status = nxd_icmp_enable(&ip_0);
if(status) {
error_counter++;
}
status = nxd_icmp_enable(&ip_1);
if(status) {
error_counter++;
}
/* Enable TCP processing for both IP instances. */
status = nx_tcp_enable(&ip_0);
status += nx_tcp_enable(&ip_1);
puts("Successfuly set up application");
}
/* Define the test threads. */
void thread_0_entry(ULONG thread_input) {
UINT status;
NX_PACKET* my_packet;
ULONG length;
NXD_ADDRESS server_ipv4_address;
NXD_ADDRESS peer_address;
ULONG peer_port;
NX_PARAMETER_NOT_USED(thread_input);
tx_thread_sleep(NX_IP_PERIODIC_RATE);
/* set the TCP server addresses. */
server_ipv4_address.nxd_ip_version = NX_IP_VERSION_V4;
server_ipv4_address.nxd_ip_address.v4 = IP_ADDRESS(1, 2, 3, 5);
/* Loop to repeat things over and over again! */
puts("Entering client loop");
while(1) {
/* Create a socket. */
status = nx_tcp_socket_create(&ip_0, &client_socket, "Client Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200,
NX_NULL, NX_NULL);
/* Check for error. */
if(status) {
error_counter++;
}
/* Bind the socket. */
status = nx_tcp_client_socket_bind(&client_socket, 12, NX_WAIT_FOREVER);
/* Check for error. */
if(status) {
error_counter++;
}
/* Attempt to connect the socket. */
status = nxd_tcp_client_socket_connect(&client_socket, &server_ipv4_address, 12, NX_IP_PERIODIC_RATE);
/* Check for error. */
if(status) {
printf("Error with socket connect: 0x%x\n", status);
return;
}
status = nxd_tcp_socket_peer_info_get(&client_socket, &peer_address, &peer_port);
/* Allocate a packet. */
status = nx_packet_allocate(&pool_0, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER);
/* Check status. */
if(status != NX_SUCCESS) {
break;
}
/* Write ABCs into the packet payload! */
nx_packet_data_append(my_packet, DEMO_DATA, sizeof(DEMO_DATA), &pool_0, TX_WAIT_FOREVER);
status = nx_packet_length_get(my_packet, &length);
if((status) || (length != sizeof(DEMO_DATA))) {
error_counter++;
}
/* Send the packet out! */
status = nx_tcp_socket_send(&client_socket, my_packet, NX_IP_PERIODIC_RATE);
/* Determine if the status is valid. */
if(status) {
error_counter++;
nx_packet_release(my_packet);
}
/* Disconnect this socket. */
status = nx_tcp_socket_disconnect(&client_socket, NX_IP_PERIODIC_RATE);
/* Determine if the status is valid. */
if(status) {
error_counter++;
}
/* Unbind the socket. */
status = nx_tcp_client_socket_unbind(&client_socket);
/* Check for error. */
if(status) {
error_counter++;
}
/* Delete the socket. */
status = nx_tcp_socket_delete(&client_socket);
/* Check for error. */
if(status) {
error_counter++;
}
/* Increment thread 0's counter. */
thread_0_counter++;
}
}
void thread_1_entry(ULONG thread_input) {
UINT status;
NX_PACKET* packet_ptr;
ULONG actual_status;
NX_PARAMETER_NOT_USED(thread_input);
/* Wait 1 second for the IP thread to finish its initilization. */
tx_thread_sleep(NX_IP_PERIODIC_RATE);
/* Ensure the IP instance has been initialized. */
status = nx_ip_status_check(&ip_1, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE);
/* Check status... */
if(status != NX_SUCCESS) {
error_counter++;
return;
}
/* Create a socket. */
status = nx_tcp_socket_create(&ip_1, &server_socket, "Server Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 100, NX_NULL,
thread_1_disconnect_received);
/* Check for error. */
if(status) {
error_counter++;
}
/* Setup this thread to listen. */
status = nx_tcp_server_socket_listen(&ip_1, 12, &server_socket, 5, thread_1_connect_received);
/* Check for error. */
if(status) {
error_counter++;
}
/* Loop to create and establish server connections. */
puts("Entering server loop");
while(1) {
/* Increment thread 1's counter. */
thread_1_counter++;
/* Accept a client socket connection. */
status = nx_tcp_server_socket_accept(&server_socket, NX_WAIT_FOREVER);
/* Check for error. */
if(status) {
error_counter++;
}
/* Receive a TCP message from the socket. */
status = nx_tcp_socket_receive(&server_socket, &packet_ptr, NX_IP_PERIODIC_RATE);
/* Check for error. */
if(status) {
error_counter++;
} else {
char buffer[64];
ULONG size;
nx_packet_data_extract_offset(packet_ptr, 0, buffer, 64, &size);
buffer[size] = 0;
printf("Received packet %lu with %s\n", thread_1_counter, buffer);
/* Release the packet. */
nx_packet_release(packet_ptr);
}
/* Disconnect the server socket. */
status = nx_tcp_socket_disconnect(&server_socket, NX_IP_PERIODIC_RATE);
/* Check for error. */
if(status) {
error_counter++;
}
/* Unaccept the server socket. */
status = nx_tcp_server_socket_unaccept(&server_socket);
/* Check for error. */
if(status) {
error_counter++;
}
/* Setup server socket for listening again. */
status = nx_tcp_server_socket_relisten(&ip_1, 12, &server_socket);
/* Check for error. */
if(status) {
error_counter++;
}
}
}
void thread_1_connect_received(NX_TCP_SOCKET* socket_ptr, UINT port) {
/* Check for the proper socket and port. */
if((socket_ptr != &server_socket) || (port != 12)) {
error_counter++;
}
}
void thread_1_disconnect_received(NX_TCP_SOCKET* socket) {
/* Check for proper disconnected socket. */
if(socket != &server_socket) {
error_counter++;
}
}

321
src/thread_demo/main.c Normal file
View File

@@ -0,0 +1,321 @@
/* This is a small demo of the high-performance ThreadX kernel. It includes
examples of eight threads of different priorities, using a message queue,
semaphore, mutex, event flags group, byte pool, and block pool. */
#include "tx_api.h"
#include <stdio.h>
#define DEMO_STACK_SIZE 1024
#define DEMO_BYTE_POOL_SIZE 9120
#define DEMO_BLOCK_POOL_SIZE 100
#define DEMO_QUEUE_SIZE 50
/* Define the ThreadX object control blocks... */
TX_THREAD thread_0;
TX_THREAD thread_1;
TX_THREAD thread_2;
TX_THREAD thread_3;
TX_THREAD thread_4;
TX_THREAD thread_5;
TX_THREAD thread_6;
TX_THREAD thread_7;
TX_QUEUE queue_0;
TX_SEMAPHORE semaphore_0;
TX_MUTEX mutex_0;
TX_EVENT_FLAGS_GROUP event_flags_0;
TX_BYTE_POOL byte_pool_0;
TX_BLOCK_POOL block_pool_0;
UCHAR memory_area[DEMO_BYTE_POOL_SIZE];
/* Define the counters used in the demo application... */
ULONG thread_0_counter;
ULONG thread_1_counter;
ULONG thread_1_messages_sent;
ULONG thread_2_counter;
ULONG thread_2_messages_received;
ULONG thread_3_counter;
ULONG thread_4_counter;
ULONG thread_5_counter;
ULONG thread_6_counter;
ULONG thread_7_counter;
/* Define thread prototypes. */
void thread_0_entry(ULONG thread_input);
void thread_1_entry(ULONG thread_input);
void thread_2_entry(ULONG thread_input);
void thread_3_and_4_entry(ULONG thread_input);
void thread_5_entry(ULONG thread_input);
void thread_6_and_7_entry(ULONG thread_input);
/* Define main entry point. */
int main() {
/* Enter the ThreadX kernel. */
tx_kernel_enter();
}
/* Define what the initial system looks like. */
void tx_application_define(void* first_unused_memory) {
CHAR* pointer = TX_NULL;
/* Create a byte memory pool from which to allocate the thread stacks. */
tx_byte_pool_create(&byte_pool_0, "byte pool 0", memory_area, DEMO_BYTE_POOL_SIZE);
/* Put system definition stuff in here, e.g. thread creates and other assorted
create information. */
/* Allocate the stack for thread 0. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
/* Create the main thread. */
tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, pointer, DEMO_STACK_SIZE, 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
/* Allocate the stack for thread 1. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
/* Create threads 1 and 2. These threads pass information through a ThreadX
message queue. It is also interesting to note that these threads have a
time slice. */
tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1, pointer, DEMO_STACK_SIZE, 16, 16, 4, TX_AUTO_START);
/* Allocate the stack for thread 2. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2, pointer, DEMO_STACK_SIZE, 16, 16, 4, TX_AUTO_START);
/* Allocate the stack for thread 3. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
/* Create threads 3 and 4. These threads compete for a ThreadX counting
semaphore. An interesting thing here is that both threads share the same
instruction area. */
tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3, pointer, DEMO_STACK_SIZE, 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
/* Allocate the stack for thread 4. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4, pointer, DEMO_STACK_SIZE, 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
/* Allocate the stack for thread 5. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
/* Create thread 5. This thread simply pends on an event flag which will be
set by thread_0. */
tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5, pointer, DEMO_STACK_SIZE, 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
/* Allocate the stack for thread 6. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
/* Create threads 6 and 7. These threads compete for a ThreadX mutex. */
tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6, pointer, DEMO_STACK_SIZE, 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
/* Allocate the stack for thread 7. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7, pointer, DEMO_STACK_SIZE, 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
/* Allocate the message queue. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_QUEUE_SIZE * sizeof(ULONG), TX_NO_WAIT);
/* Create the message queue shared by threads 1 and 2. */
tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE * sizeof(ULONG));
/* Create the semaphore used by threads 3 and 4. */
tx_semaphore_create(&semaphore_0, "semaphore 0", 1);
/* Create the event flags group used by threads 1 and 5. */
tx_event_flags_create(&event_flags_0, "event flags 0");
/* Create the mutex used by thread 6 and 7 without priority inheritance. */
tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT);
/* Allocate the memory for a small block pool. */
tx_byte_allocate(&byte_pool_0, (VOID**)&pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT);
/* Create a block memory pool to allocate a message buffer from. */
tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
/* Allocate a block and release the block memory. */
tx_block_allocate(&block_pool_0, (VOID**)&pointer, TX_NO_WAIT);
/* Release the block back to the pool. */
tx_block_release(pointer);
}
/* Define the test threads. */
void thread_0_entry(ULONG thread_input) {
UINT status;
/* This thread simply sits in while-forever-sleep loop. */
while(1) {
puts("[Thread] : thread_0_entry is here!");
/* Increment the thread counter. */
thread_0_counter++;
/* Sleep for 10 ticks. */
tx_thread_sleep(10);
/* Set event flag 0 to wakeup thread 5. */
status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
/* Check status. */
if(status != TX_SUCCESS)
break;
}
}
void thread_1_entry(ULONG thread_input) {
UINT status;
/* This thread simply sends messages to a queue shared by thread 2. */
while(1) {
/* Increment the thread counter. */
thread_1_counter++;
/* Send message to queue 0. */
status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
/* Check completion status. */
if(status != TX_SUCCESS)
break;
/* Increment the message sent. */
thread_1_messages_sent++;
printf("Sent message %i\n", thread_1_messages_sent);
}
}
void thread_2_entry(ULONG thread_input) {
ULONG received_message;
UINT status;
/* This thread retrieves messages placed on the queue by thread 1. */
while(1) {
/* Increment the thread counter. */
thread_2_counter++;
/* Retrieve a message from the queue. */
status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
printf("Received message %i\n", received_message);
/* Check completion status and make sure the message is what we
expected. */
if((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
break;
/* Otherwise, all is okay. Increment the received message count. */
thread_2_messages_received++;
}
}
void thread_3_and_4_entry(ULONG thread_input) {
UINT status;
/* This function is executed from thread 3 and thread 4. As the loop
below shows, these function compete for ownership of semaphore_0. */
while(1) {
puts("[Thread] : thread_3_and_4_entry is here!");
/* Increment the thread counter. */
if(thread_input == 3)
thread_3_counter++;
else
thread_4_counter++;
/* Get the semaphore with suspension. */
status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
/* Check status. */
if(status != TX_SUCCESS)
break;
/* Sleep for 2 ticks to hold the semaphore. */
tx_thread_sleep(2);
/* Release the semaphore. */
status = tx_semaphore_put(&semaphore_0);
/* Check status. */
if(status != TX_SUCCESS)
break;
}
}
void thread_5_entry(ULONG thread_input) {
UINT status;
ULONG actual_flags;
/* This thread simply waits for an event in a forever loop. */
while(1) {
puts("[Thread] : thread_5_entry is here!");
/* Increment the thread counter. */
thread_5_counter++;
/* Wait for event flag 0. */
status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR, &actual_flags, TX_WAIT_FOREVER);
/* Check status. */
if((status != TX_SUCCESS) || (actual_flags != 0x1))
break;
}
}
void thread_6_and_7_entry(ULONG thread_input) {
UINT status;
/* This function is executed from thread 6 and thread 7. As the loop
below shows, these function compete for ownership of mutex_0. */
while(1) {
puts("[Thread] : thread_6_and_7_entry is here!");
/* Increment the thread counter. */
if(thread_input == 6)
thread_6_counter++;
else
thread_7_counter++;
/* Get the mutex with suspension. */
status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
/* Check status. */
if(status != TX_SUCCESS)
break;
/* Get the mutex again with suspension. This shows
that an owning thread may retrieve the mutex it
owns multiple times. */
status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
/* Check status. */
if(status != TX_SUCCESS)
break;
/* Sleep for 2 ticks to hold the mutex. */
tx_thread_sleep(2);
/* Release the mutex. */
status = tx_mutex_put(&mutex_0);
/* Check status. */
if(status != TX_SUCCESS)
break;
/* Release the mutex again. This will actually
release ownership since it was obtained twice. */
status = tx_mutex_put(&mutex_0);
/* Check status. */
if(status != TX_SUCCESS)
break;
}
}