Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libtock: Rewrite and standardize API #370

Merged
merged 147 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
147 commits
Select commit Hold shift + click to select a range
94a9629
libtock/sensors
bradjc Feb 9, 2024
847b8f6
libtock/chips
bradjc Feb 9, 2024
53e491a
libtock/net
bradjc Feb 9, 2024
0835ae0
libtock/peripherals
bradjc Feb 9, 2024
2bf1cc2
libtock/crypto
bradjc Feb 9, 2024
bd913d2
libtock/storage
bradjc Feb 9, 2024
880bee0
libtock/display
bradjc Feb 9, 2024
6dfe7e7
libtock/kernel
bradjc Feb 9, 2024
fddf6f5
libtock/interface
bradjc Feb 9, 2024
d79ec45
sys: update includes
bradjc Apr 16, 2024
2d4284a
unit_test
bradjc Apr 16, 2024
dbf2fe6
Remove chip-specific userland drivers.
bradjc Apr 16, 2024
1b9acee
libtock: add folders to makefile
bradjc Apr 19, 2024
c89e45f
libtocksync: makefile
bradjc Apr 16, 2024
9953df6
make: add libtock-sync to app makefile
bradjc Mar 23, 2024
6adab08
libtock-sync: readme
bradjc Mar 23, 2024
8491493
libtock-sync: services: readme
bradjc Apr 30, 2024
df3d833
libtock: readme
bradjc Apr 30, 2024
73d19f5
doc: add guide for writing libtock-c drivers
bradjc Feb 9, 2024
c8c93fa
temperature
bradjc Apr 16, 2024
9a4bff8
button
bradjc Mar 9, 2024
eb85d15
buzzer
bradjc Feb 16, 2024
9b3b9d3
led
bradjc Feb 19, 2024
7011299
usb_keyboard_hid
bradjc Feb 19, 2024
97bd946
screen
bradjc Apr 16, 2024
7b8f332
analog_comparator
bradjc Mar 7, 2024
c2889a7
rng
bradjc Mar 7, 2024
544929a
rtc
bradjc Mar 7, 2024
5142d8b
spi_peripheral
bradjc Mar 7, 2024
e9e6e53
ambient light
bradjc Mar 7, 2024
112719b
humidity
bradjc Mar 7, 2024
1b7905f
ninedof
bradjc Mar 8, 2024
9584f33
pressure
bradjc Mar 8, 2024
2cd787b
proximity
bradjc Mar 8, 2024
39cf028
sound_pressure
bradjc Mar 9, 2024
4fef010
touch
bradjc Mar 9, 2024
fad2ce6
app_state
bradjc Apr 16, 2024
27bca82
kv
bradjc Mar 15, 2024
59865f3
nonvolatile_storage
bradjc Mar 15, 2024
9d265aa
sha
bradjc Mar 22, 2024
b761e8a
gpio
bradjc Mar 23, 2024
7f01bcb
gpio_async
bradjc Mar 23, 2024
2ee9090
lora_phy
bradjc Mar 23, 2024
ff18cfb
dac
bradjc Mar 23, 2024
cd964d4
usb
bradjc Mar 23, 2024
29faeb2
hmac
bradjc Mar 23, 2024
ecb4b86
sdcard
bradjc Mar 23, 2024
a29052e
crc
bradjc Mar 24, 2024
685e486
read_only_state
bradjc Mar 26, 2024
c9cc32c
nrf51_serialization
bradjc Mar 26, 2024
4d84021
aes
bradjc Mar 26, 2024
ea6620f
text_screen
bradjc Mar 27, 2024
1548c85
udp
tyler-potyondy Apr 5, 2024
8b7a254
console
alevy Apr 13, 2024
1a7e46e
spi
hudson-ayers Apr 12, 2024
04bdead
adc
bradjc Apr 19, 2024
8e79d41
eui64
bradjc Apr 29, 2024
e2d7376
ieee802154
tyler-potyondy Apr 24, 2024
d595ab0
i2c
bradjc May 2, 2024
8ae790a
ble
bradjc May 2, 2024
8a49820
ipc
bradjc May 2, 2024
de9dd0e
alarm
bradjc May 2, 2024
fab4145
u8g2 library
bradjc Apr 24, 2024
03d8fe6
libnrfserialization
bradjc Apr 29, 2024
15e1359
move courses to wip
bradjc May 2, 2024
89c2f59
unit_tests: nrf52840dk
bradjc Apr 16, 2024
905efee
unit_tests: pass fail
bradjc Apr 16, 2024
707032c
unit_tests: timeout
bradjc Apr 16, 2024
d9eafc6
services: ble-env-sense
bradjc Apr 16, 2024
1cd529d
tutorials: 02 button print
bradjc Apr 16, 2024
fd93a4e
tutorials: 03 ble scan
bradjc Apr 16, 2024
7563774
tutorials: 05 ipc
bradjc Apr 16, 2024
5c51db1
tutorials: hotp
bradjc Apr 16, 2024
aed5716
examples: accel-leds
bradjc Apr 16, 2024
e83139a
examples: adc
bradjc Apr 16, 2024
3d19923
examples: ble-uart
bradjc Apr 16, 2024
b921caa
examples: ble_advertising
bradjc Apr 16, 2024
1ed1291
examples: ble_passive_scanning
bradjc Apr 16, 2024
1b53fef
examples: blink
bradjc Apr 16, 2024
3b6afc1
examples: buttons
bradjc Apr 16, 2024
dbc307a
examples: c_hello
bradjc Apr 16, 2024
da200ea
examples: find_north
bradjc Apr 16, 2024
a382da4
examples: i2c-usb-bridge
bradjc Apr 16, 2024
e7ecc92
examples: ip_sense
bradjc Apr 16, 2024
fc4cea7
examples: lora
bradjc Apr 16, 2024
9151c1f
examples: rot13
bradjc Apr 16, 2024
36dba45
examples: rtcapp
bradjc Apr 16, 2024
7e6bd60
examples: security_app
bradjc Apr 16, 2024
86d82f4
examples: sensors
bradjc Apr 16, 2024
8dc8acf
example: music
bradjc Apr 16, 2024
8b54074
example: witenergy
bradjc Apr 16, 2024
4b7d93a
example: lvgl
bradjc Apr 30, 2024
b4dd984
example: unit tests
bradjc Apr 30, 2024
c4cb917
example: cxx_hello
bradjc May 2, 2024
e059615
example: lua
bradjc May 2, 2024
d8e46c4
tests: screen
bradjc Apr 16, 2024
c08990a
test: gpio
bradjc Mar 27, 2024
1a6c8a1
test: usb
bradjc Apr 29, 2024
3e5521a
test: nonvolatile_storage
bradjc Mar 26, 2024
5cb2a6f
test: button_print
bradjc Mar 23, 2024
721409d
test: ambient_light
bradjc Mar 23, 2024
4dbee96
test: crash_dummy
bradjc Mar 23, 2024
cb8d62e
test: dac
bradjc Mar 23, 2024
28096ee
test: gpio_async
bradjc Mar 23, 2024
0ade304
test: hmac
bradjc Mar 23, 2024
3e287c2
test: keyboard_hid
bradjc Mar 23, 2024
44d9962
test: number_guessing_game
bradjc Mar 23, 2024
b6c1bd5
test: proximity
bradjc Mar 23, 2024
566fe5b
test: sha
bradjc Mar 23, 2024
e420a1b
tests: kv
bradjc Mar 28, 2024
8eae7d2
test: rng
bradjc Mar 28, 2024
c4a4b15
test: text_scren
bradjc Mar 28, 2024
0742b5c
test: mpu
bradjc Mar 29, 2024
cabd53e
test: sdcard
bradjc Mar 29, 2024
f59b57f
test: yield
bradjc Mar 29, 2024
025ecd2
tests: rtc
bradjc Apr 15, 2024
db476fa
tests: hail
bradjc Apr 15, 2024
737f3f5
test: crc
bradjc Apr 16, 2024
0d37423
test: multi alarm
bradjc Apr 16, 2024
31cba57
test: analog comparator
bradjc Apr 16, 2024
576c535
test: app_state
bradjc Apr 16, 2024
20babd6
test: aes
bradjc Apr 16, 2024
d6ce255
tests: touch
bradjc Apr 16, 2024
d7bbbaf
test: u8g2-demos
bradjc Apr 23, 2024
6d958de
test: hifive1b
bradjc Apr 23, 2024
5f9d90a
test: hello_loop
bradjc Apr 23, 2024
8b9fb4e
test: console_recv_short
bradjc Apr 24, 2024
a3f3a74
test: number guess game
bradjc Apr 29, 2024
b061df5
test: ble
bradjc Apr 29, 2024
eb1ddb4
test: adc
bradjc Apr 30, 2024
4dcbe1e
test: microbitv2
bradjc Apr 30, 2024
3fb15fc
test: imix
bradjc Apr 30, 2024
2636f48
test: i2c
bradjc Apr 30, 2024
49c218a
test: spi: move to wip
bradjc Apr 30, 2024
e4a9eee
test: ieee802154
bradjc Apr 30, 2024
7fbd748
test: udp
bradjc Apr 30, 2024
a37971c
test: yield_for timeout
bradjc May 2, 2024
e415ceb
test: callback remove test
bradjc May 2, 2024
ac3533c
test: exit
bradjc May 2, 2024
76b079a
test: fault
bradjc May 2, 2024
29e973f
test: restart
bradjc May 2, 2024
436df65
test: wfr
bradjc May 2, 2024
9c73003
test: eui64
bradjc May 7, 2024
8748553
service: unit test supervisor
bradjc Apr 30, 2024
62db62a
sys / console
bradjc Apr 30, 2024
78812e7
make: configuration: include root in header search
bradjc May 2, 2024
d883da0
libtock: services: readme
bradjc May 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions AppMakefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ include $(TOCK_USERLAND_BASE_DIR)/Precompiled.mk
# library when needed.
include $(TOCK_USERLAND_BASE_DIR)/libtock/Makefile

# Include the libtock-sync Makefile. Adds rules that will rebuild the core
# libtock-sync library when needed.
include $(TOCK_USERLAND_BASE_DIR)/libtock-sync/Makefile

# Include the makefile that has the programming functions for each board.
include $(TOCK_USERLAND_BASE_DIR)/Program.mk

Expand Down
5 changes: 5 additions & 0 deletions Configuration.mk
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ override WLFLAGS += \
-Wl,--gc-sections\
-Wl,--build-id=none

# Include path for all architectures. To support `#include <libtock/*.h>` and
# `#include <libtock-sync/*.h>` in app source files, we include the root
# libtock-c folder in the preprocessor's search path.
override CPPFLAGS += -I$(TOCK_USERLAND_BASE_DIR)

# Flags to improve the quality and information in listings (debug target)
OBJDUMP_FLAGS += --disassemble-all --source -C --section-headers

Expand Down
353 changes: 353 additions & 0 deletions doc/guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,353 @@
Writing a libtock-c System Call Driver
======================================

This guide covers how to implement support in `libtock` for a new system call
driver.


## Setup


- `[name]`: String which identifies the system call driver.
- `[category]`: The general type of the system call.

The categories are:

- `crypto`: Cryptography interfaces.
- `display`: Screens and other displays.
- `interface`: Human-computer interfaces.
- `kernel`: Tock-specific kernel-level drivers.
- `net`: Networking drivers.
- `peripherals`: Interfaces for chip peripherals.
- `sensors`: Sensors.
- `storage`: Various storage drivers.


## Syscall APIs

All supported system calls (i.e., command, allow, subscribe, etc.) for a
particular driver must be wrapped in simple functions.

| Characteristic | Value |
|------------------|-------------------------------------------------|
| Location | `libtock/[category]/syscalls` |
| Source File Name | `libtock/[category]/syscalls/[name]_syscalls.c` |
| Header File Name | `libtock/[category]/syscalls/[name]_syscalls.h` |

### Header File

The `[name]_syscalls.h` file must contain a `#define` called `DRIVER_NUM_[NAME]`
with the driver number.

_All_ header files must be wrapped in `extern "C" { ... }` if the header file
is used in a C++ app.

#### Example:

```c
#pragma once

#include "../../tock.h"

#ifdef __cplusplus
extern "C" {
#endif

#define DRIVER_NUM_[NAME] 0x00000

// Other defines and signatures go here.

#ifdef __cplusplus
}
#endif
```

### Upcalls

Each supported upcall must have its own function.

The signature is:

```c
returncode_t libtock_[name]_set_upcall(subscribe_upcall callback, void* opaque);
bradjc marked this conversation as resolved.
Show resolved Hide resolved
```

If only one upcall is supported, the function name must be `[name]_set_upcall`.

If more than one upcall is supported, the function names must start with
`libtock_[name]_set_upcall_` followed by a description of what the upcall is
used for.


#### Example:

```c
returncode_t libtock_[name]_set_upcall(subscribe_upcall callback, void* opaque) {
subscribe_return_t sval = subscribe(DRIVER_NUM_[NAME], 0, callback, opaque);
return tock_subscribe_return_to_returncode(sval);
}
```

### Allows

Each supported allow (readonly, readwrite, userspace_read) must have its own
function.

The signature is:

- Read-Only Allow:
```c
returncode_t libtock_[name]_set_readonly_allow(const uint8_t* buffer, uint32_t len);
```

- Read-Write Allow:
```c
returncode_t libtock_[name]_set_readwrite_allow(uint8_t* buffer, uint32_t len);
```

- Userspace Read Allow:
```c
returncode_t libtock_[name]_set_userspace_read_allow(uint8_t* buffer, uint32_t len);
```

If only one allow is supported, the function name must be
`libtock_[name]_set_[type]_allow`.

If more than one allow is supported, the function names must start with
`libtock_[name]_set_[type]_allow_` followed by a description of what the allow
is used for.

#### Example:

```c
returncode_t libtock_[name]_set_readonly_allow_[desc](const uint8_t* buffer, uint32_t len) {
allow_ro_return_t aval = allow_readonly(DRIVER_NUM_[NAME], 0, (void*) buffer, len);
return tock_allow_ro_return_to_returncode(aval);
}
```

```c
returncode_t libtock_[name]_set_readwrite_allow_[desc](uint8_t* buffer, uint32_t len) {
allow_rw_return_t aval = allow_readwrite(DRIVER_NUM_[NAME], 0, (void*) buffer, len);
return tock_allow_rw_return_to_returncode(aval);
}
```

```c
returncode_t libtock_[name]_set_userspace_read_allow_[desc](uint8_t* buffer, uint32_t len) {
allow_userspace_r_return_t aval = allow_userspace_read(DRIVER_NUM_[NAME], 0, (void*) buffer, len);
return tock_allow_userspace_r_return_to_returncode(aval);
}
```

### Commands

Each supported command must have its own function.

The signature is:

```c
returncode_t libtock_[name]_command_[desc](<arguments>);
```

For every command, the function names must start with `libtock_[name]_command_`
followed by a description of what the command is used for.

### Example:

```c
returncode_t libtock_[name]_command_[desc](void) {
syscall_return_t cval = command(DRIVER_NUM_[NAME], 1, 0, 0);
return tock_command_return_novalue_to_returncode(cval);
}
```


### Exists

There must be a function to check for syscall driver existence.

Signature:

```
bool libtock_[name]_exists(void);
```

Example:

```c
bool libtock_[name]_exists(void) {
return driver_exists(DRIVER_NUM_[NAME]);
}
```


## Asynchronous APIs

All common system call operations should have asynchronous versions.
bradjc marked this conversation as resolved.
Show resolved Hide resolved

These asynchronous APIs must not use or include any internal/global state.

| Characteristic | Value |
|------------------|-------------------------------|
| Location | `libtock/[category]` |
| Source File Name | `libtock/[category]/[name].c` |
| Header File Name | `libtock/[category]/[name].h` |

### Header Files

The `[name].h` header file must look like:

```c
#pragma once

#include "../tock.h"
#include "syscalls/[name]_syscalls.h"

#ifdef __cplusplus
extern "C" {
#endif

// Function signatures go here.

#ifdef __cplusplus
}
#endif
```

The `[name].h` header file must include the syscalls header.

### Defining a Callback for Asynchronous Operations

For every type of callback the system call can generate, the library must have a
function signature defined as a type. The format is:

```c
typedef void (*libtock_[name]_callback_[desc])(returncode_t, int);
```

### Functions for Operations

Every operation the libtock library should expose must be defined. The return
type should generally be `returncode_t`. As these are asynchronous operations,
they should have the last argument be a callback function pointer.

```c
returncode_t libtock_[name]_[desc](<arguments>, libtock_[name]_callback_[desc] cb);
```

### Example


For example, a library called "sensor" with a sensor read operation should look
like this:

Define a suitable callback for the library:

```c
typedef void (*libtock_sensor_callback_reading)(returncode_t, int);
```

Define a upcall function to be passed to the kernel:

```c
static void sensor_temp_upcall(int ret,
int val,
__attribute__ ((unused)) int unused0,
void* opaque) {
libtock_sensor_callback_reading cb = (libtock_sensor_callback_reading) opaque;
cb(ret, val);
}
```

Define an external function for applications to use to run the asynchronous
operation:

```c
returncode_t libtock_sensor_read(libtock_sensor_callback_reading cb) {
returncode_t ret;

ret = libtock_sensor_set_upcall(sensor_temp_upcall, cb);
if (ret != RETURNCODE_SUCCESS) return ret;

ret = libtock_sensor_command_read();
return ret;
}
```

## Synchronous APIs

Most system call interfaces will want to provide a synchronous API as well.

| Characteristic | Value |
|------------------|------------------------------------|
| Location | `libtock-sync/[category]` |
| Source File Name | `libtock-sync/[category]/[name].c` |
| Header File Name | `libtock-sync/[category]/[name].h` |

### Header Files

The libtock-sync `[name].h` header file must look like:

```c
#pragma once

#include <libtock/tock.h>
#include <libtock/[category]/[name].h>

#ifdef __cplusplus
extern "C" {
#endif

// Function signatures go here.

#ifdef __cplusplus
}
#endif
```

### Synchronous APIs

For our sensor example:

Create a struct to be set by the asynchronous callback:

```c
struct data {
bool fired;
int val;
returncode_t result;
};

static struct data result = { .fired = false };
```

Define a static callback function to pass to the asynchronous implementation:

```c
static void sensor_cb(returncode_t ret, int val) {
result.val = val;
result.fired = true;
result.result = ret;
}
```

Define the external function in the `libtocksync_` name space for the sync
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you want every function to have libtock_ prepended? This seems more verbose for no benefit. I understand the purpose of putting sync, but not libtock.

Copy link
Contributor

Choose a reason for hiding this comment

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

C doesn't really give you a choice since it doesn't have a namespace concept. If your driver is implementing a timer, libtock_timer is a unique name but timer is not.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If you are writing a "pure" libtock-c app, where you are only calling libtock functions, I agree the prefix is a bit redundant. But for more complicated apps that use multiple libraries, it becomes very convenient to have namespacing to make the code easier to read.

I think we should get to a place where someone is writing a c app with some other library (e.g. lora or graphics or ML) and then just happens to use libtock, maybe for sensor data.

operation:

```c
returncode_t libtocksync_sensor_read(int* val) {
int err;
result.fired = false;

err = libtock_sensor_read(sensor_cb);
if (err != RETURNCODE_SUCCESS) return err;

// Wait for the callback.
yield_for(&result.fired);
if (result.result != RETURNCODE_SUCCESS) return result.result;

*val = result.val;
return RETURNCODE_SUCCESS;
}
```
Loading
Loading