Skip to content

Commit f25a2b2

Browse files
authored
Merge pull request #521 from tock/ywf
Implement Yield-WaitFor, add guide doc for YWF, demonstration with temperature
2 parents cc5301d + 1d1406f commit f25a2b2

File tree

11 files changed

+212
-37
lines changed

11 files changed

+212
-37
lines changed

doc/guide.md

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ they should have the last argument be a callback function pointer.
236236
returncode_t libtock_[name]_[desc](<arguments>, libtock_[name]_callback_[desc] cb);
237237
```
238238

239-
### Example
239+
### Example:
240240

241241

242242
For example, a library called "sensor" with a sensor read operation should look
@@ -277,23 +277,103 @@ returncode_t libtock_sensor_read(libtock_sensor_callback_reading cb) {
277277
278278
## Synchronous APIs
279279
280-
Most system call interfaces will want to provide a synchronous API as well.
280+
Most system call interfaces will want to provide a synchronous API as well. This
281+
requires another file for syscalls.
282+
283+
All synchronous APIs MUST use the
284+
[Yield-WaitFor](https://book.tockos.org/trd/trd104-syscalls.html#413-yield-waitfor)
285+
(`yield_wait_for()`) variant of the yield syscall. This ensures predictable
286+
behavior for `libtock-sync` users because Yield-WaitFor ensures that no other
287+
application upcall will run until the synchronous API has finished.
288+
289+
### Synchronous Syscall APIs
290+
291+
| Characteristic | Value |
292+
|------------------|------------------------------------------------------|
293+
| Location | `libtock-sync/[category]/syscalls` |
294+
| Source File Name | `libtock-sync/[category]/syscalls/[name]_syscalls.c` |
295+
| Header File Name | `libtock-sync/[category]/syscalls/[name]_syscalls.h` |
296+
297+
### Synchronous Syscall Header File
298+
299+
The `[name]_syscalls.h` must be wrapped in `extern "C" { ... }` if the header
300+
file is used in a C++ app.
301+
302+
#### Example:
303+
304+
```c
305+
#pragma once
306+
307+
#include <libtock/tock.h>
308+
#include <libtock/[category]/syscalls/[name]_syscalls.h>
309+
310+
#ifdef __cplusplus
311+
extern "C" {
312+
#endif
313+
314+
// Signatures go here.
315+
316+
#ifdef __cplusplus
317+
}
318+
#endif
319+
```
320+
321+
### Yield-WaitFor
322+
323+
Each supported upcall must have a matching Yield-WaitFor call. This function
324+
calls `yield_wait_for()` and interprets the `yield_waitfor_return_t` return
325+
value arguments.
326+
327+
The signature is:
328+
329+
```c
330+
returncode_t libtocksync_[name]_yield_wait_for(<arguments>);
331+
```
332+
333+
If only one upcall is supported, the function name must be
334+
`libtocksync_[name]_yield_wait_for`.
335+
336+
If more than one upcall is supported, the function names must start with
337+
`libtocksync_[name]_yield_wait_for_` followed by the same description of what
338+
the upcall is used for from the `libtock` library.
339+
340+
The arguments must be appropriately named pointers to data types returned by the
341+
upcall, except for any returned ReturnCode. The ReturnCode must be returned from
342+
the function.
343+
344+
#### Example:
345+
346+
```c
347+
returncode_t libtocksync_[name]_yield_wait_for(int* value) {
348+
yield_waitfor_return_t ret;
349+
ret = yield_wait_for(DRIVER_NUM_[NAME], 0);
350+
if (ret.data0 != RETURNCODE_SUCCESS) return ret.data0;
351+
352+
*value = (int) ret.data1;
353+
return RETURNCODE_SUCCESS;
354+
}
355+
```
356+
357+
### Synchronous Operations
358+
359+
The asynchronous operations should have matching synchronous versions using
360+
Yield-WaitFor internally.
281361

282362
| Characteristic | Value |
283363
|------------------|------------------------------------|
284364
| Location | `libtock-sync/[category]` |
285365
| Source File Name | `libtock-sync/[category]/[name].c` |
286366
| Header File Name | `libtock-sync/[category]/[name].h` |
287367

288-
### Header Files
368+
### Synchronous Operation Header Files
289369

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

292372
```c
293373
#pragma once
294374

375+
#include "syscalls/temperature_syscalls.h"
295376
#include <libtock/tock.h>
296-
#include <libtock/[category]/[name].h>
297377

298378
#ifdef __cplusplus
299379
extern "C" {
@@ -306,7 +386,7 @@ extern "C" {
306386
#endif
307387
```
308388

309-
### Synchronous APIs
389+
### Example:
310390

311391
For our sensor example:
312392

@@ -337,17 +417,13 @@ operation:
337417

338418
```c
339419
returncode_t libtocksync_sensor_read(int* val) {
340-
int err;
341-
result.fired = false;
420+
returncode_t err;
342421

343-
err = libtock_sensor_read(sensor_cb);
422+
err = libtock_sensor_command_read();
344423
if (err != RETURNCODE_SUCCESS) return err;
345424

346-
// Wait for the callback.
347-
yield_for(&result.fired);
348-
if (result.result != RETURNCODE_SUCCESS) return result.result;
349-
350-
*val = result.val;
351-
return RETURNCODE_SUCCESS;
425+
// Wait for the operation to finish.
426+
err = libtock_temperature_yield_wait_for(val);
427+
return err;
352428
}
353429
```
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Makefile for user application
2+
3+
# Specify this directory relative to the current application.
4+
TOCK_USERLAND_BASE_DIR = ../../..
5+
6+
# Which files to compile.
7+
C_SRCS := $(wildcard *.c)
8+
9+
# Include userland master makefile. Contains rules and flags for actually
10+
# building the application.
11+
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Simple Temperature Test
2+
=======================
3+
4+
Uses libtock-sync to read the temperature sensor.

examples/tests/temperature/main.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
#include <libtock-sync/sensors/temperature.h>
6+
7+
int main(void) {
8+
returncode_t ret;
9+
10+
if (!libtock_temperature_exists()) {
11+
printf("[Temperature] No temperature sensor found.\n");
12+
exit(-1);
13+
}
14+
15+
int temp;
16+
ret = libtocksync_temperature_read(&temp);
17+
if (ret != RETURNCODE_SUCCESS) {
18+
printf("[Temperature] Error reading temperature sensor.\n");
19+
printf("[Temperature] %s\n", tock_strrcode(ret));
20+
exit(-2);
21+
}
22+
23+
int temp_ones = temp / 100;
24+
int temp_hundredths = temp - (temp_ones * 100);
25+
printf("[Temperature] %d.%d deg C\n", temp_ones, temp_hundredths);
26+
27+
return 0;
28+
}

libtock-sync/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ $(LIBNAME)_SRCS += $(wildcard $($(LIBNAME)_DIR)/kernel/*.c)
1616
$(LIBNAME)_SRCS += $(wildcard $($(LIBNAME)_DIR)/net/*.c)
1717
$(LIBNAME)_SRCS += $(wildcard $($(LIBNAME)_DIR)/peripherals/*.c)
1818
$(LIBNAME)_SRCS += $(wildcard $($(LIBNAME)_DIR)/sensors/*.c)
19+
$(LIBNAME)_SRCS += $(wildcard $($(LIBNAME)_DIR)/sensors/syscalls/*.c)
1920
$(LIBNAME)_SRCS += $(wildcard $($(LIBNAME)_DIR)/services/*.c)
2021
$(LIBNAME)_SRCS += $(wildcard $($(LIBNAME)_DIR)/storage/*.c)
2122

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include "temperature_syscalls.h"
2+
3+
returncode_t libtocksync_temperature_yield_wait_for(int* temp) {
4+
yield_waitfor_return_t ret;
5+
ret = yield_wait_for(DRIVER_NUM_TEMPERATURE, 0);
6+
7+
*temp = (int) ret.data0;
8+
return RETURNCODE_SUCCESS;
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
3+
#include <libtock/sensors/syscalls/temperature_syscalls.h>
4+
#include <libtock/tock.h>
5+
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
// Wait for a temperature read to finish.
11+
returncode_t libtocksync_temperature_yield_wait_for(int* temp);
12+
13+
#ifdef __cplusplus
14+
}
15+
#endif

libtock-sync/sensors/temperature.c

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,13 @@
11
#include "temperature.h"
22

3-
struct data {
4-
bool fired;
5-
int temp;
6-
returncode_t result;
7-
};
8-
9-
static struct data result = { .fired = false };
10-
11-
static void temp_cb(returncode_t ret, int temperature) {
12-
result.temp = temperature;
13-
result.fired = true;
14-
result.result = ret;
15-
}
16-
173
returncode_t libtocksync_temperature_read(int* temperature) {
184
returncode_t err;
19-
result.fired = false;
205

21-
err = libtock_temperature_read(temp_cb);
6+
err = libtock_temperature_command_read();
227
if (err != RETURNCODE_SUCCESS) return err;
238

24-
// Wait for the callback.
25-
yield_for(&result.fired);
26-
if (result.result != RETURNCODE_SUCCESS) return result.result;
27-
28-
*temperature = result.temp;
9+
// Wait for the operation to finish.
10+
err = libtocksync_temperature_yield_wait_for(temperature);
2911

30-
return RETURNCODE_SUCCESS;
12+
return err;
3113
}

libtock-sync/sensors/temperature.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#pragma once
22

3-
#include <libtock/sensors/temperature.h>
3+
#include "syscalls/temperature_syscalls.h"
44
#include <libtock/tock.h>
55

66
#ifdef __cplusplus

libtock/tock.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,25 @@ int yield_no_wait(void) {
184184
return (int)result;
185185
}
186186

187+
yield_waitfor_return_t yield_wait_for(uint32_t driver, uint32_t subscribe) {
188+
register uint32_t waitfor __asm__ ("r0") = 2; // yield-waitfor
189+
register uint32_t r1 __asm__ ("r1") = driver;
190+
register uint32_t r2 __asm__ ("r2") = subscribe;
191+
register int rv0 __asm__ ("r0");
192+
register int rv1 __asm__ ("r1");
193+
register int rv2 __asm__ ("r2");
194+
195+
__asm__ volatile (
196+
"svc 0 \n"
197+
: "=r" (rv0), "=r" (rv1), "=r" (rv2)
198+
: "r" (waitfor), "r" (r1), "r" (r2)
199+
: "memory"
200+
);
201+
yield_waitfor_return_t rv = {rv0, rv1, rv2};
202+
return rv;
203+
}
204+
205+
187206
void tock_exit(uint32_t completion_code) {
188207
register uint32_t r0 __asm__ ("r0") = 0; // Terminate
189208
register uint32_t r1 __asm__ ("r1") = completion_code;
@@ -400,6 +419,23 @@ int yield_no_wait(void) {
400419
return (int)result;
401420
}
402421

422+
yield_waitfor_return_t yield_wait_for(uint32_t driver, uint32_t subscribe) {
423+
register uint32_t waitfor __asm__ ("a0") = 2; // yield-waitfor
424+
register uint32_t a1 __asm__ ("a1") = driver;
425+
register uint32_t a2 __asm__ ("a2") = subscribe;
426+
register uint32_t a4 __asm__ ("a4") = 0; // Yield
427+
register int rv0 __asm__ ("a0");
428+
register int rv1 __asm__ ("a1");
429+
register int rv2 __asm__ ("a2");
430+
__asm__ volatile (
431+
"ecall\n"
432+
: "=r" (rv0), "=r" (rv1), "=r" (rv2)
433+
: "r" (waitfor), "r" (a1), "r" (a2), "r" (a4)
434+
: "memory");
435+
yield_waitfor_return_t rv = {rv0, rv1, rv2};
436+
return rv;
437+
}
438+
403439

404440
void tock_restart(uint32_t completion_code) {
405441
register uint32_t a0 __asm__ ("a0") = 1; // exit-restart

0 commit comments

Comments
 (0)