forked from intel/zephyr.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzjs_aio_a101.c
301 lines (242 loc) · 8.05 KB
/
zjs_aio_a101.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
// Copyright (c) 2016-2018, Intel Corporation.
#ifdef BUILD_MODULE_AIO
#ifndef QEMU_BUILD
// C includes
#include <string.h>
// Zephyr includes
#include <misc/util.h>
// ZJS includes
#include "zjs_board.h"
#include "zjs_callbacks.h"
#include "zjs_event.h"
#include "zjs_ipm.h"
#include "zjs_util.h"
#define ZJS_AIO_TIMEOUT_TICKS 5000
const int MAX_TYPE_LEN = 20;
static struct k_sem aio_sem;
static jerry_value_t zjs_aio_prototype;
typedef struct aio_handle {
jerry_value_t pin_obj;
u32_t pin;
} aio_handle_t;
// get the aio handle or return a JS error
#define GET_AIO_HANDLE(obj, var) \
aio_handle_t *var = (aio_handle_t *)zjs_event_get_user_handle(obj); \
if (!var) { return zjs_error("no aio handle"); }
static bool zjs_aio_ipm_send_async(u32_t type, u32_t pin, void *data) {
zjs_ipm_message_t msg;
msg.id = MSG_ID_AIO;
msg.flags = 0;
msg.type = type;
msg.user_data = data;
msg.data.aio.pin = pin;
msg.data.aio.value = 0;
int success = zjs_ipm_send(MSG_ID_AIO, &msg);
if (success != 0) {
ERR_PRINT("failed to send message\n");
return false;
}
return true;
}
static bool zjs_aio_ipm_send_sync(zjs_ipm_message_t *send,
zjs_ipm_message_t *result)
{
send->id = MSG_ID_AIO;
send->flags = 0 | MSG_SYNC_FLAG;
send->user_data = (void *)result;
send->error_code = ERROR_IPM_NONE;
if (zjs_ipm_send(MSG_ID_AIO, send) != 0) {
ERR_PRINT("failed to send message\n");
return false;
}
// block until reply or timeout, we shouldn't see the ARC
// time out, if the ARC response comes back after it
// times out, it could pollute the result on the stack
if (k_sem_take(&aio_sem, ZJS_AIO_TIMEOUT_TICKS)) {
ERR_PRINT("FATAL ERROR, ipm timed out\n");
return false;
}
return true;
}
static void aio_free_cb(void *ptr)
{
aio_handle_t *handle = (aio_handle_t *)ptr;
// unsubscribe
zjs_aio_ipm_send_async(TYPE_AIO_PIN_UNSUBSCRIBE, handle->pin, handle);
jerry_release_value(handle->pin_obj);
zjs_free(handle);
}
static jerry_value_t zjs_aio_call_remote_function(zjs_ipm_message_t *send)
{
if (!send)
return zjs_error_context("invalid send message", 0, 0);
zjs_ipm_message_t reply;
bool success = zjs_aio_ipm_send_sync(send, &reply);
if (!success) {
return zjs_error_context("ipm message failed or timed out!", 0, 0);
}
if (reply.error_code != ERROR_IPM_NONE) {
ERR_PRINT("error code: %u\n", (unsigned int)reply.error_code);
return zjs_error_context("error received", 0, 0);
}
u32_t value = reply.data.aio.value;
return jerry_create_number(value);
}
// INTERRUPT SAFE FUNCTION: No JerryScript VM, allocs, or likely prints!
static void ipm_msg_receive_callback(void *context, u32_t id,
volatile void *data)
{
if (id != MSG_ID_AIO)
return;
zjs_ipm_message_t *msg = *(zjs_ipm_message_t **)data;
if (msg->flags & MSG_SYNC_FLAG) {
zjs_ipm_message_t *result = (zjs_ipm_message_t *)msg->user_data;
// synchronous ipm, copy the results
if (result) {
*result = *msg;
}
// un-block sync api
k_sem_give(&aio_sem);
} else {
// asynchronous ipm
aio_handle_t *handle = (aio_handle_t *)msg->user_data;
u32_t pin_value = msg->data.aio.value;
#ifdef DEBUG_BUILD
u32_t pin = msg->data.aio.pin;
#endif
ZVAL num = jerry_create_number(pin_value);
switch (msg->type) {
case TYPE_AIO_PIN_READ:
DBG_PRINT("aio async read %d\n", pin_value);
break;
case TYPE_AIO_PIN_EVENT_VALUE_CHANGE:
zjs_defer_emit_event(handle->pin_obj, "change", &num,
sizeof(num), zjs_copy_arg, zjs_release_args);
break;
case TYPE_AIO_PIN_SUBSCRIBE:
DBG_PRINT("subscribed to events on pin %u\n", pin);
break;
case TYPE_AIO_PIN_UNSUBSCRIBE:
DBG_PRINT("unsubscribed to events on pin %u\n", pin);
break;
default:
ERR_PRINT("IPM message not handled %u\n", (unsigned int)msg->type);
}
}
}
static jerry_value_t aio_pin_read(const jerry_value_t function_obj,
const jerry_value_t this,
const jerry_value_t argv[],
const jerry_length_t argc,
bool async)
{
GET_AIO_HANDLE(this, handle);
// send IPM message to the ARC side
zjs_ipm_message_t send;
send.type = TYPE_AIO_PIN_READ;
send.data.aio.pin = handle->pin;
jerry_value_t result = zjs_aio_call_remote_function(&send);
if (async) {
#ifdef ZJS_FIND_FUNC_NAME
zjs_obj_add_string(argv[0], ZJS_HIDDEN_PROP("function_name"),
"readAsync");
#endif
zjs_callback_id id = zjs_add_callback_once(argv[0], this, NULL, NULL);
zjs_signal_callback(id, &result, sizeof(result));
return ZJS_UNDEFINED;
} else {
return result;
}
}
static ZJS_DECL_FUNC(zjs_aio_pin_read)
{
return aio_pin_read(function_obj, this, argv, argc, false);
}
// Asynchronous Operations
static ZJS_DECL_FUNC(zjs_aio_pin_read_async)
{
// args: callback
ZJS_VALIDATE_ARGS(Z_FUNCTION);
return aio_pin_read(function_obj, this, argv, argc, true);
}
static ZJS_DECL_FUNC(zjs_aio_pin_close)
{
u32_t pin;
zjs_obj_get_uint32(this, "pin", &pin);
GET_AIO_HANDLE(this, handle);
aio_free_cb(handle);
return ZJS_UNDEFINED;
}
static ZJS_DECL_FUNC(zjs_aio_open)
{
// args: initialization object or int/string pin number
ZJS_VALIDATE_ARGS(Z_NUMBER Z_STRING Z_OBJECT);
ZVAL_MUTABLE pin_str = 0;
jerry_value_t pin_val = argv[0];
jerry_value_t init = 0;
if (jerry_value_is_object(argv[0])) {
init = argv[0];
pin_str = zjs_get_property(init, "pin");
pin_val = pin_str;
}
char devname[20];
int pin = zjs_board_find_aio(pin_val, devname, 20);
if (pin == FIND_PIN_INVALID) {
return TYPE_ERROR("bad pin argument");
} else if (pin == FIND_DEVICE_FAILURE) {
return zjs_error("device not found");
} else if (pin < 0) {
return zjs_error("pin not found");
}
// send IPM message to the ARC side
zjs_ipm_message_t send;
send.type = TYPE_AIO_OPEN;
send.data.aio.pin = pin;
ZVAL result = zjs_aio_call_remote_function(&send);
if (jerry_value_is_error(result))
return result;
// create the AIOPin object
jerry_value_t pinobj = zjs_create_object();
jerry_set_prototype(pinobj, zjs_aio_prototype);
aio_handle_t *handle = zjs_malloc(sizeof(aio_handle_t));
if (!handle) {
return zjs_error("out of memory");
}
memset(handle, 0, sizeof(aio_handle_t));
handle->pin = pin;
// TODO: verify that not acquiring here is okay
handle->pin_obj = pinobj;
// make it an emitter object
zjs_make_emitter(pinobj, zjs_aio_prototype, handle, aio_free_cb);
zjs_aio_ipm_send_async(TYPE_AIO_PIN_SUBSCRIBE, pin, handle);
return pinobj;
}
static void zjs_aio_cleanup(void *native)
{
jerry_release_value(zjs_aio_prototype);
}
static const jerry_object_native_info_t aio_module_type_info = {
.free_cb = zjs_aio_cleanup
};
jerry_value_t zjs_aio_init()
{
zjs_ipm_init();
zjs_ipm_register_callback(MSG_ID_AIO, ipm_msg_receive_callback);
k_sem_init(&aio_sem, 0, 1);
zjs_native_func_t array[] = {
{ zjs_aio_pin_read, "read" },
{ zjs_aio_pin_read_async, "readAsync" },
{ zjs_aio_pin_close, "close" },
{ NULL, NULL }
};
zjs_aio_prototype = zjs_create_object();
zjs_obj_add_functions(zjs_aio_prototype, array);
// create global AIO object
jerry_value_t aio_obj = zjs_create_object();
zjs_obj_add_function(aio_obj, "open", zjs_aio_open);
jerry_set_object_native_pointer(aio_obj, NULL, &aio_module_type_info);
return aio_obj;
}
JERRYX_NATIVE_MODULE(aio, zjs_aio_init)
#endif // QEMU_BUILD
#endif // BUILD_MODULE_AIO