Skip to content
This repository was archived by the owner on Aug 5, 2022. It is now read-only.

Commit 70a30cc

Browse files
Jimmy Huanggrgustaf
authored andcommitted
[sensor] Fix sensor to pass unit test (#791)
Sensor tests are broken because because the callstack is corrupted when sending IPM messages, and this patch rewrite the start sensor logic to have a callback that's called from the mainloop instead for a smaller call stack. Also fixed an issue where stop fails on AmbientLightSensor Signed-off-by: Jimmy Huang <[email protected]>
1 parent 2a5199e commit 70a30cc

File tree

1 file changed

+115
-68
lines changed

1 file changed

+115
-68
lines changed

src/zjs_sensor.c

Lines changed: 115 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ enum sensor_state {
3030
};
3131

3232
typedef struct sensor_handle {
33-
zjs_callback_id id;
33+
zjs_callback_id onchange_cb_id;
34+
zjs_callback_id onstart_cb_id;
35+
zjs_callback_id onstop_cb_id;
3436
enum sensor_channel channel;
3537
int frequency;
3638
enum sensor_state state;
@@ -83,6 +85,20 @@ static void zjs_sensor_free_handles(sensor_handle_t *handle)
8385
}
8486
}
8587

88+
static sensor_handle_t *zjs_sensor_get_handle(jerry_value_t obj)
89+
{
90+
uintptr_t ptr;
91+
sensor_handle_t *handle = NULL;
92+
if (jerry_get_object_native_handle(obj, &ptr)) {
93+
handle = (sensor_handle_t *)ptr;
94+
if (handle) {
95+
return handle;
96+
}
97+
}
98+
ERR_PRINT("cannot find handle");
99+
return NULL;
100+
}
101+
86102
static bool zjs_sensor_ipm_send_sync(zjs_ipm_message_t* send,
87103
zjs_ipm_message_t* result)
88104
{
@@ -178,11 +194,9 @@ static void zjs_sensor_set_state(jerry_value_t obj, enum sensor_state state)
178194
if (jerry_value_is_function(func)) {
179195
// if onstatechange exists, call it
180196
jerry_value_t new_state = jerry_create_string(state_str);
181-
jerry_value_t rval = jerry_call_function(func, obj, &new_state, 1);
182-
if (jerry_value_has_error_flag(rval)) {
183-
ERR_PRINT("calling onstatechange\n");
184-
}
185-
jerry_release_value(rval);
197+
zjs_callback_id id = zjs_add_callback_once(func, obj, NULL, NULL);
198+
zjs_signal_callback(id, &new_state, sizeof(new_state));
199+
jerry_release_value(new_state);
186200
}
187201
jerry_release_value(func);
188202

@@ -191,11 +205,8 @@ static void zjs_sensor_set_state(jerry_value_t obj, enum sensor_state state)
191205
func = zjs_get_property(obj, "onactivate");
192206
if (jerry_value_is_function(func)) {
193207
// if onactivate exists, call it
194-
jerry_value_t rval = jerry_call_function(func, obj, NULL, 0);
195-
if (jerry_value_has_error_flag(rval)) {
196-
ERR_PRINT("calling onactivate\n");
197-
}
198-
jerry_release_value(rval);
208+
zjs_callback_id id = zjs_add_callback_once(func, obj, NULL, NULL);
209+
zjs_signal_callback(id, NULL, 0);
199210
}
200211
jerry_release_value(func);
201212
}
@@ -262,11 +273,8 @@ static void zjs_sensor_trigger_error(jerry_value_t obj,
262273
zjs_set_property(error_obj, "name", name_val);
263274
zjs_set_property(error_obj, "message", message_val);
264275
zjs_set_property(event, "error", error_obj);
265-
jerry_value_t rval = jerry_call_function(func, obj, &event, 1);
266-
if (jerry_value_has_error_flag(rval)) {
267-
ERR_PRINT("calling onerrorhange\n");
268-
}
269-
jerry_release_value(rval);
276+
zjs_callback_id id = zjs_add_callback_once(func, obj, NULL, NULL);
277+
zjs_signal_callback(id, &event, 1);
270278
jerry_release_value(name_val);
271279
jerry_release_value(message_val);
272280
jerry_release_value(error_obj);
@@ -321,10 +329,10 @@ static void zjs_sensor_signal_callbacks(struct sensor_data *data)
321329
xyz[0] = data->reading.x;
322330
xyz[1] = data->reading.y;
323331
xyz[2] = data->reading.z;
324-
zjs_signal_callback(h->id, &xyz, sizeof(xyz));
332+
zjs_signal_callback(h->onchange_cb_id, &xyz, sizeof(xyz));
325333
} else {
326334
double dval = data->reading.dval;
327-
zjs_signal_callback(h->id, &dval, sizeof(dval));
335+
zjs_signal_callback(h->onchange_cb_id, &dval, sizeof(dval));
328336
}
329337
}
330338
}
@@ -357,53 +365,103 @@ static void zjs_sensor_callback_free(uintptr_t handle)
357365
zjs_free((sensor_handle_t *)handle);
358366
}
359367

360-
static jerry_value_t zjs_sensor_start(const jerry_value_t function_obj,
361-
const jerry_value_t this,
362-
const jerry_value_t argv[],
363-
const jerry_length_t argc)
368+
static void zjs_sensor_onstart_c_callback(void *h, void *argv)
364369
{
365-
// requires: this is a Sensor object from takes no args
366-
// effects: activates the sensor and start monitoring changes
367-
enum sensor_state state = zjs_sensor_get_state(this);
368-
if (state == SENSOR_STATE_ACTIVATING || state == SENSOR_STATE_ACTIVATED) {
369-
return ZJS_UNDEFINED;
370-
}
371-
372-
uintptr_t ptr;
373-
sensor_handle_t *handle = NULL;
374-
if (jerry_get_object_native_handle(this, &ptr)) {
375-
handle = (sensor_handle_t *)ptr;
376-
if (!handle) {
377-
return zjs_error("zjs_sensor_start: cannot find handle");
378-
}
370+
sensor_handle_t *handle = (sensor_handle_t *)h;
371+
if (!handle) {
372+
ERR_PRINT("handle not found\n");
373+
return;
379374
}
380375

381-
zjs_sensor_set_state(this, SENSOR_STATE_ACTIVATING);
376+
jerry_value_t obj = handle->sensor_obj;
382377
zjs_ipm_message_t send;
383378
send.type = TYPE_SENSOR_START;
384379
send.data.sensor.channel = handle->channel;
385380
send.data.sensor.frequency = handle->frequency;
386381
if (handle->channel == SENSOR_CHAN_LIGHT) {
387382
// AmbientLightSensor needs provide AIO pin value
388383
uint32_t pin;
389-
if (!zjs_obj_get_uint32(this, "pin", &pin)) {
390-
return zjs_error("zjs_sensor_start: pin not found");
384+
if (!zjs_obj_get_uint32(obj, "pin", &pin)) {
385+
zjs_sensor_trigger_error(obj, "DataError",
386+
"pin not found");
387+
return;
391388
}
392389
send.data.sensor.pin = pin;
393390
}
391+
394392
int error = zjs_sensor_call_remote_function(&send);
395393
if (error != ERROR_IPM_NONE) {
396394
if (error == ERROR_IPM_OPERATION_NOT_ALLOWED) {
397-
zjs_sensor_trigger_error(this, "NotAllowedError",
395+
zjs_sensor_trigger_error(obj, "NotAllowedError",
398396
"permission denied");
399-
return ZJS_UNDEFINED;
397+
} else {
398+
zjs_sensor_trigger_error(obj, "UnknownError",
399+
"IPM failed");
400+
}
401+
}
402+
403+
zjs_sensor_set_state(obj, SENSOR_STATE_ACTIVATED);
404+
}
405+
406+
static void zjs_sensor_onstop_c_callback(void *h, void *argv)
407+
{
408+
sensor_handle_t *handle = (sensor_handle_t *)h;
409+
if (!handle) {
410+
ERR_PRINT("handle not found\n");
411+
return;
412+
}
413+
414+
jerry_value_t obj = handle->sensor_obj;
415+
zjs_ipm_message_t send;
416+
send.type = TYPE_SENSOR_STOP;
417+
send.data.sensor.channel = handle->channel;
418+
419+
jerry_value_t reading_val = jerry_create_null();
420+
zjs_set_property(obj, "reading", reading_val);
421+
jerry_release_value(reading_val);
422+
if (handle->channel == SENSOR_CHAN_LIGHT) {
423+
// AmbientLightSensor needs provide AIO pin value
424+
uint32_t pin;
425+
if (!zjs_obj_get_uint32(obj, "pin", &pin)) {
426+
zjs_sensor_trigger_error(obj, "DataError",
427+
"pin not found");
428+
return;
400429
}
401-
else {
402-
// throw exception for all other errors
403-
return zjs_error("zjs_sensor_start: operation failed");
430+
send.data.sensor.pin = pin;
431+
}
432+
433+
int error = zjs_sensor_call_remote_function(&send);
434+
if (error != ERROR_IPM_NONE) {
435+
if (error == ERROR_IPM_OPERATION_NOT_ALLOWED) {
436+
zjs_sensor_trigger_error(obj, "NotAllowedError",
437+
"permission denied");
438+
} else {
439+
zjs_sensor_trigger_error(obj, "UnknownError",
440+
"IPM failed");
404441
}
442+
zjs_sensor_set_state(obj, SENSOR_STATE_ERRORED);
405443
}
406-
zjs_sensor_set_state(this, SENSOR_STATE_ACTIVATED);
444+
}
445+
446+
static jerry_value_t zjs_sensor_start(const jerry_value_t function_obj,
447+
const jerry_value_t this,
448+
const jerry_value_t argv[],
449+
const jerry_length_t argc)
450+
{
451+
// requires: this is a Sensor object from takes no args
452+
// effects: activates the sensor and start monitoring changes
453+
enum sensor_state state = zjs_sensor_get_state(this);
454+
if (state == SENSOR_STATE_ACTIVATING || state == SENSOR_STATE_ACTIVATED) {
455+
return ZJS_UNDEFINED;
456+
}
457+
458+
sensor_handle_t *handle = zjs_sensor_get_handle(this);
459+
if (!handle) {
460+
return zjs_error("cannot find handle");
461+
}
462+
463+
zjs_sensor_set_state(this, SENSOR_STATE_ACTIVATING);
464+
zjs_signal_callback(handle->onstart_cb_id, NULL, 0);
407465
return ZJS_UNDEFINED;
408466
}
409467

@@ -419,27 +477,15 @@ static jerry_value_t zjs_sensor_stop(const jerry_value_t function_obj,
419477
return ZJS_UNDEFINED;
420478
}
421479

422-
uintptr_t ptr;
423-
sensor_handle_t *handle = NULL;
424-
if (jerry_get_object_native_handle(this, &ptr)) {
425-
handle = (sensor_handle_t *)ptr;
426-
if (!handle) {
427-
return zjs_error("zjs_sensor_stop: cannot find handle");
428-
}
480+
sensor_handle_t *handle = zjs_sensor_get_handle(this);
481+
if (!handle) {
482+
return zjs_error("cannot find handle");
429483
}
430484

431-
zjs_ipm_message_t send;
432-
send.type = TYPE_SENSOR_STOP;
433-
send.data.sensor.channel = handle->channel;
434-
int error = zjs_sensor_call_remote_function(&send);
435-
if (error != ERROR_IPM_NONE) {
436-
// throw exception for all other errors
437-
return zjs_error("zjs_sensor_start: operation failed");
438-
}
439-
jerry_value_t reading_val = jerry_create_null();
440-
zjs_set_property(this, "reading", reading_val);
441-
jerry_release_value(reading_val);
485+
// we have to set state to idle first and then check if error occued
486+
// in the onstop_c_callback()
442487
zjs_sensor_set_state(this, SENSOR_STATE_IDLE);
488+
zjs_signal_callback(handle->onstop_cb_id, NULL, 0);
443489
return ZJS_UNDEFINED;
444490
}
445491

@@ -450,6 +496,7 @@ static jerry_value_t zjs_sensor_create(const jerry_value_t function_obj,
450496
enum sensor_channel channel)
451497
{
452498
double frequency = DEFAULT_SAMPLING_FREQUENCY;
499+
bool hasPin = false;
453500
uint32_t pin;
454501

455502
if (argc < 1 && channel == SENSOR_CHAN_LIGHT) {
@@ -486,9 +533,7 @@ static jerry_value_t zjs_sensor_create(const jerry_value_t function_obj,
486533
}
487534

488535
if (channel == SENSOR_CHAN_LIGHT) {
489-
if (!zjs_obj_get_uint32(options, "pin", &pin)) {
490-
return zjs_error("zjs_sensor_create: missing required field (pin)");
491-
}
536+
hasPin = zjs_obj_get_uint32(options, "pin", &pin);
492537
}
493538
}
494539

@@ -508,14 +553,16 @@ static jerry_value_t zjs_sensor_create(const jerry_value_t function_obj,
508553
zjs_set_property(sensor_obj, "reading", reading_val);
509554
jerry_release_value(reading_val);
510555

511-
if (channel == SENSOR_CHAN_LIGHT) {
556+
if (channel == SENSOR_CHAN_LIGHT && hasPin) {
512557
zjs_obj_add_number(sensor_obj, pin, "pin");
513558
}
514559

515560
jerry_set_prototype(sensor_obj, zjs_sensor_prototype);
516561

517562
sensor_handle_t* handle = zjs_sensor_alloc_handle(channel);
518-
handle->id = zjs_add_c_callback(handle, zjs_sensor_onchange_c_callback);
563+
handle->onchange_cb_id = zjs_add_c_callback(handle, zjs_sensor_onchange_c_callback);
564+
handle->onstart_cb_id = zjs_add_c_callback(handle, zjs_sensor_onstart_c_callback);
565+
handle->onstop_cb_id = zjs_add_c_callback(handle, zjs_sensor_onstop_c_callback);
519566
handle->channel = channel;
520567
handle->frequency = frequency;
521568
handle->sensor_obj = jerry_acquire_value(sensor_obj);

0 commit comments

Comments
 (0)