Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 42
Scripting Tutorial - Lesson 42: Lua Scripting and the TI Innovator™ Hub:
2. READING from the Hub
TI Innovator™ Hub Lesson 0: Using Lua to store and edit TI-BASIC programs for the Innovator™ Hub (Lua Scripting Lesson 40)
TI Innovator™ Hub Lesson 1: SENDING to the Hub: Controlling the Action (Lua Scripting Lesson 41)
TI Innovator™ Hub Lesson 2: READING from the Hub: Real world interaction and data (Lua Scripting Lesson 42)
TI Innovator™ Hub Lesson 3: Exploring the OneShotTimer: Learning to Wait! (Lua Scripting Lesson 43)
TI Innovator™ Hub Lesson 4: Making Music with the Innovator™ Hub (Lua Scripting Lesson 44)
TI Innovator™ Hub Lesson 5: Lua Script for the Norland Research/TI Innovator™ Hub Robot (Lua Scripting Lesson 45)
TI Innovator™ Hub Lesson 6: Build your own Innovator™ Hub Robot (Lua Scripting Lesson 46)
TI Innovator™ Hub Lesson 7: Create a general Innovator™ Hub Document (Lua Scripting Lesson 47)
TI Innovator™ Hub Lesson 8: Create a general Innovator™ Hub and BLE Document (Lua Scripting Lesson 48)
Download supporting file for this tutorial
Texas Instruments TI-Nspire Scripting Support Page
Scripting for the Innovator Hub: Lesson 2: READING from the Hub
I have heard the two key principles of STEM described as feedback and control.
If SENDING to the Hub is the basis of control, then reading is all about feedback: asking for information, collecting that information, organising and making sense, and then acting on what you have learned.
The wide range of sensors and other peripherals supported by the Innovator™ Hub give students and teachers a wealth of possibilities for gathering information and seeking to understand the world around them. They also give many opportunities for the creation of great dynamic and engaging lesson materials.
There are very few changes between this script and that of Lesson 1 - but this makes it worthwhile studying those changes closely and seeking to better understanding the key workings of our Innovator platform.
What do you notice in the initial values and functions?
We will continue to use variables hubStrOn and hubStrOff, even though the latter does not play a part here - this will determine the focus of the interaction, whether that be the default in-built brightness sensor, or one of the many others available.
The other key change lies in the menu offering: you will see quite a different "sample" menu here: instead of turning LEDs on and off, and playing sounds, we CONNECT a range of peripherals (I have selected just a few that I had available) and instruct the Hub to READ that device - or, more correctly, to read the voltage from that port.
NOTE that only brightness does not require a "connect" instruction to be sent - all other peripherals need to be linked to an appropriate port on the Hub. You should note that ports IN1, IN2, OUT1 and OUT2 are all 3.3V ports, while IN3 and OUT3 carry 5V. Some sensors are very particular about their voltage - so be careful with this.
You will see that, for each of the READ Samples (other than brightness), a CONNECT command is sent to the Hub: this needs to only occur once; subsequent calls to read that device will understand where it is to be found.
I would finally draw your attention to the last two "READ" options: reading generic peripherals ANALOG.IN and DIGITAL.IN - as introduced in the previous lesson, these generic commands can be used to advantage in many situations, and stand in for specific peripherals.
- As previous, with the addition of a display line for the readings to be shown.
Here we most certainly require the three Innovator functions - study them closely and see why!
In particular, the important TI_InnovatorReadCallback function, which read and defines rxValue ("received value"), which may be numeric (such as brightness or ranger distance), string (such as 'READY') or even list (such as DHT - Digitial Temperature and Humidity, Accelerometer or Barometer).
You will see the utility function list2str defined to grab just the first value of a list separated by carriage returns (string.char(10)).
For interest, the voltage is also calculated, since this is how varying values are actually read by the Hub.
A challenge: how might we use the oneShotTimer to read the current sensor repeatedly, instead of just the once when the mouse is pressed?
- These functions are as previously defined.
Once again, if you have a Hub, you can test this script yourself by copying and pasting from this page. Of course, prepared versions are also available from the download link for this page.
end-- TI Innovator Init Values
platform.apilevel = '2.7' local screen = platform.window local date = "021517"
require 'color' pcall(function() require 'asi' end)
local isASIavailable = false local hubStrOn, hubStrOff, msgStr, rxValue
function addMsg(input)
msgStr = input print(msgStr) screen:invalidate()end
function on.construction()
end--the next three lines are required for Hub connection TI_Innovator.init(TI_InnovatorStateCallback) TI_Innovator.setReadListener(TI_InnovatorReadCallback) TI_Innovator.connect()
Menu={
{"About",} toolpalette.register(Menu) screen:invalidate(){" ©2017 Compass Learning Technologies", function() end}, {" Version "..date, function() end}, {" Contact: steve@compasstech.com.au ", function() end},}, {"Controls",{"Scan and Connect", function() TI_Innovator.connect() end}, {"Disconnect", function() TI_Innovator.disconnect() on.resize() end}, {"RESET", function() on.resize() end},}, {"SET Samples", {"SET LIGHT ON/OFF (default)", function() hubStrOn = "SET LIGHT ON" hubStrOff = "SET LIGHT OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.RED ON/OFF", function() hubStrOn = "SET COLOR.RED ON" hubStrOff = "SET COLOR.RED OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" hubStrOff = "SET COLOR.GREEN OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.BLUE ON/OFF", function() hubStrOn = "SET COLOR.BLUE ON" hubStrOff = "SET COLOR.BLUE OFF" TI_Innovator.Send(hubStrOn) end}, {"SET SOUND 220 5", function() hubStrOn = "SET SOUND 220 5" hubStrOff = "SET SOUND 0 1" TI_Innovator.Send(hubStrOn) end}, {"SET SPEAKER 1 220 5", function() hubStrOn = "SET SPEAKER 1 220 5" TI_Innovator.Send("CONNECT SPEAKER 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET SPEAKER 1 0 1" end}, {"SET LED 1 ON", function() hubStrOn = "SET LED 1 ON" TI_Innovator.Send("CONNECT LED 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET LED 1 0FF" end}, {"SET SERVO 1 CW 50 5", function() TI_Innovator.Send("CONNECT SERVO 1 OUT3") hubStrOn = "SET SERVO 1 CW 50 5" hubStrOff = "SET SERVO 1 CW 50 0" TI_Innovator.Send(hubStrOn) end}, {"SET ANALOG.OUT 1 100", function() hubStrOn = "SET ANALOG.OUT 1 100" TI_Innovator.Send("CONNECT ANALOG.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET ANALOG.OUT 1 0" end}, {"SET DIGITAL.OUT 1 ON", function() hubStrOn = "SET DIGITAL.OUT 1 ON" TI_Innovator.Send("CONNECT DIGITAL.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET DIGITAL.OUT 1 0FF" end}, }, {"READ Samples",{"READ BRIGHTNESS (default)", function() hubStrOn = "READ BRIGHTNESS" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ RANGER 1", function() hubStrOn = "READ RANGER 1" TI_Innovator.Send("CONNECT RANGER 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ DHT 1", function() hubStrOn = "READ DHT 1" TI_Innovator.Send("CONNECT DHT 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ ACCEL 1", function() hubStrOn = "READ ACCEL 1" TI_Innovator.Send("CONNECT ACCEL 1 I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ BAROMETER", function() hubStrOn = "READ BAROMETER" TI_Innovator.Send("CONNECT BAROMETER I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ ANALOG.IN 1", function() hubStrOn = "READ ANALOG.IN 1" TI_Innovator.Send("CONNECT ANALOG.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = hubStrOn end}, {"READ DIGITAL.IN 1", function() hubStrOn = "READ DIGITAL.IN 1" TI_Innovator.Send("CONNECT DIGITAL.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = hubStrOn end},},-- Layout Functions
function on.resize(width, height)
w = screen:width() h = screen:height() hubStrOn, hubStrOff, msgStr, rxValue = "READ BRIGHTNESS", "READ BRIGHTNESS", "READ BRIGHTNESS", "" if TI_Innovator.isConnected() then TI_Innovator.Send('BEGIN') addMsg("TI Innovator Hub ready") end screen:invalidate()endfunction on.paint (gc)
endif TI_Innovator.isConnected() then
gc:setColorRGB (0,255,0) gc:fillRect (0, 0, w, 0.025*h)else gc:setColorRGB (255,0,0) gc:fillRect (0, 0, w, 0.025*h) gc:drawString("Wait for connection, then", 0.1*w, 0.1*h, "middle") gc:drawString("press anywhere to activate Hub", 0.1*w, 0.2*h, "middle")gc:drawString(msgStr, 0.05*w, 0.8*h, "middle") gc:drawString(rxValue, 0.05*w, 0.9*h, "middle")
-- TI Innovator User set up
function on.escapeKey()
TI_Innovator.Send(hubStrOff) on.resize() screen:invalidate()endfunction on.mouseDown(x, y)
TI_Innovator.Send(hubStrOn) -- This is an example of sending a SET command to the Hub TI_Innovator.Read() -- This is an example of sending a READ command to the Hub screen:invalidate()endfunction on.mouseUp (x,y)
TI_Innovator.Send(hubStrOff) TI_Innovator.Read() screen:invalidate()endfunction str2list(input, def) local list = {} if input:find(def) then
list = input:split(def) table.foreachi(list,print)elselist = {input}end return list endfunction TI_InnovatorReadCallback(port, error_msg) -- this is the callback function that is defined above and catches the result of a READ command sent to the Hub.
rxValue = port:getValue() or '' -- this gets the actual return value from the hub and puts it in the variable rxValue. The user may choose any variable name and also may do any calibration or ranging of the value here. Note that rxValue may be numeric, list or string (hence the utility function str2list) if tonumber(rxValue) then rxValue = math.floor(100*rxValue+0.5)/100 else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end addMsg(hubStrOn) if tonumber(rxValue) then voltage = (rxValue/2^14)*3.3 end -- an example of converting a raw 14 bit ADC value into voltage. screen:invalidate()endfunction TI_InnovatorStateCallback(event)
endaddMsg("TI_InnovatorStateCallback") if 'ready' == event then TI_InnovatorConfig() elseif "disconnected" == event then -- user may choose to do some clean up or display a msg when the Hub is disconnected. addMsg("TI_Innovator Hub disconnected") end screen:invalidate()
function TI_InnovatorConfig() -- this function is called from TI_InnovatorStateCallback() when a ready connection is succesful.
-- place CONNECT and other Hub startup commands here addMsg("TI_Innovator Hub connected")end--End of user code do not modify below this line
-- TI Innovator Code Do not modify any code below this line
-- oneShotTimer BEGINS
local timerstart = timer.start local timerstop = timer.stop timer.start = nil timer.stop = nil local currentTimer = nil
local function timerStart(t)
endcurrentTimer = t timerstart(t.period/1000)
local function timerStop()
endcurrentTimer = nil timerstop()
local function setTimer(t)
endif t.period==nil or type(t.period)~='number' or t.period < 10 then error('period in milliseconds >= 10') end timerStart(t) return t
function oneShotTimer(period, listenerHandler, ...)
endif type(listenerHandler) ~= 'function' then
error('createTimerOneShot: function expected')end setTimer {period = period, oneShot = true, listenerHandler = listenerHandler, params = { ... },}function on.timer()
endlocal ct = currentTimer if currentTimer == nil then
timerStop()end if currentTimer.oneShot thencurrentTimer = nil timerStop()end ct.listenerHandler(unpack(ct.params))-- oneShotTimer ENDS
-- TI Innovator BEGINS
TI_Innovator = { }
function TI_Innovator.init(theStateCallback)
endif not pcall(function() require 'asi' end) then
addMsg('Hub NOT available') returnendaddMsg('Hub available')
isASIavailable = true
local HANDSHAKE_GREETING = 'ISTI\n' local HANDSHAKE_ANSWER = 'TISTEM' local portFoundList = { } local state local handshakeState local notifyEvent local asiStateListener local startScanning local stopScanning local portFoundListener local portStateListener local handshake_SendListener local handshake_readListener local handshake_port local TI_Innovator_port local baudRate = asi.BAUD_RATE_DEFAULT local readTimeout = asi.READ_TIMEOUT_DEFAULT
-- User callbacks local stateCallback = theStateCallback local SendCallback local readCallback
function notifyEvent(event)
addMsg('notifying '.. event) if stateCallback thenendstateCallback(event)elseaddMsg('no callback registered')endfunction startScanning()
if isASIavailable thenendasi.startScanning(portFoundListener) notifyEvent('scanning')endfunction stopScanning()
handshake_port = nil portFoundList = { } asi.stopScanning()endfunction asiStateListener(asiState)
if asi.ON == asiState thenendif state == 'active' thenelseif asi.UNSUPPORTED == asiState thenstartScanning()endnotifyEvent(asi.UNSUPPORTED)endfunction portFoundListener(portFound)
addMsg('portFoundListener '.. portFound:getName()) table.insert(portFoundList, portFound) if not TI_Innovator_port and not handshake_port thenendhandshake_port = portFoundList[1] oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)endfunction portStateListener(reportedPort, event, error_msg)
addMsg('portStateListener '..reportedPort:getName()..' '..event) if asi.CONNECTED == event thenend-- configure port for handshake reportedPort:setWriteListener(handshake_writeListener) reportedPort:setReadListener(handshake_readListener) reportedPort:setReadTimeout(500) handshakeState = 'handshake' -- write handshake greeting addMsg("HANDSHAKE_GREETING: "..HANDSHAKE_GREETING) oneShotTimer(200, reportedPort.write, reportedPort, HANDSHAKE_GREETING)elseif asi.CONNECTING_FAILED == event thenif reportedPort == handshake_port thenelseif asi.DISCONNECTED == event thentable.remove(portFoundList, 1) if #portFoundList>0 thenelseif reportedPort == TI_Innovator_port thenhandshake_port = portFoundList[1] handshake_port:connect(portStateListener)elsehandshake_port = nilendTI_Innovator_port = nil asi.startScanning(portFoundListener)endif reportedPort == TI_Innovator_port thenendif state == 'active' thenendif reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')reportedPort:connect(portStateListener)elseTI_Innovator_port = nil asi.startScanning(portFoundListener)endfunction handshake_writeListener(reportedPort, error_msg)
if error_msg thenendaddMsg('handshake_writeListener '..error_msg) returnend if 'handshake' == handshakeState thenreportedPort:read(#HANDSHAKE_ANSWER+2)endfunction handshake_readListener(reportedPort, error_msg)
if error_msg thenendaddMsg('handshake_writeListener '..error_msg) returnend local answer = reportedPort:getValue() if 'handshake' == handshakeState then-- Validate answer if answer and answer:find(HANDSHAKE_ANSWER) thenelseif 'ready' == handshakeState thenaddMsg("HANDSHAKE_ANSWER: "..HANDSHAKE_ANSWER) stopScanning() handshakeState = 'ready' reportedPort:write('BEGIN\n') reportedPort:read(7)elsereportedPort:disconnect() table.remove(portFoundList, 1) if #portFoundList>0 thenendhandshake_port = portFoundList[1] handshake_port:connect(portStateListener)elsehandshake_port = nilendif answer and answer:find('READY') thenend-- Configure port for normal use TI_Innovator_port = reportedPort TI_Innovator_port:setReadTimeout(readTimeout) TI_Innovator.setWriteListener(SendCallback) TI_Innovator.setReadListener(readCallback) -- Notify launchpad is ready notifyEvent('ready')end-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active' startScanning()endfunction TI_Innovator.disconnect()
state = 'inactive' if isASIavailable thenendif TI_Innovator_port thenendTI_Innovator_port:disconnect() TI_Innovator_port = nilend stopScanning()function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallback if TI_Innovator_port thenendTI_Innovator_port:setWriteListener(writeCallback)endfunction TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallback if TI_Innovator_port thenendTI_Innovator_port:setReadListener(readCallback)endfunction TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRate if TI_Innovator_port thenendTI_Innovator_port:setBaudRate(baudRate)endfunction TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeout if TI_Innovator_port thenendTI_Innovator_port:setReadTimeout(readTimeout)endfunction TI_Innovator.Send(data)
if not TI_Innovator_port thenendaddMsg('No Hub attached') return 'No Hub attached'end local result = TI_Innovator_port:write(data .. '\n') if result then addMsg(tostring(data)..': '.. tostring(result)) else addMsg(tostring(data)) end return resultfunction TI_Innovator.Read(bytes_to_read)
addMsg('TI_Innovator.Read') if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:read(bytes_to_read)function TI_Innovator.request(request)
if not TI_Innovator_port thenendreturn "No TI Hub attached"end local result = TI_Innovator_port:write(request .. '\n') if result then addMsg(tostring(request) .. '): '.. tostring(result)) else addMsg(tostring(request)) end result = TI_Innovator_port:read() addMsg('read() '.. tostring(result)) if result thenaddMsg('Error sending request: ' .. tostring(request))end return resultfunction TI_Innovator.isConnected()
if not TI_Innovator_port thenendreturn falseend return TI_Innovator_port:getState() == asi.CONNECTEDfunction TI_Innovator.getName()
if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:getName()function TI_Innovator.getIdentifier()
if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:getIdentifier()-- INTERFACE -- ENDS --
-- Wait for the ASI to be up and running
asi.addStateListener(asiStateListener)
end
-- TI Innovator Init Values
platform.apilevel = '2.7' local screen = platform.window local date = "021517"
require 'color' pcall(function() require 'asi' end)
local isASIavailable = false local hubStrOn, hubStrOff msgStr, rxValue
function addMsg(input)
msgStr = input print(msgStr) screen:invalidate()end
function on.construction()
end--the next three lines are required for Hub connection TI_Innovator.init(TI_InnovatorStateCallback) TI_Innovator.setReadListener(TI_InnovatorReadCallback) TI_Innovator.connect()
Menu={
{"About",} toolpalette.register(Menu) screen:invalidate(){" ©2017 Compass Learning Technologies", function() end}, {" Version "..date, function() end}, {" Contact: steve@compasstech.com.au ", function() end},}, {"Controls",{"Scan and Connect", function() TI_Innovator.connect() end}, {"Disconnect", function() TI_Innovator.disconnect() on.resize() end}, {"RESET", function() on.resize() end},}, {"SET Samples", {"SET LIGHT ON/OFF (default)", function() hubStrOn = "SET LIGHT ON" hubStrOff = "SET LIGHT OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.RED ON/OFF", function() hubStrOn = "SET COLOR.RED ON" hubStrOff = "SET COLOR.RED OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" hubStrOff = "SET COLOR.GREEN OFF" TI_Innovator.Send(hubStrOn) end}, {"SET COLOR.BLUE ON/OFF", function() hubStrOn = "SET COLOR.BLUE ON" hubStrOff = "SET COLOR.BLUE OFF" TI_Innovator.Send(hubStrOn) end}, {"SET SOUND 220 5", function() hubStrOn = "SET SOUND 220 5" hubStrOff = "SET SOUND 0 1" TI_Innovator.Send(hubStrOn) end}, {"SET SPEAKER 1 220 5", function() hubStrOn = "SET SPEAKER 1 220 5" TI_Innovator.Send("CONNECT SPEAKER 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET SPEAKER 1 0 1" end}, {"SET LED 1 ON", function() hubStrOn = "SET LED 1 ON" TI_Innovator.Send("CONNECT LED 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET LED 1 0FF" end}, {"SET SERVO 1 CW 50 5", function() TI_Innovator.Send("CONNECT SERVO 1 OUT3") hubStrOn = "SET SERVO 1 CW 50 5" hubStrOff = "SET SERVO 1 CW 50 0" TI_Innovator.Send(hubStrOn) end}, {"SET ANALOG.OUT 1 100", function() hubStrOn = "SET ANALOG.OUT 1 100" TI_Innovator.Send("CONNECT ANALOG.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET ANALOG.OUT 1 0" end}, {"SET DIGITAL.OUT 1 ON", function() hubStrOn = "SET DIGITAL.OUT 1 ON" TI_Innovator.Send("CONNECT DIGITAL.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) hubStrOff = "SET DIGITAL.OUT 1 0FF" end}, }, {"READ Samples",{"READ BRIGHTNESS (default)", function() hubStrOn = "READ BRIGHTNESS" TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ RANGER 1", function() hubStrOn = "READ RANGER 1" TI_Innovator.Send("CONNECT RANGER 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ DHT 1", function() hubStrOn = "READ DHT 1" TI_Innovator.Send("CONNECT DHT 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ ACCEL 1", function() hubStrOn = "READ ACCEL 1" TI_Innovator.Send("CONNECT ACCEL 1 I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ BAROMETER", function() hubStrOn = "READ BAROMETER" TI_Innovator.Send("CONNECT BAROMETER I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() msgStr = rxValue or hubStrOn end}, {"READ ANALOG.IN", function() hubStrOn = "READ ANALOG.IN 1" TI_Innovator.Send("CONNECT ANALOG.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = hubStrOn end}, {"READ DIGITAL.IN", function() hubStrOn = "READ DIGITAL.IN 1" TI_Innovator.Send("CONNECT DIGITAL.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() hubStrOff = hubStrOn end},},-- Layout Functions
function on.resize(width, height)
w = screen:width() h = screen:height() hubStrOn, hubStrOff msgStr, rxValue = "READ BRIGHTNESS", "READ BRIGHTNESS", "READ BRIGHTNESS", "" if TI_Innovator.isConnected() then TI_Innovator.Send('BEGIN') addMsg("TI Innovator Hub ready") end screen:invalidate()endfunction on.paint (gc)
endif TI_Innovator.isConnected() then
gc:setColorRGB (0,255,0) gc:fillRect (0, 0, w, 0.025*h)elsegc:setColorRGB (255,0,0) gc:fillRect (0, 0, w, 0.025*h) gc:drawString("Wait for connection, then", 0.1*w, 0.1*h, "middle") gc:drawString("press anywhere to activate Hub", 0.1*w, 0.2*h, "middle")endgc:drawString(msgStr, 0.05*w, 0.8*h, "middle") gc:drawString(rxValue, 0.05*w, 0.9*h, "middle")
-- TI Innovator User set up
function on.escapeKey()
TI_Innovator.Send(hubStrOff) on.resize() screen:invalidate()endfunction on.mouseDown(x, y)
TI_Innovator.Send(hubStrOn) -- This is an example of sending a SET command to the Hub TI_Innovator.Read() -- This is an example of sending a READ command to the Hub screen:invalidate()endfunction on.mouseUp (x,y)
TI_Innovator.Send(hubStrOff) TI_Innovator.Read() screen:invalidate()endfunction str2list(input, def) local list = {} if input:find(def) then
list = input:split(def) table.foreachi(list,print)elselist = {input}end return list endfunction TI_InnovatorReadCallback(port, error_msg) -- this is the callback function that is defined above and catches the result of a READ command sent to the Hub.
rxValue = port:getValue() or '' -- this gets the actual return value from the hub and puts it in the variable rxValue. The user may choose any variable name and also may do any calibration or ranging of the value here. Note that rxValue may be numeric, list or string (hence the utility function str2list) if tonumber(rxValue) then rxValue = math.floor(100*rxValue+0.5)/100 else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end addMsg(hubStrOn) if tonumber(rxValue) then voltage = (rxValue/2^14)*3.3 end -- an example of converting a raw 14 bit ADC value into voltage. screen:invalidate()endfunction TI_InnovatorStateCallback(event)
endaddMsg("TI_InnovatorStateCallback") if 'ready' == event then TI_InnovatorConfig() elseif "disconnected" == event then -- user may choose to do some clean up or display a msg when the Hub is disconnected. addMsg("TI_Innovator Hub disconnected") end screen:invalidate()
function TI_InnovatorConfig() -- this function is called from TI_InnovatorStateCallback() when a ready connection is succesful.
-- place CONNECT and other Hub startup commands here addMsg("TI_Innovator Hub connected")end-- oneShotTimer BEGINS
local timerstart = timer.start local timerstop = timer.stop timer.start = nil timer.stop = nil local currentTimer = nil
local function timerStart(t)
endcurrentTimer = t timerstart(t.period/1000)
local function timerStop()
endcurrentTimer = nil timerstop()
local function setTimer(t)
endif t.period==nil or type(t.period)~='number' or t.period < 10 then error('period in milliseconds >= 10') end timerStart(t) return t
function oneShotTimer(period, listenerHandler, ...)
endif type(listenerHandler) ~= 'function' then
error('createTimerOneShot: function expected')end setTimer {period = period, oneShot = true, listenerHandler = listenerHandler, params = { ... },}function on.timer()
endtime = time + time_step
local ct = currentTimer if currentTimer == nil then
timerStop()end if currentTimer.oneShot thencurrentTimer = nil timerStop()end ct.listenerHandler(unpack(ct.params))-- oneShotTimer ENDS
-- TI Innovator BEGINS
TI_Innovator = { }
function TI_Innovator.init(theStateCallback)
endif not pcall(function() require 'asi' end) then
addMsg('Hub NOT available') returnendaddMsg('Hub available')
isASIavailable = true
local HANDSHAKE_GREETING = 'ISTI\n' local HANDSHAKE_ANSWER = 'TISTEM' local portFoundList = { } local state local handshakeState local notifyEvent local asiStateListener local startScanning local stopScanning local portFoundListener local portStateListener local handshake_SendListener local handshake_readListener local handshake_port local TI_Innovator_port local baudRate = asi.BAUD_RATE_DEFAULT local readTimeout = asi.READ_TIMEOUT_DEFAULT
-- User callbacks local stateCallback = theStateCallback local SendCallback local readCallback
function notifyEvent(event)
addMsg('notifying '.. event) if stateCallback thenendstateCallback(event)elseaddMsg('no callback registered')endfunction startScanning()
if isASIavailable thenendasi.startScanning(portFoundListener) notifyEvent('scanning')endfunction stopScanning()
handshake_port = nil portFoundList = { } asi.stopScanning()endfunction asiStateListener(asiState)
if asi.ON == asiState thenendif state == 'active' thenelseif asi.UNSUPPORTED == asiState thenstartScanning()endnotifyEvent(asi.UNSUPPORTED)endfunction portFoundListener(portFound)
addMsg('portFoundListener '.. portFound:getName()) table.insert(portFoundList, portFound) if not TI_Innovator_port and not handshake_port thenendhandshake_port = portFoundList[1] oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)endfunction portStateListener(reportedPort, event, error_msg)
addMsg('portStateListener '..reportedPort:getName()..' '..event) if asi.CONNECTED == event thenend-- configure port for handshake reportedPort:setWriteListener(handshake_writeListener) reportedPort:setReadListener(handshake_readListener) reportedPort:setReadTimeout(500) handshakeState = 'handshake' -- write handshake greeting addMsg("HANDSHAKE_GREETING: "..HANDSHAKE_GREETING) oneShotTimer(200, reportedPort.write, reportedPort, HANDSHAKE_GREETING)elseif asi.CONNECTING_FAILED == event thenif reportedPort == handshake_port thenelseif asi.DISCONNECTED == event thentable.remove(portFoundList, 1) if #portFoundList>0 thenelseif reportedPort == TI_Innovator_port thenhandshake_port = portFoundList[1] handshake_port:connect(portStateListener)elsehandshake_port = nilendTI_Innovator_port = nil asi.startScanning(portFoundListener)endif reportedPort == TI_Innovator_port thenendif state == 'active' thenendif reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')reportedPort:connect(portStateListener)elseTI_Innovator_port = nil asi.startScanning(portFoundListener)endfunction handshake_writeListener(reportedPort, error_msg)
if error_msg thenendaddMsg('handshake_writeListener '..error_msg) returnend if 'handshake' == handshakeState thenreportedPort:read(#HANDSHAKE_ANSWER+2)endfunction handshake_readListener(reportedPort, error_msg)
if error_msg thenendaddMsg('handshake_writeListener '..error_msg) returnend local answer = reportedPort:getValue() if 'handshake' == handshakeState then-- Validate answer if answer and answer:find(HANDSHAKE_ANSWER) thenelseif 'ready' == handshakeState thenaddMsg("HANDSHAKE_ANSWER: "..HANDSHAKE_ANSWER) stopScanning() handshakeState = 'ready' reportedPort:write('BEGIN\n') reportedPort:read(7)elsereportedPort:disconnect() table.remove(portFoundList, 1) if #portFoundList>0 thenendhandshake_port = portFoundList[1] handshake_port:connect(portStateListener)elsehandshake_port = nilendif answer and answer:find('READY') thenend-- Configure port for normal use TI_Innovator_port = reportedPort TI_Innovator_port:setReadTimeout(readTimeout) TI_Innovator.setWriteListener(SendCallback) TI_Innovator.setReadListener(readCallback) -- Notify launchpad is ready notifyEvent('ready')end-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active' startScanning()endfunction TI_Innovator.disconnect()
state = 'inactive' if isASIavailable thenendif TI_Innovator_port thenendTI_Innovator_port:disconnect() TI_Innovator_port = nilend stopScanning()function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallback if TI_Innovator_port thenendTI_Innovator_port:setWriteListener(writeCallback)endfunction TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallback if TI_Innovator_port thenendTI_Innovator_port:setReadListener(readCallback)endfunction TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRate if TI_Innovator_port thenendTI_Innovator_port:setBaudRate(baudRate)endfunction TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeout if TI_Innovator_port thenendTI_Innovator_port:setReadTimeout(readTimeout)endfunction TI_Innovator.Send(data)
if not TI_Innovator_port thenendaddMsg('No Hub attached') return 'No Hub attached'end local result = TI_Innovator_port:write(data .. '\n') if result then addMsg(tostring(data)..': '.. tostring(result)) else addMsg(tostring(data)) end return resultfunction TI_Innovator.Read(bytes_to_read)
addMsg('TI_Innovator.Read') if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:read(bytes_to_read)function TI_Innovator.request(request)
if not TI_Innovator_port thenendreturn "No TI Hub attached"end local result = TI_Innovator_port:write(request .. '\n') if result then addMsg(tostring(request) .. '): '.. tostring(result)) else addMsg(tostring(request)) end result = TI_Innovator_port:read() addMsg('read() '.. tostring(result)) if result thenaddMsg('Error sending request: ' .. tostring(request))end return resultfunction TI_Innovator.isConnected()
if not TI_Innovator_port thenendreturn falseend return TI_Innovator_port:getState() == asi.CONNECTEDfunction TI_Innovator.getName()
if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:getName()function TI_Innovator.getIdentifier()
if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:getIdentifier()-- INTERFACE -- ENDS --
-- Wait for the ASI to be up and running
asi.addStateListener(asiStateListener)
end
Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 42