Skip to content

Commit 05feaaf

Browse files
committed
add @devicescript/spi module
1 parent 7046763 commit 05feaaf

File tree

25 files changed

+338
-94
lines changed

25 files changed

+338
-94
lines changed

bytecode/bytecode.md

+2
Original file line numberDiff line numberDiff line change
@@ -644,3 +644,5 @@ Only `true` and `false` values.
644644
delay = 167
645645
fromCharCode = 168
646646
_allocRole = 169
647+
spiConfigure = 170
648+
spiXfer = 171

compiler/src/bytecode.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ export enum BuiltInObject {
281281
}
282282

283283
export enum BuiltInString {
284-
__MAX = 169,
284+
__MAX = 171,
285285
_EMPTY = 0,
286286
MINFINITY = 1, // -Infinity
287287
DEVICESCRIPT = 2,
@@ -452,6 +452,8 @@ export enum BuiltInString {
452452
DELAY = 167,
453453
FROMCHARCODE = 168,
454454
_ALLOCROLE = 169,
455+
SPICONFIGURE = 170,
456+
SPIXFER = 171,
455457
}
456458

457459
export const OP_PRINT_FMTS = [
@@ -737,6 +739,8 @@ export const BUILTIN_STRING__VAL = [
737739
"delay",
738740
"fromCharCode",
739741
"_allocRole",
742+
"spiConfigure",
743+
"spiXfer",
740744
]
741745
export const BUILTIN_OBJECT__VAL = [
742746
"Math",

devs/run-tests/allcompile.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import "@devicescript/i2c"
66
import "@devicescript/settings"
77
import "@devicescript/drivers"
88
import "@devicescript/gpio"
9+
import "@devicescript/spi"
910
import "@devicescript/runtime"
1011

1112
console.log("all libraries compiled and didn't crash!")

packages/core/src/devicescript-core.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,11 @@ declare module "@devicescript/core" {
519519

520520
export interface PinBase {
521521
_pinBrand: unknown
522+
523+
/**
524+
* Hardware pin number
525+
*/
526+
gpio: number
522527
}
523528

524529
/**

packages/core/src/utils.ts

+2
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,5 @@ Math.log2 = function log2(x) {
6262
await fn()
6363
return await ds.suspend<ds.Packet>()
6464
}
65+
// this is overridden byt the gpio package
66+
;(ds as typeof ds).gpio = gpio => ({ gpio } as any)

packages/gpio/src/pins.ts

-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ import * as ds from "@devicescript/core"
33
// extend interfaces
44
declare module "@devicescript/core" {
55
export interface PinBase {
6-
/**
7-
* hardware pin number
8-
*/
9-
gpio: number
106
/**
117
* Configure pin mode.
128
* @param mode desired mode

packages/spi/README.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# @devicescript/spi
2+
3+
[DeviceScript](https://microsoft.github.io/devicescript/) SPI master support.
4+
5+
- [Read documentation](https://microsoft.github.io/devicescript/developer/servers/spi)
6+
7+
## Contributing
8+
9+
Contributions are welcome! See [contributing page](../../CONTRIBUTING.md).
10+
11+
## Trademarks
12+
13+
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
14+
trademarks or logos is subject to and must follow
15+
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
16+
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
17+
Any use of third-party trademarks or logos are subject to those third-party's policies.

packages/spi/devsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

packages/spi/package.json

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "@devicescript/spi",
3+
"version": "2.9.12",
4+
"private": true,
5+
"dependencies": {},
6+
"devDependencies": {
7+
"@devicescript/cli": "*"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/microsoft/devicescript.git",
12+
"directory": "packages/spi"
13+
},
14+
"scripts": {
15+
"setup": "devicescript build",
16+
"build:devicescript": "devicescript build src/main.ts -F allFunctions",
17+
"build": "yarn build:devicescript",
18+
"watch:devicescript": "devicescript devtools src/main.ts",
19+
"watch": "yarn watch:devicescript",
20+
"test:devicescript": "devicescript run src/main.ts --test --test-self-exit -F allFunctions",
21+
"test": "yarn test:devicescript",
22+
"start": "yarn watch"
23+
},
24+
"main": "./src/index.ts",
25+
"license": "MIT",
26+
"devicescript": {
27+
"bundle": true,
28+
"library": true
29+
},
30+
"files": [
31+
"src/*.ts",
32+
"devsconfig.json"
33+
],
34+
"keywords": [
35+
"devicescript"
36+
],
37+
"author": "Microsoft",
38+
"publishConfig": {
39+
"access": "public"
40+
}
41+
}

packages/spi/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./spi"

packages/spi/src/main.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { describe, expect, test } from "@devicescript/test"
2+
3+
describe("drivers", () => {})

packages/spi/src/spi.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as ds from "@devicescript/core"
2+
3+
export interface SPIConfig {
4+
miso?: ds.InputPin
5+
mosi?: ds.OutputPin
6+
sck?: ds.OutputPin
7+
mode?: number
8+
hz?: number
9+
}
10+
11+
type DsSpi = typeof ds & {
12+
spiConfigure(
13+
miso: number,
14+
mosi: number,
15+
sck: number,
16+
mode: number,
17+
hz: number
18+
): void
19+
spiXfer(tx: Buffer, rx: Buffer): Promise<void>
20+
}
21+
22+
function pinNum(p: ds.Pin) {
23+
return p ? p.gpio : -1
24+
}
25+
26+
export function spiConfigure(cfg: SPIConfig) {
27+
;(ds as DsSpi).spiConfigure(
28+
pinNum(cfg.miso),
29+
pinNum(cfg.mosi),
30+
pinNum(cfg.sck),
31+
cfg.mode || 0,
32+
cfg.hz || 1000000
33+
)
34+
}
35+
36+
export async function spiWrite(buf: Buffer) {
37+
await (ds as DsSpi).spiXfer(buf, null)
38+
}
39+
40+
export async function spiRead(numbytes: number) {
41+
const r = Buffer.alloc(numbytes)
42+
await (ds as DsSpi).spiXfer(null, r)
43+
return r
44+
}
45+
46+
export async function spiXfer(buf: Buffer) {
47+
const r = Buffer.alloc(buf.length)
48+
await (ds as DsSpi).spiXfer(buf, r)
49+
return r
50+
}

packages/spi/src/tsconfig.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"compilerOptions": {
3+
"moduleResolution": "node",
4+
"target": "es2022",
5+
"module": "es2022",
6+
"lib": [],
7+
"strict": true,
8+
"strictNullChecks": false,
9+
"strictFunctionTypes": true,
10+
"sourceMap": false,
11+
"declaration": false,
12+
"experimentalDecorators": true,
13+
"preserveConstEnums": true,
14+
"noImplicitThis": true,
15+
"isolatedModules": true,
16+
"noImplicitAny": true,
17+
"moduleDetection": "force",
18+
"types": []
19+
},
20+
"include": ["**/*.ts", "../../core/src/*.ts"]
21+
}

plugin/src/plugin.ts

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ function init(modules: {
4141
"@devicescript/settings",
4242
"@devicescript/drivers",
4343
"@devicescript/gpio",
44+
"@devicescript/spi",
4445
"@devicescript/runtime",
4546
]) {
4647
json.peerDependencies[n] = "*"

runtime/devicescript/devs_bytecode.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@
261261
#define DEVS_BUILTIN_OBJECT_DSPACKETSPEC 38
262262
#define DEVS_BUILTIN_OBJECT_DSPACKETSPEC_PROTOTYPE 39
263263

264-
#define DEVS_BUILTIN_STRING___MAX 169
264+
#define DEVS_BUILTIN_STRING___MAX 171
265265
#define DEVS_BUILTIN_STRING__EMPTY 0
266266
#define DEVS_BUILTIN_STRING_MINFINITY 1 // -Infinity
267267
#define DEVS_BUILTIN_STRING_DEVICESCRIPT 2
@@ -432,6 +432,8 @@
432432
#define DEVS_BUILTIN_STRING_DELAY 167
433433
#define DEVS_BUILTIN_STRING_FROMCHARCODE 168
434434
#define DEVS_BUILTIN_STRING__ALLOCROLE 169
435+
#define DEVS_BUILTIN_STRING_SPICONFIGURE 170
436+
#define DEVS_BUILTIN_STRING_SPIXFER 171
435437

436438
#define DEVS_OP_HANDLERS \
437439
expr_invalid, exprx_builtin_object, stmt1_call0, stmt2_call1, stmt3_call2, stmt4_call3, \
@@ -475,7 +477,7 @@
475477
"_commandResponse", "isAction", "millis", "from", "hex", "utf8", "utf-8", "suspended", \
476478
"reboot", "server", "spec", "ServiceSpec", "classIdentifier", "lookup", "PacketSpec", \
477479
"parent", "response", "ServerInterface", "_onServerPacket", "_serverSend", \
478-
"notImplemented", "delay", "fromCharCode", "_allocRole"
480+
"notImplemented", "delay", "fromCharCode", "_allocRole", "spiConfigure", "spiXfer"
479481
#define DEVS_BUILTIN_OBJECT__VAL \
480482
"Math", "Object", "Object_prototype", "Array", "Array_prototype", "Buffer", \
481483
"Buffer_prototype", "String", "String_prototype", "Number", "Number_prototype", "DsFiber", \

runtime/devicescript/devs_internal.h

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ typedef struct devs_activation devs_activation_t;
3333
#define DEVS_PKT_KIND_SEND_PKT 2
3434
#define DEVS_PKT_KIND_SEND_RAW_PKT 3
3535
#define DEVS_PKT_KIND_SUSPENDED 4
36+
#define DEVS_PKT_KIND_AWAITING 5
3637

3738
typedef void (*devs_resume_cb_t)(devs_ctx_t *ctx, void *userdata);
3839

@@ -49,6 +50,7 @@ typedef struct devs_fiber {
4950
uint16_t resend_timeout;
5051
} reg_get;
5152
value_t v;
53+
uint8_t *awaiting;
5254
} pkt_data;
5355

5456
uint8_t pkt_kind : 4;
@@ -247,6 +249,8 @@ void devs_fiber_set_wake_time(devs_fiber_t *fiber, unsigned time);
247249
void devs_fiber_sleep(devs_fiber_t *fiber, unsigned time);
248250
void devs_fiber_termiante(devs_fiber_t *fiber);
249251
void devs_fiber_yield(devs_ctx_t *ctx);
252+
void devs_fiber_await(devs_fiber_t *fib, uint8_t *awaiting);
253+
void devs_fiber_await_done(uint8_t *awaiting);
250254
// if `args` is passed, `numparams==0`
251255
// otherwise, `numparams` arguments are sought on the_stack
252256
int devs_fiber_call_function(devs_fiber_t *fiber, unsigned numparams, devs_array_t *args);

runtime/devicescript/devs_proto.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ typedef struct {
1919
} handler;
2020
} devs_builtin_function_t;
2121

22-
#define DEVS_BUILTIN_MAX_ARGS 4
22+
#define DEVS_BUILTIN_MAX_ARGS 8 // not sure this does anything, except for the stack size
2323
#define DEVS_BUILTIN_FLAG_IS_PROPERTY 0x01
2424
#define DEVS_BUILTIN_FLAG_ASYNC_CALL 0x02
2525
#define DEVS_BUILTIN_FLAG_NO_SELF 0x04

runtime/devicescript/fibers.c

+15-1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,18 @@ void devs_fiber_sleep(devs_fiber_t *fiber, unsigned time) {
175175
devs_fiber_yield(fiber->ctx);
176176
}
177177

178+
void devs_fiber_await(devs_fiber_t *fib, uint8_t *awaiting) {
179+
*awaiting = 0;
180+
fib->pkt_kind = DEVS_PKT_KIND_AWAITING;
181+
fib->pkt_data.awaiting = awaiting;
182+
devs_fiber_sleep(fib, 0xffffffff);
183+
}
184+
185+
void devs_fiber_await_done(uint8_t *awaiting) {
186+
*awaiting = 1;
187+
JD_WAKE_MAIN();
188+
}
189+
178190
static void free_fiber(devs_fiber_t *fiber) {
179191
devs_jd_clear_pkt_kind(fiber);
180192
devs_ctx_t *ctx = fiber->ctx;
@@ -438,10 +450,12 @@ static int devs_fiber_wake_some(devs_ctx_t *ctx) {
438450
devs_fiber_t *fibmin = NULL;
439451

440452
for (devs_fiber_t *fiber = ctx->fibers; fiber; fiber = fiber->next) {
441-
if (fiber->role_wkp) {
453+
if (fiber->role_wkp ||
454+
(fiber->pkt_kind == DEVS_PKT_KIND_AWAITING && *fiber->pkt_data.awaiting)) {
442455
fibmin = fiber;
443456
break;
444457
}
458+
445459
if (fiber->wake_time && fiber->wake_time <= now_) {
446460
if (fibmin == NULL || fibmin->wake_time > fiber->wake_time)
447461
fibmin = fiber;

runtime/devicescript/impl_dsspi.c

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include "devs_internal.h"
2+
#include "services/interfaces/jd_spi.h"
3+
4+
void fun5_DeviceScript_spiConfigure(devs_ctx_t *ctx) {
5+
#if JD_SPI
6+
jd_spi_cfg_t cfg = {
7+
.miso = devs_arg_int(ctx, 0),
8+
.mosi = devs_arg_int(ctx, 1),
9+
.sck = devs_arg_int(ctx, 2),
10+
.mode = devs_arg_int(ctx, 3),
11+
.hz = devs_arg_int(ctx, 4),
12+
};
13+
14+
int r = jd_spi_init(&cfg);
15+
if (r)
16+
devs_throw_range_error(ctx, "SPI init failed: %d", r);
17+
#else
18+
devs_throw_not_supported_error(ctx, "SPI");
19+
#endif
20+
}
21+
22+
#if JD_SPI
23+
static uint8_t is_done;
24+
static void spi_done(void) {
25+
devs_fiber_await_done(&is_done);
26+
}
27+
28+
void throw_spi_error(devs_ctx_t *ctx, void *userdata) {
29+
devs_throw_range_error(ctx, "SPI error: %d", (int)(intptr_t)userdata);
30+
}
31+
#endif
32+
33+
void fun2_DeviceScript_spiXfer(devs_ctx_t *ctx) {
34+
#if JD_SPI
35+
value_t tx = devs_arg(ctx, 0);
36+
value_t rx = devs_arg(ctx, 1);
37+
38+
unsigned tx_sz;
39+
const void *tx_ptr = devs_bufferish_data(ctx, tx, &tx_sz);
40+
unsigned rx_sz;
41+
const void *rx_ptr = devs_bufferish_data(ctx, rx, &rx_sz);
42+
43+
if (!jd_spi_is_ready())
44+
devs_throw_range_error(ctx, "SPI busy");
45+
else if (!tx_ptr && !rx_ptr)
46+
devs_throw_expecting_error_ext(ctx, "at least one of TX/RX buffers", tx);
47+
else if (tx_ptr && rx_ptr && tx_sz != rx_sz)
48+
devs_throw_expecting_error_ext(ctx, "same size TX/RX buffers", tx);
49+
else if (rx_ptr && !devs_buffer_is_writable(ctx, rx))
50+
devs_throw_expecting_error_ext(ctx, "mutable Buffer", rx);
51+
else {
52+
if (!tx_sz)
53+
tx_sz = rx_sz;
54+
devs_fiber_t *fib = ctx->curr_fiber;
55+
devs_fiber_await(fib, &is_done);
56+
int r = jd_spi_xfer(tx_ptr, (void *)rx_ptr, tx_sz, spi_done);
57+
if (r) {
58+
// we've been already de-scheduled - arrange for exception on resume
59+
fib->resume_cb = throw_spi_error;
60+
fib->resume_data = (void *)r;
61+
devs_fiber_await_done(&is_done); // schedule resume
62+
}
63+
}
64+
65+
#else
66+
devs_throw_not_supported_error(ctx, "SPI");
67+
#endif
68+
}

runtime/devicescript/jdiface.c

+3
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ bool devs_jd_should_run(devs_fiber_t *fiber) {
375375
case DEVS_PKT_KIND_SEND_RAW_PKT:
376376
return handle_send_raw_pkt(fiber);
377377

378+
case DEVS_PKT_KIND_AWAITING:
379+
return *fiber->pkt_data.awaiting ? RESUME_USER_CODE : KEEP_WAITING;
380+
378381
default:
379382
JD_PANIC();
380383
}

0 commit comments

Comments
 (0)