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
3 changes: 3 additions & 0 deletions apps/obc/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_COMPILER_WARNINGS_AS_ERRORS=y
CONFIG_FINCH_CSP=y
CONFIG_FINCH_CSP_NODE_ADDRESS=1
CONFIG_FINCH_CSP_HOSTNAME="obc"

# Configure UART as logging backend
CONFIG_GPIO=y
Expand Down
8 changes: 8 additions & 0 deletions apps/obc/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@
* SPDX-License-Identifier: Apache-2.0
*/

#include <finch/csp/csp.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(obc);

int main(void)
{
int ret = finch_csp_init();

if (ret < 0) {
LOG_ERR("Failed to initialize FINCH CSP (%d)", ret);
Copy link
Member

@alexapostolu alexapostolu Mar 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should think of a way to recover from this if libcsp fails. We especially don't want any failures in main initialization

But this can be done in another PR

return ret;
}

while (1) {
LOG_INF("obc");
k_msleep(1000);
Expand Down
3 changes: 3 additions & 0 deletions apps/pay/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_COMPILER_WARNINGS_AS_ERRORS=y
CONFIG_FINCH_CSP=y
CONFIG_FINCH_CSP_NODE_ADDRESS=2
CONFIG_FINCH_CSP_HOSTNAME="pay"

# Configure UART as logging backend
CONFIG_GPIO=y
Expand Down
8 changes: 8 additions & 0 deletions apps/pay/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@
* SPDX-License-Identifier: Apache-2.0
*/

#include <finch/csp/csp.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(pay);

int main(void)
{
int ret = finch_csp_init();

if (ret < 0) {
LOG_ERR("Failed to initialize FINCH CSP (%d)", ret);
return ret;
}

while (1) {
LOG_INF("pay");
k_msleep(1000);
Expand Down
12 changes: 12 additions & 0 deletions include/finch/csp/csp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2026 The FINCH CubeSat Project Flight Software Contributors
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef FINCH_CSP_CSP_H_
#define FINCH_CSP_CSP_H_

int finch_csp_init(void);

#endif /* FINCH_CSP_CSP_H_ */
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
# SPDX-License-Identifier: Apache-2.0

add_subdirectory_ifdef(CONFIG_FINCH_CCSDS123B ccsds123b)
add_subdirectory_ifdef(CONFIG_FINCH_CSP csp)
1 change: 1 addition & 0 deletions lib/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
menu "FINCH CubeSat Flight Software Libraries"

rsource "ccsds123b/Kconfig"
rsource "csp/Kconfig"

endmenu
6 changes: 6 additions & 0 deletions lib/csp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) 2026 The FINCH CubeSat Project Flight Software Contributors
# SPDX-License-Identifier: Apache-2.0

zephyr_library()
zephyr_library_sources(src/core.c)
zephyr_library_link_libraries(csp)
50 changes: 50 additions & 0 deletions lib/csp/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright (c) 2026 The FINCH CubeSat Project Flight Software Contributors
# SPDX-License-Identifier: Apache-2.0

config FINCH_CSP
bool "Enable FINCH CSP integration"
select LIBCSP
help
Build the FINCH libcsp integration layer.

if FINCH_CSP

config FINCH_CSP_NODE_ADDRESS
int "CSP node address"
range 0 16382
default 1
help
CSP address used for this image.
16383 is reserved as the CSP broadcast address.

config FINCH_CSP_HOSTNAME
string "CSP hostname"
default "finch"
help
Hostname exposed via CSP management services.

config FINCH_CSP_MODEL
string "CSP model"
default "finch-flight-software"
help
Model string exposed via CSP management services.

config FINCH_CSP_REVISION
string "CSP revision"
default "dev"
help
Revision string exposed via CSP management services.

config FINCH_CSP_ROUTER_STACK_SIZE
int "CSP router thread stack size"
default 1024
help
Stack size for the CSP router thread.

config FINCH_CSP_ROUTER_PRIORITY
int "CSP router thread priority"
default 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reasoning for priority to default to 0? I am not very familiar with threading, but from what I can tell, this controls the priority for finch_csp_router_thread. If priority is zero, then it has the same priority as the main loop (0 by default). Since finch_csp_router_thread has an infinite loop, would we risk being stuck looping through this thread indefinitely and not executing the rest of main?

help
Zephyr thread priority for the CSP router thread.

endif # FINCH_CSP
119 changes: 119 additions & 0 deletions lib/csp/src/core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2026 The FINCH CubeSat Project Flight Software Contributors
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <errno.h>
#include <stdbool.h>

#include <csp/csp.h>
#include <csp/interfaces/csp_if_lo.h>
#include <finch/csp/csp.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(finch_csp);

K_THREAD_STACK_DEFINE(finch_csp_router_stack, CONFIG_FINCH_CSP_ROUTER_STACK_SIZE);
static struct k_thread finch_csp_router_thread_data;
static k_tid_t finch_csp_router_tid;
static K_MUTEX_DEFINE(finch_csp_lock);
static bool finch_csp_initialized;

static void finch_csp_router_thread(void *arg1, void *arg2, void *arg3)
{
ARG_UNUSED(arg1);
ARG_UNUSED(arg2);
ARG_UNUSED(arg3);

while (1) {
(void)csp_route_work();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we ignore the return value here? Do we want to log any errors csp_route_work returns?

}
}

static int finch_csp_bind_service(uint8_t port)
{
int ret = csp_bind_callback(csp_service_handler, port);

if ((ret == CSP_ERR_NONE) || (ret == CSP_ERR_USED) ||
(ret == CSP_ERR_ALREADY)) {
return 0;
}

LOG_ERR("Failed to bind CSP service port %u (%d)", port, ret);
return -EIO;
}

static int finch_csp_bind_services(void)
{
static const uint8_t service_ports[] = {
CSP_CMP,
CSP_PING,
CSP_MEMFREE,
CSP_REBOOT,
CSP_BUF_FREE,
CSP_UPTIME,
};

for (size_t i = 0; i < ARRAY_SIZE(service_ports); i++) {
int ret = finch_csp_bind_service(service_ports[i]);

if (ret < 0) {
return ret;
}
}

return 0;
}

int finch_csp_init(void)
{
int ret = 0;

k_mutex_lock(&finch_csp_lock, K_FOREVER);

if (finch_csp_initialized) {
goto out;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a log here to say something like "finch csp already initialized, skipping initialization"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unlock and return is better than goto I think

Copy link
Member

@TheArchons TheArchons Mar 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you think it's better? I think goto works better here because we're repeating less code. If we ever want to do anything else at the end of the function (like more cleanup) we can just add it to after out, rather than needing to update all returns, which there's a good chance we forget to update all of them.

The goto isn't that bad here because it's jumping further down the code, we aren't writing loops with a goto. But if you want to avoid gotos, would it be better to extract the main body of the function to another function and have this function just do the lock, call the other function, then unlock?

}

csp_conf.hostname = CONFIG_FINCH_CSP_HOSTNAME;
csp_conf.model = CONFIG_FINCH_CSP_MODEL;
csp_conf.revision = CONFIG_FINCH_CSP_REVISION;

csp_init();

csp_if_lo.addr = CONFIG_FINCH_CSP_NODE_ADDRESS;

ret = finch_csp_bind_services();
if (ret < 0) {
goto out;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A LOG_ERR here as well might be useful

}

finch_csp_router_tid = k_thread_create(
&finch_csp_router_thread_data,
finch_csp_router_stack,
K_THREAD_STACK_SIZEOF(finch_csp_router_stack),
finch_csp_router_thread,
NULL, NULL, NULL,
CONFIG_FINCH_CSP_ROUTER_PRIORITY,
0,
K_NO_WAIT);

if (finch_csp_router_tid == NULL) {
LOG_ERR("Failed to creat CSP router thread");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling

ret = -EIO;
goto out;
}

k_thread_name_set(finch_csp_router_tid, "finch_csp_router");
finch_csp_initialized = true;

LOG_INF("CSP core ready (addr=%u, host=%s)",
CONFIG_FINCH_CSP_NODE_ADDRESS,
CONFIG_FINCH_CSP_HOSTNAME);

out:
k_mutex_unlock(&finch_csp_lock);
return ret;
}
Loading