' 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, "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, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" close 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, "

Activation started. See below for progress

\r\n" print #fh, "

Click here to cancel

\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, "

" & log_msg & "

\r\n" print #fh, "

Please reboot the router, " print #fh, "or click here to retry.

" 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 < 300 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$)