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 hh = platform:isDeviceModeRendering()
local screen = platform.window
local date = "021517"
local ipad = platform:isTabletModeRendering()require 'color'
pcall(function () require 'bleCentral' end)
pcall(function() require 'asi' 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 = ''end
connectStatus = ''
peripheralName = ''
peripheralList = {}
alert = 0
bleName = nil
Lstart = 0
Lstop = 0
Rstart = 0
Rstop = 0sensorVoltage = nil
periodChar = nil
DDSRecord = 1
writeFlag = false
readFlag = false
returnPeriod = nil
sensorPeriod = 100setPeriodCharacteristic = nil
DDSseekRecCharacteristic = nil
DDSdataCharacteristic = nil
sensorIDCharacteristic = nilsensorID = nil
sensorLongName = ''
sensorShortName = ''
sensorEqType = nil
sensorPage =nil
sensorA = nil
sensorB = nil
sensorC =nil
sensorUnits = ''
sensorValue = nilBLEvars()
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()end
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)BLEvars()-- 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 24end
fontSize = fontSize > 6 and fontSize or 7
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}else
myColor = {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()end
inBox:setText('')
inBox:setFocus(true)
screen:invalidate()
function on.tabKey()
if inBox:getText() thenend
local input = string.upper(inBox:getText())end
input = input:gsub('%"','')
local list = {input}
if input:find(string.char(10)) then
list = input:split(string.char(10)) or {input:gsub(string.char(10),'')}end
input = list[1]
if input:find("SEND%(") then
input = input:gsub('SEND%(','')elseif input:find("SET") then
input = input:gsub('%)','')
hubStrOn = input
pcall(function() TI_Innovator.Send(input)
TI_Innovator.Read() end)
pcall(function() TI_Innovator.Send(input) end)elseif input:find("READ") then
if input:find("ON") then
hubStrOn = inputelseif input:find("OFF") then
hubStrOff = input:gsub("ON","OFF")
hubStrOff = inputend
hubStrOn = input:gsub("OFF","ON")
pcall(function() TI_Innovator.Send(input)elseif input:find("CONNECT") then
TI_Innovator.Read() end)
hubStrOn = input
hubStrOff = input
pcall(function()TI_Innovator.Send(input) end)else
local testfunction = loadstring(string.lower(input))end
pcall(function() testfunction() screen:invalidate() end)
if #list > 1 then
for k = 2, #list doend
input = list[k]end
if input:find("SEND%(") then
input = input:gsub('SEND%(','')elseif input:find("SET") then
input =input:gsub('%)','')
pcall(function() TI_Innovator.Send(input)
TI_Innovator.Read() end)
pcall(function() TI_Innovator.Send(input) end)elseif input:find("READ") then
if input:find("ON") then
hubStrOn = inputelseif input:find("OFF") then
hubStrOff = input:gsub("ON","OFF")
hubStrOff = inputend
hubStrOn = input:gsub("OFF","ON")
pcall(function() TI_Innovator.Send(input)elseif input:find("CONNECT") then
TI_Innovator.Read() end)
hubStrOn = input
hubStrOff = input
pcall(function() TI_Innovator.Send(input) end)else
local testfunction = loadstring(string.lower(input))end
pcall(function() testfunction() screen:invalidate() end)
STalerts()
screen:invalidate()
function on.mouseDown(x, y)
pcall(function()end
if hubStrOn:find("ROBOT") then
if drive:find("BRIGHT") thenelse
lightSeeker()elseif drive:find("RANGER") then
auto()else
TI_Innovator.Send("SET SERVO 1 CCW 50 5") TI_Innovator.Send("SET SERVO 2 CW 50 5")end
TI_Innovator.Read()
TI_Innovator.Send(hubStrOn) -- This is an example of sending a SET command to the Hubend
TI_Innovator.Read() -- This is an example of sending a READ command to the Hub
end)
if x > boxX and x <= boxX + boxWidth then
if y > boxY + boxHeight and y <= boxY + boxHeight + 0.1*h thenend
on.tabKey()elseif y > boxY + boxHeight + 0.1*h and y <= boxY + boxHeight + 0.2*h then
on.escapeKey()end
screen:invalidate()
function on.mouseUp (x,y)
pcall(function() if hubStrOn:find("ROBOT") thenend
if drive == '' thenend
TI_Innovator.Send("SET SERVO 1 CCW 0 0") TI_Innovator.Send("SET SERVO 2 CW 0 0")else
TI_Innovator.Read() end
timeStr = ''end
TI_Innovator.Send(hubStrOff)
TI_Innovator.Read()
end)
screen:invalidate()
function str2list(input, def)
local list = {}
if input:find(def) then
list = input:split(def)else
table.foreachi(list,print)
list = {input}end
return list
endfunction TI_InnovatorReadCallback(port, error_msg) -- this is the callback function that is defined above and catches the result of a READ command send to the Hub.
pcall(function()end
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()
function TI_InnovatorStateCallback(event)
pcall(function()end
addMsg("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()end
-- place CONNECT and other Hub startup commands here
addMsg("TI_Innovator Hub connected")
TI_Innovator.Send(hubStrOff)
end)
function wait(input)
endif input then delay = input end
time_step = 0.1
if delay >= 0 then
timeStr = "Wait Time: "..delay.." seconds"else
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 tool
dataList[#dataList+1] = tonumber(rxValue)else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end
index[#index+1]=#dataList
var.store("index", index)
var.store("dataList", dataList)
oneShotTimer(1000*time_step,wait)
pcall(function() TI_Innovator.Send(hubStrOff) end)end
delay = 0
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..")"end
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.5
screen:invalidate()
function alarm(rep,waitValue)
local tone = 220end
if waitValue then delay = waitValue end
if rep then repeats = rep end
if repeats > 0 then
timeStr = "alarm("..(math.floor(repeats+0.5))..", "..delay..")"end
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.5
screen:invalidate()
function STalerts()
if isBLEconnected thenend
if stChar then
hubStrOn = inBox:getText() or "SET LIGHT ON"end
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
screen:invalidate()
function waitTone()
if not list1 then list1 = var.recall("list1") endend
if not list2 then list2 = var.recall("list2") end
if list1 and #list1 > 0 and list2 and #list2 > 0 then
if I <= #list1 and list1[I] and list2[I] then -- don't go past the lenght of the arrayend
if list1[I] and list2[I] thenelse
local str = "SET SOUND "..list1[I]*2^(key/12).." TIME "..math.floor(100/(list2[I])+0.5)/100end
hubStrOn = str
pcall(function() TI_Innovator.Send(str) end)
oneShotTimer((tempo/list2[I])+20, waitTone)
I = I + 1
hubStrOn = "SET LIGHT ON"end
hubStrOff = "SET LIGHT OFF"
addMsg(hubStrOff)
screen:invalidate()
function playTone(list1, list2)
waitTone()end
screen:invalidate()
function fd(input)
if input thenend
inBox:setText("SET SERVO 1 CCW 100 "..input ..string.char(10).."SET SERVO 2 CW 100 "..input)end
hubStrOn = "ROBOT FORWARD"
addMsg(hubStrOn)
oneShotTimer(1000,fd)
on.tabKey()
hubStrOff = "ROBOT OFF" addMsg(hubStrOff)
screen:invalidate()
function bk(input)
if input thenend
inBox:setText("SET SERVO 1 CW 100 "..input ..string.char(10).."SET SERVO 2 CCW 100 "..input)end
hubStrOn = "ROBOT BACK"
addMsg(hubStrOn)
oneShotTimer(1000,bk)
on.tabKey()
hubStrOff = "ROBOT OFF" addMsg(hubStrOff)
screen:invalidate()
function lt(input)
if input thenend
inBox:setText("SET SERVO 1 CW 100 "..input ..string.char(10).."SET SERVO 2 CW 100 "..input)end
hubStrOn = "ROBOT LEFT"
addMsg(hubStrOn)
oneShotTimer(1000,lt)
on.tabKey()
hubStrOff = "ROBOT OFF" addMsg(hubStrOff)
screen:invalidate()
function rt(input)
if input thenend
inBox:setText("SET SERVO 1 CCW 100 "..input ..string.char(10).."SET SERVO 2 CCW 100 "..input)end
hubStrOn = "ROBOT RIGHT"
addMsg(hubStrOn)
oneShotTimer(1000,rt)
on.tabKey()
hubStrOff = "ROBOT OFF" addMsg(hubStrOff)
screen:invalidate()
function lightSeeker()
if drive:find("BRIGHT") thenend
pcall(function() TI_Innovator.Send("READ BRIGHTNESS ")end
TI_Innovator.Read() end)
if tonumber(rxValue) and tonumber(rxValue) > 0 then
if tonumber(rxValue) > 0.5 thenend
if tonumber(rxValue) > 10 thenelse
fd(1)else
bk(1)end
rt(1)
fd(0)end
hubStrOff = "ROBOT AUTO OFF"
addMsg(hubStrOff)
play = false
oneShotTimer(1000,lightSeeker)
screen:invalidate()
function auto()
if drive:find("RANGER") thenend
pcall(function() TI_Innovator.Send("READ RANGER 1 ")end
TI_Innovator.Read() end)
if tonumber(rxValue) and tonumber(rxValue) > 0 then
pcall(function() TI_Innovator.Send("SET SOUND "..1000*tonumber(rxValue).." 0.1") end)end
if tonumber(rxValue) > 0.1 then
if tonumber(rxValue) > 0.4 thenelse
fd(1)else
bk(0.5)end
rt(0.5)
fd(0)end
hubStrOff = "ROBOT AUTO OFF"
addMsg(hubStrOff)
play = false
oneShotTimer(1000,auto)
screen:invalidate()
--End of user code do not modify below this line
-- TI Innovator Code Do not modify any code below this line
-- oneShotTimer BEGINS
local timerstart = timer.start
local timerstop = timer.stop
timer.start = nil
timer.stop = nil
local currentTimer = nillocal function timerStart(t)
endcurrentTimer = t
timerstart(t.period/1000)
local function timerStop()
endcurrentTimer = nil
timerstop()
local function setTimer(t)
endif t.period==nil or type(t.period)~='number' or t.period < 10 then error('period in milliseconds >= 10') end
timerStart(t)
return t
function oneShotTimer(period, listenerHandler, ...)
endif type(listenerHandler) ~= 'function' then
error('createTimerOneShot: function expected')end
setTimer {
period = period,}
oneShot = true,
listenerHandler = listenerHandler,
params = { ... },
function on.timer()
endlocal ct = currentTimer
if currentTimer == nil then
timerStop()end
if currentTimer.oneShot then
currentTimer = nilend
timerStop()
ct.listenerHandler(unpack(ct.params))
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')end
return
addMsg('Hub available')
isASIavailable = true
local HANDSHAKE_GREETING = 'ISTI\n'
local HANDSHAKE_ANSWER = 'TISTEM'
local portFoundList = { }
local state
local handshakeState
local notifyEvent
local asiStateListener
local startScanning
local stopScanning
local portFoundListener
local portStateListener
local handshake_SendListener
local handshake_readListener
local handshake_port
local TI_Innovator_port
local baudRate = asi.BAUD_RATE_DEFAULT
local readTimeout = asi.READ_TIMEOUT_DEFAULT-- User callbacks
local stateCallback = theStateCallback
local SendCallback
local readCallbackfunction notifyEvent(event)
addMsg('notifying '.. event)end
if stateCallback then
stateCallback(event)else
addMsg('no callback registered')end
function startScanning()
if isASIavailable thenend
asi.startScanning(portFoundListener)end
notifyEvent('scanning')
function stopScanning()
handshake_port = nilend
portFoundList = { }
asi.stopScanning()
function asiStateListener(asiState)
if asi.ON == asiState thenend
if state == 'active' thenelseif asi.UNSUPPORTED == asiState then
startScanning()end
notifyEvent(asi.UNSUPPORTED)end
function portFoundListener(portFound)
addMsg('portFoundListener '.. portFound:getName())end
table.insert(portFoundList, portFound)
if not TI_Innovator_port and not handshake_port then
handshake_port = portFoundList[1]end
oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)
function portStateListener(reportedPort, event, error_msg)
addMsg('portStateListener '..reportedPort:getName()..' '..event)end
if asi.CONNECTED == event then
-- configure port for handshakeelseif asi.CONNECTING_FAILED == event then
reportedPort:setWriteListener(handshake_writeListener)
reportedPort:setReadListener(handshake_readListener)
reportedPort:setReadTimeout(500)
handshakeState = 'handshake'
-- write handshake greeting
addMsg("HANDSHAKE_GREETING: "..HANDSHAKE_GREETING)
oneShotTimer(200, reportedPort.write, reportedPort, HANDSHAKE_GREETING)
if reportedPort == handshake_port thenelseif asi.DISCONNECTED == event then
table.remove(portFoundList, 1)elseif reportedPort == TI_Innovator_port then
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
if reportedPort == TI_Innovator_port thenend
if state == 'active' thenend
if reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')
reportedPort:connect(portStateListener)else
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
function handshake_writeListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
if 'handshake' == handshakeState then
reportedPort:read(#HANDSHAKE_ANSWER+2)end
function handshake_readListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
local answer = reportedPort:getValue()
if 'handshake' == handshakeState then
-- Validate answerelseif 'ready' == handshakeState then
if answer and answer:find(HANDSHAKE_ANSWER) then
addMsg("HANDSHAKE_ANSWER: "..HANDSHAKE_ANSWER)else
stopScanning()
handshakeState = 'ready'
reportedPort:write('BEGIN\n')
reportedPort:read(7)
reportedPort:disconnect()end
table.remove(portFoundList, 1)
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
if answer and answer:find('READY') thenend
-- Configure port for normal useend
TI_Innovator_port = reportedPort
TI_Innovator_port:setReadTimeout(readTimeout)
TI_Innovator.setWriteListener(SendCallback)
TI_Innovator.setReadListener(readCallback)
-- Notify launchpad is ready
notifyEvent('ready')
-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active'end
startScanning()
function TI_Innovator.disconnect()
if isASIavailable and not ipad thenend
state = 'inactive'
if isASIavailable then
if TI_Innovator_port thenend
TI_Innovator_port:disconnect()end
TI_Innovator_port = nil
stopScanning()
end
function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallbackend
if TI_Innovator_port then
TI_Innovator_port:setWriteListener(writeCallback)end
function TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallbackend
if TI_Innovator_port then
TI_Innovator_port:setReadListener(readCallback)end
function TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRateend
if TI_Innovator_port then
TI_Innovator_port:setBaudRate(baudRate)end
function TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeoutend
if TI_Innovator_port then
TI_Innovator_port:setReadTimeout(readTimeout)end
function TI_Innovator.Send(data)
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
addMsg('No Hub attached')end
return 'No Hub attached'
local result = TI_Innovator_port:write(data .. '\n')
if result then addMsg(tostring(data)..': '.. tostring(result))
else addMsg(tostring(data)) end
return result
end
function TI_Innovator.Read(bytes_to_read)
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return "No TI Hub attached"end
return TI_Innovator_port:read(bytes_to_read)
end
function TI_Innovator.request(request)
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return "No TI Hub attached"end
local result = TI_Innovator_port:write(request .. '\n')
if result then addMsg(tostring(request) .. ': '.. tostring(result))
else addMsg(tostring(request)) end
result = TI_Innovator_port:read()
addMsg('read() '.. tostring(result))
if result then
addMsg('Error sending request: ' .. tostring(request))end
return result
end
function TI_Innovator.isConnected()
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return falseend
end
return TI_Innovator_port:getState() == asi.CONNECTED
function TI_Innovator.getName()
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return "No TI Hub attached"end
return TI_Innovator_port:getName()
endfunction TI_Innovator.getIdentifier()
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return "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) endend
------------------------------------------------------------------------
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()
endlocal Menu
if isBLEavailable then
Menu={
{"About",}
{" ©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},
else
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},
toolpalette.register(Menu)
----------------------------- 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)
endscreen:invalidate()
end
function peripheralOn()
if isBLEavailable then
if input and (inBox:getText()):find("CONNECT") and (inBox:getText()):find(input) then bleName = input endend
bleCentral.startScanning(callbackScan)
connectStatus = 'Scanning'
addMsg(connectStatus..": "..bleState)
screen:invalidate()
end
function peripheralOff()
if isBLEconnected then
bleCentral.stopScanning()end
if #peripheralList > 0 then
for p = #peripheralList, 1, -1 doend
peripheralList[p]:disconnect()end
addMsg(connectStatus..": "..bleState)
connectStatus = 'Stand by'
peripheralName = ''
isBLEconnected = false
screen:invalidate()
end
function callbackScan(peripheral)
if peripheral and peripheral:getName() then
if bleName and (peripheral:getName()):find(bleName) and (inBox:getText()):find("CONNECT") and (inBox:getText()):find(bleName) thenend
addMsg("BLE found: "..peripheral:getName())
peripheral:connect(callbackConnect)
end
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 then
local services = peripheral:getServices()end
for _,service in ipairs(services) do
service:discoverCharacteristics(callbackCharacteristics)
end
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.else
sensorVoltage = (ble.unpack('s16', (characteristic:getValue()))/6400)end
if sensorID == 2 or sensorID == 8 then
sensorVoltage = sensorVoltage -.058end
if 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 then
sensorValue = sensorB*sensorVoltage + sensorAelseif sensorEq == 2 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorC*sensorVoltage^2+sensorB*sensorVoltage + sensorAelseif sensorEq == 3 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*sensorVoltage^sensorBelseif sensorEq == 4 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*sensorB^sensorVoltageelseif sensorEq == 5 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA+sensorB*mathlog(sensorVoltage)elseif sensorEq == 6 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA + sensorB*math.log(1/sensorVoltage)elseif sensorEq == 7 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*math.exp(sensorB*sensorVoltage)elseif sensorEq == 8 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*math.exp(sensorB/sensorVoltage)elseif sensorEq == 9 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*sensorVoltage^(sensorb*sensorVoltage)elseif sensorEq == 10 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*(sensorVoltage^(sensorB/sensorVoltage))elseif sensorEq == 11 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = 1/(sensorA+sensorB*math.log(sensorC*sensorVoltage))elseif sensorEq == 12 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
local r1= 15000end
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.15
if sensorValue then
if sensorShortName:find("BARO") then
sensorValue = math.floor(100*sensorValue+0.5)/100end screen:invalidate()
if sensorValue <= 500 then sensorValue = 10*sensorValue end
sensorUnits = "mbar"elseif sensorLongName:find("TI Light") then
sensorValue = math.floor(100*sensorValue+0.5)/100else
if sensorValue <= 10 then sensorValue = 10*sensorValue end
sensorValue = math.floor(100*sensorValue+0.5)/100end
rxValue = sensorValue
addMsg(sensorLongName)
end-------------- BLE utilities ------------------------
function DDSseekRecWriteCallback(characteristic)
DDSdataCharacteristic:read()end
function 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 UUIDend
DDSdataCharacteristic:setValueUpdateListener(LNcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 8,28,20,0), true) -- long nameelse
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 8,28,20,0), true)end
function LNcallback(characteristic)
sensorLongName= characteristic:getValue()--long nameend
DDSdataCharacteristic:setValueUpdateListener(STcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 28,40,12,0), true) -- shrot nameelse
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 28,40,12,0), true)end
function STcallback(characteristic)
sensorShortName= characteristic:getValue()--short nameend
DDSdataCharacteristic:setValueUpdateListener(EQcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 56,57,1,0), true) -- Calibration equation typeelse
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 56,57,1,0), true)end
function EQcallback(characteristic)
if ipad thenend
sensorEq= string.unpack('s8', characteristic:getValue())-- equation typeelse
sensorEq= ble.unpack('s8', characteristic:getValue())-- equation typeend
DDSdataCharacteristic:setValueUpdateListener(PGcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 69,70,1,0), true) -- Calibration memeory pageelse
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 69,70,1,0), true)end
function PGcallback(characteristic)
if ipad thenend
sensorPg= string.unpack('s8', characteristic:getValue())-- calibration pageelse
sensorPg= ble.unpack('s8', characteristic:getValue())-- calibration pageend
DDSdataCharacteristic:setValueUpdateListener(Acallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 70,74,4,04), true)else
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 70,74,4,04), true) -- Aend
function Acallback(characteristic)
if ipad thenend
sensorA= string.unpack('f', characteristic:getValue())-- Aelse
sensorA= ble.unpack('f', characteristic:getValue())-- Aend
DDSdataCharacteristic:setValueUpdateListener(Bcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 74,78,4,0), true)else
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 74,78,4,0), true) -- Bend
function Bcallback(characteristic)
if ipad thenend
sensorB= string.unpack('f', characteristic:getValue())-- Belse
sensorB= ble.unpack('f', characteristic:getValue())-- Bend
DDSdataCharacteristic:setValueUpdateListener(Ccallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 78,82,4,0), true)else
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 78,82,4,0), true) -- Cend
function Ccallback(characteristic)
if ipad thenend
sensorC= string.unpack('f', characteristic:getValue())-- Celse
sensorC= ble.unpack('f', characteristic:getValue())-- Cend
DDSdataCharacteristic:setValueUpdateListener(UNcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 82,86,7,0), true)else
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 82,86,7,0), true) -- unitsend
function UNcallback(characteristic)
sensorUnits= characteristic:getValue()-- unitsend
checkAnalogDigitalSesnors()
function readSensorIDCallback(characteristic)
if ipad thenend
sensorID=string.unpack('s8', sensorIDCharacteristic:getValue())else
sensorID=ble.unpack('s8', sensorIDCharacteristic:getValue())end
function periodWriteCallback(characteristic)
periodWriteFlag = trueend
function checkAnalogDigitalSesnors()
if sensorID == 1 thenend
sensorLongName = "Thermocouple"elseif sensorID == 2 then
sensorUnits= "°C "
sensorShortName= "TC"
sensorA= 6.2115
sensorB= -2.45455
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName= "Voltage +/- 10V"elseif sensorID == 3 then
sensorUnits= "V"
sensorShortName= "Voltage10"
sensorA= -10
sensorB= 4
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Current"elseif sensorID == 4 then
sensorUnits= "Amps"
sensorShortName= "Current"
sensorA= 6.325
sensorB= -2.665
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Resistance"elseif sensorID == 8 then
sensorUnits= "Ohms"
sensorShortName= "Diff V"
sensorA= 6.25
sensorB= -2.5
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Diff Voltage"elseif sensorID == 9 then
sensorUnits= "V"
sensorShortName= "Diff V"
sensorA= 6.25
sensorB= -2.5
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Current"elseif sensorID == 10 then
sensorUnits= "Amp"
sensorShortName= "I"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Temperature"elseif sensorID == 11 then
sensorShortName ="Temp"
sensorPg = 1
sensorUnits = "°C "
sensorEq = 12
sensorA = .00102119
sensorB = .000222468
sensorC = .000000133342
sensorLongName = "Temperature"elseif sensorID == 12 then
sensorUnits= "°C "
sensorShortName= "Temp"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "TI Light"elseif sensorID == 13 then
sensorUnits= "relative"
sensorShortName= "TI Light"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Exercise Heart Rate"elseif sensorID == 14 then
sensorUnits= "V"
sensorShortName= "Ex HR"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Voltage"elseif sensorID == 15 then
sensorUnits= "V"
sensorShortName= "Volts"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "EKG"elseif sensorID == 17 then
sensorUnits= "V"
sensorShortName= "EKG"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Carbon Dioxide"elseif sensorID == 18 then
sensorUnits= "ppm"
sensorShortName= "CO2"
sensorB= 1
sensorA= 0
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Oxygen"elseif sensorID == 67 then
sensorUnits= "%"
sensorShortName= "O2"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = nilend
sensorUnits= nil
sensorShortName= nil
sensorA= nil
sensorB= nil
sensorC = nil
sensorPg = nil
sensorEq= nil
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 = 0end
characteristic:setWriteCompleteListener(callbackCharacteristic)
characteristic:write(string.char(msg), true)
if characteristic:getUUID() == ioConfig then -- 02
local msg = 1end
characteristic:setWriteCompleteListener(callbackCharacteristic)
characteristic:write(string.char(msg), true)
-- Temperature
if characteristic:getUUID() == tempRead thencharacteristic: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 thencharacteristic: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)else
msg = 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)else
setPeriodCharacteristic:write(ble.pack('u32', sensorPeriod), true)end
end
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)else
DDSseekRecCharacteristic: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 = 0end
if ipad then
keyPress = string.unpack("u8",value)else
keyPress = ble.unpack("u8",value)end
if keyPress then
if keyPress == 2 thenend
Lstart = timer.getMilliSecCounter()end
if keyPress == 1 then
Rstart = timer.getMilliSecCounter()end
if keyPress == 0 then
if Lstart ~= 0 then Lstop = math.abs((Lstart - timer.getMilliSecCounter())/1000) endend
if Rstart ~= 0 then Rstop = math.abs((Rstart - timer.getMilliSecCounter())/1000) end
if Lstop > 0 then
on.tabKey()end
Lstart = 0
Lstop = 0
if Rstop > 0 then
if Rstop > 1 thenend
on.escapeKey()else
wait(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 then
loWord, hiWord = string.unpack("s16u16",value)else
loWord, hiWord = ble.unpack("s16u16",value)end
local dietemp = tonumber(hiWord) / 128
local irtemp = tonumber(loWord) / 128
if dietemp and irtemp then
dietemp = math.floor(100*dietemp + 0.5)/100end
irtemp = math.floor(100*irtemp + 0.5)/100
if text:find("AMBIENT") then
rxValue = math.floor(100*dietemp+0.5)/100elseif text:find("IR TEMP") then
sensorLongName = "SensorTag Ambient Temperature"
rxValue = math.floor(100*irtemp +0.5)/100end
sensorLongName = "SensorTag IR Temperature"
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 thenlocal loWord, hiWord
if ipad then
loWord, hiWord = string.unpack("s16u16",value)else
loWord, 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 thenlocal temp, pressure
if ipad then
temp, pressure = string.unpack('u24', value)else
temp, pressure = ble.unpack('u24', value)end
local baTemp = temp/100
local baTemp = math.floor(100*baTemp + 0.5)/100
local baro = 0
if ipad then
baro = string.unpack("u24", pressure)/100else
baro = 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 then
rawLux = string.unpack('u16', value)else
rawLux = 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()end
if value then
local m1, m2, m3, m4, m5, m6, m7, m8, m9end
if ipad then
m1, m2, m3, m4, m5, m6, m7, m8, m9 = string.unpack("s16s16s16s16s16s16s16s16s16", value)else
m1, m2, m3, m4, m5, m6, m7, m8, m9 = ble.unpack("s16s16s16s16s16s16s16s16s16", value)end
if string.upper(text):find("GYR") then
local gyrx = math.floor(100*(-1*tonumber(m1)* 500 / 65536) + 0.5)/100end
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 "
if string.upper(text):find("ACC") then
local xa = math.floor(100*(-3.9*tonumber(m4)* 2 / 32768) + 0.5)/10end
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 "
if string.upper(text):find("MAG") or string.upper(text):find("COMPASS") then
local magx = math.floor(100*(tonumber(m7)* -4912 / 32768) + 0.5)/100end
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 "
if inBox:getText() and inBox:getText():find("Go Wireless Temp") and characteristic:getUUID() == measuredDataUUID then
--Vernier Go Tempend
local value = characteristic:getValue()
if peripheralName:find("Temp") then
local data = 0end
if ipad then
data = string.unpack('u16', value)else
data = 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 implementionsendlocal function check_int(n)
-- checking not float
if(n - math.floor(n) > 0) thenend
error("trying to use bitwise operation on non-integer!")end
local function to_bits(n)
check_int(n)end
if(n < 0) then
-- negativeend
return to_bits(bit.bnot(math.abs(n)) + 1)
-- to bits table
local tbl = {}
local cnt = 1
while (n > 0) do
local last = n % 2n = (n-last)/2
if(last == 1) then
tbl[cnt] = 1else
tbl[cnt] = 0end
cnt = cnt + 1
return tbl
local function tbl_to_number(tbl)
local n = table.getn(tbl)end
local rslt = 0
local power = 1
for i = 1, n do
rslt = rslt + tbl[i]*powerpower = power*2
end
return rslt
local function expand(tbl_m, tbl_n)
local big = {}end
local small = {}
if(table.getn(tbl_m) > table.getn(tbl_n)) then
big = tbl_melse
small = tbl_n
big = tbl_nend
small = tbl_m
-- expand small
for i = table.getn(small) + 1, table.getn(big) do
small[i] = 0end
local function bit_or(m, n)
local tbl_m = to_bits(m)end
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 do
if(tbl_m[i]== 0 and tbl_n[i] == 0) thenend
tbl[i] = 0else
tbl[i] = 1end
return tbl_to_number(tbl)
local function bit_and(m, n)
local tbl_m = to_bits(m)end
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 do
if(tbl_m[i]== 0 or tbl_n[i] == 0) thenend
tbl[i] = 0else
tbl[i] = 1end
return tbl_to_number(tbl)
local function bit_not(n)
local tbl = to_bits(n)end
local size = math.max(table.getn(tbl), 32)
for i = 1, size do
if(tbl[i] == 1) thenend
tbl[i] = 0else
tbl[i] = 1end
return tbl_to_number(tbl)
local function bit_xor(m, n)
local tbl_m = to_bits(m)end
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 do
if(tbl_m[i] ~= tbl_n[i]) thenend
tbl[i] = 1else
tbl[i] = 0end
--table.foreach(tbl, print)
return tbl_to_number(tbl)
local function bit_rshift(n, bits)
check_int(n)end
local high_bit = 0
if(n <= 0) then
-- negativeend
n = bit_not(math.abs(n)) + 1
high_bit = 2147493649 -- 0x80000000
for i=1, bits do
n = n/2end
n = bit_or(math.floor(n), high_bit)
return math.floor(n)
-- logic rightshift assures zero filling shift
local function bit_logic_rshift(n, bits)
check_int(n)end
if(n <= 0) then
-- negativeend
n = bit_not(math.abs(n)) + 1
for i=1, bits do
n = n/2end
return math.floor(n)
local function bit_lshift(n, bits)
check_int(n)end
if(n <= 0) then
-- negativeend
n = bit_not(math.abs(n)) + 1
for i=1, bits do
n = n*2end
return bit_and(n, 4294967295) -- 0xFFFFFFFF
local function bit_xor2(m, n)
local rhs = bit_or(bit_not(m), bit_not(n))end
local lhs = bit_or(m, n)
local rslt = bit_and(lhs, rhs)
return rslt
--------------------
-- bit lib interfacebit = {
-- 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 hh = platform:isDeviceModeRendering()
local screen = platform.window
local date = "021517"
local ipad = platform:isTabletModeRendering()require 'color'
pcall(function () require 'bleCentral' end)
pcall(function() require 'asi' 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 = ''end
connectStatus = ''
peripheralName = ''
peripheralList = {}
alert = 0
bleName = nil
Lstart = 0
Lstop = 0
Rstart = 0
Rstop = 0sensorVoltage = nil
periodChar = nil
DDSRecord = 1
writeFlag = false
readFlag = false
returnPeriod = nil
sensorPeriod = 100setPeriodCharacteristic = nil
DDSseekRecCharacteristic = nil
DDSdataCharacteristic = nil
sensorIDCharacteristic = nilsensorID = nil
sensorLongName = ''
sensorShortName = ''
sensorEqType = nil
sensorPage =nil
sensorA = nil
sensorB = nil
sensorC =nil
sensorUnits = ''
sensorValue = nilBLEvars()
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()end
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)BLEvars()-- 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 24end
fontSize = fontSize > 6 and fontSize or 7
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}else
myColor = {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()end
inBox:setText('')
inBox:setFocus(true)
screen:invalidate()
function on.tabKey()
if inBox:getText() thenend
local input = string.upper(inBox:getText())end
input = input:gsub('%"','')
local list = {input}
if input:find(string.char(10)) then
list = input:split(string.char(10)) or {input:gsub(string.char(10),'')}end
input = list[1]
if input:find("SEND%(") then
input = input:gsub('SEND%(','')elseif input:find("SET") then
input = input:gsub('%)','')
hubStrOn = input
pcall(function() TI_Innovator.Send(input)
TI_Innovator.Read() end)
pcall(function() TI_Innovator.Send(input) end)elseif input:find("READ") then
if input:find("ON") then
hubStrOn = inputelseif input:find("OFF") then
hubStrOff = input:gsub("ON","OFF")
hubStrOff = inputend
hubStrOn = input:gsub("OFF","ON")
pcall(function() TI_Innovator.Send(input)elseif input:find("CONNECT") then
TI_Innovator.Read() end)
hubStrOn = input
hubStrOff = input
pcall(function()TI_Innovator.Send(input) end)else
local testfunction = loadstring(string.lower(input))end
pcall(function() testfunction() screen:invalidate() end)
if #list > 1 then
for k = 2, #list doend
input = list[k]end
if input:find("SEND%(") then
input = input:gsub('SEND%(','')elseif input:find("SET") then
input =input:gsub('%)','')
pcall(function() TI_Innovator.Send(input)
TI_Innovator.Read() end)
pcall(function() TI_Innovator.Send(input) end)elseif input:find("READ") then
if input:find("ON") then
hubStrOn = inputelseif input:find("OFF") then
hubStrOff = input:gsub("ON","OFF")
hubStrOff = inputend
hubStrOn = input:gsub("OFF","ON")
pcall(function() TI_Innovator.Send(input)elseif input:find("CONNECT") then
TI_Innovator.Read() end)
hubStrOn = input
hubStrOff = input
pcall(function() TI_Innovator.Send(input) end)else
local testfunction = loadstring(string.lower(input))end
pcall(function() testfunction() screen:invalidate() end)
STalerts()
screen:invalidate()
function on.mouseDown(x, y)
pcall(function()end
if hubStrOn:find("ROBOT") then
if drive:find("BRIGHT") thenelse
lightSeeker()elseif drive:find("RANGER") then
auto()else
TI_Innovator.Send("SET SERVO 1 CCW 50 5") TI_Innovator.Send("SET SERVO 2 CW 50 5")end
TI_Innovator.Read()
TI_Innovator.Send(hubStrOn) -- This is an example of sending a SET command to the Hubend
TI_Innovator.Read() -- This is an example of sending a READ command to the Hub
end)
if x > boxX and x <= boxX + boxWidth then
if y > boxY + boxHeight and y <= boxY + boxHeight + 0.1*h thenend
on.tabKey()elseif y > boxY + boxHeight + 0.1*h and y <= boxY + boxHeight + 0.2*h then
on.escapeKey()end
screen:invalidate()
function on.mouseUp (x,y)
pcall(function() if hubStrOn:find("ROBOT") then
if drive == '' thenend
TI_Innovator.Send("SET SERVO 1 CCW 0 0") TI_Innovator.Send("SET SERVO 2 CW 0 0")else
TI_Innovator.Read() end
timeStr = ''end
TI_Innovator.Send(hubStrOff)
TI_Innovator.Read()
end)
screen:invalidate()
function str2list(input, def)
local list = {}
if input:find(def) then
list = input:split(def)else
table.foreachi(list,print)
list = {input}end
return list
endfunction TI_InnovatorReadCallback(port, error_msg) -- this is the callback function that is defined above and catches the result of a READ command send to the Hub.
pcall(function()end
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()
function TI_InnovatorStateCallback(event)
pcall(function()end
addMsg("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()end
-- place CONNECT and other Hub startup commands here
addMsg("TI_Innovator Hub connected")
TI_Innovator.Send(hubStrOff)
end)
function wait(input)
endif input then delay = input end
time_step = 0.1
if delay >= 0 then
timeStr = "Wait Time: "..delay.." seconds"else
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 tool
dataList[#dataList+1] = tonumber(rxValue)else rxValue = tostring(rxValue) rxValue = str2list(rxValue,string.char(10))[1] end
index[#index+1]=#dataList
var.store("index", index)
var.store("dataList", dataList)
STalerts()
oneShotTimer(1000*time_step,wait)
pcall(function() TI_Innovator.Send(hubStrOff) end)end
delay = 0
alert = 0
STalerts()
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..")"end
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.5
screen:invalidate()
function alarm(rep,waitValue)
local tone = 220end
if waitValue then delay = waitValue end
if rep then repeats = rep end
if repeats > 0 then
timeStr = "alarm("..(math.floor(repeats+0.5))..", "..delay..")"end
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.5
screen:invalidate()
function STalerts()
if isBLEconnected thenend
if stChar then
hubStrOn = inBox:getText() or "SET LIGHT ON"end
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
screen:invalidate()
function waitTone()
if not list1 then list1 = var.recall("list1") endend
if not list2 then list2 = var.recall("list2") end
if list1 and #list1 > 0 and list2 and #list2 > 0 then
if I <= #list1 and list1[I] and list2[I] then -- don't go past the lenght of the arrayend
if list1[I] and list2[I] thenelse
local str = "SET SOUND "..list1[I]*2^(key/12).." TIME "..math.floor(100/(list2[I])+0.5)/100end
hubStrOn = str
pcall(function() TI_Innovator.Send(str) end)
oneShotTimer((tempo/list2[I])+20, waitTone)
I = I + 1
hubStrOn = "SET LIGHT ON"end
hubStrOff = "SET LIGHT OFF"
addMsg(hubStrOff)
screen:invalidate()
function playTone(list1, list2)
waitTone()end
screen:invalidate()
function fd(input)
if input thenend
inBox:setText("SET SERVO 1 CCW 100 "..input ..string.char(10).."SET SERVO 2 CW 100 "..input)end
hubStrOn = "ROBOT FORWARD"
addMsg(hubStrOn)
oneShotTimer(1000,fd)
on.tabKey()
hubStrOff = "ROBOT OFF" addMsg(hubStrOff)
screen:invalidate()
function bk(input)
if input thenend
inBox:setText("SET SERVO 1 CW 100 "..input ..string.char(10).."SET SERVO 2 CCW 100 "..input)end
hubStrOn = "ROBOT BACK"
addMsg(hubStrOn)
oneShotTimer(1000,bk)
on.tabKey()
hubStrOff = "ROBOT OFF" addMsg(hubStrOff)
screen:invalidate()
function lt(input)
if input thenend
inBox:setText("SET SERVO 1 CW 100 "..input ..string.char(10).."SET SERVO 2 CW 100 "..input)end
hubStrOn = "ROBOT LEFT"
addMsg(hubStrOn)
oneShotTimer(1000,lt)
on.tabKey()
hubStrOff = "ROBOT OFF" addMsg(hubStrOff)
screen:invalidate()
function rt(input)
if input thenend
inBox:setText("SET SERVO 1 CCW 100 "..input ..string.char(10).."SET SERVO 2 CCW 100 "..input)end
hubStrOn = "ROBOT RIGHT"
addMsg(hubStrOn)
oneShotTimer(1000,rt)
on.tabKey()
hubStrOff = "ROBOT OFF" addMsg(hubStrOff)
screen:invalidate()
function lightSeeker()
if drive:find("BRIGHT") thenend
pcall(function() TI_Innovator.Send("READ BRIGHTNESS ")end
TI_Innovator.Read() end)
if tonumber(rxValue) and tonumber(rxValue) > 0 then
if tonumber(rxValue) > 0.5 thenend
if tonumber(rxValue) > 10 thenelse
fd(1)else
bk(1)end
rt(1)
fd(0)end
hubStrOff = "ROBOT AUTO OFF"
addMsg(hubStrOff)
play = false
oneShotTimer(1000,lightSeeker)
screen:invalidate()
function auto()
if drive:find("RANGER") thenend
pcall(function() TI_Innovator.Send("READ RANGER 1 ")end
TI_Innovator.Read() end)
if tonumber(rxValue) and tonumber(rxValue) > 0 then
pcall(function() TI_Innovator.Send("SET SOUND "..1000*tonumber(rxValue).." 0.1") end)end
if tonumber(rxValue) > 0.1 then
if tonumber(rxValue) > 0.4 thenelse
fd(1)else
bk(0.5)end
rt(0.5)
fd(0)end
hubStrOff = "ROBOT AUTO OFF"
addMsg(hubStrOff)
play = false
oneShotTimer(1000,auto)
screen:invalidate()
end-- OneShot Timer BEGIN
local timerstart = timer.start
local timerstop = timer.stop
timer.start = nil
timer.stop = nil
local currentTimer = nillocal function timerStart(t)
endcurrentTimer = t
timerstart(t.period/1000)
local function timerStop()
endcurrentTimer = nil
timerstop()
local function setTimer(t)
endif t.period==nil or type(t.period)~='number' or t.period < 10 then error('period in milliseconds >= 10') end
timerStart(t)
return t
function oneShotTimer(period, listenerHandler, ...)
endif type(listenerHandler) ~= 'function' then
error('createTimerOneShot: function expected')end
setTimer {
period = period,}
oneShot = true,
listenerHandler = listenerHandler,
params = { ... },
function on.timer()
endlocal ct = currentTimer
if currentTimer == nil then
timerStop()end
if currentTimer.oneShot then
currentTimer = nilend
timerStop()
ct.listenerHandler(unpack(ct.params))
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')end
return
addMsg('Hub available')
isASIavailable = true
local HANDSHAKE_GREETING = 'ISTI\n'
local HANDSHAKE_ANSWER = 'TISTEM'
local portFoundList = { }
local state
local handshakeState
local notifyEvent
local asiStateListener
local startScanning
local stopScanning
local portFoundListener
local portStateListener
local handshake_SendListener
local handshake_readListener
local handshake_port
local TI_Innovator_port
local baudRate = asi.BAUD_RATE_DEFAULT
local readTimeout = asi.READ_TIMEOUT_DEFAULT-- User callbacks
local stateCallback = theStateCallback
local SendCallback
local readCallbackfunction notifyEvent(event)
addMsg('notifying '.. event)end
if stateCallback then
stateCallback(event)else
addMsg('no callback registered')end
function startScanning()
if isASIavailable thenend
asi.startScanning(portFoundListener)end
notifyEvent('scanning')
function stopScanning()
handshake_port = nilend
portFoundList = { }
asi.stopScanning()
function asiStateListener(asiState)
if asi.ON == asiState thenend
if state == 'active' thenelseif asi.UNSUPPORTED == asiState then
startScanning()end
notifyEvent(asi.UNSUPPORTED)end
function portFoundListener(portFound)
addMsg('portFoundListener '.. portFound:getName())end
table.insert(portFoundList, portFound)
if not TI_Innovator_port and not handshake_port then
handshake_port = portFoundList[1]end
oneShotTimer(100, handshake_port.connect, handshake_port, portStateListener)
function portStateListener(reportedPort, event, error_msg)
addMsg('portStateListener '..reportedPort:getName()..' '..event)end
if asi.CONNECTED == event then
-- configure port for handshakeelseif asi.CONNECTING_FAILED == event then
reportedPort:setWriteListener(handshake_writeListener)
reportedPort:setReadListener(handshake_readListener)
reportedPort:setReadTimeout(500)
handshakeState = 'handshake'
-- write handshake greeting
addMsg("HANDSHAKE_GREETING: "..HANDSHAKE_GREETING)
oneShotTimer(200, reportedPort.write, reportedPort, HANDSHAKE_GREETING)
if reportedPort == handshake_port thenelseif asi.DISCONNECTED == event then
table.remove(portFoundList, 1)elseif reportedPort == TI_Innovator_port then
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
if reportedPort == TI_Innovator_port thenend
if state == 'active' thenend
if reportedPort:getState() == asi.DISCONNECTED thennotifyEvent('disconnected')
reportedPort:connect(portStateListener)else
TI_Innovator_port = nilend
asi.startScanning(portFoundListener)
function handshake_writeListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
if 'handshake' == handshakeState then
reportedPort:read(#HANDSHAKE_ANSWER+2)end
function handshake_readListener(reportedPort, error_msg)
if error_msg thenend
addMsg('handshake_writeListener '..error_msg)end
return
local answer = reportedPort:getValue()
if 'handshake' == handshakeState then
-- Validate answerelseif 'ready' == handshakeState then
if answer and answer:find(HANDSHAKE_ANSWER) then
addMsg("HANDSHAKE_ANSWER: "..HANDSHAKE_ANSWER)else
stopScanning()
handshakeState = 'ready'
reportedPort:write('BEGIN\n')
reportedPort:read(7)
reportedPort:disconnect()end
table.remove(portFoundList, 1)
if #portFoundList>0 then
handshake_port = portFoundList[1]else
handshake_port:connect(portStateListener)
handshake_port = nilend
if answer and answer:find('READY') thenend
-- Configure port for normal useend
TI_Innovator_port = reportedPort
TI_Innovator_port:setReadTimeout(readTimeout)
TI_Innovator.setWriteListener(SendCallback)
TI_Innovator.setReadListener(readCallback)
-- Notify launchpad is ready
notifyEvent('ready')
-- INTERFACE -- BEGINS --
function TI_Innovator.connect()
state = 'active'end
startScanning()
function TI_Innovator.disconnect()
if isASIavailable and not ipad thenend
state = 'inactive'
if isASIavailable then
if TI_Innovator_port thenend
TI_Innovator_port:disconnect()end
TI_Innovator_port = nil
stopScanning()
end
function TI_Innovator.setWriteListener(newWriteCallback)
writeCallback = newWriteCallbackend
if TI_Innovator_port then
TI_Innovator_port:setWriteListener(writeCallback)end
function TI_Innovator.setReadListener(newReadCallback, newReadObject)
readCallback = newReadCallbackend
if TI_Innovator_port then
TI_Innovator_port:setReadListener(readCallback)end
function TI_Innovator.setBaudRate(newBaudRate)
baudRate = newBaudRateend
if TI_Innovator_port then
TI_Innovator_port:setBaudRate(baudRate)end
function TI_Innovator.setReadTimeout(newReadTimeout)
readTimeout = newReadTimeoutend
if TI_Innovator_port then
TI_Innovator_port:setReadTimeout(readTimeout)end
function TI_Innovator.Send(data)
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
addMsg('No Hub attached')end
return 'No Hub attached'
local result = TI_Innovator_port:write(data .. '\n')
if result then addMsg(tostring(data)..': '.. tostring(result))
else addMsg(tostring(data)) end
return result
end
function TI_Innovator.Read(bytes_to_read)
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return "No TI Hub attached"end
return TI_Innovator_port:read(bytes_to_read)
end
function TI_Innovator.request(request)
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return "No TI Hub attached"end
local result = TI_Innovator_port:write(request .. '\n')
if result then addMsg(tostring(request) .. ': '.. tostring(result))
else addMsg(tostring(request)) end
result = TI_Innovator_port:read()
addMsg('read() '.. tostring(result))
if result then
addMsg('Error sending request: ' .. tostring(request))end
return result
end
function TI_Innovator.isConnected()
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return falseend
end
return TI_Innovator_port:getState() == asi.CONNECTED
function TI_Innovator.getName()
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return "No TI Hub attached"end
return TI_Innovator_port:getName()
endfunction TI_Innovator.getIdentifier()
if isASIavailable and not ipad thenend
if not TI_Innovator_port then
return "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) endend
------------------------------------------------------------------------
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()
endlocal Menu
if isBLEavailable then
Menu={
{"About",}
{" ©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},
else
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},
toolpalette.register(Menu)
-- 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)
endscreen:invalidate()
end
function peripheralOn()
if isBLEavailable then
if input and (inBox:getText()):find("CONNECT") and (inBox:getText()):find(input) then bleName = input endend
bleCentral.startScanning(callbackScan)
connectStatus = 'Scanning'
addMsg(connectStatus..": "..bleState)
screen:invalidate()
end
function peripheralOff()
if isBLEconnected then
bleCentral.stopScanning()end
if #peripheralList > 0 then
for p = #peripheralList, 1, -1 doend
peripheralList[p]:disconnect()end
addMsg(connectStatus..": "..bleState)
connectStatus = 'Stand by'
peripheralName = ''
isBLEconnected = false
screen:invalidate()
end
function callbackScan(peripheral)
if peripheral and peripheral:getName() then
if bleName and (peripheral:getName()):find(bleName) and (inBox:getText()):find("CONNECT") and (inBox:getText()):find(bleName) thenend
addMsg("BLE found: "..peripheral:getName())
peripheral:connect(callbackConnect)
end
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 then
local services = peripheral:getServices()end
for _,service in ipairs(services) do
service:discoverCharacteristics(callbackCharacteristics)
end
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.else
sensorVoltage = (ble.unpack('s16', (characteristic:getValue()))/6400)end
if sensorID == 2 or sensorID == 8 then
sensorVoltage = sensorVoltage -.058end
if 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 then
sensorValue = sensorB*sensorVoltage + sensorAelseif sensorEq == 2 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorC*sensorVoltage^2+sensorB*sensorVoltage + sensorAelseif sensorEq == 3 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*sensorVoltage^sensorBelseif sensorEq == 4 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*sensorB^sensorVoltageelseif sensorEq == 5 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA+sensorB*mathlog(sensorVoltage)elseif sensorEq == 6 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA + sensorB*math.log(1/sensorVoltage)elseif sensorEq == 7 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*math.exp(sensorB*sensorVoltage)elseif sensorEq == 8 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*math.exp(sensorB/sensorVoltage)elseif sensorEq == 9 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*sensorVoltage^(sensorb*sensorVoltage)elseif sensorEq == 10 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = sensorA*(sensorVoltage^(sensorB/sensorVoltage))elseif sensorEq == 11 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
sensorValue = 1/(sensorA+sensorB*math.log(sensorC*sensorVoltage))elseif sensorEq == 12 and sensorA~= nil and sensorB ~= nil and sensorC~= nil then
local r1= 15000end
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.15
if sensorValue then
if sensorShortName:find("BARO") then
sensorValue = math.floor(100*sensorValue+0.5)/100end screen:invalidate()
if sensorValue <= 500 then sensorValue = 10*sensorValue end
sensorUnits = "mbar"elseif sensorLongName:find("TI Light") then
sensorValue = math.floor(100*sensorValue+0.5)/100else
if sensorValue <= 10 then sensorValue = 10*sensorValue end
sensorValue = math.floor(100*sensorValue+0.5)/100end
rxValue = sensorValue
addMsg(sensorLongName)
end-------------- BLE utilities ------------------------
function DDSseekRecWriteCallback(characteristic)
DDSdataCharacteristic:read()end
function 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 UUIDend
DDSdataCharacteristic:setValueUpdateListener(LNcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 8,28,20,0), true) -- long nameelse
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 8,28,20,0), true)end
function LNcallback(characteristic)
sensorLongName= characteristic:getValue()--long nameend
DDSdataCharacteristic:setValueUpdateListener(STcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 28,40,12,0), true) -- shrot nameelse
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 28,40,12,0), true)end
function STcallback(characteristic)
sensorShortName= characteristic:getValue()--short nameend
DDSdataCharacteristic:setValueUpdateListener(EQcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 56,57,1,0), true) -- Calibration equation typeelse
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 56,57,1,0), true)end
function EQcallback(characteristic)
if ipad thenend
sensorEq= string.unpack('s8', characteristic:getValue())-- equation typeelse
sensorEq= ble.unpack('s8', characteristic:getValue())-- equation typeend
DDSdataCharacteristic:setValueUpdateListener(PGcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 69,70,1,0), true) -- Calibration memeory pageelse
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 69,70,1,0), true)end
function PGcallback(characteristic)
if ipad thenend
sensorPg= string.unpack('s8', characteristic:getValue())-- calibration pageelse
sensorPg= ble.unpack('s8', characteristic:getValue())-- calibration pageend
DDSdataCharacteristic:setValueUpdateListener(Acallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 70,74,4,04), true)else
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 70,74,4,04), true) -- Aend
function Acallback(characteristic)
if ipad thenend
sensorA= string.unpack('f', characteristic:getValue())-- Aelse
sensorA= ble.unpack('f', characteristic:getValue())-- Aend
DDSdataCharacteristic:setValueUpdateListener(Bcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 74,78,4,0), true)else
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 74,78,4,0), true) -- Bend
function Bcallback(characteristic)
if ipad thenend
sensorB= string.unpack('f', characteristic:getValue())-- Belse
sensorB= ble.unpack('f', characteristic:getValue())-- Bend
DDSdataCharacteristic:setValueUpdateListener(Ccallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 78,82,4,0), true)else
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 78,82,4,0), true) -- Cend
function Ccallback(characteristic)
if ipad thenend
sensorC= string.unpack('f', characteristic:getValue())-- Celse
sensorC= ble.unpack('f', characteristic:getValue())-- Cend
DDSdataCharacteristic:setValueUpdateListener(UNcallback)
if ipad then
DDSseekRecCharacteristic:write(string.pack('u8u8u8u8', 82,86,7,0), true)else
DDSseekRecCharacteristic:write(ble.pack('u8u8u8u8', 82,86,7,0), true) -- unitsend
function UNcallback(characteristic)
sensorUnits= characteristic:getValue()-- unitsend
checkAnalogDigitalSesnors()
function readSensorIDCallback(characteristic)
if ipad thenend
sensorID=string.unpack('s8', sensorIDCharacteristic:getValue())else
sensorID=ble.unpack('s8', sensorIDCharacteristic:getValue())end
function periodWriteCallback(characteristic)
periodWriteFlag = trueend
function checkAnalogDigitalSesnors()
if sensorID == 1 thenend
sensorLongName = "Thermocouple"elseif sensorID == 2 then
sensorUnits= "°C "
sensorShortName= "TC"
sensorA= 6.2115
sensorB= -2.45455
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName= "Voltage +/- 10V"elseif sensorID == 3 then
sensorUnits= "V"
sensorShortName= "Voltage10"
sensorA= -10
sensorB= 4
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Current"elseif sensorID == 4 then
sensorUnits= "Amps"
sensorShortName= "Current"
sensorA= 6.325
sensorB= -2.665
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Resistance"elseif sensorID == 8 then
sensorUnits= "Ohms"
sensorShortName= "Diff V"
sensorA= 6.25
sensorB= -2.5
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Diff Voltage"elseif sensorID == 9 then
sensorUnits= "V"
sensorShortName= "Diff V"
sensorA= 6.25
sensorB= -2.5
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Current"elseif sensorID == 10 then
sensorUnits= "Amp"
sensorShortName= "I"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Temperature"elseif sensorID == 11 then
sensorShortName ="Temp"
sensorPg = 1
sensorUnits = "°C "
sensorEq = 12
sensorA = .00102119
sensorB = .000222468
sensorC = .000000133342
sensorLongName = "Temperature"elseif sensorID == 12 then
sensorUnits= "°C "
sensorShortName= "Temp"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "TI Light"elseif sensorID == 13 then
sensorUnits= "relative"
sensorShortName= "TI Light"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Exercise Heart Rate"elseif sensorID == 14 then
sensorUnits= "V"
sensorShortName= "Ex HR"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Voltage"elseif sensorID == 15 then
sensorUnits= "V"
sensorShortName= "Volts"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "EKG"elseif sensorID == 17 then
sensorUnits= "V"
sensorShortName= "EKG"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Carbon Dioxide"elseif sensorID == 18 then
sensorUnits= "ppm"
sensorShortName= "CO2"
sensorB= 1
sensorA= 0
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = "Oxygen"elseif sensorID == 67 then
sensorUnits= "%"
sensorShortName= "O2"
sensorA= 0
sensorB= 1
sensorC = 0
sensorPg = 1
sensorEq= 1
sensorLongName = nilend
sensorUnits= nil
sensorShortName= nil
sensorA= nil
sensorB= nil
sensorC = nil
sensorPg = nil
sensorEq= nil
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 = 0end
characteristic:setWriteCompleteListener(callbackCharacteristic)
characteristic:write(string.char(msg), true)
if characteristic:getUUID() == ioConfig then -- 02
local msg = 1end
characteristic:setWriteCompleteListener(callbackCharacteristic)
characteristic:write(string.char(msg), true)
-- Temperature
if characteristic:getUUID() == tempRead thencharacteristic: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 thencharacteristic: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)else
msg = 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)else
setPeriodCharacteristic:write(ble.pack('u32', sensorPeriod), true)end
end
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)else
DDSseekRecCharacteristic: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 = 0end
if ipad then
keyPress = string.unpack("u8",value)else
keyPress = ble.unpack("u8",value)end
if keyPress then
if keyPress == 2 thenend
Lstart = timer.getMilliSecCounter()end
if keyPress == 1 then
Rstart = timer.getMilliSecCounter()end
if keyPress == 0 then
if Lstart ~= 0 then Lstop = math.abs((Lstart - timer.getMilliSecCounter())/1000) endend
if Rstart ~= 0 then Rstop = math.abs((Rstart - timer.getMilliSecCounter())/1000) end
if Lstop > 0 then
on.tabKey()end
Lstart = 0
Lstop = 0
if Rstop > 0 then
if Rstop > 1 thenend
on.escapeKey()else
wait(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 then
loWord, hiWord = string.unpack("s16u16",value)else
loWord, hiWord = ble.unpack("s16u16",value)end
local dietemp = tonumber(hiWord) / 128
local irtemp = tonumber(loWord) / 128
if dietemp and irtemp then
dietemp = math.floor(100*dietemp + 0.5)/100end
irtemp = math.floor(100*irtemp + 0.5)/100
if text:find("AMBIENT") then
rxValue = math.floor(100*dietemp+0.5)/100elseif text:find("IR TEMP") then
sensorLongName = "SensorTag Ambient Temperature"
rxValue = math.floor(100*irtemp +0.5)/100end
sensorLongName = "SensorTag IR Temperature"
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 thenlocal loWord, hiWord
if ipad then
loWord, hiWord = string.unpack("s16u16",value)else
loWord, 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 thenlocal temp, pressure
if ipad then
temp, pressure = string.unpack('u24', value)else
temp, pressure = ble.unpack('u24', value)end
local baTemp = temp/100
local baTemp = math.floor(100*baTemp + 0.5)/100
local baro = 0
if ipad then
baro = string.unpack("u24", pressure)/100else
baro = 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 then
rawLux = string.unpack('u16', value)else
rawLux = 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()end
if value then
local m1, m2, m3, m4, m5, m6, m7, m8, m9end
if ipad then
m1, m2, m3, m4, m5, m6, m7, m8, m9 = string.unpack("s16s16s16s16s16s16s16s16s16", value)else
m1, m2, m3, m4, m5, m6, m7, m8, m9 = ble.unpack("s16s16s16s16s16s16s16s16s16", value)end
if string.upper(text):find("GYR") then
local gyrx = math.floor(100*(-1*tonumber(m1)* 500 / 65536) + 0.5)/100end
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 "
if string.upper(text):find("ACC") then
local xa = math.floor(100*(-3.9*tonumber(m4)* 2 / 32768) + 0.5)/10end
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 "
if string.upper(text):find("MAG") or string.upper(text):find("COMPASS") then
local magx = math.floor(100*(tonumber(m7)* -4912 / 32768) + 0.5)/100end
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 "
if inBox:getText() and inBox:getText():find("Go Wireless Temp") and characteristic:getUUID() == measuredDataUUID then
--Vernier Go Tempend
local value = characteristic:getValue()
if peripheralName:find("Temp") then
local data = 0end
if ipad then
data = string.unpack('u16', value)else
data = 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 implementionsendlocal function check_int(n)
-- checking not float
if(n - math.floor(n) > 0) thenend
error("trying to use bitwise operation on non-integer!")end
local function to_bits(n)
check_int(n)end
if(n <= 0) then
-- negativeend
return to_bits(bit.bnot(math.abs(n)) + 1)
-- to bits table
local tbl = {}
local cnt = 1
while (n > 0) do
local last = n % 2n = (n-last)/2
if(last == 1) then
tbl[cnt] = 1else
tbl[cnt] = 0end
cnt = cnt + 1
return tbl
local function tbl_to_number(tbl)
local n = table.getn(tbl)end
local rslt = 0
local power = 1
for i = 1, n do
rslt = rslt + tbl[i]*powerpower = power*2
end
return rslt
local function expand(tbl_m, tbl_n)
local big = {}end
local small = {}
if(table.getn(tbl_m) > table.getn(tbl_n)) then
big = tbl_melse
small = tbl_n
big = tbl_nend
small = tbl_m
-- expand small
for i = table.getn(small) + 1, table.getn(big) do
small[i] = 0end
local function bit_or(m, n)
local tbl_m = to_bits(m)end
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 do
if(tbl_m[i]== 0 and tbl_n[i] == 0) thenend
tbl[i] = 0else
tbl[i] = 1end
return tbl_to_number(tbl)
local function bit_and(m, n)
local tbl_m = to_bits(m)end
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 do
if(tbl_m[i]== 0 or tbl_n[i] == 0) thenend
tbl[i] = 0else
tbl[i] = 1end
return tbl_to_number(tbl)
local function bit_not(n)
local tbl = to_bits(n)end
local size = math.max(table.getn(tbl), 32)
for i = 1, size do
if(tbl[i] == 1) thenend
tbl[i] = 0else
tbl[i] = 1end
return tbl_to_number(tbl)
local function bit_xor(m, n)
local tbl_m = to_bits(m)end
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 do
if(tbl_m[i] ~= tbl_n[i]) thenend
tbl[i] = 1else
tbl[i] = 0end
--table.foreach(tbl, print)
return tbl_to_number(tbl)
local function bit_rshift(n, bits)
check_int(n)end
local high_bit = 0
if(n <= 0) then
-- negativeend
n = bit_not(math.abs(n)) + 1
high_bit = 2147493649 -- 0x80000000
for i=1, bits do
n = n/2end
n = bit_or(math.floor(n), high_bit)
return math.floor(n)
-- logic rightshift assures zero filling shift
local function bit_logic_rshift(n, bits)
check_int(n)end
if(n <= 0) then
-- negativeend
n = bit_not(math.abs(n)) + 1
for i=1, bits do
n = n/2end
return math.floor(n)
local function bit_lshift(n, bits)
check_int(n)end
if(n <= 0) then
-- negativeend
n = bit_not(math.abs(n)) + 1
for i=1, bits do
n = n*2end
return bit_and(n, 4294967295) -- 0xFFFFFFFF
local function bit_xor2(m, n)
local rhs = bit_or(bit_not(m), bit_not(n))end
local lhs = bit_or(m, n)
local rslt = bit_and(lhs, rhs)
return rslt
--------------------
-- bit lib interfacebit = {
-- 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