Add Doxygen, clang-format, cppcheck, and Gitea CI
Some checks failed
CI / Build firmware (push) Failing after 2m1s
CI / Check formatting (push) Successful in 5s
CI / Static analysis (push) Failing after 5s
CI / Build documentation (push) Successful in 4s

Doxygen:
- Doxyfile: minimal config, HTML output to docs/, no LaTeX
- @file/@brief on all source files, full @param/@return on public API
- docs/ added to .gitignore

clang-format (14, Linux brace style, 4-space, column 100):
- .clang-format added
- Applied to entire codebase; this commit is the canonical baseline
- just format rewrites in-place; just format-check is the CI gate

cppcheck (--enable=warning,style,performance,portability):
- Linker-symbol pointer comparisons in startup.c suppressed with
  inline cppcheck-suppress (false positives, not real bugs)
- just lint runs cppcheck; zero warnings required to pass

Dockerfile gains clang-format, cppcheck, doxygen packages so all
tools run inside the existing container -- host stays clean.

Gitea Actions (.gitea/workflows/ci.yml):
- Four parallel jobs: build, format, lint, docs
- All jobs use the same Dockerfile-based image
- Doxygen job fails on any warning line in output
This commit is contained in:
Krzysztof Cieślik
2026-05-21 23:07:05 +02:00
parent 0e348414f8
commit 39a89036cc
15 changed files with 460 additions and 213 deletions

15
.clang-format Normal file
View File

@@ -0,0 +1,15 @@
---
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: Never
ColumnLimit: 100
AlignConsecutiveBitFields: true
AlignConsecutiveAssignments: false
AlignTrailingComments: true
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
BreakBeforeBraces: Linux
SortIncludes: false
SpaceAfterCStyleCast: false
SpaceBeforeParens: ControlStatements

99
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,99 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
IMAGE: ptt-builder
jobs:
build:
name: Build firmware
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Build container image
run: docker build -t $IMAGE .
- name: Compile firmware
run: |
docker run --rm \
--user "$(id -u):$(id -g)" \
-v "$PWD:/src" \
$IMAGE \
sh -c "cmake -B /src/build -G Ninja \
-DCMAKE_BUILD_TYPE=MinSizeRel /src \
&& ninja -C /src/build"
- name: Print size
run: |
docker run --rm \
-v "$PWD:/src" \
$IMAGE \
arm-none-eabi-size /src/build/firmware
format:
name: Check formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build container image
run: docker build -t $IMAGE .
- name: clang-format check
run: |
docker run --rm \
--user "$(id -u):$(id -g)" \
-v "$PWD:/src" \
$IMAGE \
sh -c "find /src/src /src/include -name '*.c' -o -name '*.h' | \
xargs clang-format --dry-run --Werror \
--style=file:/src/.clang-format"
lint:
name: Static analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build container image
run: docker build -t $IMAGE .
- name: cppcheck
run: |
docker run --rm \
--user "$(id -u):$(id -g)" \
-v "$PWD:/src" \
$IMAGE \
sh -c "cppcheck --error-exitcode=1 \
--enable=warning,style,performance,portability \
--suppress=missingInclude \
--inline-suppr \
--std=c11 \
-I /src/include \
/src/src/"
docs:
name: Build documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build container image
run: docker build -t $IMAGE .
- name: Doxygen
run: |
docker run --rm \
--user "$(id -u):$(id -g)" \
-v "$PWD:/src" \
$IMAGE \
sh -c "cd /src && doxygen Doxyfile 2>&1 | tee /tmp/doxy.log && \
! grep -q 'warning:' /tmp/doxy.log"

1
.gitignore vendored
View File

@@ -1 +1,2 @@
build/ build/
docs/

View File

@@ -6,6 +6,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libnewlib-arm-none-eabi \ libnewlib-arm-none-eabi \
cmake \ cmake \
ninja-build \ ninja-build \
clang-format \
cppcheck \
doxygen \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
WORKDIR /src WORKDIR /src

21
Doxyfile Normal file
View File

@@ -0,0 +1,21 @@
PROJECT_NAME = "ptt-fhss"
PROJECT_BRIEF = "Bare-metal PTT firmware for nRF52840 with FHSS"
PROJECT_NUMBER =
OUTPUT_DIRECTORY = docs
INPUT = include src
FILE_PATTERNS = *.h *.c
RECURSIVE = NO
EXTRACT_ALL = YES
EXTRACT_STATIC = YES
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_NO_PARAMDOC = YES
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_TIMESTAMP = NO
GENERATE_LATEX = NO
HAVE_DOT = NO
OPTIMIZE_OUTPUT_FOR_C = YES
JAVADOC_AUTOBRIEF = YES
PREDEFINED = NRF52840_XXAA

View File

@@ -1,6 +1,27 @@
/**
* @file fhss.h
* @brief FHSS channel sequencer based on AES-128-ECB.
*
* Both link endpoints derive the same hopping sequence independently from a
* shared 128-bit key and a monotonically increasing slot counter. No
* synchronisation traffic is required as long as both sides start from the
* same slot.
*/
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
/** @brief Reset the slot counter to zero. */
void fhss_init(void); void fhss_init(void);
uint8_t fhss_next_channel(void); /* next channel from AES-ECB PRNG sequence */
void fhss_sync_tick(void); /* call every FHSS_DWELL_MS ms */ /**
* @brief Return the next channel in the hopping sequence.
*
* Encrypts the current slot counter big-endian with AES-128-ECB, returns
* @c block[0] % 40, and advances the slot counter.
*
* @return Channel index in [0, 39].
*/
uint8_t fhss_next_channel(void);
/** @brief Advance the slot counter without transmitting (receiver side). */
void fhss_sync_tick(void);

View File

@@ -1,4 +1,16 @@
/**
* @file power.h
* @brief Power management: DC/DC regulator, GPIOTE wakeup, SYSTEM_ON sleep.
*/
#pragma once #pragma once
/** @brief Enable the DC/DC converter and configure GPIOTE wakeup on the PTT button. */
void power_init(void); void power_init(void);
void power_sleep_until_button(void); /* SYSTEM_ON WFI, woken by GPIOTE event */
/**
* @brief Enter SYSTEM_ON low-power sleep and return on the next GPIOTE event.
*
* Sets TASKS_LOWPWR then executes WFI. The CPU wakes when the GPIOTE
* interrupt fires (button press) and resumes from here.
*/
void power_sleep_until_button(void);

View File

@@ -1,7 +1,30 @@
/**
* @file radio.h
* @brief RADIO peripheral driver -- NRF_1Mbit proprietary mode.
*/
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
/** @brief Configure the RADIO peripheral (mode, packet format, address, CRC, power, channel). */
void radio_init(void); void radio_init(void);
void radio_set_channel(uint8_t ch); /* 0-39, maps to 2402-2480 MHz */
/**
* @brief Set the RF channel.
* @param ch Channel index 0-39, maps to 2400+ch MHz (MAP=0).
*/
void radio_set_channel(uint8_t ch);
/**
* @brief Transmit one packet synchronously.
*
* Loads @p data into the internal packet buffer, asserts TASKS_TXEN, and
* returns after EVENTS_END fires. The RADIO is DISABLED automatically via
* the END_DISABLE shortcut before the function returns.
*
* @param data Payload bytes.
* @param len Payload length (0-255 bytes).
*/
void radio_tx(const uint8_t *data, uint8_t len); void radio_tx(const uint8_t *data, uint8_t len);
void radio_tx_burst(void); /* TX with FHSS hopping */
/** @brief Transmit a burst with FHSS hopping (not yet implemented). */
void radio_tx_burst(void);

View File

@@ -1,15 +1,16 @@
/**
* @file regs.h
* @brief Hardware register bitfield unions for nRF52840 peripherals.
*
* Layout is guaranteed correct only with arm-none-eabi-gcc (LSB-first
* bitfields). Bit ranges match nRF52840 Product Specification v1.7.
*/
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
/*
* Hardware register bitfield unions for nRF52840 peripherals.
* Layout is guaranteed correct only with arm-none-eabi-gcc (LSB-first bitfields).
* Bit ranges match nRF52840 Product Specification v1.7.
*/
/* GPIOTE */ /* GPIOTE */
/* CONFIG[n]: channel configuration */ /** @brief GPIOTE CONFIG[n]: channel configuration register. */
typedef union { typedef union {
struct { struct {
uint32_t MODE : 2; /* [1:0] 0=Disabled 1=Event 3=Task */ uint32_t MODE : 2; /* [1:0] 0=Disabled 1=Event 3=Task */
@@ -33,7 +34,7 @@ typedef union {
#define GPIOTE_POL_HITOLO 2u #define GPIOTE_POL_HITOLO 2u
#define GPIOTE_POL_TOGGLE 3u #define GPIOTE_POL_TOGGLE 3u
/* INTENSET / INTENCLR: interrupt enable */ /** @brief GPIOTE INTENSET / INTENCLR: interrupt enable register. */
typedef union { typedef union {
struct { struct {
uint32_t IN0 : 1; /* [0] channel 0 input event */ uint32_t IN0 : 1; /* [0] channel 0 input event */
@@ -52,7 +53,7 @@ typedef union {
/* RADIO */ /* RADIO */
/* FREQUENCY: radio channel */ /** @brief RADIO FREQUENCY: RF channel selection register. */
typedef union { typedef union {
struct { struct {
uint32_t FREQUENCY : 7; /* [6:0] offset from base frequency in MHz */ uint32_t FREQUENCY : 7; /* [6:0] offset from base frequency in MHz */
@@ -66,7 +67,7 @@ typedef union {
#define RADIO_MAP_DEFAULT 0u /* channel n -> 2400+n MHz */ #define RADIO_MAP_DEFAULT 0u /* channel n -> 2400+n MHz */
#define RADIO_MAP_BLE 1u /* channel n -> 2360+n MHz */ #define RADIO_MAP_BLE 1u /* channel n -> 2360+n MHz */
/* TXPOWER: transmit power */ /** @brief RADIO TXPOWER: transmit power register. */
typedef union { typedef union {
struct { struct {
int32_t TXPOWER : 8; /* [7:0] signed dBm: +8, +7, +6, +5, +4, +3, +2, int32_t TXPOWER : 8; /* [7:0] signed dBm: +8, +7, +6, +5, +4, +3, +2,
@@ -76,7 +77,7 @@ typedef union {
uint32_t reg; uint32_t reg;
} radio_txpower_t; } radio_txpower_t;
/* MODE: radio data rate and modulation */ /** @brief RADIO MODE: data rate and modulation register. */
typedef union { typedef union {
struct { struct {
uint32_t MODE : 4; /* [3:0] 0=NRF_1Mbit 1=NRF_2Mbit 4=BLE_1Mbit ... */ uint32_t MODE : 4; /* [3:0] 0=NRF_1Mbit 1=NRF_2Mbit 4=BLE_1Mbit ... */
@@ -89,7 +90,7 @@ typedef union {
#define RADIO_MODE_NRF_2MBIT 1u #define RADIO_MODE_NRF_2MBIT 1u
#define RADIO_MODE_BLE_1MBIT 4u #define RADIO_MODE_BLE_1MBIT 4u
/* PCNF0: packet configuration register 0 */ /** @brief RADIO PCNF0: packet configuration register 0 (header fields). */
typedef union { typedef union {
struct { struct {
uint32_t LFLEN : 4; /* [3:0] length of LENGTH field in bits */ uint32_t LFLEN : 4; /* [3:0] length of LENGTH field in bits */
@@ -106,7 +107,7 @@ typedef union {
uint32_t reg; uint32_t reg;
} radio_pcnf0_t; } radio_pcnf0_t;
/* PCNF1: packet configuration register 1 */ /** @brief RADIO PCNF1: packet configuration register 1 (payload and address). */
typedef union { typedef union {
struct { struct {
uint32_t MAXLEN : 8; /* [7:0] maximum payload length in bytes */ uint32_t MAXLEN : 8; /* [7:0] maximum payload length in bytes */
@@ -120,7 +121,7 @@ typedef union {
uint32_t reg; uint32_t reg;
} radio_pcnf1_t; } radio_pcnf1_t;
/* CRCCNF: CRC configuration */ /** @brief RADIO CRCCNF: CRC configuration register. */
typedef union { typedef union {
struct { struct {
uint32_t LEN : 2; /* [1:0] 0=disabled 1=1 byte 2=2 bytes 3=3 bytes */ uint32_t LEN : 2; /* [1:0] 0=disabled 1=1 byte 2=2 bytes 3=3 bytes */
@@ -136,7 +137,7 @@ typedef union {
#define RADIO_CRCCNF_LEN_TWO 2u #define RADIO_CRCCNF_LEN_TWO 2u
#define RADIO_CRCCNF_LEN_THREE 3u #define RADIO_CRCCNF_LEN_THREE 3u
/* SHORTS: shortcut register */ /** @brief RADIO SHORTS: hardware shortcut register. */
typedef union { typedef union {
struct { struct {
uint32_t READY_START : 1; /* [0] READY -> TASKS_START */ uint32_t READY_START : 1; /* [0] READY -> TASKS_START */

View File

@@ -12,6 +12,8 @@ user_ns := `command -v podman >/dev/null 2>&1 \
&& echo "--userns=keep-id" \ && echo "--userns=keep-id" \
|| echo "--user $(id -u):$(id -g)"` || echo "--user $(id -u):$(id -g)"`
src_files := "find /src/src /src/include -name '*.c' -o -name '*.h'"
# recipes # recipes
# build container image (only rebuilt when Dockerfile changes) # build container image (only rebuilt when Dockerfile changes)
image-build: image-build:
@@ -27,6 +29,44 @@ build: image-build
-DCMAKE_BUILD_TYPE=MinSizeRel /src \ -DCMAKE_BUILD_TYPE=MinSizeRel /src \
&& ninja -C /src/{{build_dir}}" && ninja -C /src/{{build_dir}}"
# reformat all source files in-place with clang-format
format: image-build
{{engine}} run --rm \
{{user_ns}} \
-v "{{justfile_directory()}}:/src:z" \
{{image}} \
sh -c "{{src_files}} | xargs clang-format -i --style=file:/src/.clang-format"
# check formatting without modifying files (used in CI)
format-check: image-build
{{engine}} run --rm \
{{user_ns}} \
-v "{{justfile_directory()}}:/src:z" \
{{image}} \
sh -c "{{src_files}} | xargs clang-format --dry-run --Werror --style=file:/src/.clang-format"
# static analysis with cppcheck
lint: image-build
{{engine}} run --rm \
{{user_ns}} \
-v "{{justfile_directory()}}:/src:z" \
{{image}} \
sh -c "cppcheck --error-exitcode=1 \
--enable=warning,style,performance,portability \
--suppress=missingInclude \
--inline-suppr \
--std=c11 \
-I /src/include \
/src/src/"
# generate HTML documentation with Doxygen
docs: image-build
{{engine}} run --rm \
{{user_ns}} \
-v "{{justfile_directory()}}:/src:z" \
{{image}} \
sh -c "cd /src && doxygen Doxyfile"
# flash firmware via pyocd on the host (requires USB / DAPLink) # flash firmware via pyocd on the host (requires USB / DAPLink)
flash: build flash: build
pyocd flash --target nrf52840 {{build_dir}}/firmware.hex pyocd flash --target nrf52840 {{build_dir}}/firmware.hex
@@ -35,10 +75,10 @@ flash: build
gdbserver: gdbserver:
pyocd gdbserver --target nrf52840 --port 3333 pyocd gdbserver --target nrf52840 --port 3333
# remove build artifacts # remove build artifacts and generated docs
clean: clean:
rm -rf {{build_dir}} rm -rf {{build_dir}} docs
# remove build artifacts AND the container image # remove build artifacts, docs AND the container image
clean-all: clean clean-all: clean
{{engine}} rmi {{image}} 2>/dev/null || true {{engine}} rmi {{image}} 2>/dev/null || true

View File

@@ -1,3 +1,6 @@
/** @file fhss.c
* @brief FHSS channel sequencer implementation.
*/
#include "fhss.h" #include "fhss.h"
#include <aes.h> #include <aes.h>
@@ -6,8 +9,7 @@
/* TODO: replace with a real shared secret before deployment */ /* TODO: replace with a real shared secret before deployment */
static const uint8_t shared_key[16] = { static const uint8_t shared_key[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}; };
static uint32_t slot; static uint32_t slot;
@@ -26,7 +28,7 @@ uint8_t fhss_next_channel(void)
block[0] = (uint8_t)(slot >> 24); block[0] = (uint8_t)(slot >> 24);
block[1] = (uint8_t)(slot >> 16); block[1] = (uint8_t)(slot >> 16);
block[2] = (uint8_t)(slot >> 8); block[2] = (uint8_t)(slot >> 8);
block[3] = (uint8_t)(slot ); block[3] = (uint8_t)(slot);
AES_init_ctx(&ctx, shared_key); AES_init_ctx(&ctx, shared_key);
AES_ECB_encrypt(&ctx, block); /* encrypts block in-place */ AES_ECB_encrypt(&ctx, block); /* encrypts block in-place */

View File

@@ -1,8 +1,11 @@
/** @file main.c
* @brief Entry point: initialise peripherals and run the PTT event loop.
*/
#include "radio.h" #include "radio.h"
#include "power.h" #include "power.h"
#include <stdint.h> #include <stdint.h>
static const uint8_t test_frame[] = { 0xDE, 0xAD, 0xBE, 0xEF }; static const uint8_t test_frame[] = {0xDE, 0xAD, 0xBE, 0xEF};
int main(void) int main(void)
{ {

View File

@@ -1,3 +1,6 @@
/** @file power.c
* @brief Power management implementation.
*/
#include "power.h" #include "power.h"
#include "regs.h" #include "regs.h"
#include <nrf52840.h> #include <nrf52840.h>
@@ -17,10 +20,9 @@ void power_init(void)
.PSEL = BUTTON_PIN, .PSEL = BUTTON_PIN,
.PORT = 0u, .PORT = 0u,
.POLARITY = GPIOTE_POL_LOTOHI, .POLARITY = GPIOTE_POL_LOTOHI,
} }}.reg;
}.reg;
NRF_GPIOTE->INTENSET = (gpiote_inten_t){ .bit.IN0 = 1u }.reg; NRF_GPIOTE->INTENSET = (gpiote_inten_t){.bit.IN0 = 1u}.reg;
NVIC_EnableIRQ(GPIOTE_IRQn); NVIC_EnableIRQ(GPIOTE_IRQn);
} }

View File

@@ -1,3 +1,6 @@
/** @file radio.c
* @brief RADIO peripheral driver implementation.
*/
#include "radio.h" #include "radio.h"
#include "regs.h" #include "regs.h"
#include <nrf52840.h> #include <nrf52840.h>
@@ -27,20 +30,17 @@ static uint8_t pkt_buf[BUF_SIZE];
void radio_init(void) void radio_init(void)
{ {
NRF_RADIO->MODE = (radio_mode_t){ NRF_RADIO->MODE = (radio_mode_t){.bit = {.MODE = RADIO_MODE_NRF_1MBIT}}.reg;
.bit = { .MODE = RADIO_MODE_NRF_1MBIT }
}.reg;
/* 8-bit LENGTH field, no S0/S1, 8-bit preamble, CRC not part of LENGTH */ /* 8-bit LENGTH field, no S0/S1, 8-bit preamble, CRC not part of LENGTH */
NRF_RADIO->PCNF0 = (radio_pcnf0_t){ NRF_RADIO->PCNF0 =
.bit = { .LFLEN = 8, .S0LEN = 0, .S1LEN = 0, .PLEN = 0, .CRCINC = 0 } (radio_pcnf0_t){.bit = {.LFLEN = 8, .S0LEN = 0, .S1LEN = 0, .PLEN = 0, .CRCINC = 0}}.reg;
}.reg;
/* max 255-byte payload, 3-byte base address, little-endian, no whitening */ /* max 255-byte payload, 3-byte base address, little-endian, no whitening */
NRF_RADIO->PCNF1 = (radio_pcnf1_t){ NRF_RADIO->PCNF1 =
.bit = { .MAXLEN = MAX_PAYLOAD, .STATLEN = 0, .BALEN = 3, (radio_pcnf1_t){
.ENDIAN = 0, .WHITEEN = 0 } .bit = {.MAXLEN = MAX_PAYLOAD, .STATLEN = 0, .BALEN = 3, .ENDIAN = 0, .WHITEEN = 0}}
}.reg; .reg;
NRF_RADIO->BASE0 = RADIO_BASE0; NRF_RADIO->BASE0 = RADIO_BASE0;
NRF_RADIO->PREFIX0 = RADIO_PREFIX0; NRF_RADIO->PREFIX0 = RADIO_PREFIX0;
@@ -48,33 +48,29 @@ void radio_init(void)
NRF_RADIO->RXADDRESSES = 1; /* receive on logical address 0 */ NRF_RADIO->RXADDRESSES = 1; /* receive on logical address 0 */
/* 2-byte CRC, skip address field */ /* 2-byte CRC, skip address field */
NRF_RADIO->CRCCNF = (radio_crccnf_t){ NRF_RADIO->CRCCNF = (radio_crccnf_t){.bit = {.LEN = RADIO_CRCCNF_LEN_TWO, .SKIPADDR = 1}}.reg;
.bit = { .LEN = RADIO_CRCCNF_LEN_TWO, .SKIPADDR = 1 }
}.reg;
NRF_RADIO->CRCPOLY = 0x11021u; /* CRC-16/CCITT */ NRF_RADIO->CRCPOLY = 0x11021u; /* CRC-16/CCITT */
NRF_RADIO->CRCINIT = 0xFFFFu; NRF_RADIO->CRCINIT = 0xFFFFu;
NRF_RADIO->TXPOWER = (radio_txpower_t){ NRF_RADIO->TXPOWER =
.bit = { .TXPOWER = 0 } /* 0 dBm */ (radio_txpower_t){
}.reg; .bit = {.TXPOWER = 0} /* 0 dBm */
}
.reg;
NRF_RADIO->FREQUENCY = (radio_frequency_t){ NRF_RADIO->FREQUENCY =
.bit = { .FREQUENCY = DEFAULT_CHANNEL, .MAP = RADIO_MAP_DEFAULT } (radio_frequency_t){.bit = {.FREQUENCY = DEFAULT_CHANNEL, .MAP = RADIO_MAP_DEFAULT}}.reg;
}.reg;
/* READY -> START and END -> DISABLE shortcuts so CPU only triggers TXEN */ /* READY -> START and END -> DISABLE shortcuts so CPU only triggers TXEN */
NRF_RADIO->SHORTS = (radio_shorts_t){ NRF_RADIO->SHORTS = (radio_shorts_t){.bit = {.READY_START = 1, .END_DISABLE = 1}}.reg;
.bit = { .READY_START = 1, .END_DISABLE = 1 }
}.reg;
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf; NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf;
} }
void radio_set_channel(uint8_t ch) void radio_set_channel(uint8_t ch)
{ {
NRF_RADIO->FREQUENCY = (radio_frequency_t){ NRF_RADIO->FREQUENCY =
.bit = { .FREQUENCY = ch, .MAP = RADIO_MAP_DEFAULT } (radio_frequency_t){.bit = {.FREQUENCY = ch, .MAP = RADIO_MAP_DEFAULT}}.reg;
}.reg;
} }
void radio_tx(const uint8_t *data, uint8_t len) void radio_tx(const uint8_t *data, uint8_t len)

View File

@@ -1,3 +1,6 @@
/** @file startup.c
* @brief Vector table and Reset_Handler for nRF52840 (no SoftDevice).
*/
#include <stdint.h> #include <stdint.h>
/* linker script symbols */ /* linker script symbols */
@@ -14,7 +17,8 @@ void Reset_Handler(void);
static void __attribute__((used)) Default_Handler(void) static void __attribute__((used)) Default_Handler(void)
{ {
while (1); while (1)
;
} }
/* ARM Cortex-M4 core exceptions */ /* ARM Cortex-M4 core exceptions */
@@ -32,8 +36,10 @@ void SysTick_Handler(void) __attribute__((weak, alias("Default_Handler")));
void POWER_CLOCK_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); void POWER_CLOCK_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
void RADIO_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); void RADIO_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
void UARTE0_UART0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); void UARTE0_UART0_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void)
void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); __attribute__((weak, alias("Default_Handler")));
void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void)
__attribute__((weak, alias("Default_Handler")));
void NFCT_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); void NFCT_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
void GPIOTE_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); void GPIOTE_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
void SAADC_IRQHandler(void) __attribute__((weak, alias("Default_Handler"))); void SAADC_IRQHandler(void) __attribute__((weak, alias("Default_Handler")));
@@ -77,8 +83,7 @@ void SPIM3_IRQHandler(void) __attribute__((weak, al
typedef void (*vector_fn)(void); typedef void (*vector_fn)(void);
__attribute__((section(".isr_vector"), used)) __attribute__((section(".isr_vector"), used)) const vector_fn vectors[64] = {
const vector_fn vectors[64] = {
/* 0 */ (vector_fn)&_estack, /* 0 */ (vector_fn)&_estack,
/* 1 */ Reset_Handler, /* 1 */ Reset_Handler,
/* 2 */ NMI_Handler, /* 2 */ NMI_Handler,
@@ -153,16 +158,19 @@ void Reset_Handler(void)
/* copy .data initializers from Flash to RAM */ /* copy .data initializers from Flash to RAM */
uint32_t *src = &_sidata; uint32_t *src = &_sidata;
uint32_t *dst = &_sdata; uint32_t *dst = &_sdata;
// cppcheck-suppress comparePointers
while (dst < &_edata) { while (dst < &_edata) {
*dst++ = *src++; *dst++ = *src++;
} }
/* zero .bss */ /* zero .bss */
dst = &_sbss; dst = &_sbss;
// cppcheck-suppress comparePointers
while (dst < &_ebss) { while (dst < &_ebss) {
*dst++ = 0u; *dst++ = 0u;
} }
main(); main();
while (1); while (1)
;
} }