mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 10:46:31 +00:00
Remove vulnerabilities
This commit is contained in:
parent
d258b9a758
commit
0632f4e7d6
@ -1,3 +0,0 @@
|
||||
# generated by ESP-IDF
|
||||
managed_components/
|
||||
dependencies.lock
|
@ -1,7 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# include the top-level cmake
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# name the project something nice
|
||||
project(esp-sx1261)
|
@ -1,4 +0,0 @@
|
||||
# register the component and set "RadioLib", "esp_timer" and "driver" as required
|
||||
idf_component_register(SRCS "main.cpp"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES RadioLib esp_timer driver)
|
@ -1,322 +0,0 @@
|
||||
#ifndef ESP_HAL_H
|
||||
#define ESP_HAL_H
|
||||
|
||||
// include RadioLib
|
||||
#include <RadioLib.h>
|
||||
|
||||
// this example only works on ESP32 and is unlikely to work on ESP32S2/S3 etc.
|
||||
// if you need high portability, you should probably use Arduino anyway ...
|
||||
#if CONFIG_IDF_TARGET_ESP32 == 0
|
||||
#error Target is not ESP32!
|
||||
#endif
|
||||
|
||||
// include all the dependencies
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp32/rom/gpio.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/spi_struct.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
// define Arduino-style macros
|
||||
#define LOW (0x0)
|
||||
#define HIGH (0x1)
|
||||
#define INPUT (0x01)
|
||||
#define OUTPUT (0x03)
|
||||
#define RISING (0x01)
|
||||
#define FALLING (0x02)
|
||||
#define NOP() asm volatile ("nop")
|
||||
|
||||
#define MATRIX_DETACH_OUT_SIG (0x100)
|
||||
#define MATRIX_DETACH_IN_LOW_PIN (0x30)
|
||||
|
||||
// all of the following is needed to calculate SPI clock divider
|
||||
#define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1)))
|
||||
|
||||
typedef union {
|
||||
uint32_t value;
|
||||
struct {
|
||||
uint32_t clkcnt_l: 6;
|
||||
uint32_t clkcnt_h: 6;
|
||||
uint32_t clkcnt_n: 6;
|
||||
uint32_t clkdiv_pre: 13;
|
||||
uint32_t clk_equ_sysclk: 1;
|
||||
};
|
||||
} spiClk_t;
|
||||
|
||||
uint32_t getApbFrequency() {
|
||||
rtc_cpu_freq_config_t conf;
|
||||
rtc_clk_cpu_freq_get_config(&conf);
|
||||
|
||||
if(conf.freq_mhz >= 80) {
|
||||
return(80 * MHZ);
|
||||
}
|
||||
|
||||
return((conf.source_freq_mhz * MHZ) / conf.div);
|
||||
}
|
||||
|
||||
uint32_t spiFrequencyToClockDiv(uint32_t freq) {
|
||||
uint32_t apb_freq = getApbFrequency();
|
||||
if(freq >= apb_freq) {
|
||||
return SPI_CLK_EQU_SYSCLK;
|
||||
}
|
||||
|
||||
const spiClk_t minFreqReg = { 0x7FFFF000 };
|
||||
uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg);
|
||||
if(freq < minFreq) {
|
||||
return minFreqReg.value;
|
||||
}
|
||||
|
||||
uint8_t calN = 1;
|
||||
spiClk_t bestReg = { 0 };
|
||||
int32_t bestFreq = 0;
|
||||
while(calN <= 0x3F) {
|
||||
spiClk_t reg = { 0 };
|
||||
int32_t calFreq;
|
||||
int32_t calPre;
|
||||
int8_t calPreVari = -2;
|
||||
|
||||
reg.clkcnt_n = calN;
|
||||
|
||||
while(calPreVari++ <= 1) {
|
||||
calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari;
|
||||
if(calPre > 0x1FFF) {
|
||||
reg.clkdiv_pre = 0x1FFF;
|
||||
} else if(calPre <= 0) {
|
||||
reg.clkdiv_pre = 0;
|
||||
} else {
|
||||
reg.clkdiv_pre = calPre;
|
||||
}
|
||||
reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2);
|
||||
calFreq = ClkRegToFreq(®);
|
||||
if(calFreq == (int32_t) freq) {
|
||||
memcpy(&bestReg, ®, sizeof(bestReg));
|
||||
break;
|
||||
} else if(calFreq < (int32_t) freq) {
|
||||
if(RADIOLIB_ABS(freq - calFreq) < RADIOLIB_ABS(freq - bestFreq)) {
|
||||
bestFreq = calFreq;
|
||||
memcpy(&bestReg, ®, sizeof(bestReg));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(calFreq == (int32_t) freq) {
|
||||
break;
|
||||
}
|
||||
calN++;
|
||||
}
|
||||
return(bestReg.value);
|
||||
}
|
||||
|
||||
// create a new ESP-IDF hardware abstraction layer
|
||||
// the HAL must inherit from the base RadioLibHal class
|
||||
// and implement all of its virtual methods
|
||||
// this is pretty much just copied from Arduino ESP32 core
|
||||
class EspHal : public RadioLibHal {
|
||||
public:
|
||||
// default constructor - initializes the base HAL and any needed private members
|
||||
EspHal(int8_t sck, int8_t miso, int8_t mosi)
|
||||
: RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING),
|
||||
spiSCK(sck), spiMISO(miso), spiMOSI(mosi) {
|
||||
}
|
||||
|
||||
void init() override {
|
||||
// we only need to init the SPI here
|
||||
spiBegin();
|
||||
}
|
||||
|
||||
void term() override {
|
||||
// we only need to stop the SPI here
|
||||
spiEnd();
|
||||
}
|
||||
|
||||
// GPIO-related methods (pinMode, digitalWrite etc.) should check
|
||||
// RADIOLIB_NC as an alias for non-connected pins
|
||||
void pinMode(uint32_t pin, uint32_t mode) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_hal_context_t gpiohal;
|
||||
gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0);
|
||||
|
||||
gpio_config_t conf = {
|
||||
.pin_bit_mask = (1ULL<<pin),
|
||||
.mode = (gpio_mode_t)mode,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = (gpio_int_type_t)gpiohal.dev->pin[pin].int_type,
|
||||
};
|
||||
gpio_config(&conf);
|
||||
}
|
||||
|
||||
void digitalWrite(uint32_t pin, uint32_t value) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_set_level((gpio_num_t)pin, value);
|
||||
}
|
||||
|
||||
uint32_t digitalRead(uint32_t pin) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(gpio_get_level((gpio_num_t)pin));
|
||||
}
|
||||
|
||||
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
|
||||
if(interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_install_isr_service((int)ESP_INTR_FLAG_IRAM);
|
||||
gpio_set_intr_type((gpio_num_t)interruptNum, (gpio_int_type_t)(mode & 0x7));
|
||||
|
||||
// this uses function typecasting, which is not defined when the functions have different signatures
|
||||
// untested and might not work
|
||||
gpio_isr_handler_add((gpio_num_t)interruptNum, (void (*)(void*))interruptCb, NULL);
|
||||
}
|
||||
|
||||
void detachInterrupt(uint32_t interruptNum) override {
|
||||
if(interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_isr_handler_remove((gpio_num_t)interruptNum);
|
||||
gpio_wakeup_disable((gpio_num_t)interruptNum);
|
||||
gpio_set_intr_type((gpio_num_t)interruptNum, GPIO_INTR_DISABLE);
|
||||
}
|
||||
|
||||
void delay(unsigned long ms) override {
|
||||
vTaskDelay(ms / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
void delayMicroseconds(unsigned long us) override {
|
||||
uint64_t m = (uint64_t)esp_timer_get_time();
|
||||
if(us) {
|
||||
uint64_t e = (m + us);
|
||||
if(m > e) { // overflow
|
||||
while((uint64_t)esp_timer_get_time() > e) {
|
||||
NOP();
|
||||
}
|
||||
}
|
||||
while((uint64_t)esp_timer_get_time() < e) {
|
||||
NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long millis() override {
|
||||
return((unsigned long)(esp_timer_get_time() / 1000ULL));
|
||||
}
|
||||
|
||||
unsigned long micros() override {
|
||||
return((unsigned long)(esp_timer_get_time()));
|
||||
}
|
||||
|
||||
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
this->pinMode(pin, INPUT);
|
||||
uint32_t start = this->micros();
|
||||
uint32_t curtick = this->micros();
|
||||
|
||||
while(this->digitalRead(pin) == state) {
|
||||
if((this->micros() - curtick) > timeout) {
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
return(this->micros() - start);
|
||||
}
|
||||
|
||||
void spiBegin() {
|
||||
// enable peripheral
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST);
|
||||
|
||||
// reset the control struct
|
||||
this->spi->slave.trans_done = 0;
|
||||
this->spi->slave.val = 0;
|
||||
this->spi->pin.val = 0;
|
||||
this->spi->user.val = 0;
|
||||
this->spi->user1.val = 0;
|
||||
this->spi->ctrl.val = 0;
|
||||
this->spi->ctrl1.val = 0;
|
||||
this->spi->ctrl2.val = 0;
|
||||
this->spi->clock.val = 0;
|
||||
this->spi->user.usr_mosi = 1;
|
||||
this->spi->user.usr_miso = 1;
|
||||
this->spi->user.doutdin = 1;
|
||||
for(uint8_t i = 0; i < 16; i++) {
|
||||
this->spi->data_buf[i] = 0x00000000;
|
||||
}
|
||||
|
||||
// set SPI mode 0
|
||||
this->spi->pin.ck_idle_edge = 0;
|
||||
this->spi->user.ck_out_edge = 0;
|
||||
|
||||
// set bit order to MSB first
|
||||
this->spi->ctrl.wr_bit_order = 0;
|
||||
this->spi->ctrl.rd_bit_order = 0;
|
||||
|
||||
// set the clock
|
||||
this->spi->clock.val = spiFrequencyToClockDiv(2000000);
|
||||
|
||||
// initialize pins
|
||||
this->pinMode(this->spiSCK, OUTPUT);
|
||||
this->pinMode(this->spiMISO, INPUT);
|
||||
this->pinMode(this->spiMOSI, OUTPUT);
|
||||
gpio_matrix_out(this->spiSCK, HSPICLK_OUT_IDX, false, false);
|
||||
gpio_matrix_in(this->spiMISO, HSPIQ_OUT_IDX, false);
|
||||
gpio_matrix_out(this->spiMOSI, HSPID_IN_IDX, false, false);
|
||||
}
|
||||
|
||||
void spiBeginTransaction() {
|
||||
// not needed - in ESP32 Arduino core, this function
|
||||
// repeats clock div, mode and bit order configuration
|
||||
}
|
||||
|
||||
uint8_t spiTransferByte(uint8_t b) {
|
||||
this->spi->mosi_dlen.usr_mosi_dbitlen = 7;
|
||||
this->spi->miso_dlen.usr_miso_dbitlen = 7;
|
||||
this->spi->data_buf[0] = b;
|
||||
this->spi->cmd.usr = 1;
|
||||
while(this->spi->cmd.usr);
|
||||
return(this->spi->data_buf[0] & 0xFF);
|
||||
}
|
||||
|
||||
void spiTransfer(uint8_t* out, size_t len, uint8_t* in) {
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
in[i] = this->spiTransferByte(out[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void spiEndTransaction() {
|
||||
// nothing needs to be done here
|
||||
}
|
||||
|
||||
void spiEnd() {
|
||||
// detach pins
|
||||
gpio_matrix_out(this->spiSCK, MATRIX_DETACH_OUT_SIG, false, false);
|
||||
gpio_matrix_in(this->spiMISO, MATRIX_DETACH_IN_LOW_PIN, false);
|
||||
gpio_matrix_out(this->spiMOSI, MATRIX_DETACH_OUT_SIG, false, false);
|
||||
}
|
||||
|
||||
private:
|
||||
// the HAL can contain any additional private members
|
||||
int8_t spiSCK;
|
||||
int8_t spiMISO;
|
||||
int8_t spiMOSI;
|
||||
spi_dev_t * spi = (volatile spi_dev_t *)(DR_REG_SPI2_BASE);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,7 +0,0 @@
|
||||
dependencies:
|
||||
RadioLib:
|
||||
# referenced locally because the example is a part of the repository itself
|
||||
# under normal circumstances, it's preferrable to reference the repository instead
|
||||
# for other options, see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html
|
||||
path: ../../../../../RadioLib
|
||||
#git: https://github.com/jgromes/RadioLib.git
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
RadioLib Non-Arduino ESP-IDF Example
|
||||
|
||||
This example shows how to use RadioLib without Arduino.
|
||||
In this case, a Liligo T-BEAM (ESP32 and SX1276)
|
||||
is used.
|
||||
|
||||
Can be used as a starting point to port RadioLib to any platform!
|
||||
See this API reference page for details on the RadioLib hardware abstraction
|
||||
https://jgromes.github.io/RadioLib/class_hal.html
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// include the hardware abstraction layer
|
||||
#include "EspHal.h"
|
||||
|
||||
// create a new instance of the HAL class
|
||||
EspHal* hal = new EspHal(5, 19, 27);
|
||||
|
||||
// now we can create the radio module
|
||||
// NSS pin: 18
|
||||
// DIO0 pin: 26
|
||||
// NRST pin: 14
|
||||
// DIO1 pin: 33
|
||||
SX1276 radio = new Module(hal, 18, 26, 14, 33);
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// the entry point for the program
|
||||
// it must be declared as "extern C" because the compiler assumes this will be a C function
|
||||
extern "C" void app_main(void) {
|
||||
// initialize just like with Arduino
|
||||
ESP_LOGI(TAG, "[SX1276] Initializing ... ");
|
||||
int state = radio.begin();
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
ESP_LOGI(TAG, "failed, code %d\n", state);
|
||||
while(true) {
|
||||
hal->delay(1000);
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "success!\n");
|
||||
|
||||
// loop forever
|
||||
for(;;) {
|
||||
// send a packet
|
||||
ESP_LOGI(TAG, "[SX1276] Transmitting packet ... ");
|
||||
state = radio.transmit("Hello World!");
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
// the packet was successfully transmitted
|
||||
ESP_LOGI(TAG, "success!");
|
||||
|
||||
} else {
|
||||
ESP_LOGI(TAG, "failed, code %d\n", state);
|
||||
|
||||
}
|
||||
|
||||
// wait for a second before transmitting again
|
||||
hal->delay(1000);
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
build/
|
@ -1,33 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
# Pull in SDK (must be before project)
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(pico-sx1276 C CXX ASM)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Initialize the SDK
|
||||
pico_sdk_init()
|
||||
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wno-format
|
||||
-Wno-unused-function
|
||||
)
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib")
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
main.cpp
|
||||
)
|
||||
|
||||
# Pull in common dependencies
|
||||
target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_spi hardware_gpio hardware_timer RadioLib)
|
||||
|
||||
|
||||
pico_enable_stdio_usb(${PROJECT_NAME} 1)
|
||||
pico_enable_stdio_uart(${PROJECT_NAME} 0)
|
||||
|
||||
# Create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(${PROJECT_NAME})
|
@ -1,143 +0,0 @@
|
||||
#ifndef PICO_HAL_H
|
||||
#define PICO_HAL_H
|
||||
|
||||
// include RadioLib
|
||||
#include <RadioLib.h>
|
||||
|
||||
// include the necessary Pico libraries
|
||||
#include <pico/stdlib.h>
|
||||
#include "hardware/spi.h"
|
||||
#include "hardware/timer.h"
|
||||
|
||||
// create a new Raspberry Pi Pico hardware abstraction
|
||||
// layer using the Pico SDK
|
||||
// the HAL must inherit from the base RadioLibHal class
|
||||
// and implement all of its virtual methods
|
||||
class PicoHal : public RadioLibHal {
|
||||
public:
|
||||
PicoHal(spi_inst_t *spiChannel, uint32_t misoPin, uint32_t mosiPin, uint32_t sckPin, uint32_t spiSpeed = 500 * 1000)
|
||||
: RadioLibHal(GPIO_IN, GPIO_OUT, 0, 1, GPIO_IRQ_EDGE_RISE, GPIO_IRQ_EDGE_FALL),
|
||||
_spiChannel(spiChannel),
|
||||
_spiSpeed(spiSpeed),
|
||||
_misoPin(misoPin),
|
||||
_mosiPin(mosiPin),
|
||||
_sckPin(sckPin) {
|
||||
}
|
||||
|
||||
void init() override {
|
||||
stdio_init_all();
|
||||
spiBegin();
|
||||
}
|
||||
|
||||
void term() override {
|
||||
spiEnd();
|
||||
}
|
||||
|
||||
// GPIO-related methods (pinMode, digitalWrite etc.) should check
|
||||
// RADIOLIB_NC as an alias for non-connected pins
|
||||
void pinMode(uint32_t pin, uint32_t mode) override {
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_init(pin);
|
||||
gpio_set_dir(pin, mode);
|
||||
}
|
||||
|
||||
void digitalWrite(uint32_t pin, uint32_t value) override {
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_put(pin, (bool)value);
|
||||
}
|
||||
|
||||
uint32_t digitalRead(uint32_t pin) override {
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gpio_get(pin);
|
||||
}
|
||||
|
||||
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
|
||||
if (interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)interruptCb);
|
||||
}
|
||||
|
||||
void detachInterrupt(uint32_t interruptNum) override {
|
||||
if (interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, NULL);
|
||||
}
|
||||
|
||||
void delay(unsigned long ms) override {
|
||||
sleep_ms(ms);
|
||||
}
|
||||
|
||||
void delayMicroseconds(unsigned long us) override {
|
||||
sleep_us(us);
|
||||
}
|
||||
|
||||
unsigned long millis() override {
|
||||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
unsigned long micros() override {
|
||||
return to_us_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->pinMode(pin, GPIO_IN);
|
||||
uint32_t start = this->micros();
|
||||
uint32_t curtick = this->micros();
|
||||
|
||||
while (this->digitalRead(pin) == state) {
|
||||
if ((this->micros() - curtick) > timeout) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (this->micros() - start);
|
||||
}
|
||||
|
||||
void spiBegin() {
|
||||
spi_init(_spiChannel, _spiSpeed);
|
||||
spi_set_format(_spiChannel, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
||||
|
||||
gpio_set_function(_sckPin, GPIO_FUNC_SPI);
|
||||
gpio_set_function(_mosiPin, GPIO_FUNC_SPI);
|
||||
gpio_set_function(_misoPin, GPIO_FUNC_SPI);
|
||||
}
|
||||
|
||||
void spiBeginTransaction() {}
|
||||
|
||||
void spiTransfer(uint8_t *out, size_t len, uint8_t *in) {
|
||||
spi_write_read_blocking(_spiChannel, out, in, len);
|
||||
}
|
||||
|
||||
void spiEndTransaction() {}
|
||||
|
||||
void spiEnd() {
|
||||
spi_deinit(_spiChannel);
|
||||
}
|
||||
|
||||
private:
|
||||
// the HAL can contain any additional private members
|
||||
spi_inst_t *_spiChannel;
|
||||
uint32_t _spiSpeed;
|
||||
uint32_t _misoPin;
|
||||
uint32_t _mosiPin;
|
||||
uint32_t _sckPin;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
cd ..
|
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf ./build
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
RadioLib Non-Arduino Raspberry Pi Pico library example
|
||||
|
||||
Licensed under the MIT License
|
||||
|
||||
Copyright (c) 2024 Cameron Goddard
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
// define pins to be used
|
||||
#define SPI_PORT spi0
|
||||
#define SPI_MISO 4
|
||||
#define SPI_MOSI 3
|
||||
#define SPI_SCK 2
|
||||
|
||||
#define RFM_NSS 26
|
||||
#define RFM_RST 22
|
||||
#define RFM_DIO0 14
|
||||
#define RFM_DIO1 15
|
||||
|
||||
#include <pico/stdlib.h>
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// include the hardware abstraction layer
|
||||
#include "PicoHal.h"
|
||||
|
||||
// create a new instance of the HAL class
|
||||
PicoHal* hal = new PicoHal(SPI_PORT, SPI_MISO, SPI_MOSI, SPI_SCK);
|
||||
|
||||
// now we can create the radio module
|
||||
// NSS pin: 26
|
||||
// DIO0 pin: 14
|
||||
// RESET pin: 22
|
||||
// DIO1 pin: 15
|
||||
SX1276 radio = new Module(hal, RFM_NSS, RFM_DIO0, RFM_RST, RFM_DIO1);
|
||||
|
||||
int main() {
|
||||
// initialize just like with Arduino
|
||||
printf("[SX1276] Initializing ... ");
|
||||
int state = radio.begin();
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
printf("failed, code %d\n", state);
|
||||
return(1);
|
||||
}
|
||||
printf("success!\n");
|
||||
|
||||
// loop forever
|
||||
for(;;) {
|
||||
// send a packet
|
||||
printf("[SX1276] Transmitting packet ... ");
|
||||
state = radio.transmit("Hello World!");
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
// the packet was successfully transmitted
|
||||
printf("success!\n");
|
||||
|
||||
// wait for a second before transmitting again
|
||||
hal->delay(1000);
|
||||
|
||||
} else {
|
||||
printf("failed, code %d\n", state);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
|
||||
|
||||
# This can be dropped into an external project to help locate this SDK
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
|
||||
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||
|
||||
if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT)
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
# GIT_SUBMODULES_RECURSE was added in 3.17
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
GIT_SUBMODULES_RECURSE FALSE
|
||||
)
|
||||
else ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (NOT pico_sdk)
|
||||
message("Downloading Raspberry Pi Pico SDK")
|
||||
FetchContent_Populate(pico_sdk)
|
||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if (NOT EXISTS ${PICO_SDK_PATH})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
||||
|
||||
include(${PICO_SDK_INIT_CMAKE_FILE})
|
@ -1 +0,0 @@
|
||||
build/
|
@ -1,21 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
# create the project
|
||||
project(rpi-sx1261)
|
||||
|
||||
# when using debuggers such as gdb, the following line can be used
|
||||
#set(CMAKE_BUILD_TYPE Debug)
|
||||
|
||||
# if you did not build RadioLib as shared library (see wiki),
|
||||
# you will have to add it as source directory
|
||||
# the following is just an example, yours will likely be different
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib")
|
||||
|
||||
# add the executable
|
||||
add_executable(${PROJECT_NAME} main.cpp)
|
||||
|
||||
# link both libraries
|
||||
target_link_libraries(${PROJECT_NAME} RadioLib pigpio)
|
||||
|
||||
# you can also specify RadioLib compile-time flags here
|
||||
#target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_DEBUG RADIOLIB_VERBOSE)
|
@ -1,151 +0,0 @@
|
||||
#ifndef PI_HAL_H
|
||||
#define PI_HAL_H
|
||||
|
||||
// include RadioLib
|
||||
#include <RadioLib.h>
|
||||
|
||||
// include the library for Raspberry GPIO pins
|
||||
#include "pigpio.h"
|
||||
|
||||
// create a new Raspberry Pi hardware abstraction layer
|
||||
// using the pigpio library
|
||||
// the HAL must inherit from the base RadioLibHal class
|
||||
// and implement all of its virtual methods
|
||||
class PiHal : public RadioLibHal {
|
||||
public:
|
||||
// default constructor - initializes the base HAL and any needed private members
|
||||
PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000)
|
||||
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE),
|
||||
_spiChannel(spiChannel),
|
||||
_spiSpeed(spiSpeed) {
|
||||
}
|
||||
|
||||
void init() override {
|
||||
// first initialise pigpio library
|
||||
gpioInitialise();
|
||||
|
||||
// now the SPI
|
||||
spiBegin();
|
||||
|
||||
// Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio
|
||||
gpioSetMode(18, PI_OUTPUT);
|
||||
gpioWrite(18, PI_HIGH);
|
||||
}
|
||||
|
||||
void term() override {
|
||||
// stop the SPI
|
||||
spiEnd();
|
||||
|
||||
// pull the enable pin low
|
||||
gpioSetMode(18, PI_OUTPUT);
|
||||
gpioWrite(18, PI_LOW);
|
||||
|
||||
// finally, stop the pigpio library
|
||||
gpioTerminate();
|
||||
}
|
||||
|
||||
// GPIO-related methods (pinMode, digitalWrite etc.) should check
|
||||
// RADIOLIB_NC as an alias for non-connected pins
|
||||
void pinMode(uint32_t pin, uint32_t mode) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioSetMode(pin, mode);
|
||||
}
|
||||
|
||||
void digitalWrite(uint32_t pin, uint32_t value) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioWrite(pin, value);
|
||||
}
|
||||
|
||||
uint32_t digitalRead(uint32_t pin) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(gpioRead(pin));
|
||||
}
|
||||
|
||||
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
|
||||
if(interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb);
|
||||
}
|
||||
|
||||
void detachInterrupt(uint32_t interruptNum) override {
|
||||
if(interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioSetISRFunc(interruptNum, 0, 0, NULL);
|
||||
}
|
||||
|
||||
void delay(unsigned long ms) override {
|
||||
gpioDelay(ms * 1000);
|
||||
}
|
||||
|
||||
void delayMicroseconds(unsigned long us) override {
|
||||
gpioDelay(us);
|
||||
}
|
||||
|
||||
unsigned long millis() override {
|
||||
return(gpioTick() / 1000);
|
||||
}
|
||||
|
||||
unsigned long micros() override {
|
||||
return(gpioTick());
|
||||
}
|
||||
|
||||
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
this->pinMode(pin, PI_INPUT);
|
||||
uint32_t start = this->micros();
|
||||
uint32_t curtick = this->micros();
|
||||
|
||||
while(this->digitalRead(pin) == state) {
|
||||
if((this->micros() - curtick) > timeout) {
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
return(this->micros() - start);
|
||||
}
|
||||
|
||||
void spiBegin() {
|
||||
if(_spiHandle < 0) {
|
||||
_spiHandle = spiOpen(_spiChannel, _spiSpeed, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void spiBeginTransaction() {}
|
||||
|
||||
void spiTransfer(uint8_t* out, size_t len, uint8_t* in) {
|
||||
spiXfer(_spiHandle, (char*)out, (char*)in, len);
|
||||
}
|
||||
|
||||
void spiEndTransaction() {}
|
||||
|
||||
void spiEnd() {
|
||||
if(_spiHandle >= 0) {
|
||||
spiClose(_spiHandle);
|
||||
_spiHandle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// the HAL can contain any additional private members
|
||||
const unsigned int _spiSpeed;
|
||||
const uint8_t _spiChannel;
|
||||
int _spiHandle = -1;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -G "CodeBlocks - Unix Makefiles" ..
|
||||
make
|
||||
cd ..
|
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf ./build
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
RadioLib Non-Arduino Raspberry Pi Example
|
||||
|
||||
This example shows how to use RadioLib without Arduino.
|
||||
In this case, a Raspberry Pi with WaveShare SX1302 LoRaWAN Hat
|
||||
using the pigpio library.
|
||||
|
||||
Can be used as a starting point to port RadioLib to any platform!
|
||||
See this API reference page for details on the RadioLib hardware abstraction
|
||||
https://jgromes.github.io/RadioLib/class_hal.html
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// include the hardware abstraction layer
|
||||
#include "PiHal.h"
|
||||
|
||||
// create a new instance of the HAL class
|
||||
// use SPI channel 1, because on Waveshare LoRaWAN Hat,
|
||||
// the SX1261 CS is connected to CE1
|
||||
PiHal* hal = new PiHal(1);
|
||||
|
||||
// now we can create the radio module
|
||||
// pinout corresponds to the Waveshare LoRaWAN Hat
|
||||
// NSS pin: 7
|
||||
// DIO1 pin: 17
|
||||
// NRST pin: 22
|
||||
// BUSY pin: not connected
|
||||
SX1261 radio = new Module(hal, 7, 17, 22, RADIOLIB_NC);
|
||||
|
||||
// the entry point for the program
|
||||
int main(int argc, char** argv) {
|
||||
// initialize just like with Arduino
|
||||
printf("[SX1261] Initializing ... ");
|
||||
int state = radio.begin();
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
printf("failed, code %d\n", state);
|
||||
return(1);
|
||||
}
|
||||
printf("success!\n");
|
||||
|
||||
// loop forever
|
||||
for(;;) {
|
||||
// send a packet
|
||||
printf("[SX1261] Transmitting packet ... ");
|
||||
state = radio.transmit("Hello World!");
|
||||
if(state == RADIOLIB_ERR_NONE) {
|
||||
// the packet was successfully transmitted
|
||||
printf("success!\n");
|
||||
|
||||
// wait for a second before transmitting again
|
||||
hal->delay(1000);
|
||||
|
||||
} else {
|
||||
printf("failed, code %d\n", state);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
build/
|
||||
TockApp.tab
|
@ -1,61 +0,0 @@
|
||||
# RadioLib Non-Arduino Tock Library CMake script
|
||||
#
|
||||
# Licensed under the MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Alistair Francis <alistair@alistair23.me>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
# create the project
|
||||
project(tock-sx1261)
|
||||
|
||||
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/userland_generic.ld)
|
||||
|
||||
include("tock.cmake")
|
||||
|
||||
# when using debuggers such as gdb, the following line can be used
|
||||
#set(CMAKE_BUILD_TYPE Debug)
|
||||
|
||||
# if you did not build RadioLib as shared library (see wiki),
|
||||
# you will have to add it as source directory
|
||||
# the following is just an example, yours will likely be different
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib")
|
||||
|
||||
# add the executable
|
||||
add_executable(${PROJECT_NAME} main.cpp)
|
||||
|
||||
# link with RadioLib and libtock-c
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||
RadioLib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libgcc.a
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libstdc++.a
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libc.a
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libm.a
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c
|
||||
)
|
||||
|
||||
# you can also specify RadioLib compile-time flags here
|
||||
#target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_DEBUG RADIOLIB_VERBOSE)
|
@ -1,28 +0,0 @@
|
||||
# RadioLib as Tock application
|
||||
|
||||
[Tock](https://github.com/tock/tock) is an embedded operating system designed
|
||||
for running multiple concurrent, mutually distrustful applications on Cortex-M
|
||||
and RISC-V based embedded platforms.
|
||||
|
||||
RadioLib can be built as a Tock application using
|
||||
[libtock-c](https://github.com/tock/libtock-c). This is an example of running
|
||||
RadioLib as a Tock application.
|
||||
|
||||
This has been tested on the
|
||||
[SparkFun LoRa Thing Plus - expLoRaBLE board] (https://github.com/tock/tock/tree/master/boards/apollo3/lora_things_plus)
|
||||
but will work on any LoRa compatible Tock board (currently only the
|
||||
expLoRaBLE board).
|
||||
|
||||
The RadioLib example can be built with:
|
||||
|
||||
```shell
|
||||
$ git clone https://github.com/jgromes/RadioLib.git
|
||||
$ cd RadioLib/examples/NonArduino/Tock/
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
Then in the Tock repo you can flash the kernel and app with:
|
||||
|
||||
```shell
|
||||
$ make flash; APP=RadioLib/examples/NonArduino/Tock/build/tock-sx1261.tbf make flash-app
|
||||
```
|
@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
rm -rf ./build
|
||||
|
||||
cd libtock-c/libtock
|
||||
make -j4
|
||||
cd ../../
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
cmake -G "CodeBlocks - Unix Makefiles" ..
|
||||
make -j4
|
||||
|
||||
cd ..
|
||||
|
||||
elf2tab -n radio-lib --stack 4096 --app-heap 2048 --kernel-heap 2048 \
|
||||
--kernel-major 2 --kernel-minor 1 \
|
||||
-v ./build/tock-sx1261
|
@ -1,55 +0,0 @@
|
||||
name: ci
|
||||
env:
|
||||
TERM: xterm # Makes tput work in actions output
|
||||
|
||||
# Controls when the action will run. Triggers the workflow on push or pull request
|
||||
# events but only for the master branch
|
||||
on:
|
||||
push:
|
||||
branches-ignore: [ staging.tmp, trying.tmp ] # Run CI for all branches except bors tmp branches
|
||||
pull_request: # Run CI for PRs on any branch
|
||||
|
||||
jobs:
|
||||
ci-format:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04]
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: false # LVGL makefile manually installs the submodule
|
||||
- uses: fiam/arm-none-eabi-gcc@v1
|
||||
with:
|
||||
release: '10-2020-q4' # The arm-none-eabi-gcc release to use.
|
||||
- name: setup-riscv-toolchain
|
||||
run: |
|
||||
pushd $HOME; wget http://cs.virginia.edu/~bjc8c/archive/gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip; unzip gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip; echo "$HOME/gcc-riscv64-unknown-elf-8.3.0-ubuntu/bin" >> $GITHUB_PATH; popd
|
||||
- name: ci-format
|
||||
run: pushd examples; ./format_all.sh || exit; popd
|
||||
|
||||
ci-build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04]
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: fiam/arm-none-eabi-gcc@v1
|
||||
with:
|
||||
release: '10-2020-q4' # The arm-none-eabi-gcc release to use.
|
||||
- name: setup-riscv-toolchain
|
||||
run: |
|
||||
pushd $HOME; wget http://cs.virginia.edu/~bjc8c/archive/gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip; unzip gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip; echo "$HOME/gcc-riscv64-unknown-elf-8.3.0-ubuntu/bin" >> $GITHUB_PATH; popd
|
||||
- name: ci-build
|
||||
run: pushd examples; RISCV=1 ./build_all.sh || exit; popd
|
||||
- name: ci-debug-build
|
||||
run: pushd examples/blink; make debug RAM_START=0x20004000 FLASH_INIT=0x30051 || exit; popd
|
@ -1,2 +0,0 @@
|
||||
build/
|
||||
.vscode/
|
@ -1,6 +0,0 @@
|
||||
[submodule "lua53/lua"]
|
||||
path = lua53/lua
|
||||
url = https://github.com/lua/lua.git
|
||||
[submodule "lvgl/lvgl"]
|
||||
path = lvgl/lvgl
|
||||
url = https://github.com/littlevgl/lvgl.git
|
@ -1,380 +0,0 @@
|
||||
################################################################################
|
||||
##
|
||||
## libtock-c main build system Makefile.
|
||||
##
|
||||
## Individual applications use this Makefile to invoke the compiler and create
|
||||
## Tock apps.
|
||||
##
|
||||
## This Makefile works by generating at runtime the rules necessary to build the
|
||||
## libtock-c app for all desired architectures, then running each of those rules
|
||||
## to create the compiled output. Each architecture-specific compiled binary is
|
||||
## then combined into a single Tock TAB file.
|
||||
##
|
||||
################################################################################
|
||||
|
||||
# The first target Make finds is its default. So this line needs to be first to
|
||||
# specify `all` as our default rule
|
||||
all:
|
||||
|
||||
# Directory for built output.
|
||||
BUILDDIR ?= build
|
||||
|
||||
# Build settings.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/Configuration.mk
|
||||
|
||||
# Helper functions.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/Helpers.mk
|
||||
|
||||
# Include the libtock makefile. Adds rules that will rebuild the core libtock
|
||||
# library when needed.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/libtock/Makefile
|
||||
|
||||
# Connection to the Tock kernel. Apps need the ability to be loaded onto a
|
||||
# board, and that method is board-specific. So for now, we have the TOCK_BOARD
|
||||
# variable which selects one and we include the appropriate Makefile-app from
|
||||
# within the Tock base directory.
|
||||
TOCK_BOARD ?= hail
|
||||
|
||||
# Include the makefile that has the programming functions for each board.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/Program.mk
|
||||
|
||||
|
||||
|
||||
# Rules to incorporate external libraries
|
||||
define EXTERN_LIB_RULES
|
||||
EXTERN_LIB_NAME_$(notdir $(1)) := $(notdir $(1))
|
||||
|
||||
# If this library has any additional rules, add them
|
||||
-include $(1)/Makefile.app
|
||||
|
||||
# If this library has an include directory, add it to search path
|
||||
ifneq "$$(wildcard $(1)/include)" ""
|
||||
override CPPFLAGS += -I$(1)/include
|
||||
endif
|
||||
|
||||
# Add arch-specific rules for each library
|
||||
# Use the $(LIBNAME)_BUILDDIR as build directory, if set.
|
||||
$$(notdir $(1))_BUILDDIR ?= $(1)/build
|
||||
$$(foreach arch, $$(TOCK_ARCHS), $$(eval LIBS_$$(arch) += $$($(notdir $(1))_BUILDDIR)/$$(arch)/$(notdir $(1)).a))
|
||||
|
||||
endef
|
||||
|
||||
# To see the generated rules, run:
|
||||
# $(info $(foreach lib, $(EXTERN_LIBS), $(call EXTERN_LIB_RULES,$(lib))))
|
||||
$(foreach lib, $(EXTERN_LIBS), $(eval $(call EXTERN_LIB_RULES,$(lib))))
|
||||
|
||||
|
||||
# Some sanity checks for variables before they are used
|
||||
|
||||
# Warn users about LDFLAGS currently being ignored. We currently use the WLFLAGS
|
||||
# and WLFLAGS_$(arch) variables to pass linker options through the compiler, by
|
||||
# encoding them as `-Wl,...` options.
|
||||
ifdef LDFLAGS
|
||||
$(warning *******************************************************)
|
||||
$(warning LDFLAGS are currently ignored!!)
|
||||
$(warning )
|
||||
$(warning This is because we need to invoke the gcc frontend not the)
|
||||
$(warning ld frontend for the final link step, which means that we would)
|
||||
$(warning need to parse the LDFLAGS into things like -Wl,-<flag> for each)
|
||||
$(warning entry, but that proved a little fragile on first attempt so)
|
||||
$(warning it is not currently done. Sorry.)
|
||||
$(warning Please use WLFLAGS if you need to pass linker flags.)
|
||||
$(warning *******************************************************)
|
||||
endif
|
||||
|
||||
# Warn users about improperly defined `HEAP_SIZE`.
|
||||
ifdef HEAP_SIZE
|
||||
$(warning The variable HEAP_SIZE is set but will not be used.)
|
||||
$(warning Tock has two heaps, the application heap which is memory your)
|
||||
$(warning program uses and the kernel heap or grant regions, which is memory)
|
||||
$(warning dynamically allocated by drivers on behalf of your program.)
|
||||
$(warning )
|
||||
$(warning These regions are controlled by the APP_HEAP_SIZE and)
|
||||
$(warning KERNEL_HEAP_SIZE variables respectively.)
|
||||
endif
|
||||
|
||||
|
||||
# Rules to create object files for a specific architecture.
|
||||
#
|
||||
# - Argument $(1) is the architecture (e.g. cortex-m0) to compile for.
|
||||
define BUILD_RULES_PER_ARCH
|
||||
|
||||
# BUILDDIR holds architecture dependent, but board-independent outputs
|
||||
$$(BUILDDIR)/$(1):
|
||||
$$(TRACE_DIR)
|
||||
$$(Q)mkdir -p $$@
|
||||
|
||||
# First step doesn't actually compile, just generate header dependency information
|
||||
# More info on our approach here: http://stackoverflow.com/questions/97338
|
||||
$$(BUILDDIR)/$(1)/%.o: %.c | $$(BUILDDIR)/$(1)
|
||||
$$(TRACE_CC)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CC_$(1)) $$(CFLAGS) $$(CFLAGS_$(1)) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -MF"$$(@:.o=.d)" -MG -MM -MP -MT"$$(@:.o=.d)@" -MT"$$@" "$$<"
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CC_$(1)) $$(CFLAGS) $$(CFLAGS_$(1)) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -c -o $$@ $$<
|
||||
|
||||
$$(BUILDDIR)/$(1)/%.o: %.cc | $$(BUILDDIR)/$(1)
|
||||
$$(TRACE_CXX)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -MF"$$(@:.o=.d)" -MG -MM -MP -MT"$$(@:.o=.d)@" -MT"$$@" "$$<"
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -c -o $$@ $$<
|
||||
|
||||
$$(BUILDDIR)/$(1)/%.o: %.cpp | $$(BUILDDIR)/$(1)
|
||||
$$(TRACE_CXX)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -MF"$$(@:.o=.d)" -MG -MM -MP -MT"$$(@:.o=.d)@" -MT"$$@" "$$<"
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -c -o $$@ $$<
|
||||
|
||||
$$(BUILDDIR)/$(1)/%.o: %.cxx | $$(BUILDDIR)/$(1)
|
||||
$$(TRACE_CXX)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -MF"$$(@:.o=.d)" -MG -MM -MP -MT"$$(@:.o=.d)@" -MT"$$@" "$$<"
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -c -o $$@ $$<
|
||||
|
||||
OBJS_$(1) += $$(patsubst %.c,$$(BUILDDIR)/$(1)/%.o,$$(C_SRCS))
|
||||
OBJS_$(1) += $$(patsubst %.cc,$$(BUILDDIR)/$(1)/%.o,$$(filter %.cc, $$(CXX_SRCS)))
|
||||
OBJS_$(1) += $$(patsubst %.cpp,$$(BUILDDIR)/$(1)/%.o,$$(filter %.cpp, $$(CXX_SRCS)))
|
||||
OBJS_$(1) += $$(patsubst %.cxx,$$(BUILDDIR)/$(1)/%.o,$$(filter %.cxx, $$(CXX_SRCS)))
|
||||
|
||||
endef
|
||||
|
||||
|
||||
# Rules to generate an app for a given architecture and target. These actually
|
||||
# create the ELF which can be linked for a specific address as needed.
|
||||
#
|
||||
# - Argument $(1) is the architecture (e.g. cortex-m0) to build for.
|
||||
# - Argument $(2) is the output name to use for the .elf and other files.
|
||||
# - Argument $(3) is the flash address to use for linking.
|
||||
# - Argument $(4) is the RAM address to use for linking.
|
||||
#
|
||||
# Note: all variables, other than $(1), used within this block must be double
|
||||
# dollar-signed so that their values will be evaluated when run, not when
|
||||
# generated
|
||||
define BUILD_RULES
|
||||
|
||||
$$(BUILDDIR)/$(1)/$(2).custom.ld: $$(LAYOUT) | $$(BUILDDIR)/$(1)
|
||||
@# Start with a copy of the template / generic ld script
|
||||
$$(Q)cp $$< $$@
|
||||
@# #616 #635: sed is not cross-platform
|
||||
@# https://stackoverflow.com/a/22247781/358675 <-- Use perl in place of sed
|
||||
$$(Q)\
|
||||
perl -pi -e "s/(FLASH.*ORIGIN[ =]*)([x0-9]*)(,.*LENGTH)/\$$$${1}$(3)\$$$$3/" $$@ &&\
|
||||
perl -pi -e "s/(SRAM.*ORIGIN[ =]*)([x0-9]*)(,.*LENGTH)/\$$$${1}$(4)\$$$$3/" $$@
|
||||
|
||||
# Collect all desired built output.
|
||||
$$(BUILDDIR)/$(1)/$(2).elf: $$(OBJS_$(1)) $$(LIBS_$(1)) $$(LEGACY_LIBS_$(1)) $$(BUILDDIR)/$(1)/$(2).custom.ld | $$(BUILDDIR)/$(1)
|
||||
$$(TRACE_LD)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CC_$(1)) $$(CFLAGS) $$(CFLAGS_$(1)) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) $$(WLFLAGS) $$(WLFLAGS_$(1))\
|
||||
-Xlinker --defsym=STACK_SIZE=$$(STACK_SIZE)\
|
||||
-Xlinker --defsym=APP_HEAP_SIZE=$$(APP_HEAP_SIZE)\
|
||||
-Xlinker --defsym=KERNEL_HEAP_SIZE=$$(KERNEL_HEAP_SIZE)\
|
||||
-T $$(BUILDDIR)/$(1)/$(2).custom.ld\
|
||||
-nostdlib\
|
||||
-Wl,--start-group $$(OBJS_$(1)) $$(LIBS_$(1)) $$(LEGACY_LIBS_$(1)) $$(LINK_LIBS_$(1)) -Wl,--end-group\
|
||||
-Wl,-Map=$$(BUILDDIR)/$(1)/$(2).Map\
|
||||
-o $$@
|
||||
|
||||
# NOTE: This rule creates an lst file for the elf as flashed on the board
|
||||
# (i.e. at address 0x80000000). This is not likely what you want.
|
||||
$$(BUILDDIR)/$(1)/$(2).lst: $$(BUILDDIR)/$(1)/$(2).elf
|
||||
$$(TRACE_LST)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(OBJDUMP) $$(OBJDUMP_FLAGS) $$(OBJDUMP_FLAGS_$(1)) $$< > $$@
|
||||
@echo $$$$(tput bold)Listings generated at $$@$$$$(tput sgr0)
|
||||
|
||||
# checks compiled ELF files to ensure that all libraries and applications were
|
||||
# built with the correct flags in order to work on a Tock board
|
||||
.PHONY: validate_gcc_flags
|
||||
validate_gcc_flags:: $$(BUILDDIR)/$(1)/$(2).elf
|
||||
ifndef TOCK_NO_CHECK_SWITCHES
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(READELF) -p .GCC.command.line $$< 2>&1 | grep -q "does not exist" && { echo "Error: Missing section .GCC.command.line"; echo ""; echo "Tock requires that applications are built with"; echo " -frecord-gcc-switches"; echo "to validate that all required flags were used"; echo ""; echo "You can skip this check by defining the make variable TOCK_NO_CHECK_SWITCHES"; exit 1; } || exit 0
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(READELF) -p .GCC.command.line $$< | grep -q -- -msingle-pic-base && $$(READELF) -p .GCC.command.line $$< | grep -q -- -mpic-register=r9 && $$(READELF) -p .GCC.command.line $$< | grep -q -- -mno-pic-data-is-text-relative || { echo "Error: Missing required build flags."; echo ""; echo "Tock requires applications are built with"; echo " -msingle-pic-base"; echo " -mpic-register=r9"; echo " -mno-pic-data-is-text-relative"; echo "But one or more of these flags are missing"; echo ""; echo "To see the flags your application was built with, run"; echo "$$(READELF) -p .GCC.command.line $$<"; echo ""; exit 1; }
|
||||
endif
|
||||
|
||||
# rules to print the size of the built binaries
|
||||
.PHONY: size-$(1)-$(2)
|
||||
size-$(1)-$(2): $$(BUILDDIR)/$(1)/$(2).elf
|
||||
@echo Application size report for target $(2):
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(SIZE) $$^
|
||||
|
||||
size:: size-$(1)-$(2)
|
||||
|
||||
|
||||
############################################################################################
|
||||
# DEBUGGING STUFF
|
||||
#
|
||||
# The approach here is that we're going create a new elf file that is compiled
|
||||
# at the actual flash and ram offset of the loaded program
|
||||
#
|
||||
# We want to build a rule that fails if these needed env variables aren't set
|
||||
# only when actually trying to use them to build the lst file. We also want to
|
||||
# force this to rerun every time it's invoked so that it picks up new env
|
||||
# variable settings
|
||||
|
||||
|
||||
# Step 0: Force this to be built every time
|
||||
.PHONY: _FORCE_USERLAND_DEBUG_LD
|
||||
|
||||
# Step 1: Create a new linker script. Note this depends on original (non-shifted) elf
|
||||
# (supposedly this could be one-lined, but I couldn't make that work, so here goes)
|
||||
ifdef RAM_START
|
||||
ifdef FLASH_INIT
|
||||
_USERLAND_DEBUG_ALL_NEEDED_VARS := 1
|
||||
endif
|
||||
endif
|
||||
|
||||
$$(BUILDDIR)/$(1)/$(2).userland_debug.ld: $$(TOCK_USERLAND_BASE_DIR)/userland_generic.ld $$(BUILDDIR)/$(1)/$(2).elf _FORCE_USERLAND_DEBUG_LD | $$(BUILDDIR)/$(1)
|
||||
ifndef _USERLAND_DEBUG_ALL_NEEDED_VARS
|
||||
@echo "ERROR: Required variables RAM_START and FLASH_INIT are not set."
|
||||
@echo " These are needed to compute the offset your program was loaded at."
|
||||
@echo " See the kernel panic message for these values."
|
||||
@exit 1
|
||||
else
|
||||
@# Start with a copy of the template / generic ld script
|
||||
$$(Q)cp $$< $$@
|
||||
@# And with apologies to future readers, this is easier as one shell command/script so
|
||||
@# we can set intervening variables, away we go
|
||||
@#
|
||||
@# Get the offset between the init function and the start of text (0x80000000).
|
||||
@# We then use that offset to calculate where the start of text was on the actual MCU.
|
||||
@# Create a new LD file at the correct flash and ram locations.
|
||||
@#
|
||||
@# #616 #635: sed is not cross-platform
|
||||
@# https://stackoverflow.com/a/22247781/358675 <-- Use perl in place of sed
|
||||
$$(Q)set -e ;\
|
||||
ORIGINAL_ENTRY=`$$(TOOLCHAIN_$(1))$$(READELF) -h $$(BUILDDIR)/$(1)/$(2).elf | grep Entry | awk '{print $$$$4}'` ;\
|
||||
INIT_OFFSET=$$$$(($$$$ORIGINAL_ENTRY - 0x80000000)) ;\
|
||||
FLASH_START=$$$$(($$$$FLASH_INIT-$$$$INIT_OFFSET)) ;\
|
||||
perl -pi -e "s/(FLASH.*ORIGIN[ =]*)([x0-9]*)(,.*LENGTH)/\$$$${1}$$$$FLASH_START\$$$$3/" $$@ ;\
|
||||
perl -pi -e "s/(SRAM.*ORIGIN[ =]*)([x0-9]*)(,.*LENGTH)/\$$$${1}$$$$RAM_START\$$$$3/" $$@
|
||||
endif
|
||||
|
||||
# Step 2: Create a new ELF with the layout that matches what's loaded
|
||||
$$(BUILDDIR)/$(1)/$(2).userland_debug.elf: $$(OBJS_$(1)) $$(LIBS_$(1)) $$(LEGACY_LIBS_$(1)) $$(BUILDDIR)/$(1)/$(2).userland_debug.ld | $$(BUILDDIR)/$(1)
|
||||
$$(TRACE_LD)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CC_$(1)) $$(CFLAGS) $$(CFLAGS_$(1)) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) $$(WLFLAGS) $$(WLFLAGS_$(1))\
|
||||
-Xlinker --defsym=STACK_SIZE=$$(STACK_SIZE)\
|
||||
-Xlinker --defsym=APP_HEAP_SIZE=$$(APP_HEAP_SIZE)\
|
||||
-Xlinker --defsym=KERNEL_HEAP_SIZE=$$(KERNEL_HEAP_SIZE)\
|
||||
-T $$(BUILDDIR)/$(1)/$(2).userland_debug.ld\
|
||||
-nostdlib\
|
||||
-Wl,--start-group $$(OBJS_$(1)) $$(LIBS_$(1)) $$(LEGACY_LIBS_$(1)) $$(LINK_LIBS_$(1)) -Wl,--end-group\
|
||||
-Wl,-Map=$$(BUILDDIR)/$(1)/$(2).Map\
|
||||
-o $$@
|
||||
|
||||
# Step 3: Now we can finally generate an LST
|
||||
$$(BUILDDIR)/$(1)/$(2).userland_debug.lst: $$(BUILDDIR)/$(1)/$(2).userland_debug.elf
|
||||
$$(TRACE_LST)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(OBJDUMP) $$(OBJDUMP_FLAGS) $$(OBJDUMP_FLAGS_$(1)) $$< > $$@
|
||||
@echo $$$$(tput bold)Listings generated at $$@$$$$(tput sgr0)
|
||||
|
||||
# END DEBUGGING STUFF
|
||||
############################################################################################
|
||||
endef
|
||||
|
||||
|
||||
# Rules that apply to an entire architecture family (e.g. cortex-m).
|
||||
#
|
||||
# - Argument $(1) is the architecture family (e.g. cortex-m).
|
||||
# - Argument $(2) is the list of architectures in that family.
|
||||
# - Argument $(3) is the list of output names for the .elf of each arch.
|
||||
#
|
||||
# Note: all variables, other than $(1), used within this block must be double
|
||||
# dollar-signed so that their values will be evaluated when run, not when
|
||||
# generated.
|
||||
define ARCH_FAMILY_RULES
|
||||
|
||||
$(1)_DIRECTORY_NAMES := $$(addsuffix /,$(2))
|
||||
$(1)_DIRECTORY_FILES := $$(join $$($(1)_DIRECTORY_NAMES),$(3))
|
||||
$(1)_DIRECTORY_FILES_EXT := $$(addsuffix .elf,$$($(1)_DIRECTORY_FILES))
|
||||
$(1)_ELF_FILES := $$(addprefix $$(BUILDDIR)/,$$($(1)_DIRECTORY_FILES_EXT))
|
||||
|
||||
# Rule to print the size of the built binaries from an architecture family.
|
||||
.PHONY: size-$(1)
|
||||
size-$(1): $$($(1)_ELF_FILES)
|
||||
@echo Application size report for arch family $(1):
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(SIZE) -t $$^
|
||||
|
||||
endef
|
||||
|
||||
# Functions to parse the `TOCK_TARGETS` array. Entries 3 and 4 default to the
|
||||
# PIC addresses if they are not specified.
|
||||
ARCH_FN = $(firstword $(subst |, ,$1))
|
||||
OUTPUT_NAME_FN = $(if $(word 2,$(subst |, ,$1)),$(word 2,$(subst |, ,$1)),$(firstword $(subst |, ,$1)))
|
||||
FLASH_ADDRESS_FN = $(if $(word 3,$(subst |, ,$1)),$(word 3,$(subst |, ,$1)),0x80000000)
|
||||
RAM_ADDRESS_FN = $(if $(word 4,$(subst |, ,$1)),$(word 4,$(subst |, ,$1)),0x00000000)
|
||||
|
||||
# To see the generated rules, run:
|
||||
#$(info $(foreach platform, $(TOCK_ARCHS), $(eval $(call BUILD_RULES_PER_ARCH,$(platform)))))
|
||||
#$(info $(foreach platform, $(TOCK_TARGETS), $(call BUILD_RULES,$(call ARCH_FN,$(platform)),$(call OUTPUT_NAME_FN,$(platform)),$(call FLASH_ADDRESS_FN,$(platform)),$(call RAM_ADDRESS_FN,$(platform)))))
|
||||
# Actually generate the rules for each architecture
|
||||
$(foreach platform, $(TOCK_ARCHS), $(eval $(call BUILD_RULES_PER_ARCH,$(platform))))
|
||||
$(foreach platform, $(TOCK_TARGETS), $(eval $(call BUILD_RULES,$(call ARCH_FN,$(platform)),$(call OUTPUT_NAME_FN,$(platform)),$(call FLASH_ADDRESS_FN,$(platform)),$(call RAM_ADDRESS_FN,$(platform)))))
|
||||
$(foreach family, $(TOCK_ARCH_FAMILIES), $(eval $(call ARCH_FAMILY_RULES,$(family),$(foreach target, $(filter $(family)%,$(TOCK_TARGETS)), $(call ARCH_FN, $(target))),$(foreach target, $(filter $(family)%,$(TOCK_TARGETS)), $(call OUTPUT_NAME_FN, $(target))))))
|
||||
|
||||
|
||||
|
||||
|
||||
# TAB file generation. Used for Tockloader
|
||||
$(BUILDDIR)/$(PACKAGE_NAME).tab: $(foreach platform, $(TOCK_TARGETS), $(BUILDDIR)/$(call ARCH_FN,$(platform))/$(call OUTPUT_NAME_FN,$(platform)).elf)
|
||||
$(TRACE_E2T)
|
||||
$(Q)$(ELF2TAB) $(ELF2TAB_ARGS) -o $@ $^
|
||||
|
||||
|
||||
|
||||
# Rules for building apps
|
||||
SIZE_RULES = $(addprefix size-,$(TOCK_ARCH_FAMILIES))
|
||||
.PHONY: all
|
||||
all: $(BUILDDIR)/$(PACKAGE_NAME).tab $(SIZE_RULES)
|
||||
|
||||
# The size target accumulates dependencies in the platform build rule creation
|
||||
.PHONY: size
|
||||
|
||||
# Generate helpful output for debugging userland applications.
|
||||
.PHONY: debug
|
||||
debug: $(foreach platform, $(TOCK_TARGETS), $(BUILDDIR)/$(call ARCH_FN,$(platform))/$(call OUTPUT_NAME_FN,$(platform)).userland_debug.lst)
|
||||
|
||||
# Generate a .lst file for each architecture using the RAM and flash addresses
|
||||
# specified in the linker file. This will create a valid assembly file, but the
|
||||
# addresses of the instructions will be wrong unless the application was
|
||||
# compiled for specific addresses. Notably, on cortex-m platforms, which use
|
||||
# position-independent code, the addresses will be wrong, and you should use
|
||||
# `make debug` instead. For architectures without PIC support (like RISC-V),
|
||||
# `make lst` will work since the linker files uses the correct addresses.
|
||||
.PHONY: lst
|
||||
lst: $(foreach platform, $(TOCK_TARGETS), $(BUILDDIR)/$(call ARCH_FN,$(platform))/$(call OUTPUT_NAME_FN,$(platform)).lst)
|
||||
|
||||
.PHONY:
|
||||
clean::
|
||||
rm -Rf $(BUILDDIR)
|
||||
|
||||
|
||||
# Rules for running the C linter
|
||||
FORMATTED_FILES := $(patsubst %.c,$(BUILDDIR)/format/%.uncrustify,$(C_SRCS))
|
||||
FORMATTED_FILES += $(patsubst %.cc,$(BUILDDIR)/format/%.uncrustify,$(filter %.cc, $(CXX_SRCS)))
|
||||
FORMATTED_FILES += $(patsubst %.cpp,$(BUILDDIR)/format/%.uncrustify,$(filter %.cpp, $(CXX_SRCS)))
|
||||
FORMATTED_FILES += $(patsubst %.cxx,$(BUILDDIR)/format/%.uncrustify,$(filter %.cxx, $(CXX_SRCS)))
|
||||
|
||||
$(BUILDDIR)/format:
|
||||
@mkdir -p $@
|
||||
|
||||
.PHONY: fmt format
|
||||
fmt format:: $(FORMATTED_FILES)
|
||||
|
||||
$(BUILDDIR)/format/%.uncrustify: %.c | _format_check_unstaged
|
||||
$(Q)$(UNCRUSTIFY) -f $< -o $@
|
||||
$(Q)cmp -s $< $@ || (if [ "$$CI" = "true" ]; then diff -y $< $@; rm $@; exit 1; else cp $@ $<; fi)
|
||||
$(BUILDDIR)/format/%.uncrustify: %.cc | _format_check_unstaged
|
||||
$(Q)$(UNCRUSTIFY) -f $< -o $@
|
||||
$(Q)cmp -s $< $@ || (if [ "$$CI" = "true" ]; then diff -y $< $@; rm $@; exit 1; else cp $@ $<; fi)
|
||||
$(BUILDDIR)/format/%.uncrustify: %.cpp | _format_check_unstaged
|
||||
$(Q)$(UNCRUSTIFY) -f $< -o $@
|
||||
$(Q)cmp -s $< $@ || (if [ "$$CI" = "true" ]; then diff -y $< $@; rm $@; exit 1; else cp $@ $<; fi)
|
||||
$(BUILDDIR)/format/%.uncrustify: %.cxx | _format_check_unstaged
|
||||
$(Q)$(UNCRUSTIFY) -f $< -o $@
|
||||
$(Q)cmp -s $< $@ || (if [ "$$CI" = "true" ]; then diff -y $< $@; rm $@; exit 1; else cp $@ $<; fi)
|
||||
|
||||
|
||||
# Rules to help validate build configuration
|
||||
fmt format::
|
||||
$(Q)$(TOCK_USERLAND_BASE_DIR)/tools/check_override.sh
|
||||
|
||||
|
||||
#########################################################################################
|
||||
# Include dependency rules for picking up header changes (by convention at bottom of makefile)
|
||||
OBJS_NO_ARCHIVES += $(filter %.o,$(foreach platform, $(TOCK_ARCHS), $(OBJS_$(platform))))
|
||||
-include $(OBJS_NO_ARCHIVES:.o=.d)
|
@ -1,578 +0,0 @@
|
||||
################################################################################
|
||||
##
|
||||
## libtock-c build system configuration.
|
||||
##
|
||||
## This sets all of the parameters and flags required to build libtock-c
|
||||
## applications for the architectures Tock supports.
|
||||
##
|
||||
## Included by AppMakefile.mk and TockLibrary.mk.
|
||||
##
|
||||
################################################################################
|
||||
|
||||
# Ensure that this file is only included once.
|
||||
ifndef CONFIGURATION_MAKEFILE
|
||||
CONFIGURATION_MAKEFILE = 1
|
||||
|
||||
# Remove built-in rules and variables
|
||||
# n.b. no-op for make --version < 4.0
|
||||
MAKEFLAGS += -r
|
||||
MAKEFLAGS += -R
|
||||
|
||||
# Toolchain programs.
|
||||
AR := -ar
|
||||
AS := -as
|
||||
CXX := -g++
|
||||
OBJDUMP := -objdump
|
||||
RANLIB := -ranlib
|
||||
READELF := -readelf
|
||||
SIZE := -size
|
||||
|
||||
# Set default region sizes for process memory requirements.
|
||||
STACK_SIZE ?= 2048
|
||||
APP_HEAP_SIZE ?= 1024
|
||||
KERNEL_HEAP_SIZE ?= 1024
|
||||
|
||||
# Set default required kernel version.
|
||||
KERNEL_MAJOR_VERSION ?= 2
|
||||
KERNEL_MINOR_VERSION ?= 0
|
||||
|
||||
# PACKAGE_NAME is used to identify the application for IPC and for error
|
||||
# reporting. This can be overwritten per-app to customize the name, otherwise we
|
||||
# default to the name of the directory the app is in.
|
||||
PACKAGE_NAME ?= $(shell basename "$(shell pwd)")
|
||||
|
||||
# Tock app targets.
|
||||
#
|
||||
# This is a list of all of the different targets to build an app for which will
|
||||
# all be bundled into a TAB. This allows us to build an app for any board Tock
|
||||
# supports, and wait until a TAB is installed onto a board to figure out which
|
||||
# specific binary that hardware platform needs.
|
||||
#
|
||||
# Each entry is itself a list:
|
||||
#
|
||||
# 1. The name of the architecture. This is used for naming generated files and
|
||||
# variables in the Makefiles. It is generally just a human-readable name.
|
||||
# 2. (Optional) The name to use when creating the output file.
|
||||
# 3. (Optional) The address to use as the fixed start of flash.
|
||||
# 4. (Optional) The address to use as the fixed start of RAM.
|
||||
#
|
||||
# By default we currently only build the Cortex-M targets. To enable the RISC-V
|
||||
# targets, set the RISCV variable like so:
|
||||
#
|
||||
# $ make RISCV=1
|
||||
#
|
||||
# Once the RV32 toolchain distribution stabilizes (as of June 2020 the toolchain
|
||||
# isn't as easily obtained as we would like), we intend to make the RISC-V
|
||||
# targets build by default as well.
|
||||
ifeq ($(RISCV),)
|
||||
TOCK_TARGETS ?= cortex-m0 cortex-m3 cortex-m4 cortex-m7
|
||||
else
|
||||
# Specific addresses useful for the OpenTitan hardware memory map.
|
||||
OPENTITAN_TOCK_TARGETS := rv32imc|rv32imc.0x20030080.0x10005000|0x20030080|0x10005000\
|
||||
rv32imc|rv32imc.0x20030880.0x10008000|0x20030880|0x10008000\
|
||||
rv32imc|rv32imc.0x20032080.0x10008000|0x20032080|0x10008000\
|
||||
rv32imc|rv32imc.0x20034080.0x10008000|0x20034080|0x10008000
|
||||
|
||||
# Specific addresses useful for the ARTY-E21 FPGA softcore hardware memory map.
|
||||
ARTY_E21_TOCK_TARGETS := rv32imac|rv32imac.0x40430060.0x80004000|0x40430060|0x80004000\
|
||||
rv32imac|rv32imac.0x40440060.0x80007000|0x40440060|0x80007000
|
||||
|
||||
# Include the RISC-V targets.
|
||||
# rv32imac|rv32imac.0x20040060.0x80002800 # RISC-V for HiFive1b
|
||||
# rv32imac|rv32imac.0x403B0060.0x3FCC0000 # RISC-V for ESP32-C3
|
||||
# rv32imc|rv32imc.0x41000060.0x42008000 # RISC-V for LiteX Arty-A7
|
||||
# rv32imc|rv32imc.0x00080060.0x40008000 # RISC-V for LiteX Simulator
|
||||
TOCK_TARGETS ?= cortex-m0\
|
||||
cortex-m3\
|
||||
cortex-m4\
|
||||
cortex-m7\
|
||||
rv32imac|rv32imac.0x20040060.0x80002800|0x20040060|0x80002800\
|
||||
rv32imac|rv32imac.0x403B0060.0x3FCC0000|0x403B0060|0x3FCC0000\
|
||||
rv32imc|rv32imc.0x41000060.0x42008000|0x41000060|0x42008000\
|
||||
rv32imc|rv32imc.0x00080060.0x40008000|0x00080060|0x40008000\
|
||||
$(OPENTITAN_TOCK_TARGETS) \
|
||||
$(ARTY_E21_TOCK_TARGETS)
|
||||
endif
|
||||
|
||||
# Generate `TOCK_ARCH_FAMILIES`, the set of architecture families which will be
|
||||
# used to determine toolchains to use in the build process.
|
||||
TOCK_ARCH_FAMILIES := $(sort $(foreach target, $(TOCK_TARGETS), $(strip \
|
||||
$(findstring rv32i,$(target)) \
|
||||
$(findstring cortex-m,$(target)))))
|
||||
|
||||
# Generate `TOCK_ARCHS`, the set of architectures listed in `TOCK_TARGETS`.
|
||||
#
|
||||
# The architecture name is used extensively to create the correct build commands
|
||||
# for each architecture. Make targets are automatically generated in
|
||||
# `AppMakefile.mk` based on the list of `TOCK_TARGETS`. The remainder of this
|
||||
# file uses the architecture name to pull the correct flags for each stage in
|
||||
# the build process.
|
||||
TOCK_ARCHS := $(sort $(foreach target, $(TOCK_TARGETS), $(firstword $(subst |, ,$(target)))))
|
||||
|
||||
# Check if elf2tab exists, if not, install it using cargo.
|
||||
ELF2TAB ?= elf2tab
|
||||
ELF2TAB_REQUIRED_VERSION := 0.7.0
|
||||
ELF2TAB_EXISTS := $(shell $(SHELL) -c "command -v $(ELF2TAB)")
|
||||
ELF2TAB_VERSION := $(shell $(SHELL) -c "$(ELF2TAB) --version | cut -d ' ' -f 2")
|
||||
|
||||
# Check elf2tab version.
|
||||
UPGRADE_ELF2TAB := $(shell $(SHELL) -c "printf '%s\n%s\n' '$(ELF2TAB_REQUIRED_VERSION)' '$(ELF2TAB_VERSION)' | sort --check=quiet --version-sort || echo yes")
|
||||
|
||||
ifeq ($(UPGRADE_ELF2TAB),yes)
|
||||
$(info Trying to update elf2tab to >= $(ELF2TAB_REQUIRED_VERSION))
|
||||
ELF2TAB_EXISTS =
|
||||
endif
|
||||
|
||||
ifndef ELF2TAB_EXISTS
|
||||
$(shell cargo install elf2tab)
|
||||
# Check elf2tab version after install
|
||||
ELF2TAB_VERSION := $(shell $(SHELL) -c "$(ELF2TAB) --version | cut -d ' ' -f 2")
|
||||
UPGRADE_ELF2TAB := $(shell $(SHELL) -c "printf '%s\n%s\n' '$(ELF2TAB_REQUIRED_VERSION)' '$(ELF2TAB_VERSION)' | sort --check=quiet --version-sort || echo yes")
|
||||
ifeq ($(UPGRADE_ELF2TAB),yes)
|
||||
$(error Failed to automatically update elf2tab, please update manually elf2tab to >= $(ELF2TAB_REQUIRED_VERSION))
|
||||
endif
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
##
|
||||
## Shared build flags for all architectures in libtock-c.
|
||||
##
|
||||
################################################################################
|
||||
|
||||
# elf2tab flags.
|
||||
#
|
||||
# Provide the name, memory sizes, and required kernel version as arguments to
|
||||
# elf2tab so it can include the parameters in the TBF header.
|
||||
ELF2TAB_ARGS += -n $(PACKAGE_NAME)
|
||||
ELF2TAB_ARGS += --stack $(STACK_SIZE) --app-heap $(APP_HEAP_SIZE) --kernel-heap $(KERNEL_HEAP_SIZE)
|
||||
ELF2TAB_ARGS += --kernel-major $(KERNEL_MAJOR_VERSION) --kernel-minor $(KERNEL_MINOR_VERSION)
|
||||
|
||||
# Flags for building app Assembly, C, and C++ files used by all architectures.
|
||||
# n.b. CPPFLAGS are shared for C and C++ sources (it's short for C PreProcessor,
|
||||
# and C++ uses the C preprocessor). To specify flags for only C or C++, use
|
||||
# CFLAGS for C only and CXXFLAGS for C++ only. [While we're on the trivia
|
||||
# lesson, CXX is shorthand for C++ because folks on the unix/gnu side of history
|
||||
# needed a valid letter rather than a symbol (an X is a rotated +). Confusingly,
|
||||
# the dos/microsoft lineage chose `.cpp` to address this same issue, leading to
|
||||
# confusion nowadays about the meaning of 'cpp'.]
|
||||
override ASFLAGS += -mthumb
|
||||
override CFLAGS += -std=gnu11
|
||||
override CPPFLAGS += \
|
||||
-frecord-gcc-switches\
|
||||
-gdwarf-2\
|
||||
-Os\
|
||||
-fdata-sections -ffunction-sections\
|
||||
-fstack-usage\
|
||||
-D_FORTIFY_SOURCE=2\
|
||||
-Wall\
|
||||
-Wextra
|
||||
override WLFLAGS += \
|
||||
-Wl,--warn-common\
|
||||
-Wl,--gc-sections\
|
||||
-Wl,--build-id=none
|
||||
|
||||
# Flags to improve the quality and information in listings (debug target)
|
||||
OBJDUMP_FLAGS += --disassemble-all --source -C --section-headers
|
||||
|
||||
# Use a generic linker script for all libtock-c apps.
|
||||
LAYOUT ?= $(TOCK_USERLAND_BASE_DIR)/userland_generic.ld
|
||||
|
||||
# Various flags for a specific toolchain. Different compilers may have different
|
||||
# supported features. For GCC we warn if the compiler estimates the stack usage
|
||||
# will be greater than the allocated stack size.
|
||||
override CPPFLAGS_gcc += -Wstack-usage=$(STACK_SIZE)
|
||||
|
||||
# Generic PIC flags for architectures with compiler support for FDPIC. Note!
|
||||
# These flags are not sufficient for full PIC support as Tock requires. The
|
||||
# `-fPIC` flag generally only allows the .text and .data sections to be at
|
||||
# different relative addresses. However, the .text and RAM sections are not
|
||||
# fully relocatable. Therefore, just including these flags is not sufficient to
|
||||
# build a full PIC app for Tock. So, we split these out, and only include them
|
||||
# for architectures where we have full PIC support.
|
||||
override CPPFLAGS_PIC += \
|
||||
-Wl,--emit-relocs\
|
||||
-fPIC
|
||||
|
||||
################################################################################
|
||||
##
|
||||
## RISC-V compiler/linker flags
|
||||
##
|
||||
################################################################################
|
||||
|
||||
# RISC-V toolchains, irrespective of their name-tuple, can compile for
|
||||
# essentially any target. Thus, try a few known names and choose the one for
|
||||
# which a compiler is found.
|
||||
ifneq (,$(shell which riscv64-none-elf-gcc 2>/dev/null))
|
||||
TOOLCHAIN_rv32i := riscv64-none-elf
|
||||
else ifneq (,$(shell which riscv32-none-elf-gcc 2>/dev/null))
|
||||
TOOLCHAIN_rv32i := riscv32-none-elf
|
||||
else ifneq (,$(shell which riscv64-elf-gcc 2>/dev/null))
|
||||
TOOLCHAIN_rv32i := riscv64-elf
|
||||
else ifneq (,$(shell which riscv64-unknown-elf-clang 2>/dev/null))
|
||||
TOOLCHAIN_rv32i := riscv64-unknown-elf
|
||||
else ifneq (,$(shell which riscv32-unknown-elf-clang 2>/dev/null))
|
||||
TOOLCHAIN_rv32i := riscv32-unknown-elf
|
||||
else
|
||||
# Fallback option. We don't particularly want to throw an error (even if
|
||||
# RISCV=1 is set) as this configuration makefile can be useful without a
|
||||
# proper toolchain.
|
||||
TOOLCHAIN_rv32i := riscv64-unknown-elf
|
||||
endif
|
||||
TOOLCHAIN_rv32imac := $(TOOLCHAIN_rv32i)
|
||||
TOOLCHAIN_rv32imc := $(TOOLCHAIN_rv32i)
|
||||
|
||||
# For RISC-V we default to GCC, but can support clang as well. Eventually, one
|
||||
# or both toolchains might support the PIC we need, at which point we would
|
||||
# default to that.
|
||||
ifeq ($(CLANG),)
|
||||
# Default to GCC
|
||||
CC_rv32 := -gcc
|
||||
else
|
||||
# If `CLANG=1` on command line, use -clang.
|
||||
CC_rv32 := -clang
|
||||
endif
|
||||
CC_rv32i := $(CC_rv32)
|
||||
CC_rv32imc := $(CC_rv32)
|
||||
CC_rv32imac := $(CC_rv32)
|
||||
|
||||
# Set the toolchain specific flags.
|
||||
#
|
||||
# Note: There are no non-gcc, clang-specific flags currently in use, so there is
|
||||
# no equivalent CPPFLAGS_clang currently. If there are clang-only flags in the
|
||||
# future, one can/should be added.
|
||||
ifeq ($(findstring -gcc,$(CC_rv32)),-gcc)
|
||||
override CPPFLAGS_toolchain_rv32 += $(CPPFLAGS_gcc)
|
||||
override CFLAGS_toolchain_rv32 += $(CFLAGS_gcc)
|
||||
endif
|
||||
|
||||
# Set the toolchain specific `CFLAGS` for RISC-V. We use the same generic
|
||||
# toolchain flags for each RISC-V variant.
|
||||
override CFLAGS_rv32 += \
|
||||
$(CFLAGS_toolchain_rv32)
|
||||
|
||||
override CFLAGS_rv32i += $(CFLAGS_rv32)
|
||||
override CFLAGS_rv32imc += $(CFLAGS_rv32)
|
||||
override CFLAGS_rv32imac += $(CFLAGS_rv32)
|
||||
|
||||
# Set the base `CPPFLAGS` for all RISC-V variants based on the toolchain family.
|
||||
override CPPFLAGS_rv32 += \
|
||||
$(CPPFLAGS_toolchain_rv32)
|
||||
|
||||
# Set the `CPPFLAGS` for RISC-V. Here we need different flags for different
|
||||
# variants.
|
||||
override CPPFLAGS_rv32i += $(CPPFLAGS_rv32) \
|
||||
-march=rv32i\
|
||||
-mabi=ilp32\
|
||||
-mcmodel=medlow
|
||||
|
||||
override CPPFLAGS_rv32imc += $(CPPFLAGS_rv32) \
|
||||
-march=rv32imc\
|
||||
-mabi=ilp32\
|
||||
-mcmodel=medlow
|
||||
|
||||
override CPPFLAGS_rv32imac += $(CPPFLAGS_rv32) \
|
||||
-march=rv32imac\
|
||||
-mabi=ilp32\
|
||||
-mcmodel=medlow
|
||||
|
||||
# Set the base `WLFLAGS` linker flags for all RISC-V variants.
|
||||
override WLFLAGS_rv32 += \
|
||||
-Wl,--no-relax # Prevent use of global_pointer for RISC-V.
|
||||
|
||||
# Use the base linker flags for each RISC-V variant.
|
||||
override WLFLAGS_rv32i += $(WLFLAGS_rv32)
|
||||
override WLFLAGS_rv32imc += $(WLFLAGS_rv32)
|
||||
override WLFLAGS_rv32imac += $(WLFLAGS_rv32)
|
||||
|
||||
# Set the system libraries we link against for RISC-V. We support C++ apps by
|
||||
# default.
|
||||
override LINK_LIBS_rv32 += \
|
||||
-lgcc -lstdc++ -lsupc++
|
||||
|
||||
override LINK_LIBS_rv32i += $(LINK_LIBS_rv32)
|
||||
override LINK_LIBS_rv32imc += $(LINK_LIBS_rv32)
|
||||
override LINK_LIBS_rv32imac += $(LINK_LIBS_rv32)
|
||||
|
||||
# Use precompiled libaries we provide to link against.
|
||||
override LEGACY_LIBS_rv32i += \
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libc.a\
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libm.a
|
||||
|
||||
override LEGACY_LIBS_rv32im += \
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libc.a\
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libm.a
|
||||
|
||||
override LEGACY_LIBS_rv32imc += $(LEGACY_LIBS_rv32im)
|
||||
|
||||
override LEGACY_LIBS_rv32imac += \
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libc.a\
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libm.a
|
||||
|
||||
|
||||
################################################################################
|
||||
##
|
||||
## Cortex-M compiler/linker flags
|
||||
##
|
||||
################################################################################
|
||||
|
||||
# Setup the correct toolchain for each architecture. ARM has a standard
|
||||
# toolchain we can use for every variant.
|
||||
TOOLCHAIN_cortex-m := arm-none-eabi
|
||||
TOOLCHAIN_cortex-m0 := $(TOOLCHAIN_cortex-m)
|
||||
TOOLCHAIN_cortex-m3 := $(TOOLCHAIN_cortex-m)
|
||||
TOOLCHAIN_cortex-m4 := $(TOOLCHAIN_cortex-m)
|
||||
TOOLCHAIN_cortex-m7 := $(TOOLCHAIN_cortex-m)
|
||||
|
||||
# Setup the correct compiler. For cortex-m we only support GCC as it is the only
|
||||
# toolchain with the PIC support we need for Tock userspace apps.
|
||||
CC_cortex-m := -gcc
|
||||
CC_cortex-m0 := $(CC_cortex-m)
|
||||
CC_cortex-m3 := $(CC_cortex-m)
|
||||
CC_cortex-m4 := $(CC_cortex-m)
|
||||
CC_cortex-m7 := $(CC_cortex-m)
|
||||
|
||||
# Based on the toolchain used by each architecture, add in toolchain-specific
|
||||
# flags. We assume that each architecture family uses the same toolchain.
|
||||
ifeq ($(findstring -gcc,$(CC_cortex-m)),-gcc)
|
||||
override CPPFLAGS_toolchain_cortex-m += $(CPPFLAGS_gcc)
|
||||
override CFLAGS_toolchain_cortex-m += $(CFLAGS_gcc)
|
||||
endif
|
||||
|
||||
override CFLAGS_cortex-m += \
|
||||
$(CFLAGS_toolchain_cortex-m)
|
||||
|
||||
override CFLAGS_cortex-m0 += $(CFLAGS_cortex-m)
|
||||
override CFLAGS_cortex-m3 += $(CFLAGS_cortex-m)
|
||||
override CFLAGS_cortex-m4 += $(CFLAGS_cortex-m)
|
||||
override CFLAGS_cortex-m7 += $(CFLAGS_cortex-m)
|
||||
|
||||
override CPPFLAGS_cortex-m += \
|
||||
$(CPPFLAGS_toolchain_cortex-m)\
|
||||
$(CPPFLAGS_PIC)\
|
||||
-mthumb\
|
||||
-mfloat-abi=soft\
|
||||
-msingle-pic-base\
|
||||
-mpic-register=r9\
|
||||
-mno-pic-data-is-text-relative
|
||||
|
||||
# Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85606
|
||||
override CPPFLAGS_cortex-m0 += $(CPPFLAGS_cortex-m) \
|
||||
-mcpu=cortex-m0\
|
||||
-march=armv6s-m
|
||||
|
||||
override CPPFLAGS_cortex-m3 += $(CPPFLAGS_cortex-m) \
|
||||
-mcpu=cortex-m3
|
||||
|
||||
override CPPFLAGS_cortex-m4 += $(CPPFLAGS_cortex-m) \
|
||||
-mcpu=cortex-m4
|
||||
|
||||
override CPPFLAGS_cortex-m7 += $(CPPFLAGS_cortex-m) \
|
||||
-mcpu=cortex-m7
|
||||
|
||||
# Single-arch libraries, to be phased out
|
||||
override LEGACY_LIBS_cortex-m += \
|
||||
$(TOCK_USERLAND_BASE_DIR)/libc++/cortex-m/libstdc++.a\
|
||||
$(TOCK_USERLAND_BASE_DIR)/libc++/cortex-m/libsupc++.a\
|
||||
$(TOCK_USERLAND_BASE_DIR)/libc++/cortex-m/libgcc.a
|
||||
|
||||
override LEGACY_LIBS_cortex-m0 += $(LEGACY_LIBS_cortex-m) \
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/cortex-m/v6-m/libc.a\
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/cortex-m/v6-m/libm.a
|
||||
|
||||
override LEGACY_LIBS_cortex-m3 += $(LEGACY_LIBS_cortex-m) \
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/cortex-m/v7-m/libc.a\
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/cortex-m/v7-m/libm.a
|
||||
|
||||
override LEGACY_LIBS_cortex-m4 += $(LEGACY_LIBS_cortex-m) \
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/cortex-m/v7-m/libc.a\
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/cortex-m/v7-m/libm.a
|
||||
|
||||
override LEGACY_LIBS_cortex-m7 += $(LEGACY_LIBS_cortex-m) \
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/cortex-m/v7-m/libc.a\
|
||||
$(TOCK_USERLAND_BASE_DIR)/newlib/cortex-m/v7-m/libm.a
|
||||
|
||||
# Cortex-M needs an additional OBJDUMP flag.
|
||||
override OBJDUMP_FLAGS_cortex-m += --disassembler-options=force-thumb
|
||||
override OBJDUMP_FLAGS_cortex-m7 += $(OBJDUMP_FLAGS_cortex-m)
|
||||
override OBJDUMP_FLAGS_cortex-m4 += $(OBJDUMP_FLAGS_cortex-m)
|
||||
override OBJDUMP_FLAGS_cortex-m3 += $(OBJDUMP_FLAGS_cortex-m)
|
||||
override OBJDUMP_FLAGS_cortex-m0 += $(OBJDUMP_FLAGS_cortex-m)
|
||||
|
||||
|
||||
################################################################################
|
||||
# Extra warning flags not enabled by Wall or Wextra.
|
||||
#
|
||||
# I read through the gcc manual and grabbed the ones that I thought might be
|
||||
# interesting / useful. Then I grabbed that snippet below to find other things
|
||||
# that were left out of the manual that may be worth adding. Below are all
|
||||
# warnings and a short description supported by (arm-none-eabi)-gcc as of
|
||||
# v6.2.1.
|
||||
#
|
||||
# http://stackoverflow.com/questions/11714827/
|
||||
# List all supported warnings and their status:
|
||||
# gcc -Wall -Wextra -Q --help=warning
|
||||
# Below are all warnings produced in an un-merged set of sorted lists
|
||||
# broken into C/C++, C only, C++ only, other languages
|
||||
#
|
||||
# TODO(Pat) libnrfserialization noise with these, but I think they're useful
|
||||
# and I want them back when I get a chance to clean that up.
|
||||
#CPPFLAGS += -Wcast-qual # # const char* -> char*
|
||||
#CPPFLAGS += -Wswitch-default # # switch w/out default (doesn't cover all cases) (maybe annoying?)
|
||||
#CFLAGS += -Wstrict-prototypes # # function defined w/out specifying argument types
|
||||
|
||||
override CPPFLAGS += -Wdate-time # # warn if __TIME__, __DATE__, or __TIMESTAMP__ used
|
||||
# ^on b/c flashing assumes same code => no flash, these enforce
|
||||
override CPPFLAGS += -Wfloat-equal # # floats used with '=' operator, likely imprecise
|
||||
override CPPFLAGS += -Wformat-nonliteral # # can't check format string (maybe disable if annoying)
|
||||
override CPPFLAGS += -Wformat-security # # using untrusted format strings (maybe disable)
|
||||
override CPPFLAGS += -Wformat-y2k # # use of strftime that assumes two digit years
|
||||
override CPPFLAGS += -Winit-self # # { int i = i }
|
||||
override CPPFLAGS += -Wmissing-declarations # # ^same? not sure how these differ
|
||||
override CPPFLAGS += -Wmissing-field-initializers # if init'ing struct w/out field names, warn if not all used
|
||||
override CPPFLAGS += -Wmissing-format-attribute # # something looks printf-like but isn't marked as such
|
||||
override CPPFLAGS += -Wmissing-noreturn # # __attribute__((noreturn)) like -> ! in Rust, should use it
|
||||
override CPPFLAGS += -Wmultichar # # use of 'foo' instead of "foo" (surpised not on by default?)
|
||||
override CPPFLAGS += -Wpointer-arith # # sizeof things not define'd (i.e. sizeof(void))
|
||||
override CPPFLAGS += -Wredundant-decls # # { int i; int i; } (a lint)
|
||||
override CPPFLAGS += -Wshadow # # int foo(int a) { int a = 1; } inner a shadows outer a
|
||||
override CPPFLAGS += -Wunused-macros # # macro defined in this file not used
|
||||
override CPPFLAGS += -Wunused-parameter # # function parameter is unused aside from its declaration
|
||||
override CPPFLAGS += -Wwrite-strings # # { char* c = "foo"; c[0] = 'b' } <-- "foo" should be r/o
|
||||
|
||||
override CPPFLAGS_gcc += -Wlogical-op # # "suspicious use of logical operators in expressions" (a lint)
|
||||
override CPPFLAGS_gcc += -Wtrampolines # # attempt to generate a trampoline on the NX stack
|
||||
|
||||
#CPPFLAGS += -Wabi -Wabi-tag # inter-compiler abi issues
|
||||
#CPPFLAGS += -Waggregate-return # warn if things return struct's
|
||||
#CPPFLAGS += -Wcast-align # { char *c; int *i = (int*) c}, 1 byte -> 4 byte align
|
||||
#CPPFLAGS += -Wconversion # implicit conversion that may unexpectedly alter value
|
||||
# ^ A ton of these from syscalls I think, XXX look later
|
||||
#CPPFLAGS += -Wdisabled-optimization # gcc skipped an optimization for any of a thousand reasons
|
||||
#CPPFLAGS += -Wdouble-promotion # warn if float -> double implicitly XXX maybe?
|
||||
#CPPFLAGS += -Wformat-signedness # # { int i; printf("%d %u", i, i) } second bad (maybe annoying?)
|
||||
# ^ Too obnoxious when you want hex of an int
|
||||
#CPPFLAGS += -Wfloat-conversion # subset of -Wconversion
|
||||
#CPPFLAGS += -Winline # something marked `inline` wasn't inlined
|
||||
#CPPFLAGS += -Winvalid-pch # bad precompiled header found in an include dir
|
||||
#CPPFLAGS += -Wmissing-include-dirs -- XXX Didn't try, afriad could be annoying
|
||||
#CPPFLAGS += -Woverlength-strings # complier compat: strings > [509 C90, 4095 C99] chars
|
||||
#CPPFLAGS += -Wpacked # struct with __attribute__((packed)) that does nothing
|
||||
#CPPFLAGS += -Wpadded # padding added to a struct. Noisy for argument structs
|
||||
#CPPFLAGS += -Wpedantic # strict ISO C/C++
|
||||
#CPPFLAGS += -Wsign-conversion # implicit integer sign conversions, part of -Wconversion
|
||||
#CPPFLAGS += -Wstack-protector # only if -fstack-protector, on by default, warn fn not protect
|
||||
#CPPFLAGS += -Wsuggest-attribute=const # does what it sounds like - removed due to noise
|
||||
#CPPFLAGS += -Wsuggest-attribute=pure # does what it sounds like - removed due to noise
|
||||
#CPPFLAGS += -Wswitch-enum # # switch of enum doesn't explicitly cover all cases
|
||||
# ^ annoying in practice, let default: do its job
|
||||
#CPPFLAGS += -Wsystem-headers # warnings from system headers
|
||||
#CPPFLAGS += -Wtraditional # stuff gcc allows that "traditional" C doesn't
|
||||
#CPPFLAGS += -Wundef # undefined identifier is evaluated in an `#if' directive
|
||||
# ^ Lots of library #if SAMD || SMAR21 stuff
|
||||
# Should probably be ifdef, but too much noise
|
||||
#CPPFLAGS += -Wunsafe-loop-optimizations # compiler can't divine loop bounds XXX maybe interesting?
|
||||
#CPPFLAGS += -Wvariadic-macros # can't be used in ISO C
|
||||
#CPPFLAGS += -Wvector-operation-performance # perf option not appropriate for these systems
|
||||
#CPPFLAGS += -Wvla -- XXX Didn't try, but interested
|
||||
|
||||
# C-only warnings
|
||||
override CFLAGS += -Wbad-function-cast # # not obvious when this would trigger, could drop if annoying
|
||||
override CFLAGS += -Wmissing-prototypes # # global fn defined w/out prototype (should be static or in .h)
|
||||
override CFLAGS += -Wnested-externs # # mis/weird-use of extern keyword
|
||||
override CFLAGS += -Wold-style-definition # # this garbage: void bar (a) int a; { }
|
||||
|
||||
override CFLAGS_gcc += -Wjump-misses-init # # goto or switch skips over a variable initialization
|
||||
|
||||
#CFLAGS += -Wunsuffixed-float-constants # # { float f=0.67; if(f==0.67) printf("y"); else printf("n"); } => n
|
||||
# ^ doesn't seem to work right? find_north does funny stuff
|
||||
|
||||
#CFLAGS += -Wtraditional-conversion # # prototype causes a conversion different than w/o prototype (?)
|
||||
# ^ real noisy
|
||||
|
||||
# CXX-only warnings
|
||||
override CXXFLAGS += -Wctor-dtor-privacy # # unusable class b/c everything private and no friends
|
||||
override CXXFLAGS += -Wdelete-non-virtual-dtor # # catches undefined behavior
|
||||
override CXXFLAGS += -Wold-style-cast # # C-style cast in C++ code
|
||||
override CXXFLAGS += -Woverloaded-virtual # # subclass shadowing makes parent impl's unavailable
|
||||
override CXXFLAGS += -Wsign-promo # # gcc did what spec requires, but probably not what you want
|
||||
override CXXFLAGS += -Wstrict-null-sentinel # # seems like a not-very-C++ thing to do? very unsure
|
||||
override CXXFLAGS += -Wsuggest-final-methods # # does what it sounds like
|
||||
override CXXFLAGS += -Wsuggest-final-types # # does what it sounds like
|
||||
override CXXFLAGS += -Wsuggest-override # # overridden virtual func w/out override keyword
|
||||
override CXXFLAGS += -Wuseless-cast # # pretty much what ya think here
|
||||
override CXXFLAGS += -Wzero-as-null-pointer-constant # use of 0 as NULL
|
||||
|
||||
# -Wc++-compat # # C/C++ compat issues
|
||||
# -Wc++11-compat # # C11 compat issues
|
||||
# -Wc++14-compat # # C14 compat issues
|
||||
# -Wconditionally-supported # # conditionally-supported (C++11 [intro.defs]) constructs (?)
|
||||
# -Weffc++ # violations of style guidelines from Meyers' Effective C++ books
|
||||
# -Wmultiple-inheritance # used to enforce coding conventions, does what you'd think
|
||||
# -Wnamespaces # used to enforce coding conventions, warn if namespace opened
|
||||
# -Wnoexcept # # (?) I think warns if missing noexcept
|
||||
# -Wnon-virtual-dtor # # something deeply c++, part of effc++
|
||||
# -Wsynth # legacy flag, g++ != cfront
|
||||
# -Wtemplates # used to enforce coding conventions, warn if new template
|
||||
# -Wvirtual-inheritance # used to enforce coding conventions, does what you'd think
|
||||
|
||||
# Fortran-only warnings
|
||||
# -Waliasing
|
||||
# -Wampersand
|
||||
# -Warray-temporaries
|
||||
# -Wc-binding-type
|
||||
# -Wcharacter-truncation
|
||||
# -Wcompare-reals
|
||||
# -Wconversion-extra
|
||||
# -Wfunction-elimination
|
||||
# -Wimplicit-interface
|
||||
# -Wimplicit-procedure
|
||||
# -Winteger-division
|
||||
# -Wintrinsic-shadow
|
||||
# -Wintrinsics-std
|
||||
# -Wreal-q-constant
|
||||
# -Wrealloc-lhs
|
||||
# -Wrealloc-lhs-all
|
||||
# -Wsurprising
|
||||
# -Wtabs
|
||||
# -Wtarget-lifetime
|
||||
# -Wunused-dummy-argument
|
||||
# -Wuse-without-only
|
||||
|
||||
# Objective-C(++)-only
|
||||
# -Wassign-intercept
|
||||
# -Wselector
|
||||
# -Wstrict-selector-match
|
||||
# -Wundeclared-selector
|
||||
|
||||
# END WARNINGS
|
||||
################################################################################
|
||||
|
||||
|
||||
# C/C++ Linter configuration
|
||||
UNCRUSTIFY := $(TOCK_USERLAND_BASE_DIR)/tools/uncrustify/uncrustify.sh
|
||||
|
||||
|
||||
# Dump configuration for verbose builds
|
||||
ifneq ($(V),)
|
||||
$(info )
|
||||
$(info **************************************************)
|
||||
$(info TOCK USERLAND BUILD SYSTEM -- VERBOSE BUILD)
|
||||
$(info **************************************************)
|
||||
$(info Config:)
|
||||
$(info GIT: $(shell git describe --always 2>&1))
|
||||
$(info $(TOOLCHAIN_cortex-m4)$(CC_cortex-m4) --version: $(shell $(TOOLCHAIN_cortex-m4)$(CC_cortex-m4) --version))
|
||||
ifneq ($(RISCV),)
|
||||
$(info $(TOOLCHAIN_rv32i)$(CC_rv32i) --version: $(shell $(TOOLCHAIN_rv32i)$(CC_rv32i) --version))
|
||||
endif
|
||||
$(info LAYOUT=$(LAYOUT))
|
||||
$(info MAKEFLAGS=$(MAKEFLAGS))
|
||||
$(info PACKAGE_NAME=$(PACKAGE_NAME))
|
||||
$(info TOCK_ARCHS=$(TOCK_ARCHS))
|
||||
$(info TOCK_TARGETS=$(TOCK_TARGETS))
|
||||
$(info TOCK_USERLAND_BASE_DIR=$(TOCK_USERLAND_BASE_DIR))
|
||||
$(info TOOLCHAIN=$(TOOLCHAIN))
|
||||
$(info **************************************************)
|
||||
$(info )
|
||||
endif
|
||||
|
||||
endif
|
@ -1,91 +0,0 @@
|
||||
################################################################################
|
||||
##
|
||||
## libtock-c helper functions and definitions for use by Tock makefiles.
|
||||
## Included by AppMakefile.mk and libtock's Makefile
|
||||
##
|
||||
################################################################################
|
||||
|
||||
# Ensure that this file is only included once.
|
||||
ifndef HELPERS_MAKEFILE
|
||||
HELPERS_MAKEFILE = 1
|
||||
|
||||
# http://stackoverflow.com/questions/10858261/abort-makefile-if-variable-not-set
|
||||
# Check that given variables are set and all have non-empty values,
|
||||
# die with an error otherwise.
|
||||
#
|
||||
# Params:
|
||||
# 1. Variable name(s) to test.
|
||||
# 2. (optional) Error message to print.
|
||||
check_defined = \
|
||||
$(strip $(foreach 1,$1, \
|
||||
$(call __check_defined,$1,$(strip $(value 2)))))
|
||||
__check_defined = \
|
||||
$(if $(value $1),, \
|
||||
$(error Undefined $1$(if $2, ($2))))
|
||||
|
||||
# Check for a ~/ at the beginning of a path variable (TOCK_USERLAND_BASE_DIR).
|
||||
# Make will not properly expand this.
|
||||
ifdef TOCK_USERLAND_BASE_DIR
|
||||
ifneq (,$(findstring BEGINNINGOFVARIABLE~/,BEGINNINGOFVARIABLE$(TOCK_USERLAND_BASE_DIR)))
|
||||
$(error Hi! Using "~" in Makefile variables is not supported. Use "$$(HOME)" instead)
|
||||
endif
|
||||
endif
|
||||
|
||||
# # Validate the the toolchain is new enough (known not to work for gcc <= 5.1)
|
||||
# CC_VERSION_MAJOR := $(shell $(CC) -dumpversion | cut -d '.' -f1)
|
||||
# ifeq (1,$(shell expr $(CC_VERSION_MAJOR) \>= 6))
|
||||
# # Opportunistically turn on gcc 6.0+ warnings since we're already version checking:
|
||||
# override CPPFLAGS += -Wduplicated-cond # if (p->q != NULL) { ... } else if (p->q != NULL) { ... }
|
||||
# override CPPFLAGS += -Wnull-dereference # deref of NULL (thought default if -fdelete-null-pointer-checks, in -Os, but no?)
|
||||
# else
|
||||
# ifneq (5,$(CC_VERSION_MAJOR))
|
||||
# $(info CC=$(CC))
|
||||
# $(info $$(CC) -dumpversion: $(shell $(CC) -dumpversion))
|
||||
# $(error Your compiler is too old. Need gcc version > 5.1)
|
||||
# endif
|
||||
# CC_VERSION_MINOR := $(shell $(CC) -dumpversion | cut -d '.' -f2)
|
||||
# ifneq (1,$(shell expr $(CC_VERSION_MINOR) \> 1))
|
||||
# $(info CC=$(CC))
|
||||
# $(info $$(CC) -dumpversion: $(shell $(CC) -dumpversion))
|
||||
# $(error Your compiler is too old. Need gcc version > 5.1)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
|
||||
# Format check rule
|
||||
.PHONY: _format_check_unstaged
|
||||
_format_check_unstaged:
|
||||
$(Q)$(TOCK_USERLAND_BASE_DIR)/tools/check_unstaged.sh
|
||||
|
||||
#########################################################################################
|
||||
## Pretty-printing rules
|
||||
|
||||
# If environment variable V is non-empty, be verbose.
|
||||
ifneq ($(V),)
|
||||
Q=
|
||||
TRACE_DIR =
|
||||
TRACE_BIN =
|
||||
TRACE_DEP =
|
||||
TRACE_CC =
|
||||
TRACE_CXX =
|
||||
TRACE_LD =
|
||||
TRACE_AR =
|
||||
TRACE_AS =
|
||||
TRACE_LST =
|
||||
TRACE_E2T =
|
||||
ELF2TAB_ARGS += -v
|
||||
else
|
||||
Q=@
|
||||
TRACE_DIR = @echo " DIR " $@
|
||||
TRACE_BIN = @echo " BIN " $@
|
||||
TRACE_DEP = @echo " DEP " $<
|
||||
TRACE_CC = @echo " CC " $<
|
||||
TRACE_CXX = @echo " CXX " $<
|
||||
TRACE_LD = @echo " LD " $@
|
||||
TRACE_AR = @echo " AR " $@
|
||||
TRACE_AS = @echo " AS " $<
|
||||
TRACE_LST = @echo " LST " $<
|
||||
TRACE_E2T = @echo " E2T " $@
|
||||
endif
|
||||
|
||||
endif
|
@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -1,25 +0,0 @@
|
||||
Copyright (c) 2016 The Tock Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
@ -1,3 +0,0 @@
|
||||
prepush:
|
||||
cd examples; ./format_all.sh
|
||||
|
@ -1,50 +0,0 @@
|
||||
################################################################################
|
||||
##
|
||||
## Makefile for loading applications onto a Tockloader compatible board.
|
||||
##
|
||||
################################################################################
|
||||
|
||||
$(call check_defined, BUILDDIR)
|
||||
$(call check_defined, PACKAGE_NAME)
|
||||
|
||||
TOCKLOADER ?= tockloader
|
||||
OPENOCD ?= openocd
|
||||
|
||||
# Upload programs over UART with tockloader.
|
||||
ifdef PORT
|
||||
TOCKLOADER_GENERAL_FLAGS += --port $(PORT)
|
||||
endif
|
||||
|
||||
# Setup specific commands for each board.
|
||||
ifeq ("$(TOCK_BOARD)","hail")
|
||||
PROGRAM = $(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) install $<
|
||||
FLASH = $(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) install --jlink $<
|
||||
|
||||
else ifeq ("$(TOCK_BOARD)","imix")
|
||||
# Change program region offset
|
||||
TOCKLOADER_INSTALL_FLAGS += --app-address 0x40000
|
||||
PROGRAM = $(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) install $(TOCKLOADER_INSTALL_FLAGS) $<
|
||||
FLASH = $(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) install $(TOCKLOADER_INSTALL_FLAGS) --jlink $<
|
||||
|
||||
else ifeq ("$(TOCK_BOARD)","ek-tm4c1294xl")
|
||||
FLASH = $(OPENOCD) -c "source [find board/ek-tm4c1294xl.cfg]; init; reset halt; flash write_image erase $< 0x00020000 bin; reset; shutdown"
|
||||
|
||||
else ifeq ("$(TOCK_BOARD)","nrf51dk")
|
||||
FLASH = $(TOCKLOADER) install --jlink --board nrf51dk $<
|
||||
|
||||
else ifeq ("$(TOCK_BOARD)","nrf52dk")
|
||||
FLASH = $(TOCKLOADER) install --jlink --board nrf52dk $<
|
||||
|
||||
endif
|
||||
|
||||
PROGRAM ?= @(echo "Cannot program over serial $<"; exit 1)
|
||||
FLASH ?= @(echo "Cannot flash $<"; exit 1)
|
||||
|
||||
.PHONY: program
|
||||
program: $(BUILDDIR)/$(PACKAGE_NAME).tab
|
||||
$(PROGRAM)
|
||||
|
||||
# Upload programs over JTAG
|
||||
.PHONY: flash
|
||||
flash: $(BUILDDIR)/$(PACKAGE_NAME).tab
|
||||
$(FLASH)
|
@ -1,294 +0,0 @@
|
||||

|
||||
[][slack]
|
||||
|
||||
Tock Userland
|
||||
=============
|
||||
|
||||
This directory contains libraries and example applications for developing
|
||||
Tock apps that sit above the kernel.
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
1. If you have not yet done so, it might be a good idea to start with
|
||||
the [TockOS getting started
|
||||
guide](https://github.com/tock/tock/blob/master/doc/Getting_Started.md),
|
||||
which will lead you through the installation of some tools that
|
||||
will be useful for developing and deploying applications on
|
||||
TockOS. In particular, it will give you a rust environment
|
||||
(required to install `elf2tab`) and `tockloader`, which you need to
|
||||
deploy applications on most boards.
|
||||
|
||||
And it will of course give you a board with TockOS installed which
|
||||
you can use to run the applications found in this repository.
|
||||
|
||||
So, if you haven't been there before, just head over there until it
|
||||
sends you back here.
|
||||
|
||||
1. Clone this repository.
|
||||
|
||||
```
|
||||
$ git clone https://github.com/tock/libtock-c
|
||||
$ cd libtock-c
|
||||
```
|
||||
|
||||
1. The main requirement to build the C applications in this repository is having
|
||||
cross compilers for embedded targets. You will need an `arm-none-eabi`
|
||||
toolchain for Cortex-M targets.
|
||||
|
||||
**MacOS**:
|
||||
```
|
||||
$ brew tap ARMmbed/homebrew-formulae && brew update && brew install arm-none-eabi-gcc
|
||||
```
|
||||
|
||||
**Ubuntu (18.04LTS or later)**:
|
||||
```
|
||||
$ sudo apt install gcc-arm-none-eabi
|
||||
```
|
||||
|
||||
**Arch**:
|
||||
```
|
||||
$ sudo pacman -Syu arm-none-eabi-gcc arm-none-eabi-newlib
|
||||
```
|
||||
|
||||
**Fedora**:
|
||||
```
|
||||
$ sudo dnf install arm-none-eabi-newlib arm-none-eabi-gcc-cs
|
||||
```
|
||||
|
||||
2. Optional: libtock-c also includes support for building for ***RISC-V
|
||||
targets***. These are not included by default since obtaining the toolchain
|
||||
can be difficult (as of July 2022). You will need a RISC-V toolchain that
|
||||
supports rv32 targets (64 bit toolchains support rv32 if compiled with
|
||||
multilib support). Some toolchains that can work:
|
||||
|
||||
- riscv64-none-elf
|
||||
- riscv32-none-elf
|
||||
- riscv64-elf
|
||||
- riscv64-unknown-elf
|
||||
- riscv32-unknown-elf
|
||||
|
||||
To actually build for the RISC-V targets, add `RISCV=1` to the make command:
|
||||
|
||||
$ make RISCV=1
|
||||
|
||||
**MacOS**:
|
||||
```
|
||||
$ brew tap riscv/riscv && brew update && brew install riscv-gnu-toolchain
|
||||
```
|
||||
|
||||
**Ubuntu (21.10 or later)**:
|
||||
```
|
||||
$ sudo apt install gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf
|
||||
```
|
||||
|
||||
**Ubuntu (21.04 or earlier)**:
|
||||
|
||||
Unfortunately, older Ubuntu does not provide a package for RISC-V libc. We
|
||||
have created a .deb file you can use to install a suitable libc based on
|
||||
newlib:
|
||||
```
|
||||
$ wget http://cs.virginia.edu/~bjc8c/archive/newlib_3.3.0-1_amd64.deb
|
||||
$ sudo dpkg -i newlib_3.3.0-1_amd64.deb
|
||||
```
|
||||
|
||||
If you would rather compile your own newlib-based libc, follow the steps
|
||||
below. Section [newlib-nano](newlib-nano) describes some extra config options
|
||||
to build a size optimised newlib.
|
||||
```
|
||||
# Download newlib 3.3 from https://sourceware.org/newlib/
|
||||
$ wget ftp://sourceware.org/pub/newlib/newlib-3.3.0.tar.gz
|
||||
$ tar -xvf newlib-3.3.0.tar.gz
|
||||
$ cd newlib-3.3.0
|
||||
# Disable stdlib for building
|
||||
$ export CFLAGS=-nostdlib
|
||||
# Run configure
|
||||
$ ./configure --disable-newlib-supplied-syscalls --with-gnu-ld --with-newlib --enable-languages=c --target=riscv64-unknown-elf --host=x86 --disable-multi-lib --prefix /usr
|
||||
# Build and then install
|
||||
$ make -j8
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
Alternatively, you may use a pre-compiled toolchain that we created with
|
||||
Crosstool-NG.
|
||||
```
|
||||
$ wget http://cs.virginia.edu/~bjc8c/archive/gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip
|
||||
$ unzip gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip
|
||||
# add gcc-riscv64-unknown-elf-8.3.0-ubuntu/bin to your `$PATH` variable.
|
||||
```
|
||||
|
||||
**Arch**:
|
||||
```
|
||||
$ sudo pacman -Syu riscv64-elf-gcc riscv32-elf-newlib arm-none-eabi-newlib riscv64-elf-newlib
|
||||
```
|
||||
|
||||
**Fedora**:
|
||||
|
||||
**dnf** does not contain the `riscv-gnu-toolchain`, an alternative is to
|
||||
compile from source. Start with some of the tools we need to compile the
|
||||
source.
|
||||
```
|
||||
$ sudo dnf install make automake gcc gcc-c++ kernel-devel texinfo expat expat-devel
|
||||
$ sudo dnf group install "Development Tools" "C Development Tools and Libraries"
|
||||
```
|
||||
Get `riscv-gnu-toolchain`, [summarised instructions as stated
|
||||
here](https://github.com/riscv-collab/riscv-gnu-toolchain/blob/master/README.md)
|
||||
```
|
||||
$ git clone https://github.com/riscv/riscv-gnu-toolchain
|
||||
$ cd riscv-gnu-toolchain/
|
||||
```
|
||||
**Note: add /opt/riscv/bin to your PATH**, then,
|
||||
```
|
||||
$ ./configure --prefix=/opt/riscv --enable-multilib
|
||||
```
|
||||
`--enable-multilib` ensures that "the multilib compiler will have the prefix
|
||||
riscv64-unknown-elf- or riscv64-unknown-linux-gnu- but will be able to target
|
||||
both 32-bit and 64-bit systems."
|
||||
```
|
||||
$ sudo make [might need elevated privileges writing to `/opt/`]
|
||||
```
|
||||
additionally, with
|
||||
```
|
||||
$ sudo make linux
|
||||
```
|
||||
you can also build `riscv64-unknown-linux-gnu`, which can be useful with tock
|
||||
where `riscv64-unknown-linux-gnu-objcopy` is used.
|
||||
|
||||
After the the source has been compiled and copied to `/opt/riscv` and
|
||||
`/opt/riscv/bin`has appended to the PATH, the toolchain is ready to be used.
|
||||
|
||||
|
||||
**newlib-nano**:
|
||||
|
||||
newlib can require a large amount of memory, especially for printing.
|
||||
If this is a concern you can instead use a more size optimised version.
|
||||
As of August 2020 there are a few options for this.
|
||||
|
||||
- See if the version of newlib from your distro already has the flags below
|
||||
enabled. If it does it's already size optimsed.
|
||||
- See if your distro pacakges a newlib-nano (Debian does this) that will
|
||||
already include the flags below.
|
||||
- See if your distro packages picolibc, which is a optimised fork of newlib.
|
||||
- You can compile newlib with these extra flags:
|
||||
```
|
||||
--enable-newlib-reent-small \
|
||||
--disable-newlib-fvwrite-in-streamio \
|
||||
--disable-newlib-fseek-optimization \
|
||||
--disable-newlib-wide-orient \
|
||||
--enable-newlib-nano-malloc \
|
||||
--disable-newlib-unbuf-stream-opt \
|
||||
--enable-lite-exit \
|
||||
--enable-newlib-global-atexit \
|
||||
--enable-newlib-nano-formatted-io
|
||||
```
|
||||
|
||||
3. Optional: libtock-c also includes support for building RISC-V targets with
|
||||
the LLVM clang compiler. If you have a compatible clang toolchain, you can
|
||||
add `CLANG=1` to the make command to use clang instead of the default GCC.
|
||||
|
||||
$ make RISCV=1 CLANG=1
|
||||
|
||||
This support is only included for RISC-V targets as Cortex-M targets require
|
||||
the FDPIC support only present in GCC.
|
||||
|
||||
4. You will also need an up-to-date version of
|
||||
[elf2tab](https://crates.io/crates/elf2tab). The build system will install
|
||||
and update this automatically for you, but you'll need Rust's
|
||||
[cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html)
|
||||
installed. If you have followed the getting started guide, everything should
|
||||
be in place.
|
||||
|
||||
5. You will also likely need [Tockloader](https://github.com/tock/tockloader), a
|
||||
tool for programming apps onto boards. If you haven't installed it
|
||||
during the TockOS getting started guide:
|
||||
|
||||
MacOS:
|
||||
```
|
||||
$ pip3 install tockloader
|
||||
```
|
||||
|
||||
Ubuntu:
|
||||
```
|
||||
$ pip3 install tockloader --user
|
||||
```
|
||||
|
||||
Compiling and Running Applications
|
||||
----------------------------------
|
||||
|
||||
To compile all the examples, switch to the `examples` directory and execute the
|
||||
build script:
|
||||
|
||||
$ cd examples
|
||||
$ ./build_all.sh
|
||||
|
||||
This will install `elf2tab` if it is not yet installed and compile all the
|
||||
examples for cortex-m0, cortex-m3, cortex-m4, cortex-m7, and rv32imac. It does
|
||||
this because the compiler emits slightly (or significantly) different
|
||||
instructions for each variant. When installing the application, `tockloader`
|
||||
will select the correct version for the architecture of the board being
|
||||
programmed.
|
||||
|
||||
The build process will ultimately create a `tab` file (a "Tock Application
|
||||
Bundle") for each example application. The `tab` contains the executable code
|
||||
for the supported architectures and can be deployed to a board using
|
||||
`tockloader`. For example to one of the Nordic development boards:
|
||||
|
||||
```
|
||||
$ tockloader install --board nrf52dk --jlink blink/build/blink.tab
|
||||
Installing apps on the board...
|
||||
Using known arch and jtag-device for known board nrf52dk
|
||||
Finished in 2.567 seconds
|
||||
```
|
||||
|
||||
You can remove an application with
|
||||
|
||||
$ tockloader uninstall --board nrf52dk --jlink blink
|
||||
|
||||
or remove all installed applications with
|
||||
|
||||
$ tockloader uninstall --board nrf52dk --jlink
|
||||
|
||||
Tock applications are designed to be generic and run on any Tock-compatible
|
||||
board. However, compiled applications typically depend on specific drivers,
|
||||
which not all boards provide. For example, some applications expect an IEEE
|
||||
802.15.4 radio interface which not all boards support. If you load an
|
||||
application onto a board that does not support every driver/system call it uses,
|
||||
some system calls will return error codes (`ENODEVICE` or `ENOSUPPORT`).
|
||||
|
||||
Next Steps
|
||||
----------
|
||||
|
||||
The next step is to read the [overview](doc/overview.md) that describes how
|
||||
applications in TockOS are structured and then look at some of the examples in
|
||||
detail. The description of the [compilation environment](doc/compilation.md) may
|
||||
also be of interest.
|
||||
|
||||
[slack]: https://join.slack.com/t/tockos/shared_invite/enQtNDE5ODQyNDU4NTE1LWVjNTgzMTMwYzA1NDI1MjExZjljMjFmOTMxMGIwOGJlMjk0ZTI4YzY0NTYzNWM0ZmJmZGFjYmY5MTJiMDBlOTk
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Licensed under either of
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
Contributions
|
||||
-------------
|
||||
|
||||
We welcome contributions from all. We use the bors-ng bot to manage, approve,
|
||||
and merge PRs. In short, when someone replies `bors r+`, your PR has been
|
||||
approved and will be automatically merged. If a maintainer replies `bors
|
||||
delegate+`, then you have been granted the authority to mark your own PR for
|
||||
approval (usually this will happen if there are some trivial changes required).
|
||||
For a full list of bors commands, [see the bors
|
||||
documentation](https://bors.tech/documentation/).
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
@ -1,191 +0,0 @@
|
||||
################################################################################
|
||||
##
|
||||
## libtock-c library shared makefile. Included by library makefiles to build
|
||||
## libraries for use with libtock-c apps.
|
||||
##
|
||||
################################################################################
|
||||
|
||||
# The first target Make finds is its default. So this line needs to be first to
|
||||
# specify `all` as our default rule.
|
||||
all:
|
||||
|
||||
# Build settings.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/Configuration.mk
|
||||
|
||||
# Helper functions.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/Helpers.mk
|
||||
|
||||
$(call check_defined, LIBNAME)
|
||||
$(call check_defined, $(LIBNAME)_DIR)
|
||||
$(call check_defined, $(LIBNAME)_SRCS)
|
||||
|
||||
ifeq ($(strip $($(LIBNAME)_SRCS)),)
|
||||
$(error Library "$(LIBNAME)" has no SRCS?)
|
||||
endif
|
||||
|
||||
# directory for built output
|
||||
$(LIBNAME)_BUILDDIR ?= $($(LIBNAME)_DIR)/build
|
||||
|
||||
# Handle complex paths.
|
||||
#
|
||||
# Okay, so this merits some explanation:
|
||||
#
|
||||
# Our build system aspires to put everything in build/ directories, this means
|
||||
# that we have to match the path of source files (foo.c) to output directories
|
||||
# (build/<arch>/foo.o). That's easy enough if all the source files are in the
|
||||
# same directory, but restricts applications and libraries to a flat file
|
||||
# structure.
|
||||
#
|
||||
# The current solution we employ is built on make's VPATH variable, which is a
|
||||
# list of directories to search for dependencies, e.g.
|
||||
#
|
||||
# VPATH = foo/ ../bar/
|
||||
# somerule: dependency.c
|
||||
#
|
||||
# Will find any of ./dependency.c, foo/dependency.c, or ../bar/dependency.c
|
||||
# We leverage this by flattening the list of SRCS to remove all path
|
||||
# information and adding all the paths from the SRCS to the VPATH, this means
|
||||
# we can write rules as-if all the SRCS were in a flat directory.
|
||||
#
|
||||
# The obvious pitfall here is what happens when multiple directories hold a
|
||||
# source file of the same name. However, both libnrf and mbed are set up to
|
||||
# use VPATH without running into that problem, which gives some pretty serious
|
||||
# hope that it won't be an issue in practice. The day is actually is a problem,
|
||||
# we can revisit this, but the only solution I can think of presently is
|
||||
# another layer of macros that generates the build rules for each path in SRCS,
|
||||
# which is a pretty hairy sounding proposition
|
||||
|
||||
$(LIBNAME)_SRCS_FLAT := $(notdir $($(LIBNAME)_SRCS))
|
||||
$(LIBNAME)_SRCS_DIRS := $(sort $(dir $($(LIBNAME)_SRCS))) # sort removes duplicates
|
||||
|
||||
# Only use vpath for certain types of files
|
||||
# But must be a global list
|
||||
VPATH_DIRS += $($(LIBNAME)_SRCS_DIRS)
|
||||
vpath %.s $(VPATH_DIRS)
|
||||
vpath %.c $(VPATH_DIRS)
|
||||
vpath %.cc $(VPATH_DIRS)
|
||||
vpath %.cpp $(VPATH_DIRS)
|
||||
vpath %.cxx $(VPATH_DIRS)
|
||||
|
||||
# Now, VPATH allows _make_ to find all the sources, but gcc needs to be told
|
||||
# how to find all of the headers. We do this by `-I`'ing any folder that had a
|
||||
# LIB_SRC and has any .h files in it. We also check the common convention of
|
||||
# headers in an include/ folder (both in and adjacent to src/) while we're at it
|
||||
define LIB_HEADER_INCLUDES
|
||||
ifneq ($$(wildcard $(1)/*.h),"")
|
||||
override CPPFLAGS += -I$(1)
|
||||
endif
|
||||
ifneq ($$(wildcard $(1)/include/*.h),"")
|
||||
override CPPFLAGS += -I$(1)/include
|
||||
endif
|
||||
ifneq ($$(wildcard $(1)/../include/*.h),"")
|
||||
override CPPFLAGS += -I$(1)/../include
|
||||
endif
|
||||
endef
|
||||
# uncomment to print generated rules
|
||||
# $(info $(foreach hdrdir,$($(LIBNAME)_SRCS_DIRS),$(call LIB_HEADER_INCLUDES,$(hdrdir))))
|
||||
# actually generate the rules
|
||||
$(foreach hdrdir,$($(LIBNAME)_SRCS_DIRS),$(eval $(call LIB_HEADER_INCLUDES,$(hdrdir))))
|
||||
|
||||
# Rules to generate libraries for a given Architecture
|
||||
# These will be used to create the different architecture versions of LibNRFSerialization
|
||||
# Argument $(1) is the Architecture (e.g. cortex-m0) to build for
|
||||
define LIB_RULES
|
||||
|
||||
$$($(LIBNAME)_BUILDDIR)/$(1):
|
||||
$$(TRACE_DIR)
|
||||
$$(Q)mkdir -p $$@
|
||||
|
||||
$$($(LIBNAME)_BUILDDIR)/$(1)/%.o: %.c | $$($(LIBNAME)_BUILDDIR)/$(1)
|
||||
$$(TRACE_CC)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CC_$(1)) $$(CFLAGS) $$(CFLAGS_$(1)) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -MF"$$(@:.o=.d)" -MG -MM -MP -MT"$$(@:.o=.d)@" -MT"$$@" "$$<"
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(CC_$(1)) $$(CFLAGS) $$(CFLAGS_$(1)) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -c -o $$@ $$<
|
||||
|
||||
$$($(LIBNAME)_BUILDDIR)/$(1)/%.o: %.S | $$($(LIBNAME)_BUILDDIR)/$(1)
|
||||
$$(TRACE_AS)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(AS) $$(ASFLAGS) $$(CPPFLAGS) $$(CPPFLAGS_$(1)) -c -o $$@ $$<
|
||||
|
||||
$(LIBNAME)_OBJS_$(1) += $$(patsubst %.s,$$($(LIBNAME)_BUILDDIR)/$(1)/%.o,$$(filter %.s, $$($(LIBNAME)_SRCS_FLAT)))
|
||||
$(LIBNAME)_OBJS_$(1) += $$(patsubst %.c,$$($(LIBNAME)_BUILDDIR)/$(1)/%.o,$$(filter %.c, $$($(LIBNAME)_SRCS_FLAT)))
|
||||
$(LIBNAME)_OBJS_$(1) += $$(patsubst %.cc,$$($(LIBNAME)_BUILDDIR)/$(1)/%.o,$$(filter %.cc, $$($(LIBNAME)_SRCS_FLAT)))
|
||||
$(LIBNAME)_OBJS_$(1) += $$(patsubst %.cpp,$$($(LIBNAME)_BUILDDIR)/$(1)/%.o,$$(filter %.cpp, $$($(LIBNAME)_SRCS_FLAT)))
|
||||
$(LIBNAME)_OBJS_$(1) += $$(patsubst %.cxx,$$($(LIBNAME)_BUILDDIR)/$(1)/%.o,$$(filter %.cxx, $$($(LIBNAME)_SRCS_FLAT)))
|
||||
|
||||
# Dependency rules for picking up header changes
|
||||
-include $$($(LIBNAME)_OBJS_$(1):.o=.d)
|
||||
|
||||
# Useful debugging
|
||||
# $$(info -----------------------------------------------------)
|
||||
# $$(info $(LIBNAME) $(1))
|
||||
# $$(info $(LIBNAME)_SRCS: $$($(LIBNAME)_SRCS))
|
||||
# $$(info $(LIBNAME)_SRCS_FLAT: $$($(LIBNAME)_SRCS_FLAT))
|
||||
# $$(info VPATH: $$(VPATH))
|
||||
# $$(info $(LIBNAME)_OBJS_$(1): $$($(LIBNAME)_OBJS_$(1)))
|
||||
# $$(info =====================================================)
|
||||
|
||||
$$($(LIBNAME)_BUILDDIR)/$(1)/$(LIBNAME).a: $$($(LIBNAME)_OBJS_$(1)) | $$($(LIBNAME)_BUILDDIR)/$(1)
|
||||
$$(TRACE_AR)
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(AR) rc $$@ $$^
|
||||
$$(Q)$$(TOOLCHAIN_$(1))$$(RANLIB) $$@
|
||||
|
||||
# If we're building this library as part of a bigger build, add ourselves to
|
||||
# the list of libraries
|
||||
#
|
||||
# Ahh.. make. By default, the RHS of variables aren't expanded at all until the
|
||||
# variable is _used_ ("lazy set", "="), this means that LIBNAME will have
|
||||
# changed by the time the variable is evaluated. We want immediate set (":="),
|
||||
# but we'd also like to append ("+=") to grow the list. Append chooses between
|
||||
# lazy or immediate set based on how the variable was previously set (yes,
|
||||
# that's right, the RHS evaluation depends on the LHS type - make was ahead of
|
||||
# it's time! :D), and defaults to lazy set if the variable is undefined at the
|
||||
# first append. So, we force it to immediate set. Lovely.
|
||||
ifndef LIBS_$(1)
|
||||
LIBS_$(1) :=
|
||||
endif
|
||||
LIBS_$(1) += $$($(LIBNAME)_BUILDDIR)/$(1)/$(LIBNAME).a
|
||||
|
||||
endef
|
||||
|
||||
# uncomment to print generated rules
|
||||
# $(info $(foreach platform,$(TOCK_ARCHS), $(call LIB_RULES,$(call ARCH_FN,$(platform)))))
|
||||
# actually generate the rules for each architecture
|
||||
$(foreach arch,$(TOCK_ARCHS),$(eval $(call LIB_RULES,$(arch))))
|
||||
|
||||
# add each architecture as a target
|
||||
.PHONY: all
|
||||
all: $(foreach arch, $(TOCK_ARCHS),$($(LIBNAME)_BUILDDIR)/$(arch)/$(LIBNAME).a)
|
||||
|
||||
|
||||
# Force LIBNAME to be expanded now
|
||||
define CLEAN_RULE
|
||||
.PHONY: clean
|
||||
clean::
|
||||
rm -Rf $(1)
|
||||
endef
|
||||
$(eval $(call CLEAN_RULE,$($(LIBNAME)_BUILDDIR)))
|
||||
|
||||
|
||||
# Rules for running the C linter
|
||||
$(LIBNAME)_FORMATTED_FILES := $(patsubst %.c,$($(LIBNAME)_BUILDDIR)/format/%.uncrustify,$(filter %.c, $($(LIBNAME)_SRCS_FLAT)))
|
||||
$(LIBNAME)_FORMATTED_FILES += $(patsubst %.cc,$($(LIBNAME)_BUILDDIR)/format/%.uncrustify,$(filter %.cc, $($(LIBNAME)_SRCS_FLAT)))
|
||||
$(LIBNAME)_FORMATTED_FILES += $(patsubst %.cpp,$($(LIBNAME)_BUILDDIR)/format/%.uncrustify,$(filter %.cpp, $($(LIBNAME)_SRCS_FLAT)))
|
||||
$(LIBNAME)_FORMATTED_FILES += $(patsubst %.cxx,$($(LIBNAME)_BUILDDIR)/format/%.uncrustify,$(filter %.cxx, $($(LIBNAME)_SRCS_FLAT)))
|
||||
|
||||
$($(LIBNAME)_BUILDDIR)/format:
|
||||
@mkdir -p $@
|
||||
|
||||
.PHONY: fmt format
|
||||
fmt format:: $($(LIBNAME)_FORMATTED_FILES)
|
||||
|
||||
$($(LIBNAME)_BUILDDIR)/format/%.uncrustify: %.c | _format_check_unstaged
|
||||
$(Q)$(UNCRUSTIFY) -f $< -o $@
|
||||
$(Q)cmp -s $< $@ || (if [ "$$CI" = "true" ]; then diff -y $< $@; rm $@; exit 1; else cp $@ $<; fi)
|
||||
$($(LIBNAME)_BUILDDIR)/format/%.uncrustify: %.cc | _format_check_unstaged
|
||||
$(Q)$(UNCRUSTIFY) -f $< -o $@
|
||||
$(Q)cmp -s $< $@ || (if [ "$$CI" = "true" ]; then diff -y $< $@; rm $@; exit 1; else cp $@ $<; fi)
|
||||
$($(LIBNAME)_BUILDDIR)/format/%.uncrustify: %.cpp | _format_check_unstaged
|
||||
$(Q)$(UNCRUSTIFY) -f $< -o $@
|
||||
$(Q)cmp -s $< $@ || (if [ "$$CI" = "true" ]; then diff -y $< $@; rm $@; exit 1; else cp $@ $<; fi)
|
||||
$($(LIBNAME)_BUILDDIR)/format/%.uncrustify: %.cxx | _format_check_unstaged
|
||||
$(Q)$(UNCRUSTIFY) -f $< -o $@
|
||||
$(Q)cmp -s $< $@ || (if [ "$$CI" = "true" ]; then diff -y $< $@; rm $@; exit 1; else cp $@ $<; fi)
|
@ -1,19 +0,0 @@
|
||||
# List of commit statuses that must pass on the merge commit before it is
|
||||
# pushed to master.
|
||||
status = [
|
||||
"ci-format (ubuntu-20.04)",
|
||||
"ci-build (ubuntu-20.04)",
|
||||
]
|
||||
|
||||
# List of PR labels that may not be attached to a PR when it is r+-ed.
|
||||
block_labels = [
|
||||
"blocked",
|
||||
]
|
||||
|
||||
# Number of seconds from when a merge commit is created to when its statuses
|
||||
# must pass. (Default = 3600).
|
||||
#timeout_sec = 7200
|
||||
|
||||
# If set to true, and if the PR branch is on the same repository that bors-ng
|
||||
# itself is on, the branch will be deleted.
|
||||
delete_merged_branches = true
|
@ -1,167 +0,0 @@
|
||||
Compilation Environment
|
||||
=======================
|
||||
|
||||
Tock aims to provide a build environment that is easy for application authors
|
||||
to integrate with. Check out the [examples](../examples) folder for
|
||||
sample applications. The Tock userland build system will automatically build
|
||||
with all of the correct flags and generate TABs for all supported Tock
|
||||
architectures.
|
||||
|
||||
To leverage the Tock build system, you must:
|
||||
|
||||
1. Set `TOCK_USERLAND_BASE_DIR` to the path to the Tock userland.
|
||||
2. `include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk`.
|
||||
|
||||
This `include` should be the _last_ line of the Makefile for most applications.
|
||||
|
||||
In addition, you must specify the sources for your application:
|
||||
|
||||
- `C_SRCS`: A list of C files to compile.
|
||||
- `CXX_SRCS`: A list of C++ files to compile.
|
||||
- `AS_SRCS`: A list of assembly files to compile.
|
||||
- `EXTERN_LIBS`: A list of directories for libraries [**compiled for Tock**](#compiling-libraries-for-tock).
|
||||
|
||||
## Customizing the build
|
||||
|
||||
### Flags
|
||||
|
||||
The build system respects all of the standard `CFLAGS` (C only), `CXXFLAGS`
|
||||
(C++ only), `CPPFLAGS` (C and C++), `ASFLAGS` (asm only).
|
||||
|
||||
By default, if you run something like `make CPPFLAGS=-Og`, make will use _only_
|
||||
the flags specified on the command line, but that means that Tock would lose all
|
||||
of its PIC-related flags. For that reason, Tock specifies all variables using
|
||||
make's [override directive](https://www.gnu.org/software/make/manual/html_node/Override-Directive.html).
|
||||
|
||||
If you wish to set additional flags in your application Makefiles, you must also
|
||||
use `override`, or they will be ignored. That is, in your Makefile you must write
|
||||
`override CPPFLAGS += -Og` rather than just `CPPFLAGS += -Og`.
|
||||
|
||||
If you are adding supplemental flags, you can put them anywhere. If you want to
|
||||
override Tock defaults, you'll need to place these _after_ the `include` directive
|
||||
in your Makefile.
|
||||
|
||||
### Application configuration
|
||||
|
||||
Several Tock-specific variables are also useful:
|
||||
|
||||
- `STACK_SIZE`: The minimum application stack size.
|
||||
- `APP_HEAP_SIZE`: The minimum heap size for your application.
|
||||
- `KERNEL_HEAP_SIZE`: The minimum grant size for your application.
|
||||
- `PACKAGE_NAME`: The name for your application. Defaults to current folder.
|
||||
|
||||
### Advanced
|
||||
|
||||
If you want to see a verbose build that prints all the commands as run, simply
|
||||
run `make V=1`.
|
||||
|
||||
The build system is broken across three files in the `libtock-c` repo:
|
||||
|
||||
- `Configuration.mk`: Sets most variables used.
|
||||
- `Helpers.mk`: Generic rules and functions to support the build.
|
||||
- `AppMakefile.mk`: Includes the above files and supplies build recipes.
|
||||
|
||||
Applications wishing to define their own build rules can include only the
|
||||
`Configuration.mk` file to ensure all of the flags needed for Tock applications
|
||||
are included.
|
||||
|
||||
## Compiling Libraries for Tock
|
||||
|
||||
Libraries used by Tock need all of the same position-independent build flags as
|
||||
the final application. As Tock builds for all supported architectures by
|
||||
default, libraries should include images for each supported Tock architecture.
|
||||
|
||||
### Let Tock do the work: TockLibrary.mk
|
||||
|
||||
As the Tock build requirements (PIC, multiple architectures) are fairly complex,
|
||||
Tock provides a Makefile that will ensure everything is set up correctly and
|
||||
generate build rules for you. An example Makefile for `libexample`:
|
||||
|
||||
> **libexample/Makefile**
|
||||
```make
|
||||
# Base definitions
|
||||
TOCK_USERLAND_BASE_DIR ?= ..
|
||||
LIBNAME := libexample
|
||||
|
||||
# Careful! Must be a path that resolves correctly **from where make is invoked**
|
||||
#
|
||||
# If you are only ever compiling a standalone library, then it's fine to simply set
|
||||
$(LIBNAME)_DIR := .
|
||||
#
|
||||
# If you will be asking applications to rebuild this library (see the development
|
||||
# section below), then you'll need to ensure that this directory is still correct
|
||||
# when invoked from inside the application folder.
|
||||
#
|
||||
# Tock accomplishes this for in-tree libraries by having all makefiles
|
||||
# conditionally set the TOCK_USERLAND_BASE_DIR variable, so that there
|
||||
# is a common relative path everywhere.
|
||||
$(LIBNAME)_DIR := $(TOCK_USERLAND_BASE_DIR)/$(LIBNAME)
|
||||
|
||||
# Grab all relevant source files. You can list them directly:
|
||||
$(LIBNAME)_SRCS := \
|
||||
$($LIBNAME)_DIR)\libexample.c \
|
||||
$($LIBNAME)_DIR)\libexample_helper.c \
|
||||
$($LIBNAME)_DIR)\subfolders_are_fine\otherfile.c
|
||||
|
||||
# Or let make find them automatically:
|
||||
$(LIBNAME)_SRCS := \
|
||||
$(wildcard $($(LIBNAME)_DIR)/*.c) \
|
||||
$(wildcard $($(LIBNAME)_DIR)/*.cxx) \ # or .cpp or .cc
|
||||
$(wildcard $($(LIBNAME)_DIR)/*.s)
|
||||
|
||||
include $(TOCK_USERLAND_BASE_DIR)/TockLibrary.mk
|
||||
```
|
||||
|
||||
> __Note! `:=` is NOT the same as `=` in make. You must use `:=`.__
|
||||
|
||||
### Developing (building) libraries concurrently with applications
|
||||
|
||||
When developing a library, often it's useful to have the library rebuild automatically
|
||||
as part of the application build. Assuming that your library is using `TockLibrary.mk`,
|
||||
you can simply include the library's Makefile in your application's Makefile:
|
||||
|
||||
```make
|
||||
include $(TOCK_USERLAND_BASE_DIR)/libexample/Makefile
|
||||
include ../../AppMakefile.mk
|
||||
```
|
||||
|
||||
**Example:** We don't have an in-tree example of a single app that rebuilds
|
||||
a dedicated library in the Tock repository, but libtock is effectively treated
|
||||
this way as its Makefile is
|
||||
[included by AppMakefile.mk](../AppMakefile.mk#L17).
|
||||
|
||||
### Pre-built libraries
|
||||
|
||||
You can also include pre-built libraries, but recall that Tock supports multiple
|
||||
architectures, which means you must supply a pre-built image for each.
|
||||
|
||||
Pre-built libraries must adhere to the following folder structure:
|
||||
|
||||
```
|
||||
For the library "example"
|
||||
|
||||
libexample/ <-- Folder name must match library name
|
||||
├── Makefile.app <-- Optional additional rules to include when building apps
|
||||
├── build
|
||||
│ ├── cortex-m0 <-- Architecture names match gcc's -mcpu= flag
|
||||
│ │ └── libexample.a <-- Library name must match folder name
|
||||
│ └── cortex-m4
|
||||
│ └── libexample.a <-- Library name must match folder name
|
||||
│
|
||||
└── root_header.h <-- The root directory will always be added to include path
|
||||
└── include <-- An include/ directory will be added too if it exists
|
||||
└── example.h
|
||||
```
|
||||
|
||||
To include a pre-built library, add the _path_ to the root folder to the
|
||||
variable `EXTERN_LIBS` in your application Makefile, e.g.
|
||||
`EXTERN_LIBS += ../../libexample`.
|
||||
|
||||
**Example:** In the Tock repository, lua53
|
||||
[ships a pre-built archive](../lua53/build/cortex-m4).
|
||||
|
||||
### Manually including libraries
|
||||
|
||||
To manually include an external library, add the library to each `LIBS_$(arch)`
|
||||
(i.e. `LIBS_cortex-m0`) variable. You can include header paths using the
|
||||
standard search mechanisms (i.e. `CPPFLAGS += -I<path>`).
|
@ -1,99 +0,0 @@
|
||||
Overview
|
||||
========
|
||||
|
||||
The bulk of Tock applications are written in C.
|
||||
|
||||
## Entry Point
|
||||
|
||||
Applications written in C that compile against libtock should define a `main`
|
||||
method with the following signature:
|
||||
|
||||
```c
|
||||
int main(void);
|
||||
```
|
||||
|
||||
Applications **should** return 0 from `main`. Returning non-zero is undefined and the
|
||||
behavior may change in future versions of `libtock`.
|
||||
Today, `main` is called from `_start` and includes an implicit `while()` loop:
|
||||
|
||||
```c
|
||||
void _start(void* text_start, void* mem_start, void* memory_len, void* app_heap_break) {
|
||||
main();
|
||||
while (1) {
|
||||
yield();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Applications should set up a series of event subscriptions in their `main`
|
||||
method and then return.
|
||||
|
||||
## Stack and Heap
|
||||
|
||||
Applications can specify their required stack and heap sizes by defining the
|
||||
make variables `STACK_SIZE` and `APP_HEAP_SIZE`, which default to 2K and 1K
|
||||
respectively as of this writing.
|
||||
|
||||
`libtock` will set the stack pointer during startup. To allow each application
|
||||
to set its own stack size, the linker script expects a symbol `STACK_SIZE` to
|
||||
be defined. The Tock build system will define this symbol during linking, using
|
||||
the make variable `STACK_SIZE`. A consequence of this technique is that
|
||||
changing the stack size requires that any source file also be touched so that
|
||||
the app will re-link.
|
||||
|
||||
## Libraries
|
||||
|
||||
Application code does not need to stand alone, libraries are available that can
|
||||
be utilized!
|
||||
|
||||
### Newlib
|
||||
Application code written in C has access to most of the [C standard
|
||||
library](https://en.wikipedia.org/wiki/C_standard_library) which is implemented
|
||||
by [Newlib](https://en.wikipedia.org/wiki/Newlib). Newlib is focused on
|
||||
providing capabilities for embedded systems. It provides interfaces such as
|
||||
`printf`, `malloc`, and `memcpy`. Most, but not all features of the standard
|
||||
library are available to applications. The built configuration of Newlib is
|
||||
specified in [build.sh](../userland/newlib/build.sh).
|
||||
|
||||
### libtock
|
||||
In order to interact with the Tock kernel, application code can use the
|
||||
`libtock` library. The majority of `libtock` are wrappers for interacting
|
||||
with Tock drivers through system calls. They provide the user a meaningful
|
||||
function name and arguments and then internally translate these into a
|
||||
`command`, `subscribe`, etc. Where it makes sense, the libraries also provide
|
||||
a synchronous interface to a driver using an internal callback and `yield_for`
|
||||
(example:
|
||||
[`tmp006_read_sync`](https://github.com/tock/tock/blob/master/userland/libtock/tmp006.c#L19))
|
||||
|
||||
`libtock` also provides the startup code for applications
|
||||
([`crt0.c`](../userland/libtock/crt0.c)),
|
||||
an implementation for the system calls
|
||||
([`tock.c`](../userland/libtock/tock.c)),
|
||||
and pin definitions for platforms.
|
||||
|
||||
### libc++
|
||||
Provides support for C++ apps. See `examples/cxx_hello`.
|
||||
|
||||
### libnrfserialization
|
||||
Provides a pre-compiled library for using the Nordic nRF serialization library
|
||||
for writing BLE apps.
|
||||
|
||||
### lua53
|
||||
Provides support for running a lua runtime as a Tock app. See
|
||||
`examples/lua-hello`.
|
||||
|
||||
## Style & Format
|
||||
|
||||
We try to keep a consistent style in mainline userland code. For C/C++, we use
|
||||
[uncrustify](https://github.com/uncrustify/uncrustify). High level:
|
||||
|
||||
- Two space character indents.
|
||||
- Braces on the same line.
|
||||
- Spaces around most operators.
|
||||
|
||||
For details, see the [configuration](../userland/tools/uncrustify).
|
||||
|
||||
Travis will automatically check formatting. You can format code locally using
|
||||
`make format`, or check the whole codebase with
|
||||
[format_all.sh](../userland/examples/format_all.sh). Formatting will overwrite
|
||||
files when it runs.
|
@ -1,11 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,6 +0,0 @@
|
||||
Accelerometer -> LEDs
|
||||
=====================
|
||||
|
||||
This app makes the accelerometer's readings visual by assigning each
|
||||
direction (X, Y, Z) to a color. Whichever direction's magnitude of acceleration
|
||||
is greatest gets its color lit.
|
@ -1,43 +0,0 @@
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <led.h>
|
||||
#include <ninedof.h>
|
||||
|
||||
int main(void) {
|
||||
printf("[App] Accelerometer -> LEDs\n");
|
||||
|
||||
while (1) {
|
||||
int x, y, z;
|
||||
ninedof_read_acceleration_sync(&x, &y, &z);
|
||||
|
||||
// abs()
|
||||
if (x < 0) x *= -1;
|
||||
if (y < 0) y *= -1;
|
||||
if (z < 0) z *= -1;
|
||||
|
||||
// Set LEDs based on acceleration.
|
||||
int largest = INT_MIN;
|
||||
if (x > largest) largest = x;
|
||||
if (y > largest) largest = y;
|
||||
if (z > largest) largest = z;
|
||||
|
||||
if (x == largest) {
|
||||
led_on(0);
|
||||
} else {
|
||||
led_off(0);
|
||||
}
|
||||
if (y == largest) {
|
||||
led_on(1);
|
||||
} else {
|
||||
led_off(1);
|
||||
}
|
||||
if (z == largest) {
|
||||
led_on(2);
|
||||
} else {
|
||||
led_off(2);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,6 +0,0 @@
|
||||
ADC App
|
||||
=========
|
||||
|
||||
The canonical "adc" app for an embedded platform. This app will
|
||||
read all the ADC channels of the board that are registered with the kernel.
|
||||
|
@ -1,29 +0,0 @@
|
||||
#include <adc.h>
|
||||
#include <stdio.h>
|
||||
#include <timer.h>
|
||||
|
||||
int main(void) {
|
||||
// Ask the kernel how many ADC channels are on this board.
|
||||
int num_adc;
|
||||
int err = adc_channel_count(&num_adc);
|
||||
if (err < 0) {
|
||||
printf("No ADC on this board.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
printf("ADC Channels: %d\n", num_adc);
|
||||
|
||||
while (true) {
|
||||
for (int channel = 0; channel < num_adc; channel++) {
|
||||
uint16_t value;
|
||||
err = adc_sample_sync(channel, &value);
|
||||
if (err == RETURNCODE_SUCCESS) {
|
||||
printf("Channel %d: %d\n", channel, value);
|
||||
} else {
|
||||
printf("Channel %d: error(%i) %s \n", channel, err, tock_strrcode(err));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
delay_ms(1000);
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# External libraries used
|
||||
EXTERN_LIBS += $(TOCK_USERLAND_BASE_DIR)/libnrfserialization
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,21 +0,0 @@
|
||||
UART over BLE
|
||||
=============
|
||||
|
||||
This app implements the peripheral side of the
|
||||
[Nordic UART service](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v11.0.0%2Fble_sdk_app_nus_eval.html&cp=4_0_4_4_2_2_18).
|
||||
To use:
|
||||
|
||||
1. Program this app on a hardware board (imix or Hail).
|
||||
2. Download the "nRF UART" app on a smartphone.
|
||||
3. Run `tockloader listen`.
|
||||
4. In the smartphone app, connect to the device named "tock-uart".
|
||||
5. Any messages you send will appear in the terminal!
|
||||
|
||||
It should be straightforward to re-purpose this app for easy communication
|
||||
between BLE devices.
|
||||
|
||||
Supported Boards
|
||||
----------------
|
||||
|
||||
- Hail
|
||||
- imix
|
@ -1,282 +0,0 @@
|
||||
/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
|
||||
*
|
||||
* The information contained herein is property of Nordic Semiconductor ASA.
|
||||
* Terms and conditions of usage are described in detail in NORDIC
|
||||
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
|
||||
*
|
||||
* Licensees are granted free, non-transferable use of the information. NO
|
||||
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
|
||||
* the file.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ble_nus.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include "sdk_common.h"
|
||||
|
||||
#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0002 /**< The UUID of the TX Characteristic. */
|
||||
#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0003 /**< The UUID of the RX Characteristic. */
|
||||
|
||||
#define BLE_NUS_MAX_RX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the RX Characteristic (in bytes). */
|
||||
#define BLE_NUS_MAX_TX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the TX Characteristic (in bytes). */
|
||||
|
||||
#define NUS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, \
|
||||
0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the S110 SoftDevice.
|
||||
*
|
||||
* @param[in] p_nus Nordic UART Service structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_connect(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
|
||||
{
|
||||
p_nus->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GAP_EVT_DISCONNECTED event from the S110 SoftDevice.
|
||||
*
|
||||
* @param[in] p_nus Nordic UART Service structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_disconnect(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
|
||||
{
|
||||
UNUSED_PARAMETER(p_ble_evt);
|
||||
p_nus->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the S110 SoftDevice.
|
||||
*
|
||||
* @param[in] p_nus Nordic UART Service structure.
|
||||
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
|
||||
*/
|
||||
static void on_write(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
|
||||
{
|
||||
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
|
||||
|
||||
if (
|
||||
(p_evt_write->handle == p_nus->rx_handles.cccd_handle)
|
||||
&&
|
||||
(p_evt_write->len == 2)) {
|
||||
if (ble_srv_is_notification_enabled(p_evt_write->data)) {
|
||||
p_nus->is_notification_enabled = true;
|
||||
} else {
|
||||
p_nus->is_notification_enabled = false;
|
||||
}
|
||||
} else if (
|
||||
(p_evt_write->handle == p_nus->tx_handles.value_handle)
|
||||
&&
|
||||
(p_nus->data_handler != NULL)) {
|
||||
p_nus->data_handler(p_nus, p_evt_write->data, p_evt_write->len);
|
||||
} else {
|
||||
// Do Nothing. This event is not relevant for this service.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for adding RX characteristic.
|
||||
*
|
||||
* @param[in] p_nus Nordic UART Service structure.
|
||||
* @param[in] p_nus_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
static uint32_t rx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
|
||||
{
|
||||
UNUSED_PARAMETER(p_nus_init);
|
||||
/**@snippet [Adding proprietary characteristic to S110 SoftDevice] */
|
||||
ble_gatts_char_md_t char_md;
|
||||
ble_gatts_attr_md_t cccd_md;
|
||||
ble_gatts_attr_t attr_char_value;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_gatts_attr_md_t attr_md;
|
||||
|
||||
memset(&cccd_md, 0, sizeof(cccd_md));
|
||||
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
|
||||
|
||||
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
|
||||
|
||||
memset(&char_md, 0, sizeof(char_md));
|
||||
|
||||
char_md.char_props.notify = 1;
|
||||
char_md.p_char_user_desc = NULL;
|
||||
char_md.p_char_pf = NULL;
|
||||
char_md.p_user_desc_md = NULL;
|
||||
char_md.p_cccd_md = &cccd_md;
|
||||
char_md.p_sccd_md = NULL;
|
||||
|
||||
ble_uuid.type = p_nus->uuid_type;
|
||||
ble_uuid.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
|
||||
|
||||
memset(&attr_md, 0, sizeof(attr_md));
|
||||
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
|
||||
|
||||
attr_md.vloc = BLE_GATTS_VLOC_STACK;
|
||||
attr_md.rd_auth = 0;
|
||||
attr_md.wr_auth = 0;
|
||||
attr_md.vlen = 1;
|
||||
|
||||
memset(&attr_char_value, 0, sizeof(attr_char_value));
|
||||
|
||||
attr_char_value.p_uuid = &ble_uuid;
|
||||
attr_char_value.p_attr_md = &attr_md;
|
||||
attr_char_value.init_len = sizeof(uint8_t);
|
||||
attr_char_value.init_offs = 0;
|
||||
attr_char_value.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
|
||||
|
||||
return sd_ble_gatts_characteristic_add(p_nus->service_handle,
|
||||
&char_md,
|
||||
&attr_char_value,
|
||||
&p_nus->rx_handles);
|
||||
/**@snippet [Adding proprietary characteristic to S110 SoftDevice] */
|
||||
}
|
||||
|
||||
|
||||
/**@brief Function for adding TX characteristic.
|
||||
*
|
||||
* @param[in] p_nus Nordic UART Service structure.
|
||||
* @param[in] p_nus_init Information needed to initialize the service.
|
||||
*
|
||||
* @return NRF_SUCCESS on success, otherwise an error code.
|
||||
*/
|
||||
static uint32_t tx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
|
||||
{
|
||||
UNUSED_PARAMETER(p_nus_init);
|
||||
ble_gatts_char_md_t char_md;
|
||||
ble_gatts_attr_t attr_char_value;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_gatts_attr_md_t attr_md;
|
||||
|
||||
memset(&char_md, 0, sizeof(char_md));
|
||||
|
||||
char_md.char_props.write = 1;
|
||||
char_md.char_props.write_wo_resp = 1;
|
||||
char_md.p_char_user_desc = NULL;
|
||||
char_md.p_char_pf = NULL;
|
||||
char_md.p_user_desc_md = NULL;
|
||||
char_md.p_cccd_md = NULL;
|
||||
char_md.p_sccd_md = NULL;
|
||||
|
||||
ble_uuid.type = p_nus->uuid_type;
|
||||
ble_uuid.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC;
|
||||
|
||||
memset(&attr_md, 0, sizeof(attr_md));
|
||||
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
|
||||
|
||||
attr_md.vloc = BLE_GATTS_VLOC_STACK;
|
||||
attr_md.rd_auth = 0;
|
||||
attr_md.wr_auth = 0;
|
||||
attr_md.vlen = 1;
|
||||
|
||||
memset(&attr_char_value, 0, sizeof(attr_char_value));
|
||||
|
||||
attr_char_value.p_uuid = &ble_uuid;
|
||||
attr_char_value.p_attr_md = &attr_md;
|
||||
attr_char_value.init_len = 1;
|
||||
attr_char_value.init_offs = 0;
|
||||
attr_char_value.max_len = BLE_NUS_MAX_TX_CHAR_LEN;
|
||||
|
||||
return sd_ble_gatts_characteristic_add(p_nus->service_handle,
|
||||
&char_md,
|
||||
&attr_char_value,
|
||||
&p_nus->tx_handles);
|
||||
}
|
||||
|
||||
|
||||
void ble_nus_on_ble_evt(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
|
||||
{
|
||||
if ((p_nus == NULL) || (p_ble_evt == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (p_ble_evt->header.evt_id) {
|
||||
case BLE_GAP_EVT_CONNECTED:
|
||||
on_connect(p_nus, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVT_DISCONNECTED:
|
||||
on_disconnect(p_nus, p_ble_evt);
|
||||
break;
|
||||
|
||||
case BLE_GATTS_EVT_WRITE:
|
||||
on_write(p_nus, p_ble_evt);
|
||||
break;
|
||||
|
||||
default:
|
||||
// No implementation needed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
|
||||
{
|
||||
uint32_t err_code;
|
||||
ble_uuid_t ble_uuid;
|
||||
ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_nus);
|
||||
VERIFY_PARAM_NOT_NULL(p_nus_init);
|
||||
|
||||
// Initialize the service structure.
|
||||
p_nus->conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
p_nus->data_handler = p_nus_init->data_handler;
|
||||
p_nus->is_notification_enabled = false;
|
||||
|
||||
/**@snippet [Adding proprietary Service to S110 SoftDevice] */
|
||||
// Add a custom base UUID.
|
||||
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
ble_uuid.type = p_nus->uuid_type;
|
||||
ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
|
||||
|
||||
// Add the service.
|
||||
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
|
||||
&ble_uuid,
|
||||
&p_nus->service_handle);
|
||||
/**@snippet [Adding proprietary Service to S110 SoftDevice] */
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
// Add the RX Characteristic.
|
||||
err_code = rx_char_add(p_nus, p_nus_init);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
// Add the TX Characteristic.
|
||||
err_code = tx_char_add(p_nus, p_nus_init);
|
||||
VERIFY_SUCCESS(err_code);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ble_nus_string_send(ble_nus_t * p_nus, uint8_t * p_string, uint16_t length)
|
||||
{
|
||||
ble_gatts_hvx_params_t hvx_params;
|
||||
|
||||
VERIFY_PARAM_NOT_NULL(p_nus);
|
||||
|
||||
if ((p_nus->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_nus->is_notification_enabled)) {
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (length > BLE_NUS_MAX_DATA_LEN) {
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
memset(&hvx_params, 0, sizeof(hvx_params));
|
||||
|
||||
hvx_params.handle = p_nus->rx_handles.value_handle;
|
||||
hvx_params.p_data = p_string;
|
||||
hvx_params.p_len = &length;
|
||||
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
|
||||
|
||||
return sd_ble_gatts_hvx(p_nus->conn_handle, &hvx_params);
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
|
||||
*
|
||||
* The information contained herein is property of Nordic Semiconductor ASA.
|
||||
* Terms and conditions of usage are described in detail in NORDIC
|
||||
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
|
||||
*
|
||||
* Licensees are granted free, non-transferable use of the information. NO
|
||||
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
|
||||
* the file.
|
||||
*
|
||||
*/
|
||||
|
||||
/**@file
|
||||
*
|
||||
* @defgroup ble_sdk_srv_nus Nordic UART Service
|
||||
* @{
|
||||
* @ingroup ble_sdk_srv
|
||||
* @brief Nordic UART Service implementation.
|
||||
*
|
||||
* @details The Nordic UART Service is a simple GATT-based service with TX and RX characteristics.
|
||||
* Data received from the peer is passed to the application, and the data received
|
||||
* from the application of this service is sent to the peer as Handle Value
|
||||
* Notifications. This module demonstrates how to implement a custom GATT-based
|
||||
* service and characteristics using the SoftDevice. The service
|
||||
* is used by the application to send and receive ASCII text strings to and from the
|
||||
* peer.
|
||||
*
|
||||
* @note The application must propagate SoftDevice events to the Nordic UART Service module
|
||||
* by calling the ble_nus_on_ble_evt() function from the ble_stack_handler callback.
|
||||
*/
|
||||
|
||||
#ifndef BLE_NUS_H__
|
||||
#define BLE_NUS_H__
|
||||
|
||||
#include "ble.h"
|
||||
#include "ble_srv_common.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define BLE_UUID_NUS_SERVICE 0x0001 /**< The UUID of the Nordic UART Service. */
|
||||
#define BLE_NUS_MAX_DATA_LEN (GATT_MTU_SIZE_DEFAULT - 3) /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
|
||||
|
||||
/* Forward declaration of the ble_nus_t type. */
|
||||
typedef struct ble_nus_s ble_nus_t;
|
||||
|
||||
/**@brief Nordic UART Service event handler type. */
|
||||
typedef void (*ble_nus_data_handler_t) (ble_nus_t * p_nus, uint8_t * p_data, uint16_t length);
|
||||
|
||||
/**@brief Nordic UART Service initialization structure.
|
||||
*
|
||||
* @details This structure contains the initialization information for the service. The application
|
||||
* must fill this structure and pass it to the service using the @ref ble_nus_init
|
||||
* function.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ble_nus_data_handler_t data_handler; /**< Event handler to be called for handling received data. */
|
||||
} ble_nus_init_t;
|
||||
|
||||
/**@brief Nordic UART Service structure.
|
||||
*
|
||||
* @details This structure contains status information related to the service.
|
||||
*/
|
||||
struct ble_nus_s
|
||||
{
|
||||
uint8_t uuid_type; /**< UUID type for Nordic UART Service Base UUID. */
|
||||
uint16_t service_handle; /**< Handle of Nordic UART Service (as provided by the SoftDevice). */
|
||||
ble_gatts_char_handles_t tx_handles; /**< Handles related to the TX characteristic (as provided by the SoftDevice). */
|
||||
ble_gatts_char_handles_t rx_handles; /**< Handles related to the RX characteristic (as provided by the SoftDevice). */
|
||||
uint16_t conn_handle; /**< Handle of the current connection (as provided by the SoftDevice). BLE_CONN_HANDLE_INVALID if not in a connection. */
|
||||
bool is_notification_enabled; /**< Variable to indicate if the peer has enabled notification of the RX characteristic.*/
|
||||
ble_nus_data_handler_t data_handler; /**< Event handler to be called for handling received data. */
|
||||
};
|
||||
|
||||
/**@brief Function for initializing the Nordic UART Service.
|
||||
*
|
||||
* @param[out] p_nus Nordic UART Service structure. This structure must be supplied
|
||||
* by the application. It is initialized by this function and will
|
||||
* later be used to identify this particular service instance.
|
||||
* @param[in] p_nus_init Information needed to initialize the service.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the service was successfully initialized. Otherwise, an error code is returned.
|
||||
* @retval NRF_ERROR_NULL If either of the pointers p_nus or p_nus_init is NULL.
|
||||
*/
|
||||
uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init);
|
||||
|
||||
/**@brief Function for handling the Nordic UART Service's BLE events.
|
||||
*
|
||||
* @details The Nordic UART Service expects the application to call this function each time an
|
||||
* event is received from the SoftDevice. This function processes the event if it
|
||||
* is relevant and calls the Nordic UART Service event handler of the
|
||||
* application if necessary.
|
||||
*
|
||||
* @param[in] p_nus Nordic UART Service structure.
|
||||
* @param[in] p_ble_evt Event received from the SoftDevice.
|
||||
*/
|
||||
void ble_nus_on_ble_evt(ble_nus_t * p_nus, ble_evt_t * p_ble_evt);
|
||||
|
||||
/**@brief Function for sending a string to the peer.
|
||||
*
|
||||
* @details This function sends the input string as an RX characteristic notification to the
|
||||
* peer.
|
||||
*
|
||||
* @param[in] p_nus Pointer to the Nordic UART Service structure.
|
||||
* @param[in] p_string String to be sent.
|
||||
* @param[in] length Length of the string.
|
||||
*
|
||||
* @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
|
||||
*/
|
||||
uint32_t ble_nus_string_send(ble_nus_t * p_nus, uint8_t * p_string, uint16_t length);
|
||||
|
||||
#endif // BLE_NUS_H__
|
||||
|
||||
/** @} */
|
@ -1,116 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ble_advdata.h>
|
||||
#include <nordic_common.h>
|
||||
#include <nrf_error.h>
|
||||
|
||||
#include <eddystone.h>
|
||||
#include <simple_adv.h>
|
||||
#include <simple_ble.h>
|
||||
|
||||
#include <nrf51_serialization.h>
|
||||
|
||||
#include <console.h>
|
||||
#include <tock.h>
|
||||
|
||||
#include "ble_nus.h"
|
||||
#include "nrf.h"
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* BLE
|
||||
******************************************************************************/
|
||||
|
||||
uint16_t conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
|
||||
// Intervals for advertising and connections
|
||||
simple_ble_config_t ble_config = {
|
||||
.platform_id = 0x00, // used as 4th octect in device BLE address
|
||||
.device_id = DEVICE_ID_DEFAULT,
|
||||
.adv_name = "tock-uart",
|
||||
.adv_interval = MSEC_TO_UNITS(500, UNIT_0_625_MS),
|
||||
.min_conn_interval = MSEC_TO_UNITS(1000, UNIT_1_25_MS),
|
||||
.max_conn_interval = MSEC_TO_UNITS(1250, UNIT_1_25_MS)
|
||||
};
|
||||
|
||||
// State for UART library.
|
||||
static ble_nus_t m_nus;
|
||||
|
||||
void ble_address_set (void) {
|
||||
// nop
|
||||
}
|
||||
|
||||
void ble_evt_user_handler (ble_evt_t* p_ble_evt) {
|
||||
ble_gap_conn_params_t conn_params;
|
||||
memset(&conn_params, 0, sizeof(conn_params));
|
||||
conn_params.min_conn_interval = ble_config.min_conn_interval;
|
||||
conn_params.max_conn_interval = ble_config.max_conn_interval;
|
||||
conn_params.slave_latency = SLAVE_LATENCY;
|
||||
conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
|
||||
|
||||
switch (p_ble_evt->header.evt_id) {
|
||||
case BLE_GAP_EVT_CONN_PARAM_UPDATE:
|
||||
// just update them right now
|
||||
sd_ble_gap_conn_param_update(0, &conn_params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This gets called with the serial data from the BLE central.
|
||||
static void nus_data_handler(ble_nus_t* p_nus, uint8_t* p_data, uint16_t length) {
|
||||
UNUSED_PARAMETER(p_nus);
|
||||
|
||||
// In this app, just print it to the console.
|
||||
putnstr((char*) p_data, length);
|
||||
}
|
||||
|
||||
void ble_evt_connected(ble_evt_t* p_ble_evt) {
|
||||
ble_common_evt_t *common = (ble_common_evt_t*) &p_ble_evt->evt;
|
||||
conn_handle = common->conn_handle;
|
||||
|
||||
ble_nus_on_ble_evt(&m_nus, p_ble_evt);
|
||||
}
|
||||
|
||||
void ble_evt_disconnected(ble_evt_t* p_ble_evt) {
|
||||
conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
|
||||
ble_nus_on_ble_evt(&m_nus, p_ble_evt);
|
||||
}
|
||||
|
||||
// On a write, need to forward that to NUS library.
|
||||
void ble_evt_write(ble_evt_t* p_ble_evt) {
|
||||
ble_nus_on_ble_evt(&m_nus, p_ble_evt);
|
||||
}
|
||||
|
||||
void ble_error (uint32_t error_code) {
|
||||
printf("BLE ERROR: Code = %d\n", (int)error_code);
|
||||
}
|
||||
|
||||
void services_init (void) {
|
||||
uint32_t err_code;
|
||||
ble_nus_init_t nus_init;
|
||||
memset(&nus_init, 0, sizeof(nus_init));
|
||||
nus_init.data_handler = nus_data_handler;
|
||||
err_code = ble_nus_init(&m_nus, &nus_init);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* MAIN
|
||||
******************************************************************************/
|
||||
|
||||
int main (void) {
|
||||
printf("[BLE] UART over BLE\n");
|
||||
|
||||
// Setup BLE
|
||||
conn_handle = simple_ble_init(&ble_config)->conn_handle;
|
||||
|
||||
// Advertise the UART service
|
||||
ble_uuid_t adv_uuid = {0x0001, BLE_UUID_TYPE_VENDOR_BEGIN};
|
||||
simple_adv_service(&adv_uuid);
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# External libraries used
|
||||
EXTERN_LIBS += $(TOCK_USERLAND_BASE_DIR)/simple-ble
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
||||
|
||||
# Include simple-ble's Makefile so it's rebuilt automatically
|
||||
include $(TOCK_USERLAND_BASE_DIR)/simple-ble/Makefile
|
@ -1,16 +0,0 @@
|
||||
Bluetooth Low Energy Advertisement App
|
||||
======================================
|
||||
|
||||
An example application that demonstrates how the Bluetooth Low Energy API can be
|
||||
used to advertise data periodically that runs forever.
|
||||
|
||||
The application does the following:
|
||||
* Configures advertisement name to used in the advertisement
|
||||
* Configures is the device shall be detected
|
||||
* Configures the advertisement interval
|
||||
* Configures list of UUIDs (generic service and temperature service)
|
||||
* Configures temperature to a hard-coded value for demonstration purposes.
|
||||
|
||||
Supported Boards
|
||||
-----------------
|
||||
- nRF52-DK
|
@ -1,74 +0,0 @@
|
||||
#include <ble.h>
|
||||
#include <gap.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <tock.h>
|
||||
|
||||
// Sizes in bytes
|
||||
#define DEVICE_NAME_SIZE 6
|
||||
#define UUIDS_SIZE 4
|
||||
#define MANUFACTURER_DATA_SIZE 2
|
||||
#define FAKE_TEMPERATURE_DATA_SIZE 2
|
||||
|
||||
/*******************************************************************************
|
||||
* MAIN
|
||||
******************************************************************************/
|
||||
|
||||
int main(void) {
|
||||
int err;
|
||||
printf("[Tutorial] BLE Advertising\n");
|
||||
|
||||
// declarations of variables to be used in this BLE example application
|
||||
uint16_t advertising_interval_ms = 300;
|
||||
uint8_t device_name[] = "TockOS";
|
||||
uint16_t uuids[] = {0x1800, 0x1809};
|
||||
uint8_t manufacturer_data[] = {0x13, 0x37};
|
||||
uint8_t fake_temperature_data[] = {0x00, 0x00};
|
||||
|
||||
static uint8_t adv_data_buf[ADV_DATA_MAX_SIZE];
|
||||
|
||||
// configure advertisement interval to 300ms
|
||||
// configure LE only and discoverable
|
||||
printf(" - Initializing BLE... %s\n", device_name);
|
||||
AdvData_t adv_data = gap_adv_data_new(adv_data_buf, sizeof(adv_data_buf));
|
||||
|
||||
gap_add_flags(&adv_data, LE_GENERAL_DISCOVERABLE | BREDR_NOT_SUPPORTED);
|
||||
|
||||
// configure device name as TockOS
|
||||
printf(" - Setting the device name... %s\n", device_name);
|
||||
err = gap_add_device_name(&adv_data, device_name, DEVICE_NAME_SIZE);
|
||||
if (err < RETURNCODE_SUCCESS)
|
||||
printf("ble_advertise_name, error: %s\r\n", tock_strrcode(err));
|
||||
|
||||
// configure list of UUIDs */
|
||||
printf(" - Setting the device UUID...\n");
|
||||
err = gap_add_service_uuid16(&adv_data, uuids, UUIDS_SIZE);
|
||||
if (err < RETURNCODE_SUCCESS)
|
||||
printf("ble_advertise_uuid16, error: %s\r\n", tock_strrcode(err));
|
||||
|
||||
// configure manufacturer data
|
||||
printf(" - Setting manufacturer data...\n");
|
||||
err = gap_add_manufacturer_specific_data(&adv_data, manufacturer_data,
|
||||
MANUFACTURER_DATA_SIZE);
|
||||
if (err < RETURNCODE_SUCCESS)
|
||||
printf("ble_advertise_manufacturer_specific_data, error: %s\r\n",
|
||||
tock_strrcode(err));
|
||||
|
||||
// configure service data
|
||||
printf(" - Setting service data...\n");
|
||||
err = gap_add_service_data(&adv_data, uuids[1], fake_temperature_data,
|
||||
FAKE_TEMPERATURE_DATA_SIZE);
|
||||
if (err < RETURNCODE_SUCCESS)
|
||||
printf("ble_advertise_service_data, error: %s\r\n", tock_strrcode(err));
|
||||
|
||||
// start advertising
|
||||
printf(" - Begin advertising! %s\n", device_name);
|
||||
err = ble_start_advertising(ADV_NONCONN_IND, adv_data.buf, adv_data.offset, advertising_interval_ms);
|
||||
if (err < RETURNCODE_SUCCESS)
|
||||
printf("ble_start_advertising, error: %s\r\n", tock_strrcode(err));
|
||||
|
||||
// configuration complete
|
||||
printf("Now advertising every %d ms as '%s'\n", advertising_interval_ms,
|
||||
device_name);
|
||||
return 0;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
CXX_SRCS := $(wildcard *.cpp)
|
||||
|
||||
APP_HEAP_SIZE = 4096
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,105 +0,0 @@
|
||||
#include "advertisement.h"
|
||||
|
||||
Advertisement::Advertisement() {
|
||||
std::memset(&header_, 0, HEADER_SIZE);
|
||||
std::memset(&address_, 0, ADDRESS_SIZE);
|
||||
std::memset(&data_, 0, DATA_MAX_SIZE);
|
||||
}
|
||||
|
||||
Advertisement::Advertisement(const unsigned char* buf, int len)
|
||||
{
|
||||
std::memcpy(&header_, &buf[HEADER_START], HEADER_SIZE);
|
||||
std::memcpy(&address_, &buf[ADDRESS_START], ADDRESS_SIZE);
|
||||
unsigned char data_len = len - HEADER_SIZE - ADDRESS_SIZE;
|
||||
if (data_len > DATA_MAX_SIZE) {
|
||||
data_len = DATA_MAX_SIZE;
|
||||
}
|
||||
std::memcpy(&data_, &buf[DATA_START], data_len);
|
||||
}
|
||||
|
||||
bool Advertisement::device_detected(const Advertisement& other) const
|
||||
{
|
||||
return std::memcmp(&address_, &other.address_, ADDRESS_SIZE) == 0;
|
||||
}
|
||||
|
||||
bool Advertisement::operator==(const Advertisement& other) const {
|
||||
return std::memcmp(this, &other, sizeof(Advertisement)) == 0;
|
||||
}
|
||||
|
||||
bool Advertisement::operator!=(const Advertisement& other) const {
|
||||
return std::memcmp(this, &other, sizeof(Advertisement)) != 0;
|
||||
}
|
||||
|
||||
void Advertisement::print() const
|
||||
{
|
||||
printf("PDU Type: %d %s\r\n", pduType(), pduTypeStr());
|
||||
printf("PDU TxAdd: %d\r\n", pduTxAddSet() ? 1 : 0);
|
||||
printf("PDU RxAdd: %d\r\n", pduRxAddSet() ? 1 : 0);
|
||||
printf("PDU Length: %d\r\n", pduLength());
|
||||
printf("Address: %02x %02x %02x %02x %02x %02x\r\n", address_[5],
|
||||
address_[4], address_[3], address_[2], address_[1], address_[0]);
|
||||
printf("Data: ");
|
||||
for (int i = 0; i < pduLength() - ADDRESS_SIZE; i++) {
|
||||
printf("%02x ", data_[i]);
|
||||
}
|
||||
printf("\r\n\r\n");
|
||||
}
|
||||
|
||||
unsigned char Advertisement::pduLength() const
|
||||
{
|
||||
return header_[1] & PDU_LEN_HEADER_MASK;
|
||||
}
|
||||
|
||||
unsigned char Advertisement::pduType() const
|
||||
{
|
||||
return header_[0] & PDU_TYPE_HEADER_MASK;
|
||||
}
|
||||
|
||||
bool Advertisement::pduTxAddSet() const
|
||||
{
|
||||
return header_[0] & PDU_TXADD_HEADER_MASK;
|
||||
}
|
||||
|
||||
bool Advertisement::pduRxAddSet() const
|
||||
{
|
||||
return header_[0] & PDU_RXADD_HEADER_MASK;
|
||||
}
|
||||
|
||||
const char* Advertisement::pduTypeStr() const
|
||||
{
|
||||
switch (pduType()) {
|
||||
case 0:
|
||||
return "ADV_IND";
|
||||
case 1:
|
||||
return "ADV_DIRECT_IND";
|
||||
case 2:
|
||||
return "NON_CONNECT_IND";
|
||||
case 3:
|
||||
return "SCAN_REQ";
|
||||
case 4:
|
||||
return "SCAN_RSP";
|
||||
case 5:
|
||||
return "CONNECT_REQ";
|
||||
case 6:
|
||||
return "ADV_SCAN_IND";
|
||||
default:
|
||||
return "INVALID ADVERTISEMENT TYPE";
|
||||
}
|
||||
}
|
||||
|
||||
bool Advertisement::checkScanResult(const unsigned char* buf, int len)
|
||||
{
|
||||
if (buf == nullptr) {
|
||||
printf("Malformed scan result: Buffer was null!\n");
|
||||
return false;
|
||||
}
|
||||
if (len < ADV_MIN_SIZE) {
|
||||
printf("Malformed scan result: Result too small!\n");
|
||||
return false;
|
||||
}
|
||||
if (len > ADV_MAX_SIZE) {
|
||||
printf("Malformed scan result: Result too large!\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
const unsigned char HEADER_START = 0;
|
||||
const unsigned char HEADER_SIZE = 2;
|
||||
const unsigned char ADDRESS_START = 2;
|
||||
const unsigned char ADDRESS_SIZE = 6;
|
||||
const unsigned char DATA_START = 8;
|
||||
const unsigned char DATA_MAX_SIZE = 31;
|
||||
|
||||
const unsigned char ADV_MIN_SIZE = 8;
|
||||
const unsigned char ADV_MAX_SIZE = HEADER_SIZE + ADDRESS_SIZE + DATA_MAX_SIZE;
|
||||
|
||||
const unsigned char PDU_LEN_HEADER_MASK = 0x3F;
|
||||
const unsigned char PDU_TYPE_HEADER_MASK = 0xF;
|
||||
const unsigned char PDU_TXADD_HEADER_MASK = 0x40;
|
||||
const unsigned char PDU_RXADD_HEADER_MASK = 0x80;
|
||||
|
||||
class Advertisement {
|
||||
private:
|
||||
unsigned char header_[HEADER_SIZE];
|
||||
unsigned char address_[ADDRESS_SIZE];
|
||||
unsigned char data_[DATA_MAX_SIZE];
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
Advertisement(const unsigned char* buf, int len);
|
||||
Advertisement();
|
||||
|
||||
// Methods
|
||||
bool device_detected(const Advertisement& other) const;
|
||||
bool operator==(const Advertisement& other) const;
|
||||
bool operator!=(const Advertisement& other) const;
|
||||
unsigned char pduType() const;
|
||||
const char* pduTypeStr() const;
|
||||
bool pduTxAddSet() const;
|
||||
bool pduRxAddSet() const;
|
||||
unsigned char pduLength() const;
|
||||
void print() const;
|
||||
static bool checkScanResult(const unsigned char* buf, int len);
|
||||
};
|
@ -1,49 +0,0 @@
|
||||
#include "advertisement_list.h"
|
||||
|
||||
AdvertisementList::AdvertisementList()
|
||||
: currentSize_(0)
|
||||
{
|
||||
list_.resize(MAX_SIZE);
|
||||
}
|
||||
|
||||
bool AdvertisementList::tryAdd(const Advertisement& advertisement)
|
||||
{
|
||||
if (currentSize_ < MAX_SIZE && !containsDevice(advertisement)) {
|
||||
list_.push_front(advertisement);
|
||||
currentSize_ += 1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AdvertisementList::containsDevice(const Advertisement& advertisement) const
|
||||
{
|
||||
for (auto it = list_.begin(); it != list_.end(); ++it) {
|
||||
if (it->device_detected(advertisement)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AdvertisementList::tryUpdateData(const Advertisement& advertisement)
|
||||
{
|
||||
for (auto it = list_.begin(); it != list_.end(); ++it) {
|
||||
if (*it != advertisement) {
|
||||
list_.remove(*it);
|
||||
list_.push_front(advertisement);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AdvertisementList::printList() const
|
||||
{
|
||||
printf("--------------------------LIST-------------------------\r\n\r\n");
|
||||
for (auto it = list_.begin(); it != list_.end(); ++it) {
|
||||
it->print();
|
||||
}
|
||||
printf("--------------------------END---------------------------\r\n\r\n");
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <forward_list>
|
||||
#include "advertisement.h"
|
||||
|
||||
// this is left outside the class because it doesn't work
|
||||
// code-generation bug?!
|
||||
const int MAX_SIZE = 10;
|
||||
|
||||
class AdvertisementList {
|
||||
private:
|
||||
int currentSize_;
|
||||
std::forward_list<Advertisement> list_;
|
||||
bool containsDevice(const Advertisement& advertisement) const;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
AdvertisementList();
|
||||
|
||||
// Methods
|
||||
bool tryAdd(const Advertisement& advertisement);
|
||||
bool tryUpdateData(const Advertisement& advertisement);
|
||||
void printList() const;
|
||||
};
|
@ -1,45 +0,0 @@
|
||||
#include "advertisement.h"
|
||||
#include "advertisement_list.h"
|
||||
#include <ble.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* BLE Demo Application
|
||||
* Passive scanner for Bluetooth Low Energy advertisements
|
||||
*/
|
||||
|
||||
const int BUF_SIZE = 39;
|
||||
static unsigned char scan[BUF_SIZE];
|
||||
AdvertisementList list;
|
||||
|
||||
static void callback(int result, int len, __attribute__((unused)) int unused2,
|
||||
__attribute__((unused)) void* ud)
|
||||
{
|
||||
if (result == RETURNCODE_SUCCESS) {
|
||||
if (Advertisement::checkScanResult(scan, len)) {
|
||||
Advertisement advertisement(scan, len);
|
||||
|
||||
if (list.tryAdd(advertisement)) {
|
||||
list.printList();
|
||||
}
|
||||
// FIXME: add this to get dynamic behavior i.e, update every time new advertisement is detected
|
||||
// but might it fill the print buffer, use at your own risk
|
||||
// else if (list.tryUpdateData(advertisement)) {
|
||||
// list.printList();
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("[Tutorial] BLE Passive Scanner\r\n");
|
||||
|
||||
// using the pre-configured advertisement interval
|
||||
int err = ble_start_passive_scan(scan, BUF_SIZE, callback);
|
||||
|
||||
if (err < RETURNCODE_SUCCESS) {
|
||||
printf("ble_start_passive_scan, error: %s\r\n", tock_strrcode(static_cast<returncode_t>(err)));
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,8 +0,0 @@
|
||||
Blink App
|
||||
=========
|
||||
|
||||
The canonical "blink" app for an embedded platform. This app will
|
||||
blink all of the LEDs that are registered with the kernel.
|
||||
|
||||
To learn more, please see the
|
||||
[Blink an LED](../../../doc/tutorials/01_running_blink.md) tutorial.
|
@ -1,24 +0,0 @@
|
||||
#include <led.h>
|
||||
#include <timer.h>
|
||||
|
||||
int main(void) {
|
||||
// Ask the kernel how many LEDs are on this board.
|
||||
int num_leds;
|
||||
int err = led_count(&num_leds);
|
||||
if (err < 0) return err;
|
||||
|
||||
// Blink the LEDs in a binary count pattern and scale
|
||||
// to the number of LEDs on the board.
|
||||
for (int count = 0; ; count++) {
|
||||
for (int i = 0; i < num_leds; i++) {
|
||||
if (count & (1 << i)) {
|
||||
led_on(i);
|
||||
} else {
|
||||
led_off(i);
|
||||
}
|
||||
}
|
||||
|
||||
// This delay uses an underlying timer in the kernel.
|
||||
delay_ms(250);
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
NUM_JOBS=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || 4)
|
||||
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
bold=$(tput bold)
|
||||
normal=$(tput sgr0)
|
||||
red=$(tput setaf 1)
|
||||
|
||||
# Try to build everything and collect failures at the end
|
||||
declare -a failures
|
||||
|
||||
function opt_rebuild {
|
||||
if [ "${CI-}" == "true" ]; then
|
||||
echo "${bold}Rebuilding Verbose: $1${normal}"
|
||||
make CFLAGS=-Werror V=1
|
||||
fi
|
||||
}
|
||||
|
||||
for mkfile in `find . -maxdepth 6 -name Makefile`; do
|
||||
dir=`dirname $mkfile`
|
||||
if [ $dir == "." ]; then continue; fi
|
||||
# Skip directories with leading _'s, useful for leaving test apps around
|
||||
if [[ $(basename $dir) == _* ]]; then continue; fi
|
||||
|
||||
pushd $dir > /dev/null
|
||||
echo ""
|
||||
echo "Building $dir"
|
||||
make CFLAGS=-Werror -j $NUM_JOBS || { echo "${bold} ⤤ Failure building $dir${normal}" ; opt_rebuild $dir; failures+=("$dir"); }
|
||||
popd > /dev/null
|
||||
done
|
||||
|
||||
# https://stackoverflow.com/questions/7577052/bash-empty-array-expansion-with-set-u
|
||||
if [[ ${failures[@]+"${failures[@]}"} ]]; then
|
||||
echo ""
|
||||
echo "${bold}${red}Build Failures:${normal}"
|
||||
for fail in ${failures[@]}; do
|
||||
echo $fail
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "${bold}All Built.${normal}"
|
@ -1,11 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,6 +0,0 @@
|
||||
# Buttons
|
||||
|
||||
This application ties each button on a board to an LED. When the user presses a
|
||||
button, the associated LED is toggled. The program works with any number of
|
||||
buttons and LEDs on a board.
|
||||
|
@ -1,38 +0,0 @@
|
||||
// \file
|
||||
// This program waits for button presses on each of the buttons attached
|
||||
// to a board and toggles the LED with the same index. For example, if the first
|
||||
// button is pressed, the first LED is toggled. If the third button is pressed,
|
||||
// the third LED is toggled.
|
||||
|
||||
#include <button.h>
|
||||
#include <led.h>
|
||||
|
||||
// Callback for button presses.
|
||||
// btn_num: The index of the button associated with the callback
|
||||
// val: 1 if pressed, 0 if depressed
|
||||
static void button_callback(int btn_num,
|
||||
int val,
|
||||
__attribute__ ((unused)) int arg2,
|
||||
__attribute__ ((unused)) void *ud) {
|
||||
if (val == 1) {
|
||||
led_toggle(btn_num);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int err;
|
||||
|
||||
err = button_subscribe(button_callback, NULL);
|
||||
if (err < 0) return err;
|
||||
|
||||
// Enable interrupts on each button.
|
||||
int count;
|
||||
err = button_count(&count);
|
||||
if (err < 0) return err;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
button_enable_interrupt(i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,21 +0,0 @@
|
||||
/* vim: set sw=2 expandtab tw=80: */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <console.h>
|
||||
|
||||
char hello[] = "Hello World!\r\n";
|
||||
|
||||
static void nop(
|
||||
int a __attribute__((unused)),
|
||||
int b __attribute__((unused)),
|
||||
int c __attribute__((unused)),
|
||||
void* d __attribute__((unused))) {}
|
||||
|
||||
int main(void) {
|
||||
putnstr_async(hello, strlen(hello), nop, NULL);
|
||||
return 0;
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
bold=$(tput bold)
|
||||
normal=$(tput sgr0)
|
||||
|
||||
set -e
|
||||
|
||||
for mkfile in `find . -maxdepth 4 -name Makefile`; do
|
||||
dir=`dirname $mkfile`
|
||||
if [ $dir == "." ]; then continue; fi
|
||||
pushd $dir > /dev/null
|
||||
make clean > /dev/null || echo "${bold} ⤤ $dir${normal}"
|
||||
popd > /dev/null
|
||||
done
|
||||
|
||||
echo "${bold}All Clean.${normal}"
|
@ -1,15 +0,0 @@
|
||||
SenSys 2018 Tutorial
|
||||
====================
|
||||
|
||||
In November 2018 we hosted [a tutorial at SenSys](https://www.tockos.org/events/sensys2018),
|
||||
a preeminent conference for networking, sensors, and systems.
|
||||
|
||||
The goal of this tutorial was to explore how multi-tenancy can cause problems
|
||||
(one buggy app draining system [energy] resources) and also provide solutions
|
||||
(via management that allow runtime monitoring and correction).
|
||||
The tutorial begins with a general overview of Tock and its programming
|
||||
environment, then considers application development and management, and finally
|
||||
digs into the 802.15.4 and UDP/IP capabilities in Tock.
|
||||
|
||||
**If you are interested in doing this tutorial yourself, please
|
||||
`git checkout courses/2018-sensys` in both this repository and the Tock kernel.**
|
@ -1,16 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../../../../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# Change name of generated app
|
||||
PACKAGE_NAME = app1
|
||||
|
||||
APP_HEAP_SIZE := 2048
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,16 +0,0 @@
|
||||
UDP Button Press App
|
||||
====================
|
||||
|
||||
Your client needs to keep track of sporadic events and record when those
|
||||
events occur by pressing the 'user' button on the Imix.
|
||||
|
||||
This app is for platforms with an 802.15.4 radio. It broadcasts button presses
|
||||
over the network, so they can be recorded at a central server.
|
||||
Currently, this app sends UDP packets using 6lowpan to a single neighbor with
|
||||
an IP address known ahead of time.
|
||||
|
||||
## Running
|
||||
|
||||
To run this app, simply place the IP address of the destination node in the `dst_addr` struct.
|
||||
Notably, until Tock has neighbor discovery implemented, you also have to configure
|
||||
the destination MAC address in the kernel (in `boards/imix/src/main.rs`).
|
@ -1,92 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <button.h>
|
||||
|
||||
#include <ieee802154.h>
|
||||
#include <udp.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static unsigned char BUF_BIND_CFG[2 * sizeof(sock_addr_t)];
|
||||
static int button_press;
|
||||
|
||||
void print_ipv6(ipv6_addr_t *);
|
||||
|
||||
void print_ipv6(ipv6_addr_t *ipv6_addr) {
|
||||
for (int j = 0; j < 14; j += 2) {
|
||||
printf("%02x%02x:", ipv6_addr->addr[j], ipv6_addr->addr[j + 1]);
|
||||
}
|
||||
printf("%02x%02x", ipv6_addr->addr[14], ipv6_addr->addr[15]);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
char packet[64];
|
||||
button_press = 0;
|
||||
|
||||
ieee802154_set_pan(0xABCD);
|
||||
ieee802154_config_commit();
|
||||
ieee802154_up();
|
||||
|
||||
ipv6_addr_t ifaces[10];
|
||||
udp_list_ifaces(ifaces, 10);
|
||||
|
||||
sock_handle_t handle;
|
||||
sock_addr_t addr = {
|
||||
ifaces[2],
|
||||
15123
|
||||
};
|
||||
|
||||
printf("Opening socket on ");
|
||||
print_ipv6(&ifaces[2]);
|
||||
printf(" : %d\n", addr.port);
|
||||
int bind_return = udp_bind(&handle, &addr, BUF_BIND_CFG);
|
||||
if (bind_return < 0) {
|
||||
printf("Bind failed. Error code: %d\n", bind_return);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the below address to IP address of receiver
|
||||
ipv6_addr_t dest_addr = {
|
||||
{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0, 0xdf, 0xf0}
|
||||
};
|
||||
sock_addr_t destination = {
|
||||
dest_addr,
|
||||
16123
|
||||
};
|
||||
|
||||
int count = 0;
|
||||
while (1) {
|
||||
// wait for gpio pin to be pressed
|
||||
while (button_press == 0) {
|
||||
button_read(0, &button_press);
|
||||
}
|
||||
count++;
|
||||
|
||||
int len = snprintf(packet, sizeof(packet), "{\"buttons\": %d}", count);
|
||||
if (DEBUG) {
|
||||
printf("Button press detected\n");
|
||||
|
||||
printf("Sending packet (length %d) --> ", len);
|
||||
print_ipv6(&(destination.addr));
|
||||
printf(" : %d\n", destination.port);
|
||||
}
|
||||
ssize_t result = udp_send_to(packet, len, &destination);
|
||||
|
||||
switch (result) {
|
||||
case RETURNCODE_SUCCESS:
|
||||
if (DEBUG) {
|
||||
printf("Packet sent.\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("Error sending packet %d\n", result);
|
||||
}
|
||||
|
||||
// Debounce
|
||||
while (button_press != 0) {
|
||||
button_read(0, &button_press);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../../../../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
APP_HEAP_SIZE := 2048
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,31 +0,0 @@
|
||||
UDP Sensor App
|
||||
==============
|
||||
|
||||
Your customer needs to periodically measure the environment around their board.
|
||||
|
||||
This app is for platforms with hardware RNG support, environmental sensors, and
|
||||
an 802.15.4 radio. The app will broadcast periodic sensor readings over the
|
||||
network. Currently, it sends UDP packets using 6lowpan to a single neighbor
|
||||
with an IP address known ahead of time. The contents of the payload (which are
|
||||
serialized to JSON) include:
|
||||
|
||||
1. A random number, generated by the application accessing the underlying hardware RNG.
|
||||
|
||||
2. Three sensor readings (temperature, relative humidity, and light).
|
||||
|
||||
## Running
|
||||
|
||||
To run this app, simply place the IP address of the destination node in the `dst_addr` struct.
|
||||
Notably, until Tock has neighbor discovery implemented, you also have to configure
|
||||
the destination MAC address in the kernel (in `boards/imix/src/main.rs`).
|
||||
|
||||
### UDP Layer Reception Test
|
||||
|
||||
The best way to test this app is by using the UDP reception app on another Imix.
|
||||
Program the kernel on two imixs. On one imix load this app to send packets. On
|
||||
the other imix load the `sensys_udp_rx` app found in
|
||||
`userland/examples/sensys_udp_rx`. You will want to set the
|
||||
`PRINT_STRING` macro to `1` for maximum visibility.
|
||||
|
||||
If everything is working, you will see packets printed on the console.
|
||||
These lines contain the payload of the received UDP packet.
|
@ -1,111 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ambient_light.h>
|
||||
#include <button.h>
|
||||
#include <humidity.h>
|
||||
#include <rng.h>
|
||||
#include <temperature.h>
|
||||
#include <timer.h>
|
||||
|
||||
#include <ieee802154.h>
|
||||
#include <udp.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static unsigned char BUF_BIND_CFG[2 * sizeof(sock_addr_t)];
|
||||
|
||||
void print_ipv6(ipv6_addr_t *);
|
||||
int serialize_to_json(char* packet, int len, uint32_t rand, int temp, int humi, int lux);
|
||||
|
||||
int main(void) {
|
||||
|
||||
printf("[UDP] Starting UDP App.\n");
|
||||
|
||||
static unsigned int humi = 0;
|
||||
static int temp = 0;
|
||||
static int lux = 0;
|
||||
static char packet[70];
|
||||
|
||||
ieee802154_set_pan(0xABCD);
|
||||
ieee802154_config_commit();
|
||||
ieee802154_up();
|
||||
|
||||
ipv6_addr_t ifaces[10];
|
||||
udp_list_ifaces(ifaces, 10);
|
||||
|
||||
sock_handle_t handle;
|
||||
sock_addr_t addr = {
|
||||
ifaces[2],
|
||||
11111
|
||||
};
|
||||
|
||||
printf("Opening socket on ");
|
||||
print_ipv6(&ifaces[2]);
|
||||
printf(" : %d\n", addr.port);
|
||||
int bind_return = udp_bind(&handle, &addr, BUF_BIND_CFG);
|
||||
|
||||
if (bind_return < 0) {
|
||||
printf("Bind failed. Error code: %d\n", bind_return);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the below address to be the IP address of your receiver
|
||||
ipv6_addr_t dest_addr = {
|
||||
{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0, 0xdf, 0xf0}
|
||||
};
|
||||
sock_addr_t destination = {
|
||||
dest_addr,
|
||||
16123
|
||||
};
|
||||
|
||||
while (1) {
|
||||
temperature_read_sync(&temp);
|
||||
humidity_read_sync(&humi);
|
||||
ambient_light_read_intensity_sync(&lux);
|
||||
|
||||
// get randomness
|
||||
uint32_t rand = 0;
|
||||
int num_received = 0;
|
||||
int err = rng_sync((uint8_t*)&rand, 4, 4, &num_received);
|
||||
if (err < 0) {
|
||||
printf("Error obtaining random number: %d\n", err);
|
||||
} else if (num_received < 4) {
|
||||
printf("Only obtained %d bytes of randomness\n", num_received);
|
||||
}
|
||||
|
||||
int len = serialize_to_json(packet, sizeof(packet), rand, temp, humi, lux);
|
||||
if (DEBUG) {
|
||||
printf("Sending packet (length %d) --> ", len);
|
||||
print_ipv6(&(destination.addr));
|
||||
printf(" : %d\n", destination.port);
|
||||
}
|
||||
ssize_t result = udp_send_to(packet, len, &destination);
|
||||
|
||||
switch (result) {
|
||||
case RETURNCODE_SUCCESS:
|
||||
if (DEBUG) {
|
||||
printf("Packet sent.\n\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("Error sending packet %d\n\n", result);
|
||||
}
|
||||
|
||||
delay_ms(5000);
|
||||
}
|
||||
}
|
||||
|
||||
void print_ipv6(ipv6_addr_t *ipv6_addr) {
|
||||
for (int j = 0; j < 14; j += 2) {
|
||||
printf("%02x%02x:", ipv6_addr->addr[j], ipv6_addr->addr[j + 1]);
|
||||
}
|
||||
printf("%02x%02x", ipv6_addr->addr[14], ipv6_addr->addr[15]);
|
||||
}
|
||||
|
||||
int serialize_to_json(char* buf, int buflen, uint32_t rand, int temp, int humi, int lux) {
|
||||
return snprintf(buf, buflen, "{\"rand\": %lu, \"temp\": %d, \"humi\": %d, \"lux\": %d}",
|
||||
rand, temp, humi, lux);
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../../../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,4 +0,0 @@
|
||||
Test to receive UDP packets. Listens on the MAC address specified by the serial
|
||||
number of the sam4l of this device, and the link-local IPv6 address generated
|
||||
from the EUI-64 corresponding to this MAC address.
|
||||
|
@ -1,106 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "led.h"
|
||||
#include "timer.h"
|
||||
#include "tock.h"
|
||||
|
||||
#include <ieee802154.h>
|
||||
#include <udp.h>
|
||||
|
||||
// Sample UDP packet reception app.
|
||||
// Receives packets at the specified address and port indefinitely
|
||||
|
||||
#define MAX_RX_PACKET_LEN 200
|
||||
|
||||
char packet_rx[MAX_RX_PACKET_LEN];
|
||||
static unsigned char BUF_BIND_CFG[2 * sizeof(sock_addr_t)];
|
||||
sock_handle_t* handle;
|
||||
|
||||
void print_ipv6(ipv6_addr_t *);
|
||||
|
||||
void print_ipv6(ipv6_addr_t *ipv6_addr) {
|
||||
for (int j = 0; j < 14; j += 2) {
|
||||
printf("%02x%02x:", ipv6_addr->addr[j], ipv6_addr->addr[j + 1]);
|
||||
}
|
||||
printf("%02x%02x", ipv6_addr->addr[14], ipv6_addr->addr[15]);
|
||||
}
|
||||
|
||||
static void callback(int payload_len,
|
||||
__attribute__ ((unused)) int arg2,
|
||||
__attribute__ ((unused)) int arg3,
|
||||
__attribute__ ((unused)) void* ud) {
|
||||
led_toggle(0);
|
||||
|
||||
#define PRINT_STRING 0
|
||||
#if PRINT_STRING
|
||||
printf("[UDP_RCV]: Rcvd UDP Packet from: ");
|
||||
print_ipv6((ipv6_addr_t*)&BUF_BIND_CFG);
|
||||
printf(" : %d\n", (uint16_t)(BUF_BIND_CFG[16]) + ((uint16_t)(BUF_BIND_CFG[17]) << 8));
|
||||
printf("Packet Payload: %.*s\n", payload_len, packet_rx);
|
||||
#endif // PRINT_STRING
|
||||
// Serialize packet to UART. Format:
|
||||
//
|
||||
// - 2 magic: 0x8081
|
||||
// - 16 byte ipv6 address
|
||||
// - 2 byte payload length in network order
|
||||
// - payload
|
||||
ipv6_addr_t sender_addr = *((ipv6_addr_t*)BUF_BIND_CFG);
|
||||
uint8_t header[2 + 1 + 16];
|
||||
header[0] = 0x80;
|
||||
header[1] = 0x81;
|
||||
header[2] = (char)(payload_len & 0xff);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
header[3 + i] = 1 + sender_addr.addr[i];
|
||||
}
|
||||
write(0, header, sizeof(header));
|
||||
write(0, packet_rx, payload_len);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
ipv6_addr_t ifaces[10];
|
||||
udp_list_ifaces(ifaces, 10);
|
||||
|
||||
sock_addr_t addr = {
|
||||
ifaces[2],
|
||||
16123 // arbitrary port choice
|
||||
};
|
||||
|
||||
printf("Opening socket on ");
|
||||
print_ipv6(&ifaces[2]);
|
||||
printf(" : %d\n", addr.port);
|
||||
sock_handle_t h;
|
||||
handle = &h;
|
||||
udp_bind(handle, &addr, BUF_BIND_CFG);
|
||||
|
||||
// ieee802154_set_address(0x802); //Mac addr is configured in the kernel from serial num
|
||||
ieee802154_set_pan(0xABCD);
|
||||
ieee802154_config_commit();
|
||||
ieee802154_up();
|
||||
|
||||
memset(packet_rx, 0, MAX_RX_PACKET_LEN);
|
||||
ssize_t result = udp_recv(callback, packet_rx, MAX_RX_PACKET_LEN);
|
||||
|
||||
switch (result) {
|
||||
case RETURNCODE_SUCCESS:
|
||||
printf("Succesfully bound to socket, listening for UDP packets\n\n");
|
||||
break;
|
||||
case RETURNCODE_EINVAL:
|
||||
printf("The address requested is not a local interface\n");
|
||||
break;
|
||||
case RETURNCODE_EBUSY:
|
||||
printf("Another userland app has already bound to this addr/port\n");
|
||||
break;
|
||||
case RETURNCODE_ERESERVE:
|
||||
printf("Receive Failure. Must bind to a port before calling receive\n");
|
||||
break;
|
||||
default:
|
||||
printf("Failed to bind to socket %d\n", result);
|
||||
break;
|
||||
}
|
||||
/* Tock keeps the app alive waiting for callbacks after
|
||||
* returning from main, so no need to busy wait */
|
||||
}
|
@ -1 +0,0 @@
|
||||
node_modules/
|
File diff suppressed because it is too large
Load Diff
@ -1,21 +0,0 @@
|
||||
{
|
||||
"author": "Tock Developers",
|
||||
"name": "sensys_rx",
|
||||
"description": "",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"homepage": "http://github.com/tock/libtock-c",
|
||||
"keywords": [],
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node stream.js"
|
||||
},
|
||||
"main": "./stream.js",
|
||||
"dependencies": {
|
||||
"serialport": "7.0.*",
|
||||
"express": "4.17.*",
|
||||
"serve-static": "1.13.*"
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Common metas -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>
|
||||
Important Client(tm) Imix Dashboard
|
||||
</title>
|
||||
<!-- SEO metas -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
table {
|
||||
width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
table td, table th {
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
function update() {
|
||||
fetch("/data").then((data) => data.json()).then((body) => {
|
||||
let content = document.getElementById("content");
|
||||
while (content.firstChild) {
|
||||
content.removeChild(content.firstChild);
|
||||
}
|
||||
let header = content.appendChild(document.createElement("tr"));
|
||||
header.appendChild(document.createElement("th")).innerText = "Node";
|
||||
header.appendChild(document.createElement("th")).innerText = "Last Updated";
|
||||
for (let node in body) {
|
||||
let nodeElem = document.createElement("tr");
|
||||
let nodeName = nodeElem.appendChild(document.createElement("td")).appendChild(document.createElement("a"));
|
||||
nodeName.innerText = node;
|
||||
nodeName.href = "/node.html?" + node;
|
||||
nodeElem.appendChild(document.createElement("td")).innerText = new Date(body[node].timestamp).toLocaleString();
|
||||
content.appendChild(nodeElem);
|
||||
}
|
||||
});
|
||||
}
|
||||
update();
|
||||
window.setInterval(update, 5000);
|
||||
</script>
|
||||
<h1>Imix Dashboard</h1>
|
||||
<table id="content">
|
||||
|
||||
</table>
|
||||
</body>
|
@ -1,63 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Common metas -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>
|
||||
Important Client(tm) Imix Dashboard
|
||||
</title>
|
||||
<!-- SEO metas -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
table {
|
||||
width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
table td, table th {
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
const node = location.search.slice(1);
|
||||
|
||||
function update() {
|
||||
fetch("/data/" + node).then((data) => data.json()).then((body) => {
|
||||
let content = document.getElementById("content");
|
||||
while (content.firstChild) {
|
||||
content.removeChild(content.firstChild);
|
||||
}
|
||||
let header = content.appendChild(document.createElement("tr"));
|
||||
header.appendChild(document.createElement("th")).innerText = "Node";
|
||||
header.appendChild(document.createElement("th")).innerText = node;
|
||||
|
||||
let timestamp = content.appendChild(document.createElement("tr"));
|
||||
timestamp.appendChild(document.createElement("td")).innerText = "Last updated";
|
||||
timestamp.appendChild(document.createElement("td")).innerText = new Date(body.timestamp).toLocaleString();
|
||||
for (let reading in body.payload) {
|
||||
let row = document.createElement("tr");
|
||||
row.appendChild(document.createElement("td")).innerText = reading;
|
||||
row.appendChild(document.createElement("td")).innerText = body.payload[reading];
|
||||
content.appendChild(row);
|
||||
}
|
||||
});
|
||||
}
|
||||
update();
|
||||
window.setInterval(update, 5000);
|
||||
</script>
|
||||
<h1>Single Node Dashboard</h1>
|
||||
<table id="content">
|
||||
|
||||
</table>
|
||||
</body>
|
@ -1,111 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const stream = require('stream');
|
||||
const SerialPort = require('serialport');
|
||||
|
||||
function createMyStream(){
|
||||
const magic = Buffer.from([0x80, 0x81]);
|
||||
const header_len = magic.length + 16 + 2;
|
||||
let address = null;
|
||||
let bytes_left = 0;
|
||||
let payload_len = 0;
|
||||
let buffer = Buffer.from('');
|
||||
|
||||
return new stream.Writable({
|
||||
writableObjectMode: true,
|
||||
write: function(chunk, encoding, callback) {
|
||||
console.log(chunk.toString('hex'));
|
||||
buffer = Buffer.concat([buffer, chunk]);
|
||||
while (true) {
|
||||
if (bytes_left == 0) {
|
||||
let m = buffer.indexOf(magic);
|
||||
if (m >= 0 && buffer.length - m >= header_len) {
|
||||
buffer = buffer.slice(m + magic.length);
|
||||
payload_len = buffer[0];
|
||||
buffer = buffer.slice(1);
|
||||
address = buffer.slice(0, 16);
|
||||
let new_addr = [];
|
||||
for (const i of address.values()) {
|
||||
new_addr.push(i - 1);
|
||||
}
|
||||
address = Buffer.from(new_addr);
|
||||
buffer = buffer.slice(16);
|
||||
if (payload_len == buffer.length) {
|
||||
bytes_left = -1;
|
||||
} else {
|
||||
bytes_left = payload_len - buffer.length;
|
||||
}
|
||||
} else {
|
||||
buffer = buffer.slice(-(magic.length - 1));
|
||||
break;
|
||||
}
|
||||
} else if (buffer.length >= payload_len) {
|
||||
let payload = buffer.slice(0, payload_len);
|
||||
buffer = buffer.slice(payload_len);
|
||||
bytes_left = 0;
|
||||
let result = {
|
||||
address: address,
|
||||
payload: JSON.parse(payload)
|
||||
};
|
||||
this.emit("packet", result);
|
||||
} else {
|
||||
console.log("want more", bytes_left, payload_len);
|
||||
bytes_left = payload_len - buffer.length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (process.argv.length < 3) {
|
||||
console.log("Usage: node stream.js [serial-device], e.g. node stream.js /dev/ttyUSB0");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const port = process.argv[2];
|
||||
const serialport = new SerialPort(port, {baudRate: 115200});
|
||||
|
||||
serialport.on("open", () => {
|
||||
serialport.set({rts: false, dtr: false});
|
||||
});
|
||||
|
||||
const mystream = createMyStream();
|
||||
serialport.pipe(mystream);
|
||||
|
||||
let recent_data = {
|
||||
"ffed": {
|
||||
timestamp: new Date().valueOf(),
|
||||
payload: {
|
||||
humi: 5432,
|
||||
temp: 2376,
|
||||
lux: 5555,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
mystream.on('packet', (packet) => {
|
||||
let address_last2 = packet.address.slice(-2).readUInt16BE().toString(16);
|
||||
if (!(address_last2 in recent_data)) {
|
||||
recent_data[address_last2] = {payload: {}};
|
||||
}
|
||||
let slot = recent_data[address_last2];
|
||||
slot.timestamp = new Date().valueOf();
|
||||
for (k in packet.payload) {
|
||||
slot.payload[k] = packet.payload[k];
|
||||
}
|
||||
recent_data[address_last2] = slot;
|
||||
console.log(recent_data);
|
||||
});
|
||||
|
||||
const express = require('express');
|
||||
serveStatic = require('serve-static');
|
||||
app = express();
|
||||
web_port = 3000;
|
||||
|
||||
app.use(serveStatic('static'));
|
||||
app.get('/data', (req, res) => res.json(recent_data));
|
||||
app.get('/data/:addr', (req, res) => res.json(recent_data[req.params.addr]));
|
||||
|
||||
app.listen(web_port, () => console.log(`Web app listening on port ${web_port}!`));
|
||||
|
@ -1,18 +0,0 @@
|
||||
Courses
|
||||
=======
|
||||
|
||||
The Tock team periodically puts on courses teaching various aspects of Tock.
|
||||
|
||||
Tock is a fast-moving project and courses are sometimes a bit specialized,
|
||||
which means the materials here may fall somewhat out of date over time.
|
||||
However they are still a good starting point.
|
||||
|
||||
Each course README includes pointers to commits for both libtock and the Tock
|
||||
kernel at the time the course was taught. If you're interested in running
|
||||
through the course, please hop back in time to ensure everything works as
|
||||
planned. If find anything that does not work or is confusing, please feel free
|
||||
to [open an issue](https://github.com/tock/libtock-c/issues/new) or even better
|
||||
to [submit a pull request](https://github.com/tock/libtock-c/pulls/new) with a
|
||||
suggested fix.
|
||||
|
||||
**Happy Hacking!**
|
@ -1,11 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# C++ files to compile.
|
||||
CXX_SRCS := $(wildcard *.cc)
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,47 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <timer.h>
|
||||
|
||||
class Base {
|
||||
public:
|
||||
virtual void function1() {
|
||||
printf("Base says hello\n");
|
||||
};
|
||||
virtual void function2() {};
|
||||
};
|
||||
|
||||
class D1: public Base {
|
||||
public:
|
||||
virtual void function1() override {
|
||||
printf("D1 says hello\n");
|
||||
};
|
||||
};
|
||||
|
||||
class D2: public Base {
|
||||
public:
|
||||
virtual void function1() override {
|
||||
printf("D2 says hello\n");
|
||||
};
|
||||
};
|
||||
|
||||
int main() {
|
||||
volatile uint8_t test_branch = 0;
|
||||
|
||||
D1 d1class;
|
||||
D2 d2class;
|
||||
Base *pClass;
|
||||
while (1) {
|
||||
if (test_branch % 2) {
|
||||
pClass = &d1class;
|
||||
pClass->function1();
|
||||
} else {
|
||||
pClass = &d2class;
|
||||
pClass->function1();
|
||||
}
|
||||
test_branch++;
|
||||
|
||||
delay_ms(1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,5 +0,0 @@
|
||||
Find North
|
||||
==========
|
||||
|
||||
This app uses the magnetometer to turn on an LED when the board
|
||||
is pointed north.
|
@ -1,47 +0,0 @@
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <led.h>
|
||||
#include <ninedof.h>
|
||||
|
||||
int main(void) {
|
||||
int x, y, z;
|
||||
int err;
|
||||
|
||||
// Choose the LED to use. We want green (which is usually
|
||||
// second in RGB), but will take anything.
|
||||
int led = 0;
|
||||
int num_leds;
|
||||
err = led_count(&num_leds);
|
||||
if (err < 0) {
|
||||
printf("No LEDs on this board.\n");
|
||||
return err;
|
||||
}
|
||||
if (num_leds > 1) led = 1;
|
||||
|
||||
while (1) {
|
||||
err = ninedof_read_magnetometer_sync(&x, &y, &z);
|
||||
if (err < 0) {
|
||||
printf("No magnetometer on this board.\n");
|
||||
return err;
|
||||
}
|
||||
printf("x: %d, y: %d, z: %d\n", x, y, z);
|
||||
|
||||
// Compute the X-Y angle of the board.
|
||||
double angle = atan2((double) y, (double) x);
|
||||
if (y > 0) {
|
||||
angle = 90 - angle * (180 / M_PI);
|
||||
} else {
|
||||
angle = 270 - angle * (180 / M_PI);
|
||||
}
|
||||
|
||||
// Turn the LED on if the board is pointing in a certain range.
|
||||
if (angle > 50 && angle < 310) {
|
||||
led_off(led);
|
||||
} else {
|
||||
led_on(led);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
bold=$(tput bold)
|
||||
normal=$(tput sgr0)
|
||||
|
||||
$SCRIPT_DIR/../tools/check_unstaged.sh || exit
|
||||
export TOCK_NO_CHECK_UNSTAGED=1
|
||||
|
||||
function opt_rebuild {
|
||||
if [ "$CI" == "true" ]; then
|
||||
echo "${bold}Rebuilding Verbose: $1${normal}"
|
||||
make format V=1
|
||||
fi
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "${bold}Formatting examples${normal}"
|
||||
|
||||
for mkfile in `find . -maxdepth 4 -name Makefile`; do
|
||||
dir=`dirname $mkfile`
|
||||
if [ $dir == "." ]; then continue; fi
|
||||
# Skip directories with leading _'s, useful for leaving test apps around
|
||||
if [[ $(basename $dir) == _* ]]; then continue; fi
|
||||
|
||||
pushd $dir > /dev/null
|
||||
echo ""
|
||||
echo "Formatting $dir"
|
||||
make format || (echo "${bold} ⤤ Failure formatting $dir${normal}" ; opt_rebuild $dir; exit 1)
|
||||
popd > /dev/null
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "${bold}All formatted.${normal}"
|
@ -1,13 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
APP_HEAP_SIZE := 2048
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,18 +0,0 @@
|
||||
IPv6 Sensor App
|
||||
=============
|
||||
|
||||
An example app for platforms with sensors and an 802.15.4 radio that broadcasts
|
||||
periodic sensor readings over the network. Currently, it sends UDP packets
|
||||
using 6lowpan to a single neighbor with an IP address known ahead of time.
|
||||
|
||||
## Running
|
||||
|
||||
This application should be tested using the `udp_rx` app in `examples/tests/udp/udp_rx`.
|
||||
Flash one Imix with this application, and flash a second Imix with `udp_rx`. If both
|
||||
apps are working correctly, the second Imix will blink its user LED every
|
||||
time an app is received, and will print the payload of each received packet
|
||||
to the console. If you wish to use this app to send to a board with a different
|
||||
address than the one hardcoded in this application, change the destination IPv6 address
|
||||
to match the source IPv6 address of your intended receiver. Note that in order
|
||||
to send to a different receiver you must also change the destination MAC address,
|
||||
which is currently configured in the kernel (in `boards/imix/src/main.rs`)
|
@ -1,88 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ambient_light.h>
|
||||
#include <humidity.h>
|
||||
#include <temperature.h>
|
||||
#include <timer.h>
|
||||
|
||||
#include <ieee802154.h>
|
||||
#include <udp.h>
|
||||
|
||||
static unsigned char BUF_BIND_CFG[2 * sizeof(sock_addr_t)];
|
||||
|
||||
void print_ipv6(ipv6_addr_t *);
|
||||
|
||||
void print_ipv6(ipv6_addr_t *ipv6_addr) {
|
||||
for (int j = 0; j < 14; j += 2) {
|
||||
printf("%02x%02x:", ipv6_addr->addr[j], ipv6_addr->addr[j + 1]);
|
||||
}
|
||||
printf("%02x%02x", ipv6_addr->addr[14], ipv6_addr->addr[15]);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("[IPv6_Sense] Starting IPv6 Sensors App.\n");
|
||||
printf("[IPv6_Sense] Sensors will be sampled and transmitted.\n");
|
||||
|
||||
unsigned int humi = 0;
|
||||
int temp = 0;
|
||||
int lux = 0;
|
||||
char packet[64];
|
||||
|
||||
ieee802154_set_pan(0xABCD);
|
||||
ieee802154_config_commit();
|
||||
ieee802154_up();
|
||||
|
||||
ipv6_addr_t ifaces[10];
|
||||
udp_list_ifaces(ifaces, 10);
|
||||
|
||||
sock_handle_t handle;
|
||||
sock_addr_t addr = {
|
||||
ifaces[0],
|
||||
15123
|
||||
};
|
||||
|
||||
printf("Opening socket on ");
|
||||
print_ipv6(&ifaces[0]);
|
||||
printf(" : %d, and binding to that socket.\n", addr.port);
|
||||
int bind_return = udp_bind(&handle, &addr, BUF_BIND_CFG);
|
||||
|
||||
if (bind_return < 0) {
|
||||
printf("Failed to bind to port: failure=%d\n", bind_return);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sock_addr_t destination = {
|
||||
ifaces[1],
|
||||
16123
|
||||
};
|
||||
|
||||
while (1) {
|
||||
temperature_read_sync(&temp);
|
||||
humidity_read_sync(&humi);
|
||||
ambient_light_read_intensity_sync(&lux);
|
||||
|
||||
int len = snprintf(packet, sizeof(packet), "%d deg C; %d%% humidity; %d lux;\n",
|
||||
temp / 100, humi / 100, lux);
|
||||
int max_tx_len;
|
||||
udp_get_max_tx_len(&max_tx_len);
|
||||
if (len > max_tx_len) {
|
||||
printf("Cannot send packets longer than %d bytes without changing"
|
||||
" constants in kernel\n", max_tx_len);
|
||||
return 0;
|
||||
}
|
||||
printf("Sending packet (length %d) --> ", len);
|
||||
print_ipv6(&(destination.addr));
|
||||
printf(" : %d\n", destination.port);
|
||||
ssize_t result = udp_send_to(packet, len, &destination);
|
||||
|
||||
switch (result) {
|
||||
case RETURNCODE_SUCCESS:
|
||||
printf("Packet sent.\n\n");
|
||||
break;
|
||||
default:
|
||||
printf("Error sending packet %d\n\n", result);
|
||||
}
|
||||
delay_ms(4000);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# We only compile this for Cortex-M platforms because of compiler
|
||||
# errors when building lua on risc-v.
|
||||
TOCK_TARGETS := cortex-m0 cortex-m3 cortex-m4 cortex-m7
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS := $(wildcard *.c)
|
||||
|
||||
# External libraries used
|
||||
EXTERN_LIBS += $(TOCK_USERLAND_BASE_DIR)/lua53
|
||||
|
||||
override CFLAGS += -I$(TOCK_USERLAND_BASE_DIR)/lua53/include
|
||||
|
||||
STACK_SIZE = 3072
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
@ -1,66 +0,0 @@
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <timer.h>
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
|
||||
// POSIX wrapper for `nanosleep` to make this compilable and runnable on
|
||||
// Linux/OS X/BSD for testing.
|
||||
#if defined(__unix__)
|
||||
#include <time.h>
|
||||
void delay_ms(int ms) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = (long)ms * 1000 * 1000;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
// Open lua
|
||||
lua_State *L = luaL_newstate();
|
||||
|
||||
luaL_requiref(L, "_G", luaopen_base, true);
|
||||
|
||||
// Execution of a lua string
|
||||
int err;
|
||||
err = luaL_loadstring(L, "main = function() print(\"Hello from Lua!\") end");
|
||||
|
||||
if (err != LUA_OK) {
|
||||
switch (err) {
|
||||
case LUA_ERRSYNTAX:
|
||||
printf("Syntax error\n");
|
||||
break;
|
||||
case LUA_ERRMEM:
|
||||
printf("Out of memory\n");
|
||||
break;
|
||||
case LUA_ERRGCMM:
|
||||
printf("Garbage collection error\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown error %d\n", err);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
lua_call(L, 0, 0);
|
||||
|
||||
while (1) {
|
||||
lua_getglobal(L, "main");
|
||||
lua_call(L, 0, 0);
|
||||
|
||||
int kb = lua_gc(L, LUA_GCCOUNT, 0);
|
||||
int bytes = lua_gc(L, LUA_GCCOUNT, 0);
|
||||
printf("> %dKB and %d bytes used\n", kb, bytes);
|
||||
delay_ms(500);
|
||||
}
|
||||
|
||||
// Close lua
|
||||
lua_close(L);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
# Makefile for user application
|
||||
|
||||
# Specify this directory relative to the current application.
|
||||
TOCK_USERLAND_BASE_DIR = ../..
|
||||
|
||||
# External libraries used
|
||||
EXTERN_LIBS += $(TOCK_USERLAND_BASE_DIR)/lvgl
|
||||
|
||||
override CFLAGS += -I$(TOCK_USERLAND_BASE_DIR)/lvgl
|
||||
|
||||
# Which files to compile.
|
||||
C_SRCS += $(wildcard *.c)
|
||||
|
||||
APP_HEAP_SIZE := 40000
|
||||
STACK_SIZE := 4096
|
||||
|
||||
# Include userland master makefile. Contains rules and flags for actually
|
||||
# building the application.
|
||||
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
|
||||
|
||||
# Ensure the required submodule is present
|
||||
lvgl_driver.c: | ../../lvgl/lvgl/lvgl.h
|
||||
|
||||
../../lvgl/lvgl/lvgl.h:
|
||||
git submodule init ../../lvgl/lvgl
|
||||
git submodule update ../../lvgl/lvgl
|
@ -1,82 +0,0 @@
|
||||
#include "lvgl_driver.h"
|
||||
|
||||
static lv_disp_draw_buf_t disp_buf;
|
||||
static lv_disp_drv_t disp_drv;
|
||||
static lv_disp_t *display_device;
|
||||
|
||||
static lv_indev_drv_t indev_drv;
|
||||
static lv_indev_t *touch_input_device;
|
||||
|
||||
static int touch_status = TOUCH_STATUS_UNSTARTED;
|
||||
static int touch_x = 0, touch_y = 0;
|
||||
|
||||
/* screen driver */
|
||||
static void screen_lvgl_driver(lv_disp_drv_t * disp, const lv_area_t * area,
|
||||
__attribute__ ((unused)) lv_color_t * color_p)
|
||||
{
|
||||
int32_t x, y;
|
||||
x = area->x1;
|
||||
y = area->y1;
|
||||
int w = area->x2 - area->x1 + 1;
|
||||
int h = area->y2 - area->y1 + 1;
|
||||
screen_set_frame(x, y, w, h);
|
||||
screen_write((w * h) * sizeof(lv_color_t));
|
||||
|
||||
lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/
|
||||
}
|
||||
|
||||
static void touch_event (int status, int x, int y, __attribute__((unused)) void* ud) {
|
||||
touch_status = status;
|
||||
touch_x = x;
|
||||
touch_y = y;
|
||||
}
|
||||
|
||||
static void my_input_read(__attribute__((unused)) lv_indev_drv_t * drv, lv_indev_data_t*data)
|
||||
{
|
||||
if (touch_status == TOUCH_STATUS_PRESSED || touch_status == TOUCH_STATUS_MOVED) {
|
||||
data->point.x = touch_x;
|
||||
data->point.y = touch_y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
int lvgl_driver_init (int buffer_lines)
|
||||
{
|
||||
size_t width, height;
|
||||
int error = screen_get_resolution(&width, &height);
|
||||
if (error == RETURNCODE_SUCCESS) {
|
||||
error = screen_init(width * buffer_lines * sizeof(lv_color_t));
|
||||
if (error == RETURNCODE_SUCCESS) {
|
||||
/* share the frame buffer with littlevgl */
|
||||
lv_color_t *buf = (lv_color_t*)screen_buffer();
|
||||
|
||||
/* initialize littlevgl */
|
||||
lv_init();
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.flush_cb = screen_lvgl_driver;
|
||||
disp_drv.hor_res = width;
|
||||
disp_drv.ver_res = height;
|
||||
lv_disp_draw_buf_init(&disp_buf, buf, NULL, width * buffer_lines);
|
||||
disp_drv.draw_buf = &disp_buf;
|
||||
display_device = lv_disp_drv_register(&disp_drv);
|
||||
|
||||
int touches;
|
||||
if (get_number_of_touches(&touches) == RETURNCODE_SUCCESS && touches >= 1) {
|
||||
enable_single_touch();
|
||||
single_touch_set_callback(touch_event, NULL);
|
||||
lv_indev_drv_init(&indev_drv);
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
indev_drv.read_cb = my_input_read;
|
||||
touch_input_device = lv_indev_drv_register(&indev_drv);
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void lvgl_driver_event (int millis) {
|
||||
lv_tick_inc(millis);
|
||||
lv_task_handler();
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <tock.h>
|
||||
#include <screen.h>
|
||||
#include <touch.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
int lvgl_driver_init (int buffer_size);
|
||||
void lvgl_driver_event (int mills);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user