Main /
Duktape Implementation in ARM-M4Minimum RequirementsIn order to use Accessor in with Duktape, the system shall have the following as a minimum:
Note: Above configuration is assuming bare-metal application, OS is NOT considered. Duktape ConfigurationFor smaller devices like ARM-Cortex M without File System the next options needs to be set:
For details on what each option does, refer to Duktape Feature Options Duktape Auxiliary print optionDuktape implements the print function as a mechanism to send information to the screen. In case of small devices, there is no such availability, however it is possible to create a new print function which will redirect the information to a desired port or display. Example: Using Semi-host trace function as Duktape printWhen Duktape has the option DUK_OPT_NO_FILE_IO it automatically disable all print functions. To create and register a new function using the Semihost option trace provided in Eclipse, use the next funciton #include <stdio.h> #include "duktape.h" static duk_ret_t my_print(duk_context *ctx) { duk_idx_t i, n; trace_printf("PRINT: "); for (i = 0, n = duk_get_top(ctx); i < n; i++) { if (i > 0) { trace_printf(" "); } trace_printf("%s", duk_safe_to_string(ctx, i)); } trace_printf("\n"); return 0; } void my_print_register(duk_context *ctx) { duk_push_global_object(ctx); duk_push_c_function(ctx, my_print, DUK_VARARGS); duk_put_prop_string(ctx, -2, "print"); duk_pop(ctx); } Call the function my_print_register and now we have a print function available. It can be changed to send data via serial port or any other way. Accessor Host Integration to DuktapeAccessor duktape is divided in two groups:
As it appears in the terraswarm repository, we can divide the files as shown below: As it can be seen, the file nofileio.c has a double function:
If it is desired to modify the application, it will be necessary to re-create nofileio.c Necessary Modifications
// print_pop_error is from Duktape's duk_cmdline.c /* Print error to stderr and pop error. */ void print_pop_error(duk_context *ctx) { /* Print error objects with a stack trace specially. * Note that getting the stack trace may throw an error * so this also needs to be safe call wrapped. */ (void) duk_safe_call(ctx, get_stack_raw, 1 /*nargs*/, 1 /*nrets*/); trace_printf("%s\n", duk_safe_to_string(ctx, -1)); // fflush(f); duk_pop(ctx); } main Function callThe main function to run Accessor consist of function registration and event thread execution as follows int main (void) { const char *accessorFileName = "RampJSTestDisplay.js"; // Desired Accessor to run duk_context *ctx = NULL; int timeout = 5000; int returnValue = 0; // Normally at this stage most of the microcontroller subsystems, including // the clock, were initialised by the CMSIS SystemInit() function invoked // from the startup file, before calling main(). // (see system/src/cortexm/_initialize_hardware.c) // If further initialisations are required, customise __initialize_hardware() // or add the additional initialisation here, for example: // trace_puts("Hello ARM-M$ World!"); HAL_Init(); // Create duktape environment ctx = duk_create_heap_default(); // Register Modules eventloop_register(ctx); modSearch_register(ctx); nofileio_register(ctx); my_print_register(ctx); trace_printf("Registered all the modules.\n"); trace_printf("eduk: About to run %s\n", accessorFileName); returnValue = runAccessorHost(ctx, accessorFileName, timeout); return returnValue; } runAccessorHost/** Run the accessor. * @param accessorFileName The file name of the accessor, suitable getAccessorCode() * @param timeout The number of milliseconds to wait after the * accessor is instantiated and initialized. If the timeout is less than zero, * then the timeout will be forever. * @return 0 if successfully, non-zero if there is an error. */ int runAccessorHost(duk_context *ctx, const char *accessorFileName, int timeout) { int rc; //ftrace_printf(stderr, "%s:%d: About to load C version of c_eventloop.\n", __FILE__, __LINE__); // Use duk_peval_string_noresult() and avoid interning the string. Good // for low memory, see // http://duktape.org/api.html#duk_peval_string_noresult if (duk_peval_string(ctx, c_eventloop_js) != 0) { trace_printf("%s:%d: Loading C version of c_eventloop failed. Error was:\n", __FILE__, __LINE__); print_pop_error(ctx); return 1; } else { trace_printf("%s: Loading C version of c_eventloop worked\n", __FILE__); duk_pop(ctx); } // Use duk_peval_string_noresult() and avoid interning the string. Good // for low memory, see // http://duktape.org/api.html#duk_peval_string_noresult if (duk_peval_string(ctx, ___duktapeHost_js) != 0) { trace_printf("%s:%d: Loading C version of duktapeHost failed. Error was:\n", __FILE__, __LINE__); print_pop_error(ctx); return 2; } else { trace_printf("%s: Loading C version of duktapeHost worked\n", __FILE__); duk_pop(ctx); } // Call instantiateAndInitialize() on the accessorFileName, then timeout. // Build the command to be evaled. int length = my_strlen(accessorFileName) + 200; char buf[length]; if (timeout >= 0) { // Timeout. requestEventLoopExit() is defined in ecma_eventloop.js. snprintf(buf, length, "var args = ['%s'];\ninstantiateAndInitialize(args);\nsetTimeout(function () {requestEventLoopExit()}, %d);", accessorFileName, timeout); } else { // Prevent the script from exiting by repeating the empty function // every ~25 days. snprintf(buf, length, "var args = ['%s'];\ninstantiateAndInitialize(args);\nsetInterval(function () {}, 2147483647);", accessorFileName); } // Eval the command, avoid interning the string. if (duk_peval_string(ctx, buf) != 0) { trace_printf("%s:%d: Failed to invoke accessor %s. Command was:\n%s\nError was:\n", __FILE__, __LINE__, accessorFileName, buf); print_pop_error(ctx); return 3; } else { duk_pop(ctx); } // Compile solution //duk_compile(ctx, 0); /* duk_push_global_object(ctx); /\* 'this' binding *\/ */ /* duk_insert(ctx, -2); /\* [ ... global func ] *\/ */ /* duk_put_prop_string(ctx, -2, "_USERCODE"); */ /* duk_pop(ctx); */ /* duk_eval_string(ctx, "setTimeout(function() { _USERCODE(); }, 0);"); */ /* duk_pop(ctx); */ rc = duk_safe_call(ctx, eventloop_run, 0 /*nargs*/, 1 /*nrets*/); if (rc != 0) { trace_printf("%s:%d: %s: Failed invoke eventloop_run()\n", __FILE__, __LINE__, accessorFileName); return 4; } trace_printf("runAccessorHost() done.\n"); return 0; } IssuesOnce that above changes were completed, we built the system and tried to run it on ARM-Cortex M4 (LPC 4088)
eduk: About to run RampJSTestDisplay.js ../src/main.c:61 Loading C version of c_eventloop failed. Error was: SyntaxError: utf8 decode failed (line 1) ../src/main.c:1 duk_lexer.c:314 We tried using different J2H tool (the one that we developed internally) and the program started running. PRINT: loading module: commonHost SyntaxError: utf8 decode failed (line 1) ../src/main.c:1 duk_lexer.c:314 As we progress, we identified that all JS programs needed to be re-created. We replaced all JS files and the system worked as expected. Hello ARM-M$ World! SDRMA Init and OK Registered all the modules. eduk: About to run RampJSTestDisplay.js ../src/main.c: Loading C version of c_eventloop worked PRINT: loading module: commonHost PRINT: loading module: util PRINT: loading module: events ../src/main.c: Loading C version of duktapeHost worked PRINT: duktapeHost.js: instantiateAndInitialize() start: RampJSTestDisplay.js 1 PRINT: duktapeHost.js: instantiateAndInitialize(): about to handle RampJSTestDisplay.js PRINT: duktapeHost.js: instantiateAndInitialize(): about to call initialize name RampJSTestDisplay.js Class RampJSTestDisplay.js PRINT: duktapeHost.js: before instantiate() : accessor RampJSTestDisplay.js with class RampJSTestDisplay.js PRINT: Memory allocated successfully for accessor = RampJSTestDisplay.js.TestSpontaneous PRINT: Memory allocated successfully for accessor = RampJSTestDisplay.js.TestDisplay PRINT: Memory allocated successfully for accessor = RampJSTestDisplay.js.TrainableTest PRINT: Memory allocated successfully for accessor = RampJSTestDisplay.js PRINT: duktapeHost.js: instantiate() done: Instantiated accessor RampJSTestDisplay.js with class RampJSTestDisplay.js PRINT: duktapeHost.js: instantiateAndInitialize(): about to call initialize on [object Object] PRINT: duktapeHost.js: instantiateAndInitialize(): done with RampJSTestDisplay.js PRINT: duktapeHost.js: instantiateAndInitialize() done PRINT: 1 PRINT: 2 PRINT: 3 PRINT: 4 Comparing both one file using Terraswarm J2H tool and ours we notice:
See Also
|