' gobiact.sb
'
' This runs through the Over-The-Air Service Provisioning procedure
' for the Verizon and Sprint networks on a Qualcomm GOBI2000 module.
' Usage:
'
' bas gobiact.sb
'
' The Sarian should be rebooted when the operation is completed.
' The script automatically works out which ASY ports from the modemcc 0 asy_add and info_asy_add settings
' It also deactivates the PPP instance in case it's in use.
' Progress and final result is reported in the eventlog
' Progress is also logged to a RAM file called sstat.txt
' Web files sstat.asp and sstat1.asp are also generated to allow progress
' to be observed at the web interface
' the following line makes all string comparisons case insensitive
'
OPTION COMPARE sbCaseInsensitive
' set up the error handler
'
on error goto ErrorLabel
const nl = "\r\n"
' Enter an error message in the event log
' Also prints message to console output
' And appends the message to the web log file
'
function eventmsg(msg)
print #aspout, msg, nl
print msg, nl
junk = system("setevent \"" & msg & "\"" & " 0")
end function
' Appends the message to the web log file
'
function logmsg(msg)
print #aspout, msg, nl
print msg, nl
end function
' Generate the log files for monitoring progress at the web interface
'
function init_log_files
local fh
fh = 0
open "sstat.asp" for output as fh
print #fh, "\r\n"
print #fh, "
\r\n"
print #fh, "\r\n"
print #fh, "\r\n"
print #fh, "\r\n"
close fh
aspout=0
open "sstat.txt" for output as aspout
end function
' Generate a final status message which can be displayed at the web interface
' This re-writes the top sstat1 frame page
function log_status(log_msg)
local fh
fh = 0
open "sstat1.asp" for output as fh
print #fh, "\r\n"
print #fh, "\r\n"
print #fh, "Provisioning Status\r\n"
print #fh, "\r\n"
print #fh, "\r\n"
print #fh, "\r\n"
print #fh, "\r\n"
print #fh, "\r\n"
print #fh, "
"
print #fh, "\r\n"
print #fh, "\r\n"
print #fh, "\r\n"
close fh
end function
' Enter an error message in the event log and exit
' Also prints message to console output
' And updates the web status page
'
function errexit(msg)
log_status(msg)
print #aspout, msg, nl
print msg, nl
print "Please reboot the router", nl
junk = system("setevent \"" & msg & "\"" & " 6")
junk = mibset("provision.0.userstring2", msg)
stop
end function
' Return the value of Sarian parameter in rsp
' strCmd needs to be of form " ?"
' e.g. "ppp 0 ans ?"
function getParam(strCmd,rsp)
local res, tmp, tmpPos, x, pos2
getParam = false
res = execute(strCmd, 0, tmp)
if res = true then
tmpPos = InStr(tmp, nl & "OK" & nl)
if tmpPos > 0 then
For x = tmpPos To 1 Step -1
pos2 = InStr(tmp, nl, x - 3)
If pos2 > 0 and pos2 <> tmpPos then
x = 1
endif
next x
if pos2 > 0 and pos2 <> tmpPos then
rsp = mid(tmp, pos2 + 2, tmpPos - pos2 - 2)
getParam = true
endif
endif
endif
end function
' find the first PPP instance configured for GPRS
' returns TRUE if we found one, and put the instance number into num
' otherwise returns FALSE
'
function get_gprs_ppp_instance(num)
local mdmstr, i
get_gprs_ppp_instance = false
for i = 0 to 4
if getParam("ppp " & i & " use_modem ?", mdmstr) = TRUE then
' print "PPP ", i, " use_modem = ", mdmstr, nl
if mdmstr = "1" or mdmstr = "4" or mdmstr = "5" then
get_gprs_ppp_instance = true
num = i
exit function
endif
else
print "Failed to get PPP ", i, " use_modem", nl
endif
next i
end function
' init_mc75io - opens a serial port and initialises a receive buffer for it
' Sets the following GLOBAL vars:
' mc75in - the input file handle
' mc75out - the output file handle
' mc75rxbuf - the receive buffer
' Parameter required is a GLOBAL variable mc75asyport, eg "ASY5"
'
function init_mc75io
' open the serial port used for the MC75
' two handles, one for input and one for output
mc75in = 0
open mc75asyport for input as mc75in
' if error() <> 0 then
' print "error opening asy port", nl
' endif
mc75out = 0
open mc75asyport for output as mc75out
mc75rxbuf = ""
junk = setevent(0)
junk = setevent(mc75in)
end function
' clear the receive buffer
'
function clear_mc75io
local junk, infobuf, tbuf
mx75rxbuf = ""
if waitevents(1000) = mc75in then
junk = sockinfo(mc75in, infobuf)
if infobuf[2] <> 0 then
tbuf = input(infobuf[2], mc75in)
endif
endif
end function
' gets a character from mc75in
' timeout is fixed at 10 secs for now
' Return TRUE if successful, otherwise FALSE
' If TRUE, then character is retuned in the rsp parameter
'
function getchar(rsp)
local tstart, junk, sinfo
getchar = FALSE
tstart = ticks
while ticks-tstart < 1000
if len(mc75rxbuf) <> 0 then
rsp = left(mc75rxbuf, 1)
mc75rxbuf = mid(mc75rxbuf, 2)
getchar = TRUE
exit function
endif
junk = sockinfo(mc75in, sinfo)
' print "Bytes available = ", sinfo[2], nl
if sinfo[2] <> 0 then
' print "Reading ", sinfo[2], " Bytes", nl
mc75rxbuf = input(sinfo[2], mc75in)
' else
' sleep(1)
endif
wend
end function
' Get a line from mc75in
' Return TRUE if successful, otherwise FALSE
' If TRUE, then line is returned in the rsp parameter
'
function getline(rsp)
local junk, sinfo, tbuf, tchr
getline = FALSE
tbuf = ""
while TRUE
if getchar(tchr) <> TRUE then exit function
' see if we received a LF (our end of line)
if asc(tchr) = 0x0a then
rsp = tbuf
getline = TRUE
exit function
endif
' ignore CR, append all other chars
if asc(tchr) <> 0x0d then
tbuf = tbuf & tchr
endif
wend
end function
function getOKline
local i, myline
getOKline = FALSE
for i = 1 to 10
if getline(myline) <> TRUE then exit function
if myline = "OK" then
getOKline = TRUE
exit function
endif
next i
end function
'
' Collect a number of lines into an array
' Stop at OK, ERROR or timeout
' return the number of lines received.
'
function getResplines(rsplines)
local nlines, i, myline
nlines = 0
getResplines = 0
for i = 1 to 10
if getline(myline) <> TRUE then exit function
rsplines[nlines] = myline
nlines += 1
getResplines = nlines
if (instr(myline, "OK") <> undef) or (instr(myline, "ERROR") <> undef) then
exit function
endif
next i
end function
' Close i/o handles and try to put the config back the way it was
' If using a TCP socket we only have one handle to close.
function restorecfg
local res, resstr
if atopened <> 0 then
if socketopened = 0 then
close(mc75out)
endif
close(mc75in)
endif
if cnsopened <> 0 then
close(cnsout)
close(cnsin)
endif
sleep(1)
if asyportchanged <> 0 then
res = execute("modemcc 0 asy_add " & asystr, 0, resstr)
else
res = execute("modemconn", 0, resstr)
endif
end function
' sends a command to the modem and returns the first reponse line
'
function modem_cmd(cmd_str)
local i, nlines, rsplines
modem_cmd = ""
print #mc75out, cmd_str & "\r"
nlines = getResplines(rsplines)
if nlines = 0 then
eventmsg "No response to " & cmd_str
exit function
endif
if rsplines[nlines-1] <> "OK" then
eventmsg cmd_str & " did not return OK, got " & rsplines[nlines-1]
exit function
endif
' for i = 0 to nlines-1
' eventmsg "Got line: " & rsplines[i]
' next i
for i = 0 to nlines-1
if rsplines[i] <> "" AND rsplines[i] <> cmd_str then
modem_cmd = rsplines[i]
exit function
endif
next i
end function
' sends a command to the modem and returns the reponse lines
'
function modem_cmd_lines(cmd_str, rsplines)
local i, j, nlines, rlines
modem_cmd_lines = 0
print #mc75out, cmd_str & "\r"
nlines = getResplines(rlines)
if nlines = 0 then
eventmsg "No response to " & cmd_str
exit function
endif
j = 0
for i = 0 to nlines-1
if rlines[i] <> "" AND rlines[i] <> cmd_str then
rsplines[j] = rlines[i]
j += 1
endif
next i
modem_cmd_lines = j
end function
' check to see if the user clicked cancel
' The web form handler signals this to us by setting the MIB variable
' provision.0.userstring1 = ABORT
'
function check_user_abort
if mib_val("provision.0.userstring1") = "ABORT" then
restorecfg()
errexit "Activation cancelled by user"
endif
end function
' This function uses the mib() function to read
' a MIB variable. It then breaks up the resultant
' string and returns the value of the variable.
'
function mib_val(var_name)
local a, ps
mib_val = ""
a = chomp(mib(var_name))
ps = instr(a, " = ")
if ps > 0 then
mib_val = mid(a, ps+3)
endif
end function
' Extract a parameter value from a parameter list
function getPar(strdata, strname)
local pos, pos1
getPar = ""
pos = instr(strdata, strname)
if pos > 0 then
pos1 = instr(strdata,NL,pos)
if pos1 > 0 then
getPar = mid(strData,pos + len(strname) + 1,pos1 - pos - len(strname) - 1)
end if
end if
end function
function getActivationState(state)
local res, tmp, actstate
getActivationState = false
res = execute("modemstat ?", 0, tmp)
if instr(tmp, "Got modem status OK") > 0 then
actstate = getPar(tmp,"Activation status:")
if actstate <> "" then
state = actstate
getActivationState = true
endif
endif
end function
function decode_actstate(actstate)
if actstate = 0 then
decode_actstate = "Not activated"
elseif actstate = 1 then
decode_actstate = "Activated"
elseif actstate = 2 then
decode_actstate = "Connecting"
elseif actstate = 3 then
decode_actstate = "Connected"
elseif actstate = 4 then
decode_actstate = "Authenticated"
elseif actstate = 5 then
decode_actstate = "NAM downloaded"
elseif actstate = 6 then
decode_actstate = "MDN downloaded"
elseif actstate = 7 then
decode_actstate = "IMSI downloaded"
elseif actstate = 8 then
decode_actstate = "PRL downloaded"
elseif actstate = 9 then
decode_actstate = "SPC downloaded"
elseif actstate = 10 then
decode_actstate = "OTASP settings committed"
else
decode_actstate = "Unknown(" & actstate & ")"
endif
end function
' returns true if we are running GOBI CDMA firmware
'
function gobi_module_detected
local res, tmp
gobi_module_detected = false
res = execute("tags", 0, tmp)
if res = true then
if InStr(tmp, "QUALCOMM_GOBI_CDMA") > 0 then
gobi_module_detected = true
endif
endif
end function
'
' Do Sprint IOTA activation for the Qualcomm GOBI module
'
function do_gobi_iota
local iota_cmd, iotastatus_cmd, rsp, ticks_end, iota_done
eventmsg "Sprint IOTA provisioning starting"
iota_cmd = "AT$QCIOTA?start"
iotastatus_cmd = "AT$QCIOTA?status"
' Start up the IOTA session
'
eventmsg "Sent " & iota_cmd
print #mc75out, iota_cmd, "\r"
if getOKline() = false then
restorecfg()
errexit "Sprint IOTA activation failed: bad response to " & iota_cmd
endif
eventmsg "Monitoring status (up to 5 mins)..."
' set the end time. ticks are units of 10ms
' 5 mins normally
ticks_end = ticks + 5*60*100
' 15 secs for debugging
' ticks_end = ticks + 15*100
' now sit and wait for OTASP notifications
'
iota_done = FALSE
while ticks <= ticks_end and iota_done = FALSE
sleep(2)
check_user_abort()
rsp = modem_cmd(iotastatus_cmd)
if instr(rsp, "SUCCESS") > 0 then
iota_done = TRUE
elseif instr(rsp, "FAILED") > 0 then
restorecfg()
errexit "Sprint IOTA activation failed: status result: " & rsp
endif
wend
if iota_done = FALSE then
restorecfg()
errexit "Activation failed: timeout awaiting completion"
endif
restorecfg()
errexit "Activation SUCCESSFUL"
end function
'
' Do Sprint OMADM activation for the Qualcomm GOBI module
'
function do_gobi_omadm
local i, omadm_cmd, omadmstatus_cmd, rsp, nrsp, prev_rsp, prev_nrsp, tstart, ticks_end, omadm_done, state_changed
eventmsg "Sprint OMADM provisioning starting"
omadm_cmd = "AT+OMADM=2"
omadmstatus_cmd = "AT+OMADM=?"
' Start up the OMADM session
'
eventmsg "Sent " & omadm_cmd
print #mc75out, omadm_cmd, "\r"
if getOKline() = false then
restorecfg()
errexit "Sprint OMADM activation failed: bad response to " & omadm_cmd
endif
eventmsg "Monitoring status (up to 5 mins)..."
' set the end time. ticks are units of 10ms
' 5 mins normally
' ticks_end = ticks + 5*60*100
' 60 secs for debugging
ticks_end = ticks + 60*100
tstart = ticks
' now sit and wait for OTASP notifications
'
prev_nrsp = 0
omadm_done = FALSE
omadm_status = "Unknown"
while ticks <= ticks_end and omadm_done = FALSE
sleep(1)
check_user_abort()
nrsp = modem_cmd_lines(omadmstatus_cmd, rsp)
if nrsp <> 0 then
' for i = 0 to nrsp-1
' if instr(rsp[i], "Device is programmed") > 0 then
' omadm_done = TRUE
' endif
' next i
' check to see if state info has changed
state_changed = 0
if nrsp <> prev_nrsp then
state_changed = 1
else
for i = 0 to nrsp-1
if prev_rsp[i] <> rsp[i] then
state_changed = 1
endif
next i
endif
' and only report state if it has changed
if state_changed <> 0 then
for i = 0 to nrsp-1
eventmsg rsp[i]
prev_rsp[i] = rsp[i]
next i
prev_nrsp = nrsp
endif
'
' look for "none" after "Current device config session status:"
' Don't check during the first 5 secs
'
if ticks-tstart > 500 then
for i = 0 to nrsp-1
if instr(rsp[i], "Current device config session status") > 0 then
if instr(rsp[i+1], "None") > 0 then
omadm_done = TRUE
omadm_status = rsp[i-1]
endif
endif
next i
endif
endif
wend
if omadm_done = FALSE then
restorecfg()
errexit "Activation failed: timeout awaiting completion"
endif
restorecfg()
errexit "Activation complete, status: " & omadm_status
end function
'
' Do Verizon OTASP activation for the Qualcomm GOBI module
'
function do_gobi_otasp
local i, GotOK, actstate, initial_actstate, state_changed
eventmsg "Verizon OTASP provisioning starting"
' Get the initial activation state
'
i = 0
GotOK = false
while i < 20 and GotOK = false
i += 1
print "Getting status...", nl
if getActivationState(actstate) = true then
GotOK = true
else
sleep(2)
endif
wend
if gotOK = true then
print "GOBI activation state is: ", decode_actstate(actstate), nl
else
restorecfg()
errexit "Activation cannot start: unable to get GOBI activation state"
endif
initial_actstate = actstate
' Now initiate the provisioning call (we don't expect a response from this command)
'
eventmsg "Sent AT+CDV*22899"
print #mc75out, "AT+CDV*22899\r"
' and monitor the activation state until we get activated(1), committed(10) or timeout
' Current timeout is 60 secs for now, but we might want longer.
' Also, we currently output the status every 1 sec; this could be simplified just to indicate changes.
' Currently we don't deal with the case where the initial activation state is already activated.
i = 0
GotOK = false
state_changed = false
while i < 60 and GotOK = false
i += 1
print "Checking status...", nl
if getActivationState(actstate) = true then
eventmsg "Activation state is: " & decode_actstate(actstate)
if state_changed = false then
if actstate <> initial_actstate then
state_changed = true
endif
endif
if state_changed = false and i < 30 then
' hold off checking for the first 30 secs if there is no state change
else
if actstate = "1" or actstate = "10" then
gotOK = true
endif
endif
endif
if gotOK = false then sleep(1)
wend
restorecfg()
if gotOK = true then
errexit "OTASP activation successful, activation state is: " & decode_actstate(actstate)
else
errexit "OTASP activation failed, activation state is: " & decode_actstate(actstate)
endif
end function
' Activation for the GOBI module
'
function do_gobi_act
local res, resstr, i, gobifw, actstate
' reset the modem and disable the driver
'
res = execute("modemoff", 0, resstr)
eventmsg "Resetting modem..."
for i = 1 to 5
sleep(1)
check_user_abort()
next i
' and release only the AT port, not the info port
'
res = execute("modemcc 0 asy_add 255", 0, resstr)
asyportchanged = 1
for i = 1 to 35
sleep(1)
check_user_abort()
next i
' initialise the AT serial port IO
'
AsyPortName = "ASY" & asystr
mc75asyport = AsyPortName
print "AsyPortName = ", AsyPortName, nl
init_mc75io()
atopened = 1
' First make sure we can talk to the device by ATing it
' until we get OK back
'
i = 0
GotOK = false
while i < 10 and GotOK = false
i += 1
print "Sending AT...", nl
print #mc75out, "AT\r"
if getOKline() = true then GotOK = true
check_user_abort()
wend
if GotOK = false then
restorecfg()
errexit "Activation failed: cannot AT device on " & AsyPortName
endif
clear_mc75io()
manufacturer = modem_cmd("AT+GMI")
eventmsg "Manufacturer is: " & manufacturer
' Find out what GOBI firmware is in use from the QDL config setting
'
if getParam("qdl 0 fw ?", gobifw) = TRUE then
print "GOBI firmware is: ", gobifw, nl
else
restorecfg()
errexit "Activation cannot start: unable to get GOBI firmware version"
endif
if gobifw = 1 then
do_gobi_otasp()
stop
endif
if gobifw = 2 then
do_gobi_omadm()
stop
endif
restorecfg()
errexit "Activation cannot start: unregognized GOBI firmware version (" & gobifw & ")"
end function
' ******** MAIN PROGRAM STARTS HERE ********
errcnt = 0
socketopened = 0
cnsopened = 0
atopened = 0
asyportchanged = 0
init_log_files()
tnow = now() and 0x7fffffff
eventmsg "GOBI Activation script started at " & FormatDate("0D-MON-YY 0H:0m:0s",tnow)
' clear the abort signal
'
junk = mibset("provision.0.userstring1", "")
' clear the last exit message
'
junk = mibset("provision.0.userstring2", "Started at " & FormatDate("0D-MON-YY 0H:0m:0s",tnow))
' Find out what ASY port is used by modemcc for GPRS
'
if getParam("modemcc 0 asy_add ?", asystr) = TRUE then
print "modemcc 0 asy_add is: ", asystr, nl
else
errexit "Activation cannot start: unable to get modemcc 0 asy_add"
endif
if asystr = "255" or asystr = "0" or asystr = "" then
errexit "Activation cannot start: invalid modemcc asy_add (try muxon)"
endif
' Find out what INFO ASY port is used by modemcc for GPRS
'
if getParam("modemcc 0 info_asy_add ?", infoasystr) = TRUE then
print "modemcc 0 info_asy_add is: ", infoasystr, nl
else
errexit "Activation cannot start: unable to get modemcc 0 info_asy_add"
endif
if infoasystr = "0" or infoasystr = "" then
errexit "Activation cannot start: invalid modemcc info_asy_add (try muxon)"
endif
' Find out which PPP instance is configured for GPRS
'
got_gprs_ppp = get_gprs_ppp_instance(gprs_ppp_instance)
' deactivate PPP
'
if got_gprs_ppp then
print "PPP ", gprs_ppp_instance, " is configured for GPRS", nl
res = execute("ppp " & gprs_ppp_instance & " deact_rq", 0, resstr)
sleep(1)
else
print "No PPP instances configured for GPRS", nl
endif
' if we have a GOBI module, then we jump to the GOBI activation script
'
if gobi_module_detected() then
do_gobi_act()
stop
endif
restorecfg()
errexit "Cannot start activation: router is not configured for a GOBI module"
stop
ErrorLabel:
'print "Got error code: ", error(), "(", error$, ")", nl
if error() = 22 and errcnt < 20 then
print "Retrying connection ...", nl
sleep(1)
errcnt = errcnt + 1
on error goto ErrorLabel
resume
endif
restorecfg()
errexit(error$)