1 / 28

MoCo Programming Language Junkies

Converting Asynchronous Code to Synchronous Code with Embedded Lua. MoCo Programming Language Junkies. Josh Handley February 6, 2014. http://www.meetup.com/mcpjunkies /. Motivation. How do we support custom test protocols for a medical diagnostic device? Simple scripting language

kanoa
Download Presentation

MoCo Programming Language Junkies

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Converting Asynchronous Code to Synchronous Code with Embedded Lua MoCo Programming Language Junkies Josh Handley February 6, 2014 http://www.meetup.com/mcpjunkies/

  2. Motivation • How do we support custom test protocols for a medical diagnostic device? • Simple scripting language • Add new protocols without new firmware • Hide complexity

  3. What we Had voidTestingPage::instructionPageCancelled() { switch (screen_) { caseElectrodeSetup: test_->cancelTest(); // Mark this specific test as cancelled. A retry will make a new test. gotoConfirmCancelScreen(); break; caseAlignPupil: caseTesting: qCritical("instructionPageCancelled when aligning or testing pupil?"); // Can't happen. break; caseErrorOccurred: gotoConfirmCancelScreen(); break; caseConfirmingCancel: caseConfirmingSkip: emitrestartTest(); // User said no to cancel or skip. Tell the controller to restart the test. break;     } }

  4. What we Wanted connectElectrodes() alignPupil() setTestConfiguration(testParams) results = runTest() showResultsScreen(results)

  5. What Language to Use • Custom language Too much work • Python Too big • Javascript No coroutines • Scheme Too many parentheses • Lua Just right

  6. Overview of Lua • Small • 20,000 lines of C code • < 250K compiled • no dependencies • Easy to embed in C • Has coroutines • Significant commercial use • Game engines (Angry Birds, WoW) • Adobe Lightroom • Ginga(Brazillian Digital TV Spec)

  7. Basic Types -- Number print(12) -- 12 print(1.2) -- 1.2 print((1.2 + 0.8)/2) -- 1 -- Bool print(trueorfalseandtrue) -- true -- String print("hello") -- hello print("hello "..tostring(1)) -- hello 1 print(string.format("hello %d", 1)) -- hello 1

  8. DynamicTyping v = 12 print(type(v)) –- number v = "hello" print(type(v)) -- string

  9. Functions - Recursion functionfactorial(n) if n == 0 then return 1 else return n * factorial(n - 1) end end print(factorial(10)) -- 3628800

  10. Functions – Multiple Return Values functionaddVector(x1, y1, x2, y2) return x1 + y1, x2 +y2 end x, y = addVector(1, 6, 2, 4) print(x,y) -- 7 6

  11. Functions – First Class function curry(f, x) returnfunction (y, ...) returnf(x,y,...) end end plusOne= curry(function(x, y) return x + y end, 1) print(plusOne(2)) -- 3

  12. Global by Default -- global n = 12 s = "hello" functionsqr(x) return x * x end -- local to file localn_local = 12 locals_local = "hello2" localfunctionsqr_local(x) return x * x end -- local to block function foo() local message = "dude"-- not visible outside function print(message) print(s_local) -- locals in this file are in foo closure ("up values") end

  13. Loops -- repeat i = 1 repeat print(i) i = i + 1 untili == 5 -- while i= 1 whilei < 5 do print(i) i = i + 1 end -- for fori = 1, 4 do print(i) end

  14. Tables – THE Data Structure -- Arrays localarr = {1, 2, 3, 4, "foo"} print(arr[1]) -- 1 print(arr[5]) -- foo arr[8] = 12 print(arr[8]) – 12 print(arr[7]) -- nil

  15. Tables – THE Data Structure -- Dictionaries localdict = { firstName = "John", lastName = "Doe", dateOfBirth = {year = 1999, month = 12, day = 15} } print(dict.firstName) -- John print(dict.dateOfBirth.year) -- 1999 print(dict["firstName"]) -- John

  16. Tables - Iteration -- Arrays fori, v inipairs(arr) do print(i.." = "..tostring(v)) end -- Dictionaries for k, v in pairs(dict) do print(k.." = "..tostring(v)) end

  17. Errors -- error function error("This will abort the program and show this message") -- assert function assert(foo == 6, "Error: foo is not 6") -- nil, message pattern local file, errorMessage = io.open("myfile.txt", "r") if file == nilthen error("Error opening file: "..errorMessage) end -- nil, message with assert local file2 = assert(io.open("loops.lua", "r"))

  18. pcall localfunctionparseConfigFile(filename) … end local status, resultOrErrorMessage = pcall(parseConfigFile, "config.txt") if status then print(string.format("Sucessfully parsed config file.")) for k, v in pairs(resultOrErrorMessage) do print(k, v) end else print("Failed to parse config file. "..resultOrErrorMessage) end

  19. Coroutines - Generators localevenNumbers = coroutine.create(function() locali = 2 whiletruedo coroutine.yield(i) i = i + 2 end end ) print(evenNumbers) -- thread: 002FF108 print(coroutine.resume(evenNumbers)) -- true 2 print(coroutine.resume(evenNumbers)) -- true 4

  20. Coroutines – Producer/Consumer local producer = coroutine.create(function() fori = 1, 4 do print("Enter something:") coroutine.yield(io.read("*line")) end end ) local consumer = coroutine.create(function(prod) whiletruedo local status, value = coroutine.resume(prod) print("Consume: "..value) end end ) coroutine.resume(consumer, producer)

  21. CallingLuafrom C #include<lua.h> #include<lauxlib.h> #include<lualib.h> int main(intargc, char *argv[]) { lua_State* L = luaL_newstate(); luaL_openlibs(L); constchar *luaCode= "print('Hello World')"; luaL_dostring(L, luaCode); lua_close(L); return 0; }

  22. Exposing C functions to Lua intmyCFunction(lua_State* L) { constchar *arg = luaL_checkstring(L, -1); lua_pushstring(L, "Hello from C"); return 1; } int main(intargc, char *argv[]) { lua_State* L = luaL_newstate(); luaL_openlibs(L); lua_pushcfunction(L, myCFunction); lua_setglobal(L, "myCFunction"); constchar* luaCode = "local answerFromC = myCFunction('Hello From Lua')" "print('C says: '..answerFromC)"; luaL_dostring(L, luaCode); lua_close(L); return 0; }

  23. Back to the Original Problem • Create Lua bindings for our existing C++ objects/functions • Load Lua protocol script from disk • Create coroutine for the script • C++ resumes the coroutine • Lua scripts yield back to C++ to wait for events

  24. Coroutines Straight Line Code • C++ Event Loop • onStartTest() • Load protocol script • Create Luacoroutine • Resume coroutine • Back to event loop • onEventForLua() • Resume coroutine • If coroutine done end test • Back to event loop Lua showConnectElectrodeScreen() localevt repeat evt = waitForEvent() -- yields until evt.id == Event_Next

  25. Protocols Look Synchronous functionrunTests(testParameterList) localpreliminaryResults = {} teststeps.doConnectElectrodes() teststeps.doAlignPupil() ui.showTestingScreen() -- Run the tests fori = 1, #testParameterListdo localparams = testParameterList[i] localtestStimulus = stimconfig.buildStimulusConfig(params.flash, params.background) table.insert(preliminaryResults, teststeps.doTest(testStimulus)) ui.showTestingProgress(i, #testParameterList) end returnpreliminaryResults end

  26. Wrap Everything in a pcall whiletruedo localok,results_or_err = pcall(runTests, testParams) if ok then saveTestResults(results_or_err) break end local err = results_or_err -- If the user cancelled or skipped a test, confirm before taking action if err == RffID.Event_UI_Cancelledthen ifui.doConfirmCancelScreen() ~= RffID.Event_UI_Nextthen err = RffID.Event_UI_Restart end elseif err == RffID.Event_UI_Skippedthen ifui.doConfirmSkipScreen() ~= RffID.Event_UI_Nextthen err = RffID.Event_UI_Restart end end if err == RffID.Event_UI_Skippedthen break elseif err == RffID.Event_UI_Restartthen -- Back to top of loop to restart else -- Cancel or some other error, throw it again and let C++ (or another Luapcall) handle it error(err, 0) end end

  27. Lovin’ Lua • 4,000+ lines of Lua code • Beyond protocol scripts • On-board diagnostics • Interactive Lua shell for testing on device • Windows Lua shell controls device via RPC • Report generation • Viewing saved test results • Manufacturing/calibration

  28. Resources • Programming in Lua • http://www.lua.org/pil/ • Lua reference manual • http://www.lua.org/manual/5.2/ • luausers.org wiki • http://lua-users.org/wiki/ • Source code from this talk • http://github.com/jhandley/mcp-junkies-lua

More Related