This is main:
/*
* User Input with 8 buttons and 2 encoders.
*
* Created: 03/02/2026 10:00:00
* Author : Simon
*/
#include "nano_lib.h"
#include "sam.h"
#include "project_settings.hpp"
#include "clock.hpp"
#include "rtc.hpp"
#include "class_gpio.hpp"
#include "class_user_encoder.hpp"
#include "can_open_class.hpp"
#include "can_regs.hpp"
#include "ioboard1_canopen_profile.hpp"
uint32_t last_btn_read_time = 0;
gpioCls btn[10];
encoder_class encoder1(PA10, PA11, 30, pull_up );
encoder_class encoder2(PA12, PA13, 30, pull_up );
can_open_class bus(CAN0);
io_board_1_class io( SERVER, &bus, 4UL, &encoder1, &encoder2 );
int main(void)
{
clock_setup();
rtc_initialize();
/* SOFTWARE SYSTEM SETUP */
encoder1.initialize( );
encoder2.initialize( );
btn[0].initializeInput( PB00, pullEnable, active_low );
btn[1].initializeInput( PB01, pullEnable, active_low );
btn[2].initializeInput( PB02, pullEnable, active_low );
btn[3].initializeInput( PB03, pullEnable, active_low );
btn[4].initializeInput( PB08, pullEnable, active_low );
btn[5].initializeInput( PB09, pullEnable, active_low );
btn[6].initializeInput( PB04, pullEnable, active_low );
btn[7].initializeInput( PB05, pullEnable, active_low );
btn[8].initializeInput( PB07, pullEnable, active_low );
btn[9].initializeInput( PB06, pullEnable, active_low );
encoder1.enable( );
encoder2.enable( );
bus.initialize( );
while (1)
{
io.encoder_config_update( ); // checks for new encoder commands and updates accordingly
if (( ms_time( ) - last_btn_read_time ) >= 2) {
last_btn_read_time = ms_time( );
io.short_press = 0;
io.long_press = 0;
for (uint32_t i = 0; i < 10; i++) {
btn[i].buttonCycle( );
io.short_press |= btn[i].short_press( ) << i;
io.long_press |= btn[i].long_press( ) << i;
}
if (( io.short_press != 0 ) || ( io.long_press != 0 )) {
bus.transmit_pdo( io.node_id, tpdo2 );
}
}
bus.heartBeatsTransmit( 500 );
}
}
void RTC_Handler(void)
{
RTC_REGS->MODE0.RTC_INTFLAG = 0xFFFF; // clear all status bits
}
void CAN0_Handler(void)
{
bus.interrupt_routine( );
}
void EIC_Handler( ) {
io.interrupt_routine( );
}
The warnings are all around the instantiation of io_board_1_class io( SERVER, &bus, 4UL, &encoder1, &encoder2 );
The constructor is:
io_board_1_class::io_board_1_class(device_type deviceType, can_open_class *new_bus, uint32_t new_node_n,
encoder_class * encoder0ptr, encoder_class * encoder1ptr)
{
bus->addNode(deviceType, node_id, object);
encoder[0] = encoder0ptr;
encoder[1] = encoder1ptr;
bus = new_bus;
node_id = new_node_n;
node_status.od_size = sizeof(object) / sizeof(od_type);
node_status.NMT_state = HB_OPERATIONAL;
node_status.heartbeat_time_stamp = 0;
// RPDO 1
node_status.pdo[0].cob_id.bit.not_valid = 0;
node_status.pdo[0].mapped_objects_n = 2; // set to the actual number of mapped objects but check the slave data sheet to ensure max is not exceeded
node_status.pdo[0].map[0] = ENCODER_0_HIGH_LIMIT;
node_status.pdo[0].map[1] = ENCODER_0_LOW_LIMIT;
node_status.pdo[0].map[2] = 0;
node_status.pdo[0].map[3] = 0;
node_status.pdo[0].highest_sub_index_supported = 5;
node_status.pdo[0].transmission_type = 1;
node_status.pdo[0].start_sync = 1;
node_status.pdo[0].cob_id.bit.cob_id = 0x200 + node_id;
// RPDO 2
node_status.pdo[1].cob_id.bit.not_valid = 0;
node_status.pdo[1].mapped_objects_n = 1; // set to the actual number of mapped objects but check the slave data sheet to ensure max is not exceeded
node_status.pdo[1].map[0] = ENCODER_0_COMMAND; //
node_status.pdo[1].map[1] = 0; //
node_status.pdo[1].map[2] = 0; //
node_status.pdo[1].map[3] = 0; //
node_status.pdo[1].highest_sub_index_supported = 5;
node_status.pdo[1].transmission_type = 1;
node_status.pdo[1].start_sync = 1;
node_status.pdo[1].cob_id.bit.cob_id = 0x300 + node_id;
// RPDO 3
node_status.pdo[2].cob_id.bit.not_valid = 0;
node_status.pdo[2].mapped_objects_n = 2; // set to the actual number of mapped objects but check the slave data sheet to ensure max is not exceeded
node_status.pdo[2].map[0] = ENCODER_1_HIGH_LIMIT; //
node_status.pdo[2].map[1] = ENCODER_1_LOW_LIMIT; //
node_status.pdo[2].map[2] = 0; //
node_status.pdo[2].map[3] = 0;
node_status.pdo[2].highest_sub_index_supported = 5;
node_status.pdo[2].transmission_type = 1;
node_status.pdo[2].start_sync = 1;
node_status.pdo[2].cob_id.bit.cob_id = 0x400 + node_id;
// RPDO 4
node_status.pdo[3].cob_id.bit.not_valid = 0;
node_status.pdo[3].mapped_objects_n = 1; // set to the actual number of mapped objects but check the slave data sheet to ensure max is not exceeded
node_status.pdo[3].map[0] = ENCODER_1_COMMAND; //
node_status.pdo[3].map[1] = 0; //
node_status.pdo[3].map[2] = 0; //
node_status.pdo[3].map[3] = 0;
node_status.pdo[3].highest_sub_index_supported = 5;
node_status.pdo[3].transmission_type = 1;
node_status.pdo[3].start_sync = 1;
node_status.pdo[3].cob_id.bit.cob_id = 0x500 + node_id;
// TPDO 1
node_status.pdo[4].cob_id.bit.not_valid = 0;
node_status.pdo[4].mapped_objects_n = 2; // set to the actual number of mapped objects but check the slave data sheet to ensure max is not exceeded
node_status.pdo[4].map[0] = ENCODER_0_COUNT; // number of dictionary object
node_status.pdo[4].map[1] = ENCODER_1_COUNT; // number of dictionary object
node_status.pdo[4].map[2] = 0;
node_status.pdo[4].map[3] = 0;
node_status.pdo[4].highest_sub_index_supported = 5;
node_status.pdo[4].transmission_type = 1;
node_status.pdo[4].start_sync = 1;
node_status.pdo[4].cob_id.bit.cob_id = 0x180 + node_id;
// TPDO 2
node_status.pdo[5].cob_id.bit.not_valid = 0;
node_status.pdo[5].mapped_objects_n = 4; // set to the actual number of mapped objects but check the slave data sheet to ensure max is not exceeded
node_status.pdo[5].map[0] = SHORT_PRESS_STATE; // number of dictionary object
node_status.pdo[5].map[1] = LONG_PRESS_STATE; // number of dictionary object
node_status.pdo[5].map[2] = 0; // number of dictionary object
node_status.pdo[5].map[3] = 0; // number of dictionary object
node_status.pdo[5].highest_sub_index_supported = 5;
node_status.pdo[5].transmission_type = 1;
node_status.pdo[5].start_sync = 1;
node_status.pdo[5].cob_id.bit.cob_id = 0x280 + node_id;
// TPDO 3
node_status.pdo[6].cob_id.bit.not_valid = 1;
node_status.pdo[6].mapped_objects_n = 1; // set to the actual number of mapped objects but check the slave data sheet to ensure max is not exceeded
node_status.pdo[6].map[0] = 0; // number of dictionary object
node_status.pdo[6].map[1] = 0; // number of dictionary object
node_status.pdo[6].map[2] = 0; // number of dictionary object
node_status.pdo[6].map[3] = 0; // number of dictionary object
node_status.pdo[6].highest_sub_index_supported = 5;
node_status.pdo[6].transmission_type = 1;
node_status.pdo[6].start_sync = 1;
node_status.pdo[6].cob_id.bit.cob_id = 0x380 + node_id;
// TPDO 4
node_status.pdo[7].cob_id.bit.not_valid = 1;
node_status.pdo[7].mapped_objects_n = 0; // set to the actual number of mapped objects but check the slave data sheet to ensure max is not exceeded
node_status.pdo[7].map[0] = 0; // number of dictionary object
node_status.pdo[7].map[1] = 0; // number of dictionary object
node_status.pdo[7].map[2] = 0; // number of dictionary object
node_status.pdo[7].map[3] = 0; // number of dictionary object
node_status.pdo[7].highest_sub_index_supported = 5;
node_status.pdo[7].transmission_type = 1;
node_status.pdo[7].start_sync = 1;
node_status.pdo[7].cob_id.bit.cob_id = 0x480 + node_id;
node_status.pdo_setup_state[0] = PDO_DEFAULT;
node_status.pdo_setup_state[1] = PDO_DEFAULT;
node_status.pdo_setup_state[2] = PDO_DEFAULT;
node_status.pdo_setup_state[3] = PDO_DEFAULT;
node_status.pdo_setup_state[4] = PDO_DEFAULT;
node_status.pdo_setup_state[5] = PDO_DEFAULT;
node_status.pdo_setup_state[6] = PDO_DEFAULT;
node_status.pdo_setup_state[7] = PDO_DEFAULT;
}
The make file started life as one of Ataradov's but by the time copilot has had it's way with it I don't know how much is left:
##############################################################################
BUILD = build
BIN = main
COMPILER = gcc
SYSTEM = ../../system
LIB = $(SYSTEM)/LIBS
MCU_SYSTEM = $(SYSTEM)/SAMC21
MCU_HW_LIB = $(MCU_SYSTEM)/lib_cpp
STARTUP = $(MCU_SYSTEM)/$(COMPILER)/$(COMPILER)/startup_samc21j17a.c
##############################################################################
.PHONY: all directory clean size
CC = arm-none-eabi-gcc
CXX = arm-none-eabi-g++
OBJCOPY = arm-none-eabi-objcopy
SIZE = arm-none-eabi-size
MKDIR = mkdir -p
CFLAGS += -W -Wall --std=gnu11 -Os -g
CFLAGS += -fno-diagnostics-show-caret
CFLAGS += -fdata-sections -ffunction-sections
CFLAGS += -funsigned-char -funsigned-bitfields
CFLAGS += -mcpu=cortex-m0plus -mthumb
CFLAGS += -MD -MP -MT $(BUILD)/$(*F).o -MF $(BUILD)/$(@F).d
CXXFLAGS += -W -Wall --std=gnu++17 -Os -g
CXXFLAGS += -fno-diagnostics-show-caret
CXXFLAGS += -fdata-sections -ffunction-sections
CXXFLAGS += -funsigned-char -funsigned-bitfields
CXXFLAGS += -mcpu=cortex-m0plus -mthumb
CXXFLAGS += -fno-exceptions -fno-rtti
CXXFLAGS += -MD -MP -MT $(BUILD)/$(*F).o -MF $(BUILD)/$(@F).d
LDFLAGS += --specs=nano.specs --specs=nosys.specs
LDFLAGS += -mcpu=cortex-m0plus -mthumb
LDFLAGS += -Wl,--gc-sections
LDFLAGS += -Wl,-wrap=_malloc_r -Wl,-wrap,_free_r
LDFLAGS += -Wl,--script=linker_script.ld
LDFLAGS += -Wl,-Map=$(BUILD)/$(BIN).map,--cref
# defines, must be updated in c_cpproperties.json as well
DEFINES += \
-D__m0plus__ \
-D__SAMC__ \
-D__SAMC21__ \
-D__SAMC21J__ \
-D__SAMC21J17A__ \
-DDONT_USE_CMSIS_INIT \
-DF_CPU=48000000UL \
INCLUDES += \
-I$(MCU_SYSTEM)/include \
-I$(MCU_SYSTEM)/include/m-profile \
-I$(MCU_SYSTEM)/include/component \
-I$(MCU_SYSTEM)/include/instance \
-I$(MCU_SYSTEM)/include/pio \
-I$(MCU_SYSTEM)/gcc \
-I$(MCU_HW_LIB) \
-I$(LIB) \
-I../settings \
-I./ \
SRCS += \
../main.cpp \
$(STARTUP)/startup_samc21j17a.c \
$(MCU_HW_LIB)/clock.cpp \
$(MCU_HW_LIB)/rtc.cpp \
$(LIB)/port_control.cpp \
$(LIB)/can_open_class.cpp \
$(LIB)/can_open_class_interrupt.cpp \
$(LIB)/class_gpio.cpp \
$(LIB)/class_user_encoder.cpp \
$(LIB)/ioboard1_canopen_profile.cpp \
CFLAGS += $(INCLUDES) $(DEFINES)
CXXFLAGS += $(INCLUDES) $(DEFINES)
OBJS = $(addprefix $(BUILD)/, $(notdir $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SRCS)))))
all: directory $(BUILD)/$(BIN).elf $(BUILD)/$(BIN).hex $(BUILD)/$(BIN).bin size
$(BUILD)/$(BIN).elf: $(OBJS)
$(CXX) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
$(BUILD)/$(BIN).hex: $(BUILD)/$(BIN).elf
$(OBJCOPY) -O ihex $^ $@
$(BUILD)/$(BIN).bin: $(BUILD)/$(BIN).elf
$(OBJCOPY) -O binary $^ $@
# Build C++ files in main directory
$(BUILD)/%.o: ../%.cpp
$(CXX) $(CXXFLAGS) $< -c -o $@
# Build C files in main directory
$(BUILD)/%.o: ../%.c
$(CC) $(CFLAGS) $< -c -o $@
# Build C files in system files directory
$(BUILD)/%.o: $(MCU_SYSTEM)/gcc/gcc/%.c
$(CC) $(CFLAGS) $< -c -o $@
# Build C++ files in my library directory
$(BUILD)/%.o: $(LIB)/%.cpp
$(CXX) $(CXXFLAGS) $< -c -o $@
# Build C++ files in mcu hardware library directory
$(BUILD)/%.o: $(MCU_HW_LIB)/%.cpp
$(CXX) $(CXXFLAGS) $< -c -o $@
directory:
-@powershell -Command "if (!(Test-Path '$(BUILD)')) { New-Item -ItemType Directory -Path '$(BUILD)' | Out-Null }"
size: $(BUILD)/$(BIN).elf
$(SIZE) -t $^
clean:
-@powershell -Command "if (Test-Path '$(BUILD)') { Remove-Item -Recurse -Force '$(BUILD)' }"
-include $(wildcard $(BUILD)/*.d)