Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 49
Scripting Tutorial - Lesson 49: Lua Scripting and the TI Innovator™ Hub:
9. Create a General Innovator™ Hub and BLE Document
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 TI Innovator™ Hub Rover (Lua Scripting Lesson 45)
TI Innovator™ Hub Lesson 6: Lua Script for the Norland Research/TI Innovator™ Hub Robot (Lua Scripting Lesson 46)
TI Innovator™ Hub Lesson 7: Build your own Innovator™ Hub Robot (Lua Scripting Lesson 47)
TI Innovator™ Hub Lesson 8: Create a general Innovator™ Hub Document (Lua Scripting Lesson 48)
TI Innovator™ Hub Lesson 9: Create a general Innovator™ Hub and BLE Document (Lua Scripting Lesson 49)
Download supporting file for this tutorial
Texas Instruments TI-Nspire Scripting Support Page
Scripting for the Innovator Hub: Lesson 9: Create a General Innovator™ Hub and BLE Document
As we begin to develop content for the TI-Nspire platform that makes use of the amazing learning benefits offered by the Innovator™ Hub, it seems likely that there will increasingly be ways in which the same content may be offered across handheld, desktop and tablets. For the last, then the chance to develop learning tools that correspond between Innovator and BLE seems too good to pass up.
We are already seeing documents which lend themselves to this approach. The Science Through Engineering Design activity STEM: One Giant Leaf for Mankind offers a great example of an excellent learning tool that could be used with the Hub OR on iPad with BLE-enabled devices such as the Vernier Go Wireless Link coupled with TI Light probe, or, of course, the CC2650 SensorTag from TI.
The sample document developed in this lesson will work well across both USB and BLE. Connect an Innovator Hub on handheld or desktop software, and it will automatically connect; run it on an iPad and it will readily link to Vernier Go Wireless Link (or Go Wireless Temp), or to a CC2650 SensorTag. Data from any platform is easily collected using our little OneShotTimer "wait" function and dropped into index and dataList lists, ready for viewing and analysis.
Of course, much more is possible - the included document is just a starting point, and is readily extendable. For example, sensors such as accelerometer, barometer and DHT (Digital Humidity and Temperature) deliver their data in lists. There is an included str2list function which makes it easy to break these into their component elements.
Using such a document as a template for further content development ensures that, where appropriate, we are able to take advantage of the full range of excellent TI Tools for STEM.
![]()
Obviously, adding BLE functionality involves adding a bunch of new values to the script - the many UUID values for SensorTag, and for the Vernier Go devices are easily added. Most of these are added at the end of the script so as not to confuse things early on. The values which are likely to change when running the script are defined inside a function which can be easily run to reset things (in this case, inside on.resize.)
Similarly, the menu definition is shifted to the end as it gets much bigger. We define two menus - one for BLE and the other for Hub platforms.
- A key element for running our existing Innovator script on non-Innovator platforms like the iPad is to avoid the errors that will follow when specialised commands appear. To work around this, we simply place a protected call (pcall wrapper around any Innovator-specific commands.)
All the previous user set-up functions are bundled together here.
No changes from that previously defined.
- This block of code will serve to connect and run Vernier Go Wireless Link and Temp devices, and TI CC2650 SensorTag.
Obviously, other BLE devices may be readily added as desired.
This includes the TI-Nspire iPad Apps using BLE (BlueTooth Low Energy) and the TI MSP432 LaunchPad.
Use the free Energia software to flash the attached sketch to the LaunchPad via USB, then follow the guides outlined in LaunchPad lessons LP5 and LP6.
Best results will be obtained using the general LuaHubBLE document found here, which includes a musical keyboard, or you may prefer the general Lua Hub/BLE Control Panel document.
-- TI Innovator/BLE Init Values
platform.apilevel = '2.7' local screen = platform.window local date = "021517"
local hh = platform:isDeviceModeRendering() local ipad = platform:isTabletModeRendering()require 'color' pcall(function() require 'asi' end)
pcall(function () require 'bleCentral' end)local isBLEavailable = false local isBLEconnected = false local isASIavailable = false
local hubStrOn, hubStrOff, msgStr, rxValue, timeStr, delay, repeats, drive local tempo, key, I local list1, list2 = {}, {} local index, dataList = {}, {} var.store("index", index) var.store("dataList", dataList) local inBox = D2Editor.newRichText() local help = "Connect your device, and use the samples menu to enter different commands. Press 'tabKey' or 'SUBMIT' to try these out: edit them and try your own."local stChar = nil
function BLEvars()
bleState = '' connectStatus = '' peripheralName = '' peripheralList = {} alert = 0 bleName = nil Lstart = 0 Lstop = 0 Rstart = 0 Rstop = 0endsensorVoltage = nil periodChar = nil DDSRecord = 1 writeFlag = false readFlag = false returnPeriod = nil sensorPeriod = 100
setPeriodCharacteristic = nil DDSseekRecCharacteristic = nil DDSdataCharacteristic = nil sensorIDCharacteristic = nil
sensorID = nil sensorLongName = '' sensorShortName = '' sensorEqType = nil sensorPage =nil sensorA = nil sensorB = nil sensorC =nil sensorUnits = '' sensorValue = nil
BLEvars()
function addMsg(input)
msgStr = input print(msgStr) screen:invalidate()end
function on.construction()
endpcall(function() ble.addStateListener(listenerCallback) end) pcall(function()-- To run on all platforms, we need to place a protective wrapper around all our TI Innovator commands
TI_Innovator.init(TI_InnovatorStateCallback) TI_Innovator.setReadListener(TI_InnovatorReadCallback) TI_Innovator.connect()
end)
refreshMenu() --The menu is becoming a little unwieldy and so has been shifted to the end of the script.
screen:invalidate()-- Layout Functions
function on.resize(width, height)
w = screen:width() h = screen:height() hubStrOn, hubStrOff, msgStr, rxValue = "SET LIGHT ON", "SET LIGHT OFF", "SET LIGHT OFF", "" timeStr, delay, repeats, drive = "", 0, 1, "" tempo = 1000 key = 0 I=1 list1, list2 = {}, {} index, dataList = {}, {} var.store("index", index) var.store("dataList", dataList)endBLEvars()-- A quick and easy way to reset multiple variable values
boxX, boxY, boxWidth, boxHeight = 0.025*w, 0.05*h, 0.95*w, 0.45*h fontSize = math.floor(h/20 + 0.5) if hh then
fontSize = fontSize <= 24 and fontSize or 24 fontSize = fontSize > 6 and fontSize or 7end inBox:move(boxX, boxY) inBox:resize(boxWidth, boxHeight) inBox:setFontSize(fontSize) inBox:setTextColor(color.black) inBox:setBorder(1) inBox:setVisible(true) inBox:setFocus(true) inBox:setText(help)pcall(function() if TI_Innovator.isConnected() then TI_Innovator.Send('BEGIN') addMsg("TI Innovator Hub ready") end end) screen:invalidate()
function on.paint (gc)
endlocal myColor = {255,0,0}
pcall(function() if isBLEconnected or TI_Innovator.isConnected() then
myColor = {0,255,0}elsemyColor = {255,0,0}end end) gc:setColorRGB (unpack(myColor)) gc:fillRect (0, 0, w, 0.025*h)gc:setColorRGB (color.lightgray) gc:fillRect (boxX, boxY + boxHeight, boxWidth, 0.1*h) gc:setColorRGB (unpack(myColor)) gc:drawRect(boxX, boxY + boxHeight, boxWidth, 0.1*h)
gc:setFont("sansserif","r",fontSize) local str = "SUBMIT" local sw = gc:getStringWidth(str) gc:drawString(str, boxX + (boxWidth-sw)/2, boxY + boxHeight + 0.05*h, "middle")
gc:setColorRGB (color.lightgray) gc:fillRect (boxX, boxY + boxHeight + 0.1*h, boxWidth, 0.1*h) gc:setColorRGB (unpack(myColor)) gc:drawRect(boxX, boxY + boxHeight + 0.1*h, boxWidth, 0.1*h)
gc:setFont("sansserif","r",fontSize) local str = "RESET" local sw = gc:getStringWidth(str) gc:drawString(str, boxX + (boxWidth-sw)/2, boxY + boxHeight + 0.15*h, "middle")
gc:drawString(timeStr, 0.05*w, 0.75*h, "middle") gc:drawString(msgStr, 0.05*w, 0.85*h, "middle")
gc:drawString(rxValue..' '..sensorUnits, 0.05*w, 0.95*h, "middle")
-- TI Innovator User set up
function on.escapeKey()
on.resize() inBox:setText('') inBox:setFocus(true) screen:invalidate()endfunction on.tabKey()
if inBox:getText() thenendlocal input = string.upper(inBox:getText()) input = input:gsub('%"','') local list = {input} if input:find(string.char(10)) thenend screen:invalidate()list = input:split(string.char(10)) or {input:gsub(string.char(10),'')}end input = list[1] if input:find("SEND%(") theninput = input:gsub('SEND%(','') input = input:gsub('%)','') hubStrOn = input pcall(function() TI_Innovator.Send(input) TI_Innovator.Read() end)elseif input:find("SET") thenpcall(function() TI_Innovator.Send(input) end) if input:find("ON") thenelseif input:find("READ") thenhubStrOn = input hubStrOff = input:gsub("ON","OFF")elseif input:find("OFF") thenhubStrOff = input hubStrOn = input:gsub("OFF","ON")endpcall(function() TI_Innovator.Send(input) TI_Innovator.Read() end) hubStrOn = input hubStrOff = inputelseif input:find("CONNECT") thenpcall(function()TI_Innovator.Send(input) end)elselocal testfunction = loadstring(string.lower(input)) pcall(function() testfunction() screen:invalidate() end)endif #list > 1 then
for k = 2, #list doend STalerts()input = list[k] if input:find("SEND%(") thenendinput = input:gsub('SEND%(','') input =input:gsub('%)','') pcall(function() TI_Innovator.Send(input) TI_Innovator.Read() end)elseif input:find("SET") thenpcall(function() TI_Innovator.Send(input) end) if input:find("ON") thenelseif input:find("READ") thenhubStrOn = input hubStrOff = input:gsub("ON","OFF")elseif input:find("OFF") thenhubStrOff = input hubStrOn = input:gsub("OFF","ON")endpcall(function() TI_Innovator.Send(input) TI_Innovator.Read() end) hubStrOn = input hubStrOff = inputelseif input:find("CONNECT") thenpcall(function() TI_Innovator.Send(input) end)elselocal testfunction = loadstring(string.lower(input)) pcall(function() testfunction() screen:invalidate() end)endfunction on.mouseDown(x, y)
pcall(function() if hubStrOn:find("ROBOT") thenendif drive:find("BRIGHT") thenelselightSeeker()elseif drive:find("RANGER") thenauto()elseTI_Innovator.Send("SET SERVO 1 CCW 50 5") TI_Innovator.Send("SET SERVO 2 CW 50 5") TI_Innovator.Read()endTI_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 Hubend end)if x > boxX and x <= boxX + boxWidth then
if y > boxY + boxHeight and y <= boxY + boxHeight + 0.1*h thenendon.tabKey()elseif y > boxY + boxHeight + 0.1*h and y <= boxY + boxHeight + 0.2*h thenon.escapeKey()endscreen:invalidate()
function on.mouseUp (x,y)
pcall(function() if hubStrOn:find("ROBOT") thenendif drive == '' thenendTI_Innovator.Send("SET SERVO 1 CCW 0 0") TI_Innovator.Send("SET SERVO 2 CW 0 0") TI_Innovator.Read() endelsetimeStr = '' TI_Innovator.Send(hubStrOff) TI_Innovator.Read()end end) screen:invalidate()function 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 send to the Hub.
pcall(function() 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 list2str) 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. end) screen:invalidate()endfunction TI_InnovatorStateCallback(event)
pcall(function()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 end) screen:invalidate()
function TI_InnovatorConfig() -- this function is called from TI_InnovatorStateCallback() when a ready connection is succesful.
pcall(function() -- place CONNECT and other Hub startup commands here addMsg("TI_Innovator Hub connected") TI_Innovator.Send(hubStrOff) end)endfunction wait(input)
endif input then delay = input end time_step = 0.1 if delay >= 0 then
timeStr = "Wait Time: "..delay.." seconds" delay = math.floor((1/time_step)*(delay - time_step)+0.5)*time_step pcall(function() TI_Innovator.Send(hubStrOn) if hubStrOn:find("READ") then TI_Innovator.Read() end end) if tonumber(rxValue) then -- This allows our wait function to serve as a timed data collection toolelsedataList[#dataList+1] = tonumber(rxValue) index[#index+1]=#dataList var.store("index", index) var.store("dataList", dataList)else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end oneShotTimer(1000*time_step,wait)pcall(function() TI_Innovator.Send(hubStrOff) end) delay = 0end screen:invalidate()function blink(rep,waitValue)
endlocal lightState = "OFF" if waitValue then delay = waitValue end if rep then repeats = rep end if repeats > 0 then
timeStr = "blink("..(math.floor(repeats+0.5))..", "..delay..")" if math.floor(repeats) == repeats then lightState = "ON" alert = 1 else lightState = "OFF" alert = 0 end pcall(function() TI_Innovator.Send("SET LIGHT "..lightState) end) STalerts() oneShotTimer(1000*delay,blink) repeats = repeats - 0.5end screen:invalidate()function alarm(rep,waitValue)
local tone = 220 if waitValue then delay = waitValue end if rep then repeats = rep end if repeats > 0 thenendtimeStr = "alarm("..(math.floor(repeats+0.5))..", "..delay..")" if math.floor(repeats) == repeats then tone = 440 alert = 5 else tone = 220 alert = 2 end pcall(function() TI_Innovator.Send("SET SOUND "..tone) end) STalerts() oneShotTimer(1000*delay,alarm) repeats = repeats - 0.5end screen:invalidate()function STalerts()
if isBLEconnected then if stChar thenendhubStrOn = inBox:getText() or "SET LIGHT ON" hubStrOff = hubStrOn:gsub("ON","OFF") if string.upper(hubStrOn):find("COLOR.RED") and string.upper(hubStrOn):find("COLOR.GREEN") and string.upper(hubStrOn):find("BUZZER") and string.upper(hubStrOn):find("ON") then alert = 7 elseif string.upper(hubStrOn):find("COLOR.GREEN") and string.upper(hubStrOn):find("BUZZER") and string.upper(hubStrOn):find("ON") then alert = 6 elseif string.upper(hubStrOn):find("COLOR.RED") and string.upper(hubStrOn):find("BUZZER") and string.upper(hubStrOn):find("ON") then alert = 5 elseif string.upper(hubStrOn):find("SET BUZZER ON") then alert = 4 elseif string.upper(hubStrOn):find("COLOR.RED") and string.upper(hubStrOn):find("COLOR.GREEN") and string.upper(hubStrOn):find("ON") then alert = 3 elseif string.upper(hubStrOn):find("COLOR.GREEN") and string.upper(hubStrOn):find("ON") then alert = 2 elseif string.upper(hubStrOn):find("COLOR.RED") and string.upper(hubStrOn):find("ON") then alert = 1 elseif string.upper(hubStrOn):find("LIGHT") and string.upper(hubStrOn):find("ON") then alert = 1 elseif string.upper(hubStrOn):find("OFF") then alert = 0 end stChar:write(alert,true) addMsg("SensorTag alert "..alert)end end screen:invalidate()function waitTone()
if not list1 then list1 = var.recall("list1") end if not list2 then list2 = var.recall("list2") end if list1 and #list1 > 0 and list2 and #list2 > 0 thenendif I <= #list1 and list1[I] and list2[I] then -- don't go past the lenght of the arrayend screen:invalidate()if list1[I] and list2[I] thenelselocal str = "SET SOUND "..list1[I]*2^(key/12).." TIME "..math.floor(100/(list2[I])+0.5)/100 hubStrOn = str pcall(function() TI_Innovator.Send(str) end) oneShotTimer((tempo/list2[I])+20, waitTone) I = I + 1endhubStrOn = "SET LIGHT ON" hubStrOff = "SET LIGHT OFF" addMsg(hubStrOff)endfunction playTone(list1, list2)
waitTone() screen:invalidate()endfunction fd(input)
if input thenendinBox:setText("SET SERVO 1 CCW 100 "..input ..string.char(10).."SET SERVO 2 CW 100 "..input) hubStrOn = "ROBOT FORWARD" addMsg(hubStrOn) oneShotTimer(1000,fd) on.tabKey()end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function bk(input)
if input thenendinBox:setText("SET SERVO 1 CW 100 "..input ..string.char(10).."SET SERVO 2 CCW 100 "..input) hubStrOn = "ROBOT BACK" addMsg(hubStrOn) oneShotTimer(1000,bk) on.tabKey()end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function lt(input)
if input thenendinBox:setText("SET SERVO 1 CW 100 "..input ..string.char(10).."SET SERVO 2 CW 100 "..input) hubStrOn = "ROBOT LEFT" addMsg(hubStrOn) oneShotTimer(1000,lt) on.tabKey()end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function rt(input)
if input thenendinBox:setText("SET SERVO 1 CCW 100 "..input ..string.char(10).."SET SERVO 2 CCW 100 "..input) hubStrOn = "ROBOT RIGHT" addMsg(hubStrOn) oneShotTimer(1000,rt) on.tabKey()end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function lightSeeker()
if drive:find("BRIGHT") thenendpcall(function() TI_Innovator.Send("READ BRIGHTNESS ") TI_Innovator.Read() end) if tonumber(rxValue) and tonumber(rxValue) > 0 thenend oneShotTimer(1000,lightSeeker) screen:invalidate()if tonumber(rxValue) > 0.5 thenendif tonumber(rxValue) > 10 thenelsefd(1)elsebk(1) rt(1)endfd(0) hubStrOff = "ROBOT AUTO OFF" addMsg(hubStrOff) play = falseendfunction auto()
if drive:find("RANGER") thenendpcall(function() TI_Innovator.Send("READ RANGER 1 ") TI_Innovator.Read() end) if tonumber(rxValue) and tonumber(rxValue) > 0 thenend oneShotTimer(1000,auto) screen:invalidate()pcall(function() TI_Innovator.Send("SET SOUND "..1000*tonumber(rxValue).." 0.1") end) if tonumber(rxValue) > 0.1 thenendif tonumber(rxValue) > 0.4 thenelsefd(1)elsebk(0.5) rt(0.5)endfd(0) hubStrOff = "ROBOT AUTO OFF" addMsg(hubStrOff) play = falseend--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)) screen:invalidate()-- 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()
if isASIavailable and not ipad then state = 'inactive' if isASIavailable thenendif TI_Innovator_port thenend endTI_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 isASIavailable and not ipad then 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 result endfunction TI_Innovator.Read(bytes_to_read)
if isASIavailable and not ipad then if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:read(bytes_to_read) endfunction TI_Innovator.request(request)
if isASIavailable and not ipad then 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 result endfunction TI_Innovator.isConnected()
if isASIavailable and not ipad then if not TI_Innovator_port thenendreturn falseend end return TI_Innovator_port:getState() == asi.CONNECTEDfunction TI_Innovator.getName()
if isASIavailable and not ipad then if not TI_Innovator_port thenend endreturn "No TI Hub attached"end return TI_Innovator_port:getName()function TI_Innovator.getIdentifier()
if isASIavailable and not ipad then if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:getIdentifier() end-- INTERFACE -- ENDS --
-- Wait for the ASI to be up and running
if isASIavailable and not ipad then asi.addStateListener(asiStateListener) end
end
------------------------------------------------------------------------
notes_aliens = {392,440,349,175,261} times_aliens = {1,1,1,1,1} notes_bgame = {262,523,440,392,330,392,294,262,523,440,392,330,392,415,440,415,440,330,349,392,440,349,294,440,440,440,494,523,587,494,440,392,349,294,262,523,440,392,330,392,294,262,294,330,349,392,440,440,494,523,523,523,494,440,392,370,392,440,494,523} times_bgame = {2,4,4,4,4,1.333333333,1.333333333,2,4,4,4,4,1,4,4,4,4,4,4,4,2,4,1.333333333,2,4,4,4,4,4,4,4,4,4,4,2,4,4,4,4,1.333333333,1.333333333,2,4,4,4,4,1,4,4,1.333333333,1.333333333,4,4,4,4,4,4,1.333333333,1.333333333,1} notes_bday = {260,262,294,262,349,330,260,262,294,262,392,349,260,262,523,440,349,349,330,294,466,465,440,349,392,349} times_bday = {4,4,2,2,2,1,4,4,2,2,2,1,4,4,2,2,4,4,2,1,4,4,2,2,2,1} notes_brain = {440,466,523,440,349,392,440,349,0,392,440,349,294,330,349,294,0,294,262,261,262,261,262,0,349,330,294,294,587,523,466,440,392,349,330,331,660,587,523,466,440,392,349,349,349,349,349} times_brain = {16,49,16,49,16,49,24,16,49,24,16,49,16,49,24,16,49,24,16,49,16,49,6,1.5,16,49,16,49,16,49,16,49,16,49,16,49,16,49,16,49,16,49,16,49,16,49,6} notes_elise = {330,660,622,660,622,660,494,587,523,440,262,330,440,494,330,415,494,523,330,660,622,660,622,660,494,587,523,440,262,330,440,494,262,523,494,440,440} times_elise = {4,4,4,4,4,4,4,4,4,1,4,4,4,1,4,4,4,1,4,4,4,4,4,4,4,4,4,1,4,4,4,1,4,4,4,1,1} notes_home = {262,294,330,349,440,392,330,392,349,330,349,294,262,262} times_home = {4,4,2,4,4,2,4,4,4,4,4,4,1,1} notes_harmonic = {440.,495,550.,586.67,660.,733.33,806.67,880.} notes_welltemp = {440.,493.883,554.365,587.33,659.255,739.99,830.61,880.} times_scale = {2,2,2,2,2,2,2,2}
-- Menu -------------------------------
function refreshMenu()
end toolpalette.register(Menu)local Menu
if isBLEavailable then Menu={
{"About",} else{" ©2017 Compass Learning Technologies", function() end}, {" Version "..date, function() end}, {" Contact: steve@compasstech.com.au ", function() end},}, {"Controls",{"Scan and Connect", function() peripheralOn() end}, {"Disconnect", function() peripheralOff() on.resize() end}, {"RESET", function() on.resize() end},}, {"Connect BLE",{"Connect Go Wireless Link", function() bleName = "Go Wireless Link" inBox:setText("CONNECT "..bleName) peripheralOn(bleName) end}, {"Connect Go Wireless Temp", function() bleName = "Go Wireless Temp" inBox:setText("CONNECT "..bleName) peripheralOn(bleName) end}, {"Connect CC2650 SensorTag", function() bleName = "CC2650 SensorTag" inBox:setText("CONNECT "..bleName) peripheralOn("Tag") end},}, {"SET Samples (CC2650 SensorTag)",{"SET LIGHT ON/OFF (default)", function() hubStrOn = "SET LIGHT ON" inBox:setText(hubStrOn) hubStrOff = "SET LIGHT OFF" msgStr = hubStrOn end}, {"SET COLOR.RED ON/OFF (default)", function() hubStrOn = "SET COLOR.RED ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED OFF" msgStr = hubStrOn end}, {"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.GREEN OFF" msgStr = hubStrOn end}, {"SET BUZZER ON/OFF", function() hubStrOn = "SET BUZZER ON" inBox:setText(hubStrOn) hubStrOff = "SET BUZZER OFF" msgStr = hubStrOn end}, {"SET COLOR.RED AND COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.RED AND COLOR.GREEN ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED AND COLOR.GREEN OFF" msgStr = hubStrOn end}, {"SET COLOR.RED AND BUZZER ON/OFF", function() hubStrOn = "SET COLOR.RED AND BUZZER ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED AND BUZZER OFF" msgStr = hubStrOn end}, {"SET COLOR.GREEN AND BUZZER ON/OFF", function() hubStrOn = "SET COLOR.GREEN AND BUZZER ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.GREEN AND BUZZER OFF" msgStr = hubStrOn end}, {"SET COLOR.RED AND COLOR.GREEN AND BUZZER ON/OFF", function() hubStrOn = "SET COLOR.RED AND COLOR.GREEN AND BUZZER ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED AND COLOR.GREEN AND BUZZER OFF" msgStr = hubStrOn end},}, {"Read Samples",{'Go Wireless Link', function() hubStrOn = "READ Go Wireless Link" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'Go Wireless Temp', function() hubStrOn = "READ Go Wireless Temp" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Temperature (ambient)', function() hubStrOn = "READ AMBIENT TEMPERATURE SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Temperature (IR)', function() hubStrOn = "READ IR TEMPERATURE SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Light Intensity', function() hubStrOn = "READ LIGHTLEVEL SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Humidity', function() hubStrOn = "READ HUMIDITY SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Barometer', function() hubStrOn = "READ BAROMETER SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Compass', function() hubStrOn = "READ COMPASS SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Accelerometer', function() hubStrOn = "READ ACCELEROMETER SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Gyroscope', function() hubStrOn = "READ GYROSCOPE SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end},}, {"TIMER Samples",{"wait(5)", function() wait(5) end}, {"blink(5,1)", function() blink(5,1) end}, {"alarm(5,1)", function() alarm(5,1) end},},Menu={
{"About",}{" ©2017 Compass Learning Technologies", function() end}, {" Version "..date, function() end}, {" Contact: steve@compasstech.com.au ", function() end},}, {"Controls",{"Scan and Connect", function() pcall(function() TI_Innovator.connect() end) end}, {"Disconnect", function() pcall(function() TI_Innovator.disconnect() end) on.resize() end}, {"RESET", function() on.resize() end},}, {"SET Samples", {"SET LIGHT ON/OFF (default)", function() hubStrOn = "SET LIGHT ON" inBox:setText(hubStrOn) hubStrOff = "SET LIGHT OFF" on.tabKey() end}, {"SET COLOR.RED ON/OFF", function() hubStrOn = "SET COLOR.RED ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED OFF" on.tabKey() end}, {"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.GREEN OFF" on.tabKey() end}, {"SET COLOR.BLUE ON/OFF", function() hubStrOn = "SET COLOR.BLUE ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.BLUE OFF" on.tabKey() end}, {"SET SOUND 220 5", function() hubStrOn = "SET SOUND 220 5" inBox:setText(hubStrOn) hubStrOff = "SET SOUND 0 1" on.tabKey() end}, {"SET SPEAKER 1 220 5", function() hubStrOn = "SET SPEAKER 1 220 5" pcall(function() TI_Innovator.Send("CONNECT SPEAKER 1 OUT1") TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SPEAKER 1 0 1" end}, {"SET LED 1 ON", function() hubStrOn = "SET LED 1 ON" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT LED 1 OUT1") TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET LED 1 0FF" end}, {"SET SERVO 1 CW 50 5 (BB9)", function() pcall(function() TI_Innovator.Send("CONNECT SERVO 1 BB9") end) hubStrOn = "SET SERVO 1 CW 50 5" inBox:setText(hubStrOn) hubStrOff = "SET SERVO 1 CW 50 0" on.tabKey() end}, {"SET ANALOG.OUT 1 100", function() hubStrOn = "SET ANALOG.OUT 1 100" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT ANALOG.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET ANALOG.OUT 1 0" end}, {"SET DIGITAL.OUT 1 ON", function() hubStrOn = "SET DIGITAL.OUT 1 ON" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT DIGITAL.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET DIGITAL.OUT 1 0FF" end}, }, {"READ Samples",{"READ BRIGHTNESS (default)", function() hubStrOn = "READ BRIGHTNESS" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ RANGER 1", function() hubStrOn = "READ RANGER 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT RANGER 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ DHT 1", function() hubStrOn = "READ DHT 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT DHT 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ ACCEL 1", function() hubStrOn = "READ ACCEL 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT ACCEL 1 I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ BAROMETER", function() hubStrOn = "READ BAROMETER" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT BAROMETER I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ ANALOG.IN 1", function() hubStrOn = "READ ANALOG.IN 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT ANALOG.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) hubStrOff = hubStrOn end}, {"READ DIGITAL.IN 1", function() hubStrOn = "READ DIGITAL.IN 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT DIGITAL.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) hubStrOff = hubStrOn end},}, {"Select Sound",{"C4", function() hubStrOn = "SET SOUND 262 TIME 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"A4", function() hubStrOn = "SET SOUND 440 TIME 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"C5", function() hubStrOn = "SET SOUND 523 TIME 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"No tone", function() hubStrOn = "SET SOUND 0 TIME 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"Aliens", function() inBox:setText('Aliens') tempo = 1000 I=1 list1 = notes_aliens list2 = times_aliens playTone(list1,list2) hubStrOff = "Aliens" msgStr = hubStrOff end}, {"BallGame", function() inBox:setText('BallGame') tempo = 1000 I=1 list1 = notes_bgame list2 = times_bgame playTone(list1,list2) hubStrOff = "Take me out to the Ball Game" msgStr = hubStrOff end}, {"Happy Birthday", function() inBox:setText('Happy Birthday') tempo = 1000 I=1 list1 = notes_bday list2 = times_bday playTone(list1,list2) hubStrOff = "Happy Birthday" msgStr = hubStrOff end}, {"If I Only Had a Brain", function() inBox:setText('If I Only Had a Brain') tempo = 4000 I=1 list1 = notes_brain list2 = times_brain playTone(list1,list2) hubStrOff = "If I only had a brain" msgStr = hubStrOff end}, {"Fur Elise", function() inBox:setText('Fur Elise') tempo = 1000 I=1 list1 = notes_elise list2 = times_elise playTone(list1,list2) hubStrOff = "Fur Elise" msgStr = hubStrOff end}, {"Home on the Range", function() inBox:setText('Home on the Range') tempo = 1000 I=1 list1 = notes_home list2 = times_home playTone(list1,list2) hubStrOff = "Home on the Range" msgStr = hubStrOff end}, {"Well-tempered Scale", function() inBox:setText('Well-tempered Scale') tempo = 1000 I=1 list1 = notes_welltemp list2 = times_scale playTone(list1,list2) hubStrOff = "Well tempered scale" msgStr = hubStrOff end}, {"Harmonic Scale", function() inBox:setText('Harmonic Scale') tempo = 1000 I=1 list1 = notes_harmonic list2 = times_scale playTone(list1,list2) hubStrOff = "Harmonic scale" msgStr = hubStrOff end},}, {"TIMER Samples",{"wait(5)", function() wait(5) end}, {"blink(5,1)", function() blink(5,1) end}, {"alarm(5,0.5)", function() alarm(5,0.5) end},}, {"Robot Samples",{"CONNECT ROBOT SERVOS (BB9/BB10)", function() showKeyBoard = false TI_Innovator.Send("CONNECT SERVO 1 BB9") TI_Innovator.Send("CONNECT SERVO 2 BB10") end}, {"ROBOT FD 1 secs", function() fd(1) end}, {"ROBOT BK 1 secs", function() bk(1) end}, {"ROBOT LT 1 secs", function() lt(1) end}, {"ROBOT RT 1 secs", function() rt(1) end}, {"AUTO drive (BRIGHTNESS)", function() drive = "BRIGHTNESS" lightSeeker() end}, {"AUTO drive (DISTANCE)", function() pcall(function() TI_Innovator.Send("CONNECT RANGER 1 IN1") end) drive = "RANGER" auto() end},},----------------------------- BLE ----- BEGINS --------------
-- TI Sensor Tag Init Variables
-- Temperature tempRead = 'F000AA01-0451-4000-B000-000000000000' tempStart = 'F000AA02-0451-4000-B000-000000000000' -- Humidity humidData = 'F000AA21-0451-4000-B000-000000000000' humidConf = 'F000AA22-0451-4000-B000-000000000000' -- Barometric Pressure baData = 'F000AA41-0451-4000-B000-000000000000' baConfig = 'F000AA42-0451-4000-B000-000000000000' baCalib = 'F000AA43-0451-4000-B000-000000000000' baPeriod = 'F000AA44-0451-4000-B000-000000000000' -- Light optData = 'F000AA71-0451-4000-B000-000000000000' optSwitch = 'F000AA72-0451-4000-B000-000000000000' -- 0: disable, 1: enable optPeriod = 'F000AA73-0451-4000-B000-000000000000' -- Period in tens of milliseconds -- Movement moveData = 'F000AA81-0451-4000-B000-000000000000' moveConf = 'F000AA82-0451-4000-B000-000000000000' movePeriod = 'F000AA83-0451-4000-B000-000000000000' ioData = 'F000AA65-0451-4000-B000-000000000000' ioConfig = 'F000AA66-0451-4000-B000-000000000000'
--Vernier GoLink measuredDataUUID = '1A97C2F8-DA04-11E2-B53A-00264AA53EFC' periodUUID = '1A97C2FA-DA04-11E2-B53A-00264AA53EFC' sensorIdUUID = '1A97C30D-DA04-11E2-B53A-00264AA53EFC' DDSseekRecUUID = '1A97C30E-DA04-11E2-B53A-00264AA53EFC' DDSdataUUID = '1A97C30F-DA04-11E2-B53A-00264AA53EFC' -- Vernier GoTemp VST_FIREFLY_TEMPERATURE_DATA_UUID = '1A97C2F8-DA04-11E2-B53A-00264AA53EFC'
function listenerCallback(state, scriptError)
if state == ble.ON then bleState = 'BLE ON' isBLEavailable = true elseif state == ble.OFF then bleState = 'BLE OFF' isBLEavailable = false elseif state == ble.RESETTING then bleState = 'BLE RESET' isBLEavailable = true elseif state == ble.UNSUPPORTED then bleState = 'UNSUPPORTED' isBLEavailable = false if scriptError then print('Error message: BLE not supported') end addMsg(bleState) end
screen:invalidate()
end
function peripheralOn()
if isBLEavailable thenif input and (inBox:getText()):find("CONNECT") and (inBox:getText()):find(input) then bleName = input end bleCentral.startScanning(callbackScan) connectStatus = 'Scanning' addMsg(connectStatus..": "..bleState)end screen:invalidate()end
function peripheralOff()
if isBLEconnected thenbleCentral.stopScanning() if #peripheralList > 0 thenend connectStatus = 'Stand by' peripheralName = '' isBLEconnected = false screen:invalidate()for p = #peripheralList, 1, -1 doend addMsg(connectStatus..": "..bleState)peripheralList[p]:disconnect()endend
function callbackScan(peripheral)
if peripheral and peripheral:getName() thenif bleName and (peripheral:getName()):find(bleName) and (inBox:getText()):find("CONNECT") and (inBox:getText()):find(bleName) then addMsg("BLE found: "..peripheral:getName()) peripheral:connect(callbackConnect) endend screen:invalidate()end
function callbackConnect(peripheral, event)
if event == bleCentral.CONNECTED then
bleCentral.stopScanning() peripheralName = peripheral:getName() connectStatus = "Connected to "..peripheralName isBLEconnected = true addMsg(connectStatus) local str = "You are connected to "..peripheralName if peripheralName:find("Tag") then
str = str..string.char(10).."To read values from the associated sensors, select from the BLE Samples menu."end inBox:setText(str) table.insert(peripheralList, peripheral) peripheralName = peripheralName:gsub('%(unsupported%)', '') peripheral:discoverServices(callbackServices)elseif event == bleCentral.DISCONNECTED then connectStatus = 'Disconnected' peripheralName = ''
end screen:invalidate()
end
function callbackServices(peripheral)
if peripheral ~= nil and peripheral:getState() and peripheral:getState() == bleCentral.CONNECTED thenlocal services = peripheral:getServices() for _,service in ipairs(services) do service:discoverCharacteristics(callbackCharacteristics) endend screen:invalidate()end
-------------- Vernier Go Wireless utilities ------------------------
function voltageReady(characteristic)
if ipad then
sensorVoltage = (string.unpack('s16', (characteristic:getValue()))/6400) -- divding by 64 bitshifts the 16 bit ADC readiing to a 10 bit reading, dividing by 1000 converts from mV to V.elsesensorVoltage = (ble.unpack('s16', (characteristic:getValue()))/6400)end if sensorID == 2 or sensorID == 8 thensensorVoltage = sensorVoltage -.058endif sensorEq == 0 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorVoltageelseif sensorEq == 1 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorB*sensorVoltage + sensorAelseif sensorEq == 2 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorC*sensorVoltage^2+sensorB*sensorVoltage + sensorAelseif sensorEq == 3 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*sensorVoltage^sensorBelseif sensorEq == 4 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*sensorB^sensorVoltageelseif sensorEq == 5 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA+sensorB*mathlog(sensorVoltage)elseif sensorEq == 6 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA + sensorB*math.log(1/sensorVoltage)elseif sensorEq == 7 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*math.exp(sensorB*sensorVoltage)elseif sensorEq == 8 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*math.exp(sensorB/sensorVoltage)elseif sensorEq == 9 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*sensorVoltage^(sensorb*sensorVoltage)elseif sensorEq == 10 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*(sensorVoltage^(sensorB/sensorVoltage))elseif sensorEq == 11 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = 1/(sensorA+sensorB*math.log(sensorC*sensorVoltage))elseif sensorEq == 12 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thenlocal r1= 15000 local temp r= (r1*(5/sensorVoltage)-1) r=(sensorVoltage*r1)/(5-sensorVoltage) temp = 1/(sensorA+(sensorB*math.log(r))+ (sensorC*(math.log(r)^3))) sensorValue = temp - 273.15endif sensorValue then
if sensorShortName:find("BARO") thensensorValue = math.floor(100*sensorValue+0.5)/100 if sensorValue <= 500 then sensorValue = 10*sensorValue endend screen:invalidate() endsensorUnits = "mbar"elseif sensorLongName:find("TI Light") thensensorValue = math.floor(100*sensorValue+0.5)/100 if sensorValue <= 10 then sensorValue = 10*sensorValue endelsesensorValue = math.floor(100*sensorValue+0.5)/100end rxValue = sensorValue addMsg(sensorLongName)-------------- BLE utilities ------------------------
function DDSseekRecWriteCallback(characteristic)
DDSdataCharacteristic:read()endfunction IDcallback(characteristic)
--sensorID=ble.unpack('s8', characteristic:getValue())--ID Using DDSdata does not return analog and digital sensors. Must use the seperate ID characteristic and UUID DDSdataCharacteristic:setValueUpdateListener(LNcallback) if ipad thenendDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 8,28,20,0), true) -- long nameelseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 8,28,20,0), true)endfunction LNcallback(characteristic)
sensorLongName= characteristic:getValue()--long name DDSdataCharacteristic:setValueUpdateListener(STcallback) if ipad thenendDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 28,40,12,0), true) -- shrot nameelseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 28,40,12,0), true)endfunction STcallback(characteristic)
sensorShortName= characteristic:getValue()--short name DDSdataCharacteristic:setValueUpdateListener(EQcallback) if ipad thenendDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 56,57,1,0), true) -- Calibration equation typeelseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 56,57,1,0), true)endfunction EQcallback(characteristic)
if ipad thenendsensorEq= string.unpack('s8', characteristic:getValue())-- equation typeelsesensorEq= ble.unpack('s8', characteristic:getValue())-- equation typeend DDSdataCharacteristic:setValueUpdateListener(PGcallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 69,70,1,0), true) -- Calibration memeory pageelseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 69,70,1,0), true)endfunction PGcallback(characteristic)
if ipad thenendsensorPg= string.unpack('s8', characteristic:getValue())-- calibration pageelsesensorPg= ble.unpack('s8', characteristic:getValue())-- calibration pageend DDSdataCharacteristic:setValueUpdateListener(Acallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 70,74,4,04), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 70,74,4,04), true) -- Aendfunction Acallback(characteristic)
if ipad thenendsensorA= string.unpack('f', characteristic:getValue())-- AelsesensorA= ble.unpack('f', characteristic:getValue())-- Aend DDSdataCharacteristic:setValueUpdateListener(Bcallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 74,78,4,0), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 74,78,4,0), true) -- Bendfunction Bcallback(characteristic)
if ipad thenendsensorB= string.unpack('f', characteristic:getValue())-- BelsesensorB= ble.unpack('f', characteristic:getValue())-- Bend DDSdataCharacteristic:setValueUpdateListener(Ccallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 78,82,4,0), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 78,82,4,0), true) -- Cendfunction Ccallback(characteristic)
if ipad thenendsensorC= string.unpack('f', characteristic:getValue())-- CelsesensorC= ble.unpack('f', characteristic:getValue())-- Cend DDSdataCharacteristic:setValueUpdateListener(UNcallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 82,86,7,0), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 82,86,7,0), true) -- unitsendfunction UNcallback(characteristic)
sensorUnits= characteristic:getValue()-- units checkAnalogDigitalSesnors()endfunction readSensorIDCallback(characteristic)
if ipad thenendsensorID=string.unpack('s8', sensorIDCharacteristic:getValue())elsesensorID=ble.unpack('s8', sensorIDCharacteristic:getValue())endfunction periodWriteCallback(characteristic)
periodWriteFlag = trueendfunction checkAnalogDigitalSesnors()
if sensorID == 1 thenendsensorLongName = "Thermocouple" sensorUnits= "°C " sensorShortName= "TC" sensorA= 6.2115 sensorB= -2.45455 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 2 thensensorLongName= "Voltage +/- 10V" sensorUnits= "V" sensorShortName= "Voltage10" sensorA= -10 sensorB= 4 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 3 thensensorLongName = "Current" sensorUnits= "Amps" sensorShortName= "Current" sensorA= 6.325 sensorB= -2.665 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 4 thensensorLongName = "Resistance" sensorUnits= "Ohms" sensorShortName= "Diff V" sensorA= 6.25 sensorB= -2.5 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 8 thensensorLongName = "Diff Voltage" sensorUnits= "V" sensorShortName= "Diff V" sensorA= 6.25 sensorB= -2.5 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 9 thensensorLongName = "Current" sensorUnits= "Amp" sensorShortName= "I" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 10 thensensorLongName = "Temperature" sensorShortName ="Temp" sensorPg = 1 sensorUnits = "°C " sensorEq = 12 sensorA = .00102119 sensorB = .000222468 sensorC = .000000133342elseif sensorID == 11 thensensorLongName = "Temperature" sensorUnits= "°C " sensorShortName= "Temp" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 12 thensensorLongName = "TI Light" sensorUnits= "relative" sensorShortName= "TI Light" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 13 thensensorLongName = "Exercise Heart Rate" sensorUnits= "V" sensorShortName= "Ex HR" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 14 thensensorLongName = "Voltage" sensorUnits= "V" sensorShortName= "Volts" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 15 thensensorLongName = "EKG" sensorUnits= "V" sensorShortName= "EKG" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 17 thensensorLongName = "Carbon Dioxide" sensorUnits= "ppm" sensorShortName= "CO2" sensorB= 1 sensorA= 0 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 18 thensensorLongName = "Oxygen" sensorUnits= "%" sensorShortName= "O2" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 67 thensensorLongName = nil sensorUnits= nil sensorShortName= nil sensorA= nil sensorB= nil sensorC = nil sensorPg = nil sensorEq= nilend addMsg("Sensor Ready!")-- BLE Specific Functions ---------
function callbackCharacteristics(service)
local characteristicsList = service:getCharacteristics()
for _,characteristic in ipairs(characteristicsList) do
-- Simple Keys if characteristic:getUUID() == keysRead then characteristic:setValueUpdateListener(callbackCharacteristic)
characteristic:setNotify(true)end-- IO control
if characteristic:getUUID() == ioData then
local msg = 0 characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(msg), true)endif characteristic:getUUID() == ioConfig then -- 02
local msg = 1 characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(msg), true)end-- Temperature if characteristic:getUUID() == tempRead then
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == tempStart then
characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(1), true)
end
-- Humidity if characteristic:getUUID() == humidData then
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == humidConf then
characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(1), true)
end
-- Barometric Pressure if characteristic:getUUID() == baData then
readBa = characteristic readBa:setValueUpdateListener(callbackCharacteristic) readBa:setNotify(true)
end
if characteristic:getUUID() == baCalib then
calibBa = characteristic calibBa:setValueUpdateListener(callbackCharacteristic) calibBa:read()
end
if characteristic:getUUID() == baConfig then
writeBa = characteristic local msg = string.char(1) writeBa:setWriteCompleteListener(callbackCharacteristic) writeBa:write(msg, true) local msg = string.char(2) writeBa:setWriteCompleteListener(callbackCharacteristic) writeBa:write(msg, true)
end
-- Light
if characteristic:getUUID() == optData then --01
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == optSwitch then -- 02
local msg = 1 characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(msg), true)
end
-- Movement Sensors
if characteristic:getUUID() == moveData then -- 01
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == moveConf then -- 02
local msg if ipad then
msg = string.pack('u16', 0x007F)elsemsg = ble.pack('u16', 0x007F)end characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(msg, true)end
if characteristic:getUUID() == movePeriod then -- 03
characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(1), true)
end
if characteristic:getUUID() == VST_FIREFLY_TEMPERATURE_DATA_UUID and peripheralName and peripheralName:find("Temp") then
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == measuredDataUUID and peripheralName and peripheralName:find("Link") then
characteristic:setValueUpdateListener(voltageReady) characteristic:setNotify(true)
end
if characteristic:getUUID() == periodUUID then
setPeriodCharacteristic = characteristic if ipad then
setPeriodCharacteristic:write(string.pack('u32', sensorPeriod), true)elsesetPeriodCharacteristic:write(ble.pack('u32', sensorPeriod), true)endend
if characteristic:getUUID() == sensorIdUUID then
sensorIDCharacteristic = characteristic sensorIDCharacteristic:setValueUpdateListener(readSensorIDCallback) sensorIDCharacteristic:read()
end
if characteristic:getUUID() == DDSseekRecUUID then
DDSseekRecCharacteristic = characteristic DDSseekRecCharacteristic:setWriteCompleteListener(DDSseekRecWriteCallback)
end
if characteristic:getUUID() == DDSdataUUID then
DDSdataCharacteristic = characteristic if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 01,02,01,0), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 01,02,01,0), true)end DDSdataCharacteristic:setValueUpdateListener(IDcallback) addMsg("Reading Sensor Configuration")end
end
end
function callbackCharacteristic(characteristic)
local text = inBox:getText() or '' if text then text = string.upper(text) end if characteristic:getUUID() == ioData then
stChar = characteristicend-- Simple Keys
if characteristic:getUUID() == keysRead then local value = characteristic:getValue() if value and string.len(tostring(value)) == 1 then
local keyPress = 0 if ipad thenendkeyPress = string.unpack("u8",value)elsekeyPress = ble.unpack("u8",value)end if keyPress thenif keyPress == 2 thenendLstart = timer.getMilliSecCounter()end if keyPress == 1 thenRstart = timer.getMilliSecCounter()end if keyPress == 0 thenif Lstart ~= 0 then Lstop = math.abs((Lstart - timer.getMilliSecCounter())/1000) end if Rstart ~= 0 then Rstop = math.abs((Rstart - timer.getMilliSecCounter())/1000) endend if Lstop > 0 thenon.tabKey() Lstart = 0 Lstop = 0end if Rstop > 0 thenif Rstop > 1 thenendon.escapeKey()elsewait(5)end Rstart = 0 Rstop = 0 end--Temperature
if characteristic:getUUID() == tempRead and string.upper(text):find("READ") and string.upper(text):find("TEMP") then
local value = characteristic:getValue() if value and string.len(tostring(value)) == 4 then
local loWord, hiWord if ipad thenloWord, hiWord = string.unpack("s16u16",value)elseloWord, hiWord = ble.unpack("s16u16",value)end local dietemp = tonumber(hiWord) / 128 local irtemp = tonumber(loWord) / 128 if dietemp and irtemp thendietemp = math.floor(100*dietemp + 0.5)/100 irtemp = math.floor(100*irtemp + 0.5)/100 if text:find("AMBIENT") thenendrxValue = math.floor(100*dietemp+0.5)/100 sensorLongName = "SensorTag Ambient Temperature"elseif text:find("IR TEMP") thenrxValue = math.floor(100*irtemp +0.5)/100 sensorLongName = "SensorTag IR Temperature"end addMsg(sensorLongName) sensorUnits= "°C "end
end
-- Humidity if characteristic:getUUID() == humidData and string.upper(text):find("READ") and string.upper(text):find("HUMID") then
local value = characteristic:getValue() if value and string.len(tostring(value)) == 4 then
local loWord, hiWord if ipad thenloWord, hiWord = string.unpack("s16u16",value)elseloWord, hiWord = ble.unpack("s16u16",value)end local Humidity = -6 + 125*tonumber(hiWord)/65536 local theHumidityTemp = -40 + 165*tonumber(loWord)/65536 rxValue = math.floor(100*Humidity+0.5)/100 sensorLongName = "SensorTag Humidity" addMsg(sensorLongName.." (+Temp: "..(math.floor(10*theHumidityTemp+0.5)/10).."°C)") sensorUnits= "% "end
end
--BAROMETER if characteristic:getUUID() == baData and string.upper(text):find("READ") and string.upper(text):find("BARO") then
local value = characteristic:getValue() if value and string.len(tostring(value)) > 4 then
local temp, pressure if ipad thentemp, pressure = string.unpack('u24', value)elsetemp, pressure = ble.unpack('u24', value)end local baTemp = temp/100 local baTemp = math.floor(100*baTemp + 0.5)/100 local baro = 0 if ipad thenbaro = string.unpack("u24", pressure)/100elsebaro = ble.unpack("u24", pressure)/100end baro = math.floor(100*baro + 0.5)/100 local p0 = var.recall("basepa") or 1013.25 local alt = 44330.*(1-(((baro)/(p0)))^(((1)/(5.255)))) alt = math.floor(100*alt + 0.5)/100 rxValue = math.floor(100*baro+0.5)/100 sensorLongName = "SensorTag Baro" sensorUnits= " mbar " addMsg(sensorLongName.." (+Temp: "..(math.floor(10*baTemp+0.5)/10).."°C Alt: "..(math.floor(10*alt+0.5)/10).." m)")end
end
-- Light Intensity if characteristic:getUUID() == optData and string.upper(text):find("READ") and string.upper(text):find("LIGHT") then
local value = characteristic:getValue() if value thenlocal rawLux = '' if ipad thenrawLux = string.unpack('u16', value)elserawLux = ble.unpack('u16', value)end local exponent = bit.brshift(bit.band(rawLux, 0xF000), 12) local mantissa = bit.band(rawLux, 0x0FFF) local light = mantissa * math.pow(2, exponent)/1000 light = math.floor(100*light + 0.5)/100 rxValue = math.floor(100*light +0.5)/100 sensorLongName = "SensorTag Light Intensity" addMsg(sensorLongName) sensorUnits= "lux "end
end
-- Movement if characteristic:getUUID() == moveData and string.upper(text):find("READ") then
local value = characteristic:getValue() if value thenendlocal m1, m2, m3, m4, m5, m6, m7, m8, m9 if ipad thenendm1, m2, m3, m4, m5, m6, m7, m8, m9 = string.unpack("s16s16s16s16s16s16s16s16s16", value)elsem1, m2, m3, m4, m5, m6, m7, m8, m9 = ble.unpack("s16s16s16s16s16s16s16s16s16", value)endif string.upper(text):find("GYR") then
local gyrx = math.floor(100*(-1*tonumber(m1)* 500 / 65536) + 0.5)/100 local gyry = math.floor(100*(-1*tonumber(m2)* 500 / 65536) + 0.5)/100 local gyrz = math.floor(100*(-1*tonumber(m3)* 500 / 65536) + 0.5)/100 rxValue = "{"..gyrx..", "..gyry..", "..gyrz.."}" sensorLongName = "SensorTag Gyroscope" addMsg(sensorLongName) sensorUnits= "°/s "endif string.upper(text):find("ACC") then
local xa = math.floor(100*(-3.9*tonumber(m4)* 2 / 32768) + 0.5)/10 local ya = math.floor(100*(-3.9*tonumber(m5)* 2 / 32768) + 0.5)/10 local za = math.floor(100*(-3.9*tonumber(m6)* 2 / 32768) + 0.5)/10 rxValue = "{"..xa..", "..ya..", "..za.."}" sensorLongName = "SensorTag Accelerometer" addMsg(sensorLongName) sensorUnits= "G "endif string.upper(text):find("MAG") or string.upper(text):find("COMPASS") then
local magx = math.floor(100*(tonumber(m7)* -4912 / 32768) + 0.5)/100 local magy = math.floor(100*(tonumber(m8)* -4912 / 32768) + 0.5)/100 local magz = math.floor(100*(tonumber(m9)* -4912 / 32768) + 0.5)/100 rxValue = "{"..magx..", "..magy..", "..magz.."}" sensorLongName = "SensorTag Magnetometer" addMsg(sensorLongName) sensorUnits= "μT "endif inBox:getText() and inBox:getText():find("Go Wireless Temp") and characteristic:getUUID() == measuredDataUUID then
--Vernier Go Temp local value = characteristic:getValue() if peripheralName:find("Temp") thenendlocal data = 0 if ipad thenenddata = string.unpack('u16', value)elsedata = ble.unpack('u16', value)end vTemp = data/128 vTempF = (vTemp*9/5)+32 rxValue = math.floor(100*vTemp+0.5)/100 sensorLongName = "Go Wireless Temp" addMsg(sensorLongName) sensorUnits= "°C "screen:invalidate()
end
-- LuaBit v0.3 (Lua bit library) ---------
--[[--------------- LuaBit v0.3 ------------------- a bitwise operation lib for lua. http://luaforge.net/projects/bit/ Under the MIT license. copyright(c) 2006 hanzhao (abrash_han@hotmail.com) --]]---------------
do
------------------------ -- bit lib implementions
endlocal function check_int(n) -- checking not float
if(n - math.floor(n) > 0) thenenderror("trying to use bitwise operation on non-integer!")endlocal function to_bits(n)
check_int(n) if(n < 0) thenend return tbl-- negative return to_bits(bit.bnot(math.abs(n)) + 1)end -- to bits table local tbl = {} local cnt = 1 while (n > 0) dolocal last = n % 2 if(last == 1) thenn = (n-last)/2 cnt = cnt + 1tbl[cnt] = 1elsetbl[cnt] = 0endlocal function tbl_to_number(tbl)
local n = table.getn(tbl) local rslt = 0 local power = 1 for i = 1, n doendrslt = rslt + tbl[i]*powerpower = power*2 end return rsltlocal function expand(tbl_m, tbl_n)
local big = {} local small = {} if(table.getn(tbl_m) > table.getn(tbl_n)) thenendbig = tbl_m small = tbl_nelsebig = tbl_n small = tbl_mend -- expand small for i = table.getn(small) + 1, table.getn(big) dosmall[i] = 0endlocal function bit_or(m, n)
local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n)) for i = 1, rslt doendif(tbl_m[i]== 0 and tbl_n[i] == 0) thenend return tbl_to_number(tbl)tbl[i] = 0elsetbl[i] = 1endlocal function bit_and(m, n)
local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n)) for i = 1, rslt doendif(tbl_m[i]== 0 or tbl_n[i] == 0) thenend return tbl_to_number(tbl)tbl[i] = 0elsetbl[i] = 1endlocal function bit_not(n)
local tbl = to_bits(n) local size = math.max(table.getn(tbl), 32) for i = 1, size doendif(tbl[i] == 1) thenend return tbl_to_number(tbl)tbl[i] = 0elsetbl[i] = 1endlocal function bit_xor(m, n)
local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n)) for i = 1, rslt doendif(tbl_m[i] ~= tbl_n[i]) thenend --table.foreach(tbl, print) return tbl_to_number(tbl)tbl[i] = 1elsetbl[i] = 0endlocal function bit_rshift(n, bits)
check_int(n) local high_bit = 0 if(n <= 0) thenend-- negative n = bit_not(math.abs(n)) + 1 high_bit = 2147493649 -- 0x80000000end for i=1, bits don = n/2 n = bit_or(math.floor(n), high_bit)end return math.floor(n)-- logic rightshift assures zero filling shift
local function bit_logic_rshift(n, bits)
check_int(n) if(n <= 0) thenend-- negative n = bit_not(math.abs(n)) + 1end for i=1, bits don = n/2end return math.floor(n)local function bit_lshift(n, bits)
check_int(n) if(n <= 0) thenend-- negative n = bit_not(math.abs(n)) + 1end for i=1, bits don = n*2end return bit_and(n, 4294967295) -- 0xFFFFFFFFlocal function bit_xor2(m, n)
local rhs = bit_or(bit_not(m), bit_not(n)) local lhs = bit_or(m, n) local rslt = bit_and(lhs, rhs) return rsltend-------------------- -- bit lib interface
bit = {
-- bit operations bnot = bit_not, band = bit_and, bor = bit_or, bxor = bit_xor, brshift = bit_rshift, blshift = bit_lshift, bxor2 = bit_xor2, blogic_rshift = bit_logic_rshift,-- utility func tobits = to_bits, tonumb = tbl_to_number, }
end
-- TI Innovator/BLE Init Values
platform.apilevel = '2.7' local screen = platform.window local date = "021517"
local hh = platform:isDeviceModeRendering() local ipad = platform:isTabletModeRendering()require 'color' pcall(function() require 'asi' end)
pcall(function () require 'bleCentral' end)local isBLEavailable = false local isBLEconnected = false local isASIavailable = false
local hubStrOn, hubStrOff, msgStr, rxValue, timeStr, delay, repeats, drive local tempo, key, I local list1, list2 = {}, {} local index, dataList = {}, {} var.store("index", index) var.store("dataList", dataList) local inBox = D2Editor.newRichText() local help = "Connect your device, and use the samples menu to enter different commands. Press 'tabKey' or 'SUBMIT' to try these out: edit them and try your own."local stChar = nil
function BLEvars()
bleState = '' connectStatus = '' peripheralName = '' peripheralList = {} alert = 0 bleName = nil Lstart = 0 Lstop = 0 Rstart = 0 Rstop = 0endsensorVoltage = nil periodChar = nil DDSRecord = 1 writeFlag = false readFlag = false returnPeriod = nil sensorPeriod = 100
setPeriodCharacteristic = nil DDSseekRecCharacteristic = nil DDSdataCharacteristic = nil sensorIDCharacteristic = nil
sensorID = nil sensorLongName = '' sensorShortName = '' sensorEqType = nil sensorPage =nil sensorA = nil sensorB = nil sensorC =nil sensorUnits = '' sensorValue = nil
BLEvars()
function addMsg(input)
msgStr = input print(msgStr) screen:invalidate()end
function on.construction()
endpcall(function() ble.addStateListener(listenerCallback) end) pcall(function()-- To run on all platforms, we need to place a protective wrapper around all our TI Innovator commands
TI_Innovator.init(TI_InnovatorStateCallback) TI_Innovator.setReadListener(TI_InnovatorReadCallback) TI_Innovator.connect()
end)
refreshMenu() --The menu is becoming a little unwieldy and so has been shifted to the end of the script.
screen:invalidate()-- Layout Functions
function on.resize(width, height)
w = screen:width() h = screen:height() hubStrOn, hubStrOff, msgStr, rxValue = "SET LIGHT ON", "SET LIGHT OFF", "SET LIGHT OFF", "" timeStr, delay, repeats, drive = "", 0, 1, "" tempo = 1000 key = 0 I=1 list1, list2 = {}, {} index, dataList = {}, {} var.store("index", index) var.store("dataList", dataList)endBLEvars()-- A quick and easy way to reset multiple variable values
boxX, boxY, boxWidth, boxHeight = 0.025*w, 0.05*h, 0.95*w, 0.45*h fontSize = math.floor(h/20 + 0.5) if hh then
fontSize = fontSize <= 24 and fontSize or 24 fontSize = fontSize > 6 and fontSize or 7end inBox:move(boxX, boxY) inBox:resize(boxWidth, boxHeight) inBox:setFontSize(fontSize) inBox:setTextColor(color.black) inBox:setBorder(1) inBox:setVisible(true) inBox:setFocus(true) inBox:setText(help)pcall(function() if TI_Innovator.isConnected() then TI_Innovator.Send('BEGIN') addMsg("TI Innovator Hub ready") end end) screen:invalidate()
function on.paint (gc)
endlocal myColor = {255,0,0}
pcall(function() if isBLEconnected or TI_Innovator.isConnected() then
myColor = {0,255,0}elsemyColor = {255,0,0}end end) gc:setColorRGB (unpack(myColor)) gc:fillRect (0, 0, w, 0.025*h)gc:setColorRGB (color.lightgray) gc:fillRect (boxX, boxY + boxHeight, boxWidth, 0.1*h) gc:setColorRGB (unpack(myColor)) gc:drawRect(boxX, boxY + boxHeight, boxWidth, 0.1*h)
gc:setFont("sansserif","r",fontSize) local str = "SUBMIT" local sw = gc:getStringWidth(str) gc:drawString(str, boxX + (boxWidth-sw)/2, boxY + boxHeight + 0.05*h, "middle")
gc:setColorRGB (color.lightgray) gc:fillRect (boxX, boxY + boxHeight + 0.1*h, boxWidth, 0.1*h) gc:setColorRGB (unpack(myColor)) gc:drawRect(boxX, boxY + boxHeight + 0.1*h, boxWidth, 0.1*h)
gc:setFont("sansserif","r",fontSize) local str = "RESET" local sw = gc:getStringWidth(str) gc:drawString(str, boxX + (boxWidth-sw)/2, boxY + boxHeight + 0.15*h, "middle")
gc:drawString(timeStr, 0.05*w, 0.75*h, "middle") gc:drawString(msgStr, 0.05*w, 0.85*h, "middle")
gc:drawString(rxValue..' '..sensorUnits, 0.05*w, 0.95*h, "middle")
-- TI Innovator User set up
function on.escapeKey()
on.resize() inBox:setText('') inBox:setFocus(true) screen:invalidate()endfunction on.tabKey()
if inBox:getText() thenendlocal input = string.upper(inBox:getText()) input = input:gsub('%"','') local list = {input} if input:find(string.char(10)) thenend screen:invalidate()list = input:split(string.char(10)) or {input:gsub(string.char(10),'')}end input = list[1] if input:find("SEND%(") theninput = input:gsub('SEND%(','') input = input:gsub('%)','') hubStrOn = input pcall(function() TI_Innovator.Send(input) TI_Innovator.Read() end)elseif input:find("SET") thenpcall(function() TI_Innovator.Send(input) end) if input:find("ON") thenelseif input:find("READ") thenhubStrOn = input hubStrOff = input:gsub("ON","OFF")elseif input:find("OFF") thenhubStrOff = input hubStrOn = input:gsub("OFF","ON")endpcall(function() TI_Innovator.Send(input) TI_Innovator.Read() end) hubStrOn = input hubStrOff = inputelseif input:find("CONNECT") thenpcall(function()TI_Innovator.Send(input) end)elselocal testfunction = loadstring(string.lower(input)) pcall(function() testfunction() screen:invalidate() end)endif #list > 1 then
for k = 2, #list doend STalerts()input = list[k] if input:find("SEND%(") thenendinput = input:gsub('SEND%(','') input =input:gsub('%)','') pcall(function() TI_Innovator.Send(input) TI_Innovator.Read() end)elseif input:find("SET") thenpcall(function() TI_Innovator.Send(input) end) if input:find("ON") thenelseif input:find("READ") thenhubStrOn = input hubStrOff = input:gsub("ON","OFF")elseif input:find("OFF") thenhubStrOff = input hubStrOn = input:gsub("OFF","ON")endpcall(function() TI_Innovator.Send(input) TI_Innovator.Read() end) hubStrOn = input hubStrOff = inputelseif input:find("CONNECT") thenpcall(function() TI_Innovator.Send(input) end)elselocal testfunction = loadstring(string.lower(input)) pcall(function() testfunction() screen:invalidate() end)endfunction on.mouseDown(x, y)
pcall(function() if hubStrOn:find("ROBOT") thenendif drive:find("BRIGHT") thenelselightSeeker()elseif drive:find("RANGER") thenauto()elseTI_Innovator.Send("SET SERVO 1 CCW 50 5") TI_Innovator.Send("SET SERVO 2 CW 50 5") TI_Innovator.Read()endTI_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 Hubend end)if x > boxX and x <= boxX + boxWidth then
if y > boxY + boxHeight and y <= boxY + boxHeight + 0.1*h thenendon.tabKey()elseif y > boxY + boxHeight + 0.1*h and y <= boxY + boxHeight + 0.2*h thenon.escapeKey()endscreen:invalidate()
function on.mouseUp (x,y)
pcall(function() if hubStrOn:find("ROBOT") thenif drive == '' thenendTI_Innovator.Send("SET SERVO 1 CCW 0 0") TI_Innovator.Send("SET SERVO 2 CW 0 0") TI_Innovator.Read() endelsetimeStr = '' TI_Innovator.Send(hubStrOff) TI_Innovator.Read()end end) screen:invalidate()function 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 send to the Hub.
pcall(function() 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 list2str) 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. end) screen:invalidate()endfunction TI_InnovatorStateCallback(event)
pcall(function()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 end) screen:invalidate()
function TI_InnovatorConfig() -- this function is called from TI_InnovatorStateCallback() when a ready connection is succesful.
pcall(function() -- place CONNECT and other Hub startup commands here addMsg("TI_Innovator Hub connected") TI_Innovator.Send(hubStrOff) end)endfunction wait(input)
endif input then delay = input end time_step = 0.1 if delay >= 0 then
timeStr = "Wait Time: "..delay.." seconds" delay = math.floor((1/time_step)*(delay - time_step)+0.5)*time_step pcall(function() TI_Innovator.Send(hubStrOn) if hubStrOn:find("READ") then TI_Innovator.Read() end end) if tonumber(rxValue) then -- This allows our wait function to serve as a timed data collection toolelsedataList[#dataList+1] = tonumber(rxValue) index[#index+1]=#dataList var.store("index", index) var.store("dataList", dataList)else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end STalerts() oneShotTimer(1000*time_step,wait)pcall(function() TI_Innovator.Send(hubStrOff) end) delay = 0 alert = 0 STalerts()end screen:invalidate()function blink(rep,waitValue)
endlocal lightState = "OFF" if waitValue then delay = waitValue end if rep then repeats = rep end if repeats > 0 then
timeStr = "blink("..(math.floor(repeats+0.5))..", "..delay..")" if math.floor(repeats) == repeats then lightState = "ON" alert = 1 else lightState = "OFF" alert = 0 end pcall(function() TI_Innovator.Send("SET LIGHT "..lightState) end) STalerts() oneShotTimer(1000*delay,blink) repeats = repeats - 0.5end screen:invalidate()function alarm(rep,waitValue)
local tone = 220 if waitValue then delay = waitValue end if rep then repeats = rep end if repeats > 0 thenendtimeStr = "alarm("..(math.floor(repeats+0.5))..", "..delay..")" if math.floor(repeats) == repeats then tone = 440 alert = 5 else tone = 220 alert = 2 end pcall(function() TI_Innovator.Send("SET SOUND "..tone) end) STalerts() oneShotTimer(1000*delay,alarm) repeats = repeats - 0.5end screen:invalidate()function STalerts()
if isBLEconnected then if stChar thenendhubStrOn = inBox:getText() or "SET LIGHT ON" hubStrOff = hubStrOn:gsub("ON","OFF") if string.upper(hubStrOn):find("COLOR.RED") and string.upper(hubStrOn):find("COLOR.GREEN") and string.upper(hubStrOn):find("BUZZER") and string.upper(hubStrOn):find("ON") then alert = 7 elseif string.upper(hubStrOn):find("COLOR.GREEN") and string.upper(hubStrOn):find("BUZZER") and string.upper(hubStrOn):find("ON") then alert = 6 elseif string.upper(hubStrOn):find("COLOR.RED") and string.upper(hubStrOn):find("BUZZER") and string.upper(hubStrOn):find("ON") then alert = 5 elseif string.upper(hubStrOn):find("SET BUZZER ON") then alert = 4 elseif string.upper(hubStrOn):find("COLOR.RED") and string.upper(hubStrOn):find("COLOR.GREEN") and string.upper(hubStrOn):find("ON") then alert = 3 elseif string.upper(hubStrOn):find("COLOR.GREEN") and string.upper(hubStrOn):find("ON") then alert = 2 elseif string.upper(hubStrOn):find("COLOR.RED") and string.upper(hubStrOn):find("ON") then alert = 1 elseif string.upper(hubStrOn):find("LIGHT") and string.upper(hubStrOn):find("ON") then alert = 1 elseif string.upper(hubStrOn):find("OFF") then alert = 0 end stChar:write(alert,true) addMsg("SensorTag alert "..alert)end end screen:invalidate()function waitTone()
if not list1 then list1 = var.recall("list1") end if not list2 then list2 = var.recall("list2") end if list1 and #list1 > 0 and list2 and #list2 > 0 thenendif I <= #list1 and list1[I] and list2[I] then -- don't go past the lenght of the arrayend screen:invalidate()if list1[I] and list2[I] thenelselocal str = "SET SOUND "..list1[I]*2^(key/12).." TIME "..math.floor(100/(list2[I])+0.5)/100 hubStrOn = str pcall(function() TI_Innovator.Send(str) end) oneShotTimer((tempo/list2[I])+20, waitTone) I = I + 1endhubStrOn = "SET LIGHT ON" hubStrOff = "SET LIGHT OFF" addMsg(hubStrOff)endfunction playTone(list1, list2)
waitTone() screen:invalidate()endfunction fd(input)
if input thenendinBox:setText("SET SERVO 1 CCW 100 "..input ..string.char(10).."SET SERVO 2 CW 100 "..input) hubStrOn = "ROBOT FORWARD" addMsg(hubStrOn) oneShotTimer(1000,fd) on.tabKey()end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function bk(input)
if input thenendinBox:setText("SET SERVO 1 CW 100 "..input ..string.char(10).."SET SERVO 2 CCW 100 "..input) hubStrOn = "ROBOT BACK" addMsg(hubStrOn) oneShotTimer(1000,bk) on.tabKey()end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function lt(input)
if input thenendinBox:setText("SET SERVO 1 CW 100 "..input ..string.char(10).."SET SERVO 2 CW 100 "..input) hubStrOn = "ROBOT LEFT" addMsg(hubStrOn) oneShotTimer(1000,lt) on.tabKey()end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function rt(input)
if input thenendinBox:setText("SET SERVO 1 CCW 100 "..input ..string.char(10).."SET SERVO 2 CCW 100 "..input) hubStrOn = "ROBOT RIGHT" addMsg(hubStrOn) oneShotTimer(1000,rt) on.tabKey()end hubStrOff = "ROBOT OFF" addMsg(hubStrOff) screen:invalidate()function lightSeeker()
if drive:find("BRIGHT") thenendpcall(function() TI_Innovator.Send("READ BRIGHTNESS ") TI_Innovator.Read() end) if tonumber(rxValue) and tonumber(rxValue) > 0 thenend oneShotTimer(1000,lightSeeker) screen:invalidate()if tonumber(rxValue) > 0.5 thenendif tonumber(rxValue) > 10 thenelsefd(1)elsebk(1) rt(1)endfd(0) hubStrOff = "ROBOT AUTO OFF" addMsg(hubStrOff) play = falseendfunction auto()
if drive:find("RANGER") thenendpcall(function() TI_Innovator.Send("READ RANGER 1 ") TI_Innovator.Read() end) if tonumber(rxValue) and tonumber(rxValue) > 0 thenend oneShotTimer(1000,auto) screen:invalidate()pcall(function() TI_Innovator.Send("SET SOUND "..1000*tonumber(rxValue).." 0.1") end) if tonumber(rxValue) > 0.1 thenendif tonumber(rxValue) > 0.4 thenelsefd(1)elsebk(0.5) rt(0.5)endfd(0) hubStrOff = "ROBOT AUTO OFF" addMsg(hubStrOff) play = falseendend-- OneShot Timer BEGIN
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)) screen:invalidate()-- 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()
if isASIavailable and not ipad then state = 'inactive' if isASIavailable thenendif TI_Innovator_port thenend endTI_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 isASIavailable and not ipad then 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 result endfunction TI_Innovator.Read(bytes_to_read)
if isASIavailable and not ipad then if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:read(bytes_to_read) endfunction TI_Innovator.request(request)
if isASIavailable and not ipad then 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 result endfunction TI_Innovator.isConnected()
if isASIavailable and not ipad then if not TI_Innovator_port thenendreturn falseend end return TI_Innovator_port:getState() == asi.CONNECTEDfunction TI_Innovator.getName()
if isASIavailable and not ipad then if not TI_Innovator_port thenend endreturn "No TI Hub attached"end return TI_Innovator_port:getName()function TI_Innovator.getIdentifier()
if isASIavailable and not ipad then if not TI_Innovator_port thenendreturn "No TI Hub attached"end return TI_Innovator_port:getIdentifier() end-- INTERFACE -- ENDS --
-- Wait for the ASI to be up and running
if isASIavailable and not ipad then asi.addStateListener(asiStateListener) end
end
------------------------------------------------------------------------
notes_aliens = {392,440,349,175,261} times_aliens = {1,1,1,1,1} notes_bgame = {262,523,440,392,330,392,294,262,523,440,392,330,392,415,440,415,440,330,349,392,440,349,294,440,440,440,494,523,587,494,440,392,349,294,262,523,440,392,330,392,294,262,294,330,349,392,440,440,494,523,523,523,494,440,392,370,392,440,494,523} times_bgame = {2,4,4,4,4,1.333333333,1.333333333,2,4,4,4,4,1,4,4,4,4,4,4,4,2,4,1.333333333,2,4,4,4,4,4,4,4,4,4,4,2,4,4,4,4,1.333333333,1.333333333,2,4,4,4,4,1,4,4,1.333333333,1.333333333,4,4,4,4,4,4,1.333333333,1.333333333,1} notes_bday = {260,262,294,262,349,330,260,262,294,262,392,349,260,262,523,440,349,349,330,294,466,465,440,349,392,349} times_bday = {4,4,2,2,2,1,4,4,2,2,2,1,4,4,2,2,4,4,2,1,4,4,2,2,2,1} notes_brain = {440,466,523,440,349,392,440,349,0,392,440,349,294,330,349,294,0,294,262,261,262,261,262,0,349,330,294,294,587,523,466,440,392,349,330,331,660,587,523,466,440,392,349,349,349,349,349} times_brain = {16,49,16,49,16,49,24,16,49,24,16,49,16,49,24,16,49,24,16,49,16,49,6,1.5,16,49,16,49,16,49,16,49,16,49,16,49,16,49,16,49,16,49,16,49,16,49,6} notes_elise = {330,660,622,660,622,660,494,587,523,440,262,330,440,494,330,415,494,523,330,660,622,660,622,660,494,587,523,440,262,330,440,494,262,523,494,440,440} times_elise = {4,4,4,4,4,4,4,4,4,1,4,4,4,1,4,4,4,1,4,4,4,4,4,4,4,4,4,1,4,4,4,1,4,4,4,1,1} notes_home = {262,294,330,349,440,392,330,392,349,330,349,294,262,262} times_home = {4,4,2,4,4,2,4,4,4,4,4,4,1,1} notes_harmonic = {440.,495,550.,586.67,660.,733.33,806.67,880.} notes_welltemp = {440.,493.883,554.365,587.33,659.255,739.99,830.61,880.} times_scale = {2,2,2,2,2,2,2,2}
-- Menu -------------------------------
function refreshMenu()
end toolpalette.register(Menu)local Menu
if isBLEavailable then Menu={
{"About",} else{" ©2016 Texas Instruments", function() end}, {" Version "..date, function() end}, {" Contact: steve.arnold@ti.com ", function() end},}, {"Controls",{"Scan and Connect", function() peripheralOn() end}, {"Disconnect", function() peripheralOff() on.resize() end}, {"RESET", function() on.resize() end},}, {"Connect BLE",{"Connect Go Wireless Link", function() bleName = "Go Wireless Link" inBox:setText("CONNECT "..bleName) peripheralOn(bleName) end}, {"Connect Go Wireless Temp", function() bleName = "Go Wireless Temp" inBox:setText("CONNECT "..bleName) peripheralOn(bleName) end}, {"Connect CC2650 SensorTag", function() bleName = "CC2650 SensorTag" inBox:setText("CONNECT "..bleName) peripheralOn("Tag") end},}, {"SET Samples (CC2650 SensorTag)",{"SET LIGHT ON/OFF (default)", function() hubStrOn = "SET LIGHT ON" inBox:setText(hubStrOn) hubStrOff = "SET LIGHT OFF" msgStr = hubStrOn end}, {"SET COLOR.RED ON/OFF (default)", function() hubStrOn = "SET COLOR.RED ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED OFF" msgStr = hubStrOn end}, {"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.GREEN OFF" msgStr = hubStrOn end}, {"SET BUZZER ON/OFF", function() hubStrOn = "SET BUZZER ON" inBox:setText(hubStrOn) hubStrOff = "SET BUZZER OFF" msgStr = hubStrOn end}, {"SET COLOR.RED AND COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.RED AND COLOR.GREEN ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED AND COLOR.GREEN OFF" msgStr = hubStrOn end}, {"SET COLOR.RED AND BUZZER ON/OFF", function() hubStrOn = "SET COLOR.RED AND BUZZER ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED AND BUZZER OFF" msgStr = hubStrOn end}, {"SET COLOR.GREEN AND BUZZER ON/OFF", function() hubStrOn = "SET COLOR.GREEN AND BUZZER ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.GREEN AND BUZZER OFF" msgStr = hubStrOn end}, {"SET COLOR.RED AND COLOR.GREEN AND BUZZER ON/OFF", function() hubStrOn = "SET COLOR.RED AND COLOR.GREEN AND BUZZER ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED AND COLOR.GREEN AND BUZZER OFF" msgStr = hubStrOn end},}, {"Read Samples",{'Go Wireless Link', function() hubStrOn = "READ Go Wireless Link" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'Go Wireless Temp', function() hubStrOn = "READ Go Wireless Temp" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Temperature (ambient)', function() hubStrOn = "READ AMBIENT TEMPERATURE SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Temperature (IR)', function() hubStrOn = "READ IR TEMPERATURE SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Light Intensity', function() hubStrOn = "READ LIGHTLEVEL SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Humidity', function() hubStrOn = "READ HUMIDITY SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Barometer', function() hubStrOn = "READ BAROMETER SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Compass', function() hubStrOn = "READ COMPASS SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Accelerometer', function() hubStrOn = "READ ACCELEROMETER SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end}, {'CC2650 SensorTag - Gyroscope', function() hubStrOn = "READ GYROSCOPE SensorTag" inBox:setText(hubStrOn) hubStrOff = hubStrOn end},}, {"TIMER Samples",{"wait(5)", function() wait(5) end}, {"blink(5,1)", function() blink(5,1) end}, {"alarm(5,1)", function() alarm(5,1) end},},Menu={
{"About",}{" ©2016 Texas Instruments", function() end}, {" Version "..date, function() end}, {" Contact: steve.arnold@ti.com ", function() end},}, {"Controls",{"Scan and Connect", function() pcall(function() TI_Innovator.connect() end) end}, {"Disconnect", function() pcall(function() TI_Innovator.disconnect() end) on.resize() end}, {"RESET", function() on.resize() end},}, {"SET Samples", {"SET LIGHT ON/OFF (default)", function() hubStrOn = "SET LIGHT ON" inBox:setText(hubStrOn) hubStrOff = "SET LIGHT OFF" on.tabKey() end}, {"SET COLOR.RED ON/OFF", function() hubStrOn = "SET COLOR.RED ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.RED OFF" on.tabKey() end}, {"SET COLOR.GREEN ON/OFF", function() hubStrOn = "SET COLOR.GREEN ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.GREEN OFF" on.tabKey() end}, {"SET COLOR.BLUE ON/OFF", function() hubStrOn = "SET COLOR.BLUE ON" inBox:setText(hubStrOn) hubStrOff = "SET COLOR.BLUE OFF" on.tabKey() end}, {"SET SOUND 220 5", function() hubStrOn = "SET SOUND 220 5" inBox:setText(hubStrOn) hubStrOff = "SET SOUND 0 1" on.tabKey() end}, {"SET SPEAKER 1 220 5", function() hubStrOn = "SET SPEAKER 1 220 5" pcall(function() TI_Innovator.Send("CONNECT SPEAKER 1 OUT1") TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SPEAKER 1 0 1" end}, {"SET LED 1 ON", function() hubStrOn = "SET LED 1 ON" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT LED 1 OUT1") TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET LED 1 0FF" end}, {"SET SERVO 1 CW 50 5", function() pcall(function() TI_Innovator.Send("CONNECT SERVO 1 BB9") end) hubStrOn = "SET SERVO 1 CW 50 5" inBox:setText(hubStrOn) hubStrOff = "SET SERVO 1 CW 50 0" on.tabKey() end}, {"SET ANALOG.OUT 1 100", function() hubStrOn = "SET ANALOG.OUT 1 100" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT ANALOG.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET ANALOG.OUT 1 0" end}, {"SET DIGITAL.OUT 1 ON", function() hubStrOn = "SET DIGITAL.OUT 1 ON" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT DIGITAL.OUT 1 OUT1") TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET DIGITAL.OUT 1 0FF" end}, }, {"READ Samples",{"READ BRIGHTNESS (default)", function() hubStrOn = "READ BRIGHTNESS" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ RANGER 1", function() hubStrOn = "READ RANGER 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT RANGER 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ DHT 1", function() hubStrOn = "READ DHT 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT DHT 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ ACCEL 1", function() hubStrOn = "READ ACCEL 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT ACCEL 1 I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ BAROMETER", function() hubStrOn = "READ BAROMETER" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT BAROMETER I2C") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) msgStr = rxValue or hubStrOn end}, {"READ ANALOG.IN 1", function() hubStrOn = "READ ANALOG.IN 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT ANALOG.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) hubStrOff = hubStrOn end}, {"READ DIGITAL.IN 1", function() hubStrOn = "READ DIGITAL.IN 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send("CONNECT DIGITAL.IN 1 IN1") TI_Innovator.Send(hubStrOn) TI_Innovator.Read() end) hubStrOff = hubStrOn end},}, {"Select Sound",{"C4", function() hubStrOn = "SET SOUND 262 TIME 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"A4", function() hubStrOn = "SET SOUND 440 TIME 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"C5", function() hubStrOn = "SET SOUND 523 TIME 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"No tone", function() hubStrOn = "SET SOUND 0 TIME 1" inBox:setText(hubStrOn) pcall(function() TI_Innovator.Send(hubStrOn) end) hubStrOff = "SET SOUND 0 1" msgStr = hubStrOff end}, {"Aliens", function() inBox:setText('Aliens') tempo = 1000 I=1 list1 = notes_aliens list2 = times_aliens playTone(list1,list2) hubStrOff = "Aliens" msgStr = hubStrOff end}, {"BallGame", function() inBox:setText('BallGame') tempo = 1000 I=1 list1 = notes_bgame list2 = times_bgame playTone(list1,list2) hubStrOff = "Take me out to the Ball Game" msgStr = hubStrOff end}, {"Happy Birthday", function() inBox:setText('Happy Birthday') tempo = 1000 I=1 list1 = notes_bday list2 = times_bday playTone(list1,list2) hubStrOff = "Happy Birthday" msgStr = hubStrOff end}, {"If I Only Had a Brain", function() inBox:setText('If I Only Had a Brain') tempo = 4000 I=1 list1 = notes_brain list2 = times_brain playTone(list1,list2) hubStrOff = "If I only had a brain" msgStr = hubStrOff end}, {"Fur Elise", function() inBox:setText('Fur Elise') tempo = 1000 I=1 list1 = notes_elise list2 = times_elise playTone(list1,list2) hubStrOff = "Fur Elise" msgStr = hubStrOff end}, {"Home on the Range", function() inBox:setText('Home on the Range') tempo = 1000 I=1 list1 = notes_home list2 = times_home playTone(list1,list2) hubStrOff = "Home on the Range" msgStr = hubStrOff end}, {"Well-tempered Scale", function() inBox:setText('Well-tempered Scale') tempo = 1000 I=1 list1 = notes_welltemp list2 = times_scale playTone(list1,list2) hubStrOff = "Well tempered scale" msgStr = hubStrOff end}, {"Harmonic Scale", function() inBox:setText('Harmonic Scale') tempo = 1000 I=1 list1 = notes_harmonic list2 = times_scale playTone(list1,list2) hubStrOff = "Harmonic scale" msgStr = hubStrOff end},}, {"TIMER Samples",{"wait(5)", function() wait(5) end}, {"blink(5,1)", function() blink(5,1) end}, {"alarm(5,0.5)", function() alarm(5,0.5) end},}, {"Robot Samples",{"CONNECT ROBOT SERVOS (BB9/BB10)", function() showKeyBoard = false TI_Innovator.Send("CONNECT SERVO 1 BB9") TI_Innovator.Send("CONNECT SERVO 2 BB10") end}, {"ROBOT FD 1 secs", function() fd(1) end}, {"ROBOT BK 1 secs", function() bk(1) end}, {"ROBOT LT 1 secs", function() lt(1) end}, {"ROBOT RT 1 secs", function() rt(1) end}, {"AUTO drive (BRIGHTNESS)", function() drive = "BRIGHTNESS" lightSeeker() end}, {"AUTO drive (DISTANCE)", function() pcall(function() TI_Innovator.Send("CONNECT RANGER 1 IN1") end) drive = "RANGER" auto() end},},-- BLE BEGINS
----------------------------- BLE ----- BEGINS --------------
-- TI Sensor Tag Init Variables
-- Temperature tempRead = 'F000AA01-0451-4000-B000-000000000000' tempStart = 'F000AA02-0451-4000-B000-000000000000' -- Humidity humidData = 'F000AA21-0451-4000-B000-000000000000' humidConf = 'F000AA22-0451-4000-B000-000000000000' -- Barometric Pressure baData = 'F000AA41-0451-4000-B000-000000000000' baConfig = 'F000AA42-0451-4000-B000-000000000000' baCalib = 'F000AA43-0451-4000-B000-000000000000' baPeriod = 'F000AA44-0451-4000-B000-000000000000' -- Light optData = 'F000AA71-0451-4000-B000-000000000000' optSwitch = 'F000AA72-0451-4000-B000-000000000000' -- 0: disable, 1: enable optPeriod = 'F000AA73-0451-4000-B000-000000000000' -- Period in tens of milliseconds -- Movement moveData = 'F000AA81-0451-4000-B000-000000000000' moveConf = 'F000AA82-0451-4000-B000-000000000000' movePeriod = 'F000AA83-0451-4000-B000-000000000000' ioData = 'F000AA65-0451-4000-B000-000000000000' ioConfig = 'F000AA66-0451-4000-B000-000000000000'
--Vernier GoLink measuredDataUUID = '1A97C2F8-DA04-11E2-B53A-00264AA53EFC' periodUUID = '1A97C2FA-DA04-11E2-B53A-00264AA53EFC' sensorIdUUID = '1A97C30D-DA04-11E2-B53A-00264AA53EFC' DDSseekRecUUID = '1A97C30E-DA04-11E2-B53A-00264AA53EFC' DDSdataUUID = '1A97C30F-DA04-11E2-B53A-00264AA53EFC' -- Vernier GoTemp VST_FIREFLY_TEMPERATURE_DATA_UUID = '1A97C2F8-DA04-11E2-B53A-00264AA53EFC'
function listenerCallback(state, scriptError)
if state == ble.ON then bleState = 'BLE ON' isBLEavailable = true elseif state == ble.OFF then bleState = 'BLE OFF' isBLEavailable = false elseif state == ble.RESETTING then bleState = 'BLE RESET' isBLEavailable = true elseif state == ble.UNSUPPORTED then bleState = 'UNSUPPORTED' isBLEavailable = false if scriptError then print('Error message: BLE not supported') end addMsg(bleState) end
screen:invalidate()
end
function peripheralOn()
if isBLEavailable thenif input and (inBox:getText()):find("CONNECT") and (inBox:getText()):find(input) then bleName = input end bleCentral.startScanning(callbackScan) connectStatus = 'Scanning' addMsg(connectStatus..": "..bleState)end screen:invalidate()end
function peripheralOff()
if isBLEconnected thenbleCentral.stopScanning() if #peripheralList > 0 thenend connectStatus = 'Stand by' peripheralName = '' isBLEconnected = false screen:invalidate()for p = #peripheralList, 1, -1 doend addMsg(connectStatus..": "..bleState)peripheralList[p]:disconnect()endend
function callbackScan(peripheral)
if peripheral and peripheral:getName() thenif bleName and (peripheral:getName()):find(bleName) and (inBox:getText()):find("CONNECT") and (inBox:getText()):find(bleName) then addMsg("BLE found: "..peripheral:getName()) peripheral:connect(callbackConnect) endend screen:invalidate()end
function callbackConnect(peripheral, event)
peripheral:discoverServices(callbackServices)if event == bleCentral.CONNECTED then
bleCentral.stopScanning() peripheralName = peripheral:getName() connectStatus = "Connected to "..peripheralName isBLEconnected = true addMsg(connectStatus) local str = "You are connected to "..peripheralName if peripheralName:find("Tag") then
str = str..string.char(10).."To read values from the associated sensors, select from the BLE Samples menu."end inBox:setText(str) table.insert(peripheralList, peripheral) peripheralName = peripheralName:gsub('%(unsupported%)', '')elseif event == bleCentral.DISCONNECTED then connectStatus = 'Disconnected' peripheralName = ''
end screen:invalidate()
end
function callbackServices(peripheral)
if peripheral ~= nil and peripheral:getState() and peripheral:getState() == bleCentral.CONNECTED thenlocal services = peripheral:getServices() for _,service in ipairs(services) do service:discoverCharacteristics(callbackCharacteristics) endend screen:invalidate()end
-------------- Vernier Go Wireless utilities ------------------------
function voltageReady(characteristic)
if ipad then
sensorVoltage = (string.unpack('s16', (characteristic:getValue()))/6400) -- divding by 64 bitshifts the 16 bit ADC readiing to a 10 bit reading, dividing by 1000 converts from mV to V.elsesensorVoltage = (ble.unpack('s16', (characteristic:getValue()))/6400)end if sensorID == 2 or sensorID == 8 thensensorVoltage = sensorVoltage -.058endif sensorEq == 0 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorVoltageelseif sensorEq == 1 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorB*sensorVoltage + sensorAelseif sensorEq == 2 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorC*sensorVoltage^2+sensorB*sensorVoltage + sensorAelseif sensorEq == 3 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*sensorVoltage^sensorBelseif sensorEq == 4 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*sensorB^sensorVoltageelseif sensorEq == 5 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA+sensorB*mathlog(sensorVoltage)elseif sensorEq == 6 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA + sensorB*math.log(1/sensorVoltage)elseif sensorEq == 7 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*math.exp(sensorB*sensorVoltage)elseif sensorEq == 8 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*math.exp(sensorB/sensorVoltage)elseif sensorEq == 9 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*sensorVoltage^(sensorb*sensorVoltage)elseif sensorEq == 10 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = sensorA*(sensorVoltage^(sensorB/sensorVoltage))elseif sensorEq == 11 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thensensorValue = 1/(sensorA+sensorB*math.log(sensorC*sensorVoltage))elseif sensorEq == 12 and sensorA~= nil and sensorB ~= nil and sensorC~= nil thenlocal r1= 15000 local temp r= (r1*(5/sensorVoltage)-1) r=(sensorVoltage*r1)/(5-sensorVoltage) temp = 1/(sensorA+(sensorB*math.log(r))+ (sensorC*(math.log(r)^3))) sensorValue = temp - 273.15endif sensorValue then
if sensorShortName:find("BARO") thensensorValue = math.floor(100*sensorValue+0.5)/100 if sensorValue <= 500 then sensorValue = 10*sensorValue endend screen:invalidate() endsensorUnits = "mbar"elseif sensorLongName:find("TI Light") thensensorValue = math.floor(100*sensorValue+0.5)/100 if sensorValue <= 10 then sensorValue = 10*sensorValue endelsesensorValue = math.floor(100*sensorValue+0.5)/100end rxValue = sensorValue addMsg(sensorLongName)-------------- BLE utilities ------------------------
function DDSseekRecWriteCallback(characteristic)
DDSdataCharacteristic:read()endfunction IDcallback(characteristic)
--sensorID=ble.unpack('s8', characteristic:getValue())--ID Using DDSdata does not return analog and digital sensors. Must use the seperate ID characteristic and UUID DDSdataCharacteristic:setValueUpdateListener(LNcallback) if ipad thenendDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 8,28,20,0), true) -- long nameelseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 8,28,20,0), true)endfunction LNcallback(characteristic)
sensorLongName= characteristic:getValue()--long name DDSdataCharacteristic:setValueUpdateListener(STcallback) if ipad thenendDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 28,40,12,0), true) -- shrot nameelseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 28,40,12,0), true)endfunction STcallback(characteristic)
sensorShortName= characteristic:getValue()--short name DDSdataCharacteristic:setValueUpdateListener(EQcallback) if ipad thenendDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 56,57,1,0), true) -- Calibration equation typeelseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 56,57,1,0), true)endfunction EQcallback(characteristic)
if ipad thenendsensorEq= string.unpack('s8', characteristic:getValue())-- equation typeelsesensorEq= ble.unpack('s8', characteristic:getValue())-- equation typeend DDSdataCharacteristic:setValueUpdateListener(PGcallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 69,70,1,0), true) -- Calibration memeory pageelseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 69,70,1,0), true)endfunction PGcallback(characteristic)
if ipad thenendsensorPg= string.unpack('s8', characteristic:getValue())-- calibration pageelsesensorPg= ble.unpack('s8', characteristic:getValue())-- calibration pageend DDSdataCharacteristic:setValueUpdateListener(Acallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 70,74,4,04), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 70,74,4,04), true) -- Aendfunction Acallback(characteristic)
if ipad thenendsensorA= string.unpack('f', characteristic:getValue())-- AelsesensorA= ble.unpack('f', characteristic:getValue())-- Aend DDSdataCharacteristic:setValueUpdateListener(Bcallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 74,78,4,0), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 74,78,4,0), true) -- Bendfunction Bcallback(characteristic)
if ipad thenendsensorB= string.unpack('f', characteristic:getValue())-- BelsesensorB= ble.unpack('f', characteristic:getValue())-- Bend DDSdataCharacteristic:setValueUpdateListener(Ccallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 78,82,4,0), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 78,82,4,0), true) -- Cendfunction Ccallback(characteristic)
if ipad thenendsensorC= string.unpack('f', characteristic:getValue())-- CelsesensorC= ble.unpack('f', characteristic:getValue())-- Cend DDSdataCharacteristic:setValueUpdateListener(UNcallback) if ipad thenDDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 82,86,7,0), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 82,86,7,0), true) -- unitsendfunction UNcallback(characteristic)
sensorUnits= characteristic:getValue()-- units checkAnalogDigitalSesnors()endfunction readSensorIDCallback(characteristic)
if ipad thenendsensorID=string.unpack('s8', sensorIDCharacteristic:getValue())elsesensorID=ble.unpack('s8', sensorIDCharacteristic:getValue())endfunction periodWriteCallback(characteristic)
periodWriteFlag = trueendfunction checkAnalogDigitalSesnors()
if sensorID == 1 thenendsensorLongName = "Thermocouple" sensorUnits= "°C " sensorShortName= "TC" sensorA= 6.2115 sensorB= -2.45455 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 2 thensensorLongName= "Voltage +/- 10V" sensorUnits= "V" sensorShortName= "Voltage10" sensorA= -10 sensorB= 4 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 3 thensensorLongName = "Current" sensorUnits= "Amps" sensorShortName= "Current" sensorA= 6.325 sensorB= -2.665 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 4 thensensorLongName = "Resistance" sensorUnits= "Ohms" sensorShortName= "Diff V" sensorA= 6.25 sensorB= -2.5 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 8 thensensorLongName = "Diff Voltage" sensorUnits= "V" sensorShortName= "Diff V" sensorA= 6.25 sensorB= -2.5 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 9 thensensorLongName = "Current" sensorUnits= "Amp" sensorShortName= "I" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 10 thensensorLongName = "Temperature" sensorShortName ="Temp" sensorPg = 1 sensorUnits = "°C " sensorEq = 12 sensorA = .00102119 sensorB = .000222468 sensorC = .000000133342elseif sensorID == 11 thensensorLongName = "Temperature" sensorUnits= "°C " sensorShortName= "Temp" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 12 thensensorLongName = "TI Light" sensorUnits= "relative" sensorShortName= "TI Light" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 13 thensensorLongName = "Exercise Heart Rate" sensorUnits= "V" sensorShortName= "Ex HR" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 14 thensensorLongName = "Voltage" sensorUnits= "V" sensorShortName= "Volts" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 15 thensensorLongName = "EKG" sensorUnits= "V" sensorShortName= "EKG" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 17 thensensorLongName = "Carbon Dioxide" sensorUnits= "ppm" sensorShortName= "CO2" sensorB= 1 sensorA= 0 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 18 thensensorLongName = "Oxygen" sensorUnits= "%" sensorShortName= "O2" sensorA= 0 sensorB= 1 sensorC = 0 sensorPg = 1 sensorEq= 1elseif sensorID == 67 thensensorLongName = nil sensorUnits= nil sensorShortName= nil sensorA= nil sensorB= nil sensorC = nil sensorPg = nil sensorEq= nilend addMsg("Sensor Ready!")-- BLE Specific Functions ---------
function callbackCharacteristics(service)
local characteristicsList = service:getCharacteristics()
for _,characteristic in ipairs(characteristicsList) do
-- Simple Keys if characteristic:getUUID() == keysRead then characteristic:setValueUpdateListener(callbackCharacteristic)
characteristic:setNotify(true)end-- IO control
if characteristic:getUUID() == ioData then
local msg = 0 characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(msg), true)endif characteristic:getUUID() == ioConfig then -- 02
local msg = 1 characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(msg), true)end-- Temperature if characteristic:getUUID() == tempRead then
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == tempStart then
characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(1), true)
end
-- Humidity if characteristic:getUUID() == humidData then
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == humidConf then
characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(1), true)
end
-- Barometric Pressure if characteristic:getUUID() == baData then
readBa = characteristic readBa:setValueUpdateListener(callbackCharacteristic) readBa:setNotify(true)
end
if characteristic:getUUID() == baCalib then
calibBa = characteristic calibBa:setValueUpdateListener(callbackCharacteristic) calibBa:read()
end
if characteristic:getUUID() == baConfig then
writeBa = characteristic local msg = string.char(1) writeBa:setWriteCompleteListener(callbackCharacteristic) writeBa:write(msg, true) local msg = string.char(2) writeBa:setWriteCompleteListener(callbackCharacteristic) writeBa:write(msg, true)
end
-- Light
if characteristic:getUUID() == optData then --01
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == optSwitch then -- 02
local msg = 1 characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(msg), true)
end
-- Movement Sensors
if characteristic:getUUID() == moveData then -- 01
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == moveConf then -- 02
local msg if ipad then
msg = string.pack('u16', 0x007F)elsemsg = ble.pack('u16', 0x007F)end characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(msg, true)end
if characteristic:getUUID() == movePeriod then -- 03
characteristic:setWriteCompleteListener(callbackCharacteristic) characteristic:write(string.char(1), true)
end
if characteristic:getUUID() == VST_FIREFLY_TEMPERATURE_DATA_UUID and peripheralName and peripheralName:find("Temp") then
characteristic:setValueUpdateListener(callbackCharacteristic) characteristic:setNotify(true)
end
if characteristic:getUUID() == measuredDataUUID and peripheralName and peripheralName:find("Link") then
characteristic:setValueUpdateListener(voltageReady) characteristic:setNotify(true)
end
if characteristic:getUUID() == periodUUID then
setPeriodCharacteristic = characteristic if ipad then
setPeriodCharacteristic:write(string.pack('u32', sensorPeriod), true)elsesetPeriodCharacteristic:write(ble.pack('u32', sensorPeriod), true)endend
if characteristic:getUUID() == sensorIdUUID then
sensorIDCharacteristic = characteristic sensorIDCharacteristic:setValueUpdateListener(readSensorIDCallback) sensorIDCharacteristic:read()
end
if characteristic:getUUID() == DDSseekRecUUID then
DDSseekRecCharacteristic = characteristic DDSseekRecCharacteristic:setWriteCompleteListener(DDSseekRecWriteCallback)
end
if characteristic:getUUID() == DDSdataUUID then
DDSdataCharacteristic = characteristic if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 01,02,01,0), true)elseDDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 01,02,01,0), true)end DDSdataCharacteristic:setValueUpdateListener(IDcallback) addMsg("Reading Sensor Configuration")end
end
end
function callbackCharacteristic(characteristic)
local text = inBox:getText() or '' if text then text = string.upper(text) end if characteristic:getUUID() == ioData then
stChar = characteristicend-- Simple Keys
if characteristic:getUUID() == keysRead then local value = characteristic:getValue() if value and string.len(tostring(value)) == 1 then
local keyPress = 0 if ipad thenendkeyPress = string.unpack("u8",value)elsekeyPress = ble.unpack("u8",value)end if keyPress thenif keyPress == 2 thenendLstart = timer.getMilliSecCounter()end if keyPress == 1 thenRstart = timer.getMilliSecCounter()end if keyPress == 0 thenif Lstart ~= 0 then Lstop = math.abs((Lstart - timer.getMilliSecCounter())/1000) end if Rstart ~= 0 then Rstop = math.abs((Rstart - timer.getMilliSecCounter())/1000) endend if Lstop > 0 thenon.tabKey() Lstart = 0 Lstop = 0end if Rstop > 0 thenif Rstop > 1 thenendon.escapeKey()elsewait(5)end Rstart = 0 Rstop = 0 end--Temperature
if characteristic:getUUID() == tempRead and string.upper(text):find("READ") and string.upper(text):find("TEMP") then
local value = characteristic:getValue() if value and string.len(tostring(value)) == 4 then
local loWord, hiWord if ipad thenloWord, hiWord = string.unpack("s16u16",value)elseloWord, hiWord = ble.unpack("s16u16",value)end local dietemp = tonumber(hiWord) / 128 local irtemp = tonumber(loWord) / 128 if dietemp and irtemp thendietemp = math.floor(100*dietemp + 0.5)/100 irtemp = math.floor(100*irtemp + 0.5)/100 if text:find("AMBIENT") thenendrxValue = math.floor(100*dietemp+0.5)/100 sensorLongName = "SensorTag Ambient Temperature"elseif text:find("IR TEMP") thenrxValue = math.floor(100*irtemp +0.5)/100 sensorLongName = "SensorTag IR Temperature"end addMsg(sensorLongName) sensorUnits= "°C "end
end
-- Humidity if characteristic:getUUID() == humidData and string.upper(text):find("READ") and string.upper(text):find("HUMID") then
local value = characteristic:getValue() if value and string.len(tostring(value)) == 4 then
local loWord, hiWord if ipad thenloWord, hiWord = string.unpack("s16u16",value)elseloWord, hiWord = ble.unpack("s16u16",value)end local Humidity = -6 + 125*tonumber(hiWord)/65536 local theHumidityTemp = -40 + 165*tonumber(loWord)/65536 rxValue = math.floor(100*Humidity+0.5)/100 sensorLongName = "SensorTag Humidity" addMsg(sensorLongName.." (+Temp: "..(math.floor(10*theHumidityTemp+0.5)/10).."°C)") sensorUnits= "% "end
end
--BAROMETER if characteristic:getUUID() == baData and string.upper(text):find("READ") and string.upper(text):find("BARO") then
local value = characteristic:getValue() if value and string.len(tostring(value)) > 4 then
local temp, pressure if ipad thentemp, pressure = string.unpack('u24', value)elsetemp, pressure = ble.unpack('u24', value)end local baTemp = temp/100 local baTemp = math.floor(100*baTemp + 0.5)/100 local baro = 0 if ipad thenbaro = string.unpack("u24", pressure)/100elsebaro = ble.unpack("u24", pressure)/100end baro = math.floor(100*baro + 0.5)/100 local p0 = var.recall("basepa") or 1013.25 local alt = 44330.*(1-(((baro)/(p0)))^(((1)/(5.255)))) alt = math.floor(100*alt + 0.5)/100 rxValue = math.floor(100*baro+0.5)/100 sensorLongName = "SensorTag Baro" sensorUnits= " mbar " addMsg(sensorLongName.." (+Temp: "..(math.floor(10*baTemp+0.5)/10).."°C Alt: "..(math.floor(10*alt+0.5)/10).." m)")end
end
-- Light Intensity if characteristic:getUUID() == optData and string.upper(text):find("READ") and string.upper(text):find("LIGHT") then
local value = characteristic:getValue() if value thenlocal rawLux = '' if ipad thenrawLux = string.unpack('u16', value)elserawLux = ble.unpack('u16', value)end local exponent = bit.brshift(bit.band(rawLux, 0xF000), 12) local mantissa = bit.band(rawLux, 0x0FFF) local light = mantissa * math.pow(2, exponent)/1000 light = math.floor(100*light + 0.5)/100 rxValue = math.floor(100*light +0.5)/100 sensorLongName = "SensorTag Light Intensity" addMsg(sensorLongName) sensorUnits= "lux "end
end
-- Movement if characteristic:getUUID() == moveData and string.upper(text):find("READ") then
local value = characteristic:getValue() if value thenendlocal m1, m2, m3, m4, m5, m6, m7, m8, m9 if ipad thenendm1, m2, m3, m4, m5, m6, m7, m8, m9 = string.unpack("s16s16s16s16s16s16s16s16s16", value)elsem1, m2, m3, m4, m5, m6, m7, m8, m9 = ble.unpack("s16s16s16s16s16s16s16s16s16", value)endif string.upper(text):find("GYR") then
local gyrx = math.floor(100*(-1*tonumber(m1)* 500 / 65536) + 0.5)/100 local gyry = math.floor(100*(-1*tonumber(m2)* 500 / 65536) + 0.5)/100 local gyrz = math.floor(100*(-1*tonumber(m3)* 500 / 65536) + 0.5)/100 rxValue = "{"..gyrx..", "..gyry..", "..gyrz.."}" sensorLongName = "SensorTag Gyroscope" addMsg(sensorLongName) sensorUnits= "°/s "endif string.upper(text):find("ACC") then
local xa = math.floor(100*(-3.9*tonumber(m4)* 2 / 32768) + 0.5)/10 local ya = math.floor(100*(-3.9*tonumber(m5)* 2 / 32768) + 0.5)/10 local za = math.floor(100*(-3.9*tonumber(m6)* 2 / 32768) + 0.5)/10 rxValue = "{"..xa..", "..ya..", "..za.."}" sensorLongName = "SensorTag Accelerometer" addMsg(sensorLongName) sensorUnits= "G "endif string.upper(text):find("MAG") or string.upper(text):find("COMPASS") then
local magx = math.floor(100*(tonumber(m7)* -4912 / 32768) + 0.5)/100 local magy = math.floor(100*(tonumber(m8)* -4912 / 32768) + 0.5)/100 local magz = math.floor(100*(tonumber(m9)* -4912 / 32768) + 0.5)/100 rxValue = "{"..magx..", "..magy..", "..magz.."}" sensorLongName = "SensorTag Magnetometer" addMsg(sensorLongName) sensorUnits= "μT "endif inBox:getText() and inBox:getText():find("Go Wireless Temp") and characteristic:getUUID() == measuredDataUUID then
--Vernier Go Temp local value = characteristic:getValue() if peripheralName:find("Temp") thenendlocal data = 0 if ipad thenenddata = string.unpack('u16', value)elsedata = ble.unpack('u16', value)end vTemp = data/128 vTempF = (vTemp*9/5)+32 rxValue = math.floor(100*vTemp+0.5)/100 sensorLongName = "Go Wireless Temp" addMsg(sensorLongName) sensorUnits= "°C "screen:invalidate()
end
-- LuaBit v0.3 (Lua bit library) ---------
--[[--------------- LuaBit v0.3 ------------------- a bitwise operation lib for lua. http://luaforge.net/projects/bit/ Under the MIT license. copyright(c) 2006 hanzhao (abrash_han@hotmail.com) --]]---------------
do
------------------------ -- bit lib implementions
endlocal function check_int(n) -- checking not float
if(n - math.floor(n) > 0) thenenderror("trying to use bitwise operation on non-integer!")endlocal function to_bits(n)
check_int(n) if(n <= 0) thenend return tbl-- negative return to_bits(bit.bnot(math.abs(n)) + 1)end -- to bits table local tbl = {} local cnt = 1 while (n > 0) dolocal last = n % 2 if(last == 1) thenn = (n-last)/2 cnt = cnt + 1tbl[cnt] = 1elsetbl[cnt] = 0endlocal function tbl_to_number(tbl)
local n = table.getn(tbl) local rslt = 0 local power = 1 for i = 1, n doendrslt = rslt + tbl[i]*powerpower = power*2 end return rsltlocal function expand(tbl_m, tbl_n)
local big = {} local small = {} if(table.getn(tbl_m) > table.getn(tbl_n)) thenendbig = tbl_m small = tbl_nelsebig = tbl_n small = tbl_mend -- expand small for i = table.getn(small) + 1, table.getn(big) dosmall[i] = 0endlocal function bit_or(m, n)
local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n)) for i = 1, rslt doendif(tbl_m[i]== 0 and tbl_n[i] == 0) thenend return tbl_to_number(tbl)tbl[i] = 0elsetbl[i] = 1endlocal function bit_and(m, n)
local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n)) for i = 1, rslt doendif(tbl_m[i]== 0 or tbl_n[i] == 0) thenend return tbl_to_number(tbl)tbl[i] = 0elsetbl[i] = 1endlocal function bit_not(n)
local tbl = to_bits(n) local size = math.max(table.getn(tbl), 32) for i = 1, size doendif(tbl[i] == 1) thenend return tbl_to_number(tbl)tbl[i] = 0elsetbl[i] = 1endlocal function bit_xor(m, n)
local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n)) for i = 1, rslt doendif(tbl_m[i] ~= tbl_n[i]) thenend --table.foreach(tbl, print) return tbl_to_number(tbl)tbl[i] = 1elsetbl[i] = 0endlocal function bit_rshift(n, bits)
check_int(n) local high_bit = 0 if(n <= 0) thenend-- negative n = bit_not(math.abs(n)) + 1 high_bit = 2147493649 -- 0x80000000end for i=1, bits don = n/2 n = bit_or(math.floor(n), high_bit)end return math.floor(n)-- logic rightshift assures zero filling shift
local function bit_logic_rshift(n, bits)
check_int(n) if(n <= 0) thenend-- negative n = bit_not(math.abs(n)) + 1end for i=1, bits don = n/2end return math.floor(n)local function bit_lshift(n, bits)
check_int(n) if(n <= 0) thenend-- negative n = bit_not(math.abs(n)) + 1end for i=1, bits don = n*2end return bit_and(n, 4294967295) -- 0xFFFFFFFFlocal function bit_xor2(m, n)
local rhs = bit_or(bit_not(m), bit_not(n)) local lhs = bit_or(m, n) local rslt = bit_and(lhs, rhs) return rsltend-------------------- -- bit lib interface
bit = {
-- bit operations bnot = bit_not, band = bit_and, bor = bit_or, bxor = bit_xor, brshift = bit_rshift, blshift = bit_lshift, bxor2 = bit_xor2, blogic_rshift = bit_logic_rshift,-- utility func tobits = to_bits, tonumb = tbl_to_number, }
end
Home ← STEM HQ ← TI-Nspire Authoring ← TI-Nspire Scripting HQ ← Scripting Tutorial - Lesson 49