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, rxValuefunction 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",}
{" ©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},
toolpalette.register(Menu)
screen:invalidate()
-- Layout Functions
function on.resize(width, height)
w = screen:width()end
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()
function on.paint (gc)
endif TI_Innovator.isConnected() then
gc:setColorRGB (0,255,0)else
gc:fillRect (0, 0, w, 0.025*h)
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)end
on.resize()
screen:invalidate()
function on.mouseDown(x, y)
TI_Innovator.Send(hubStrOn) -- This is an example of sending a SET command to the Hubend
TI_Innovator.Read() -- This is an example of sending a READ command to the Hub screen:invalidate()
function on.mouseUp (x,y)
TI_Innovator.Send(hubStrOff)end
TI_Innovator.Read()
screen:invalidate()
function str2list(input, def)
local list = {}
if input:find(def) then
list = input:split(def)else
table.foreachi(list,print)
list = {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)end
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()
function 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 hereend
addMsg("TI_Innovator Hub connected")
--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 = nillocal 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 then
currentTimer = nilend
timerStop()
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')end
return
addMsg('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 readCallbackfunction notifyEvent(event)
addMsg('notifying '.. event)end
if stateCallback then
stateCallback(event)else
addMsg('no callback registered')end
function startScanning()
if isASIavailable thenend
asi.startScanning(portFoundListener)end
notifyEvent('scanning')
function stopScanning()
handshake_port = nilend
portFoundList = { }
asi.stopScanning()
function asiStateListener(asiState)
if asi.ON == asiState thenend
if state == 'active' thenelseif asi.UNSUPPORTED == asiState then
startScanning()end
notifyEvent(asi.UNSUPPORTED)end
function portFoundListener(portFound)
addMsg('portFoundListener '.. portFound:getName())end
table.insert(portFoundList, portFound)
if not TI_Innovator_port and not handshake_port then
handshake_port = portFoundList[1]end
oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)
function portStateListener(reportedPort, event, error_msg)
addMsg('portStateListener '..reportedPort:getName()..' '..event)end
if asi.CONNECTED == event then
-- configure port for handshakeelseif asi.CONNECTING_FAILED == event then
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)
if reportedPort == handshake_port thenelseif asi.DISCONNECTED == event then
table.remove(portFoundList, 1)elseif reportedPort == TI_Innovator_port then
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
if reportedPort == TI_Innovator_port thenend
if state == 'active' thenend
if reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')
reportedPort:connect(portStateListener)else
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
function handshake_writeListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
if 'handshake' == handshakeState then
reportedPort:read(#HANDSHAKE_ANSWER+2)end
function handshake_readListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
local answer = reportedPort:getValue()
if 'handshake' == handshakeState then
-- Validate answerelseif 'ready' == handshakeState then
if answer and answer:find(HANDSHAKE_ANSWER) then
addMsg("HANDSHAKE_ANSWER: "..HANDSHAKE_ANSWER)else
stopScanning()
handshakeState = 'ready'
reportedPort:write('BEGIN\n')
reportedPort:read(7)
reportedPort:disconnect()end
table.remove(portFoundList, 1)
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
if answer and answer:find('READY') thenend
-- Configure port for normal useend
TI_Innovator_port = reportedPort
TI_Innovator_port:setReadTimeout(readTimeout)
TI_Innovator.setWriteListener(SendCallback)
TI_Innovator.setReadListener(readCallback)
-- Notify launchpad is ready
notifyEvent('ready')
-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active'end
startScanning()
function TI_Innovator.disconnect()
state = 'inactive'end
if isASIavailable then
if TI_Innovator_port thenend
TI_Innovator_port:disconnect()end
TI_Innovator_port = nil
stopScanning()
function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallbackend
if TI_Innovator_port then
TI_Innovator_port:setWriteListener(writeCallback)end
function TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallbackend
if TI_Innovator_port then
TI_Innovator_port:setReadListener(readCallback)end
function TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRateend
if TI_Innovator_port then
TI_Innovator_port:setBaudRate(baudRate)end
function TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeoutend
if TI_Innovator_port then
TI_Innovator_port:setReadTimeout(readTimeout)end
function TI_Innovator.Send(data)
if not TI_Innovator_port thenend
addMsg('No Hub attached')end
return 'No Hub attached'
local result = TI_Innovator_port:write(data .. '\n')
if result then addMsg(tostring(data)..': '.. tostring(result))
else addMsg(tostring(data)) end
return result
function TI_Innovator.Read(bytes_to_read)
addMsg('TI_Innovator.Read')end
if not TI_Innovator_port then
return "No TI Hub attached"end
return TI_Innovator_port:read(bytes_to_read)
function TI_Innovator.request(request)
if not TI_Innovator_port thenend
return "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 then
addMsg('Error sending request: ' .. tostring(request))end
return result
function TI_Innovator.isConnected()
if not TI_Innovator_port thenend
return falseend
return TI_Innovator_port:getState() == asi.CONNECTED
function TI_Innovator.getName()
if not TI_Innovator_port thenend
return "No TI Hub attached"end
return TI_Innovator_port:getName()
function TI_Innovator.getIdentifier()
if not TI_Innovator_port thenend
return "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, rxValuefunction 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",}
{" ©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},
toolpalette.register(Menu)
screen:invalidate()
-- Layout Functions
function on.resize(width, height)
w = screen:width()end
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()
function on.paint (gc)
endif TI_Innovator.isConnected() then
gc:setColorRGB (0,255,0)else
gc:fillRect (0, 0, w, 0.025*h)
gc:setColorRGB (255,0,0)end
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)end
on.resize()
screen:invalidate()
function on.mouseDown(x, y)
TI_Innovator.Send(hubStrOn) -- This is an example of sending a SET command to the Hubend
TI_Innovator.Read() -- This is an example of sending a READ command to the Hub
screen:invalidate()
function on.mouseUp (x,y)
TI_Innovator.Send(hubStrOff)end
TI_Innovator.Read()
screen:invalidate()
function str2list(input, def)
local list = {}
if input:find(def) then
list = input:split(def)else
table.foreachi(list,print)
list = {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)end
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()
function 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 hereend
addMsg("TI_Innovator Hub connected")
-- oneShotTimer BEGINS
local timerstart = timer.start
local timerstop = timer.stop
timer.start = nil
timer.stop = nil
local currentTimer = nillocal 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 then
currentTimer = nilend
timerStop()
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')end
return
addMsg('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 readCallbackfunction notifyEvent(event)
addMsg('notifying '.. event)end
if stateCallback then
stateCallback(event)else
addMsg('no callback registered')end
function startScanning()
if isASIavailable thenend
asi.startScanning(portFoundListener)end
notifyEvent('scanning')
function stopScanning()
handshake_port = nilend
portFoundList = { }
asi.stopScanning()
function asiStateListener(asiState)
if asi.ON == asiState thenend
if state == 'active' thenelseif asi.UNSUPPORTED == asiState then
startScanning()end
notifyEvent(asi.UNSUPPORTED)end
function portFoundListener(portFound)
addMsg('portFoundListener '.. portFound:getName())end
table.insert(portFoundList, portFound)
if not TI_Innovator_port and not handshake_port then
handshake_port = portFoundList[1]end
oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)
function portStateListener(reportedPort, event, error_msg)
addMsg('portStateListener '..reportedPort:getName()..' '..event)end
if asi.CONNECTED == event then
-- configure port for handshakeelseif asi.CONNECTING_FAILED == event then
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)
if reportedPort == handshake_port thenelseif asi.DISCONNECTED == event then
table.remove(portFoundList, 1)elseif reportedPort == TI_Innovator_port then
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
if reportedPort == TI_Innovator_port thenend
if state == 'active' thenend
if reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')
reportedPort:connect(portStateListener)else
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
function handshake_writeListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
if 'handshake' == handshakeState then
reportedPort:read(#HANDSHAKE_ANSWER+2)end
function handshake_readListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
local answer = reportedPort:getValue()
if 'handshake' == handshakeState then
-- Validate answerelseif 'ready' == handshakeState then
if answer and answer:find(HANDSHAKE_ANSWER) then
addMsg("HANDSHAKE_ANSWER: "..HANDSHAKE_ANSWER)else
stopScanning()
handshakeState = 'ready'
reportedPort:write('BEGIN\n')
reportedPort:read(7)
reportedPort:disconnect()end
table.remove(portFoundList, 1)
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
if answer and answer:find('READY') thenend
-- Configure port for normal useend
TI_Innovator_port = reportedPort
TI_Innovator_port:setReadTimeout(readTimeout)
TI_Innovator.setWriteListener(SendCallback)
TI_Innovator.setReadListener(readCallback)
-- Notify launchpad is ready
notifyEvent('ready')
-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active'end
startScanning()
function TI_Innovator.disconnect()
state = 'inactive'end
if isASIavailable then
if TI_Innovator_port thenend
TI_Innovator_port:disconnect()end
TI_Innovator_port = nil
stopScanning()
function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallbackend
if TI_Innovator_port then
TI_Innovator_port:setWriteListener(writeCallback)end
function TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallbackend
if TI_Innovator_port then
TI_Innovator_port:setReadListener(readCallback)end
function TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRateend
if TI_Innovator_port then
TI_Innovator_port:setBaudRate(baudRate)end
function TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeoutend
if TI_Innovator_port then
TI_Innovator_port:setReadTimeout(readTimeout)end
function TI_Innovator.Send(data)
if not TI_Innovator_port thenend
addMsg('No Hub attached')end
return 'No Hub attached'
local result = TI_Innovator_port:write(data .. '\n')
if result then addMsg(tostring(data)..': '.. tostring(result))
else addMsg(tostring(data)) end
return result
function TI_Innovator.Read(bytes_to_read)
addMsg('TI_Innovator.Read')end
if not TI_Innovator_port then
return "No TI Hub attached"end
return TI_Innovator_port:read(bytes_to_read)
function TI_Innovator.request(request)
if not TI_Innovator_port thenend
return "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 then
addMsg('Error sending request: ' .. tostring(request))end
return result
function TI_Innovator.isConnected()
if not TI_Innovator_port thenend
return falseend
return TI_Innovator_port:getState() == asi.CONNECTED
function TI_Innovator.getName()
if not TI_Innovator_port thenend
return "No TI Hub attached"end
return TI_Innovator_port:getName()
function TI_Innovator.getIdentifier()
if not TI_Innovator_port thenend
return "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