--[[
ģƣ
ģ鹦ܣźŲѯGSM״̬ѯָʾƿơٽСϢѯ
ģ޸ʱ䣺2017.02.17
]]

--ģ,
local base = _G
local string = require"string"
local sys = require "sys"
local ril = require "ril"
local pio = require"pio"
local sim = require "sim"
module("net")

--سõȫֺ
local dispatch = sys.dispatch
local req = ril.request
local smatch,ssub = string.match,string.sub
local tonumber,tostring,print = base.tonumber,base.tostring,base.print
--GSM״̬
--INITʼе״̬
--REGISTEREDעGSM
--UNREGISTERδעGSM
local state = "INIT"
--SIM״̬trueΪ쳣falsenilΪ
local simerrsta

--lacλID
--ciСID
--rssiźǿ
local lac,ci,rssi = "","",0

--csqqrypriodźǿȶʱѯ
--cengqrypriodǰٽСϢʱѯ
local csqqrypriod,cengqrypriod = 60*1000

--cellinfoǰСٽСϢ
--flymodeǷڷģʽ
--csqswitchʱѯźǿȿ
--cengswitchʱѯǰٽСϢ
--multicellcbȡСĻص
local cellinfo,flymode,csqswitch,cengswitch,multicellcb = {}

--ledstateָʾ״̬INIT,FLYMODE,SIMERR,IDLE,CREG,CGATT,SCK
--INITܹر״̬
--FLYMODEģʽ
--SIMERRδ⵽SIMSIMpin쳣
--IDLEδעGSM
--CREGעGSM
--CGATTѸGPRS
--SCKûsocketϺ̨
--ledontimeָʾƵʱ()
--ledofftimeָʾϨʱ()
--usersckconnectûsocketǷϺ̨
--userscksslconnectûsocketǷϺ̨
local ledstate,ledontime,ledofftime,usersckconnect,userscksslconnect = "INIT",0,0
--ledflgָʾƿ
--ledpinָʾƿ
--ledvalidֵƽָʾƣ1Ϊߣ0Ϊ
--ledidleon,ledidleoff,ledcregon,ledcregoff,ledcgatton,ledcgattoff,ledsckon,ledsckoffIDLE,CREG,CGATT,SCK״ָ̬ʾƵĵϨʱ()
local ledflg,ledpin,ledvalid,ledflymodeon,ledflymodeoff,ledsimerron,ledsimerroff,ledidleon,ledidleoff,ledcregon,ledcregoff,ledcgatton,ledcgattoff,ledsckon,ledsckoff = false,((base.MODULE_TYPE=="Air800" or base.MODULE_TYPE=="Air801") and pio.P0_28 or pio.P1_1),1,0,0xFFFF,300,5700,300,3700,300,1700,300,700,100,100

--[[
creg
  CREGϢ
  
		dataCREGϢַ+CREG: 2+CREG: 1,"18be","93e1"+CREG: 5,"18a7","cb51"
ֵ
]]
local function creg(data)
	local p1,s
	--ȡע״̬
	_,_,p1 = string.find(data,"%d,(%d)")
	if p1 == nil then
		_,_,p1 = string.find(data,"(%d)")
		if p1 == nil then
			return
		end
	end

	--ע
	if p1 == "1" or p1 == "5" then
		s = "REGISTERED"		
	--δע
	else
		s = "UNREGISTER"
	end
	--ע״̬˸ı
	if s ~= state then
		--ٽСѯ
		if not cengqrypriod and s == "REGISTERED" then
			setcengqueryperiod(60000)
		else
			cengquery()
		end
		state = s
		--һڲϢNET_STATE_CHANGEDʾGSMע״̬仯
		dispatch("NET_STATE_CHANGED",s)
		--ָʾƿ
		procled()
	end
	--עᲢlacci˱仯
	if state == "REGISTERED" then
		p2,p3 = string.match(data,"\"(%x+)\",\"(%x+)\"")
		if lac ~= p2 or ci ~= p3 then
			lac = p2
			ci = p3
			--һڲϢNET_CELL_CHANGEDʾlacci˱仯
			dispatch("NET_CELL_CHANGED")
		end
	end
end

--[[
resetcellinfo
  õǰСٽСϢ
  
ֵ
]]
local function resetcellinfo()
	local i
	cellinfo.cnt = 11 --
	for i=1,cellinfo.cnt do
		cellinfo[i] = {}
		cellinfo[i].mcc,cellinfo[i].mnc = nil
		cellinfo[i].lac = 0
		cellinfo[i].ci = 0
		cellinfo[i].rssi = 0
		cellinfo[i].ta = 0
	end
end

--[[
ceng
  ǰСٽСϢ
  
		dataǰСٽСϢַеÿһУ
		+CENG:1,1
		+CENG:0,"573,24,99,460,0,13,49234,10,0,6311,255"
		+CENG:1,"579,16,460,0,5,49233,6311"
		+CENG:2,"568,14,460,0,26,0,6311"
		+CENG:3,"584,13,460,0,10,0,6213"
		+CENG:4,"582,13,460,0,51,50146,6213"
		+CENG:5,"11,26,460,0,3,52049,6311"
		+CENG:6,"29,26,460,0,32,0,6311"
ֵ
]]
local function ceng(data)
	--ֻЧCENGϢ
	if string.find(data,"%+CENG:%d+,\".+\"") then
		local id,rssi,lac,ci,ta,mcc,mnc
		id = string.match(data,"%+CENG:(%d)")
		id = tonumber(id)
		--һCENGϢĸʽͬ
		if id == 0 then
			rssi,mcc,mnc,ci,lac,ta = string.match(data, "%+CENG:%d,\"%d+,(%d+),%d+,(%d+),(%d+),%d+,(%d+),%d+,%d+,(%d+),(%d+)\"")
		else
			rssi,mcc,mnc,ci,lac,ta = string.match(data, "%+CENG:%d,\"%d+,(%d+),(%d+),(%d+),%d+,(%d+),(%d+)\"")
		end
		--ȷ
		if rssi and ci and lac and mcc and mnc then
			--ǵһϢ
			if id == 0 then
				resetcellinfo()
			end
			--mccmnclaccirssita
			cellinfo[id+1].mcc = mcc
			cellinfo[id+1].mnc = mnc
			cellinfo[id+1].lac = tonumber(lac)
			cellinfo[id+1].ci = tonumber(ci)
			cellinfo[id+1].rssi = (tonumber(rssi) == 99) and 0 or tonumber(rssi)
			cellinfo[id+1].ta = tonumber(ta or "0")
			--һڲϢCELL_INFO_INDʾȡµĵǰСٽСϢ
			if id == 0 then
				dispatch("CELL_INFO_IND",cellinfo)
			end
		end
	end
end

--[[
neturc
  ģڡעĵײcoreͨ⴮ϱ֪ͨĴ
  
		dataַ֪ͨϢ
		prefix֪ͨǰ׺
ֵ
]]
local function neturc(data,prefix)
	if prefix == "+CREG" then
		--յ״̬仯ʱ,һźֵ
		csqquery()
		--cregϢ
		creg(data)
	elseif prefix == "+CENG" then
		--cengϢ
		ceng(data)
	end
end

--[[
getstate
  ȡGSMע״̬
  
ֵGSMע״̬(INITREGISTEREDUNREGISTER)
]]
function getstate()
	return state
end

--[[
getmcc
  ȡǰСmcc
  
ֵǰСmccûעGSM磬򷵻simmcc
]]
function getmcc()
	return cellinfo[1].mcc or sim.getmcc()
end

--[[
getmnc
  ȡǰСmnc
  
ֵǰСmncûעGSM磬򷵻simmnc
]]
function getmnc()
	return cellinfo[1].mnc or sim.getmnc()
end

--[[
getlac
  ȡǰλID
  
ֵǰλID(16ַ"18be")ûעGSM磬򷵻""
]]
function getlac()
	return lac
end

--[[
getci
  ȡǰСID
  
ֵǰСID(16ַ"93e1")ûעGSM磬򷵻""
]]
function getci()
	return ci
end

--[[
getrssi
  ȡźǿ
  
ֵǰźǿ(ȡֵΧ0-31)
]]
function getrssi()
	return rssi
end

--[[
getcell
  ȡǰٽСԼźǿȵƴַ
  
ֵǰٽСԼźǿȵƴַ磺49234.30.49233.23.49232.18.
]]
function getcell()
	local i,ret = 1,""
	for i=1,cellinfo.cnt do
		if cellinfo[i] and cellinfo[i].lac and cellinfo[i].lac ~= 0 and cellinfo[i].ci and cellinfo[i].ci ~= 0 then
			ret = ret..cellinfo[i].ci.."."..cellinfo[i].rssi.."."
		end
	end
	return ret
end

--[[
getcellinfo
  ȡǰٽλСԼźǿȵƴַ
  
ֵǰٽλСԼźǿȵƴַ磺6311.49234.30;6311.49233.23;6322.49232.18;
]]
function getcellinfo()
	local i,ret = 1,""
	for i=1,cellinfo.cnt do
		if cellinfo[i] and cellinfo[i].lac and cellinfo[i].lac ~= 0 and cellinfo[i].ci and cellinfo[i].ci ~= 0 then
			ret = ret..cellinfo[i].lac.."."..cellinfo[i].ci.."."..cellinfo[i].rssi..";"
		end
	end
	return ret
end

--[[
getcellinfoext
  ȡǰٽλСmccmncԼźǿȵƴַ
  
ֵǰٽλСmccmncԼźǿȵƴַ磺460.01.6311.49234.30;460.01.6311.49233.23;460.02.6322.49232.18;
]]
function getcellinfoext()
	local i,ret = 1,""
	for i=1,cellinfo.cnt do
		if cellinfo[i] and cellinfo[i].mcc and cellinfo[i].mnc and cellinfo[i].lac and cellinfo[i].lac ~= 0 and cellinfo[i].ci and cellinfo[i].ci ~= 0 then
			ret = ret..cellinfo[i].mcc.."."..cellinfo[i].mnc.."."..cellinfo[i].lac.."."..cellinfo[i].ci.."."..cellinfo[i].rssi..";"
		end
	end
	return ret
end

--[[
getta
  ȡTAֵ
  
ֵTAֵ
]]
function getta()
	return cellinfo[1].ta
end

--[[
startquerytimer
  պ޹ܣֻΪ˼֮ǰдӦýű
  
ֵ
]]
function startquerytimer() end

--[[
simind
  ڲϢSIM_INDĴ
  
		paraʾSIM״̬
ֵ
]]
local function simind(para)
	print("simind",simerrsta,para)
	if simerrsta ~= (para~="RDY") then
		simerrsta = (para~="RDY")
		procled()
	end
	--sim
	if para ~= "RDY" then
		--GSM״̬
		state = "UNREGISTER"
		--ڲϢNET_STATE_CHANGEDʾ״̬仯
		dispatch("NET_STATE_CHANGED",state)
	end
	return true
end

--[[
flyind
  ڲϢFLYMODE_INDĴ
  
		paraʾģʽ״̬trueʾģʽfalseʾ˳ģʽ
ֵ
]]
local function flyind(para)
	--ģʽ״̬仯
	if flymode~=para then
		flymode = para
		--ָʾ
		procled()
	end
	--˳ģʽ
	if not para then
		----ѯʱ
		startcsqtimer()
		startcengtimer()
		--λGSM״̬
		neturc("2","+CREG")
	end
	return true
end

--[[
workmodeind
  ڲϢSYS_WORKMODE_INDĴ
  
		paraʾϵͳģʽ
ֵ
]]
local function workmodeind(para)
	--ѯʱ
	startcengtimer()
	startcsqtimer()
	return true
end

--[[
startcsqtimer
  ѡԵźǿȲѯʱ
  
ֵ
]]
function startcsqtimer()
	--Ƿģʽ  (˲ѯ  ģʽΪģʽ)
	if not flymode and (csqswitch or sys.getworkmode()==sys.FULL_MODE) then
		--AT+CSQѯ
		csqquery()
		--ʱ
		sys.timer_start(startcsqtimer,csqqrypriod)
	end
end

--[[
startcengtimer
  ѡԵǰٽСϢѯʱ
  
ֵ
]]
function startcengtimer()
	--˲ѯ  Ƿģʽ  (˲ѯ  ģʽΪģʽ)
	if cengqrypriod and not flymode and (cengswitch or sys.getworkmode()==sys.FULL_MODE) then
		--AT+CENG?ѯ
		cengquery()
		--ʱ
		sys.timer_start(startcengtimer,cengqrypriod)
	end
end

--[[
rsp
  ģڡͨ⴮ڷ͵ײcoreATӦ
  
		cmdӦӦAT
		successATִнtruefalse
		responseATӦеִнַ
		intermediateATӦемϢ
ֵ
]]
local function rsp(cmd,success,response,intermediate)
	local prefix = string.match(cmd,"AT(%+%u+)")

	if intermediate ~= nil then
		if prefix == "+CSQ" then
			local s = smatch(intermediate,"+CSQ:%s*(%d+)")
			if s ~= nil then
				rssi = tonumber(s)
				rssi = rssi == 99 and 0 or rssi
				--һڲϢGSM_SIGNAL_REPORT_INDʾȡźǿ
				dispatch("GSM_SIGNAL_REPORT_IND",success,rssi)
			end
		elseif prefix == "+CENG" then
		end
	end
end

--[[
setcsqqueryperiod
  áźǿȡѯ
  
		periodѯλ
ֵ
]]
function setcsqqueryperiod(period)
	csqqrypriod = period
	startcsqtimer()
end

--[[
setcengqueryperiod
  áǰٽСϢѯ
  
		periodѯλ롣Сڵ0ʾֹͣѯ
ֵ
]]
function setcengqueryperiod(period)
	if period ~= cengqrypriod then		
		if period <= 0 then
			sys.timer_stop(startcengtimer)
		else
			cengqrypriod = period
			startcengtimer()
		end
	end
end

--[[
cengquery
  ѯǰٽСϢ
  
ֵ
]]
function cengquery()
	--ǷģʽAT+CENG?
	if not flymode then	req("AT+CENG?")	end
end

--[[
setcengswitch
  áǰٽСϢѯ
  
		vtrueΪΪر
ֵ
]]
function setcengswitch(v)
	cengswitch = v
	--ҲǷģʽ
	if v and not flymode then startcengtimer() end
end

--[[
cellinfoind
  CELL_INFO_INDϢĴ
  
ֵûԶĻȡվϢĻص򷵻nil򷵻true
]]
local function cellinfoind()
	if multicellcb then
		local cb = multicellcb
		multicellcb = nil
		cb(getcellinfoext())
	else
		return true
	end
end

--[[
getmulticell
  ȡǰٽСϢ
  
		cbصȡСϢ󣬻ô˻صʽΪcb(cells)cellsΪstringͣʽΪ
		    ǰٽλСmccmncԼźǿȵƴַ磺460.01.6311.49234.30;460.01.6311.49233.23;460.02.6322.49232.18;
ֵ 
]]
function getmulticell(cb)
	multicellcb = cb
	cengquery()
end

--[[
csqquery
  ѯźǿȡ
  
ֵ
]]
function csqquery()
	--ǷģʽAT+CSQ
	if not flymode then req("AT+CSQ") end
end

--[[
setcsqswitch
  áźǿȡѯ
  
		vtrueΪΪر
ֵ
]]
function setcsqswitch(v)
	csqswitch = v
	--ҲǷģʽ
	if v and not flymode then startcsqtimer() end
end

--[[
ledblinkon
  ָʾ
  
ֵ
]]
local function ledblinkon()
	--print("ledblinkon",ledstate,ledontime,ledofftime)
	--ƽָʾƵ
	pio.pin.setval(ledvalid==1 and 1 or 0,ledpin)
	--
	if ledontime==0 and ledofftime==0xFFFF then
		ledblinkoff()
	--
	elseif ledontime==0xFFFF and ledofftime==0 then
		--رյʱʱϨʱʱ
		sys.timer_stop(ledblinkon)
		sys.timer_stop(ledblinkoff)
	--˸
	else
		--ʱʱʱ֮Ϩָʾ
		sys.timer_start(ledblinkoff,ledontime)
	end	
end

--[[
ledblinkoff
  Ϩָʾ
  
ֵ
]]
function ledblinkoff()
	--print("ledblinkoff",ledstate,ledontime,ledofftime)
	--ƽָʾϨ
	pio.pin.setval(ledvalid==1 and 0 or 1,ledpin)
	--
	if ledontime==0 and ledofftime==0xFFFF then
		--رյʱʱϨʱʱ
		sys.timer_stop(ledblinkon)
		sys.timer_stop(ledblinkoff)
	--
	elseif ledontime==0xFFFF and ledofftime==0 then
		ledblinkon()
	--˸
	else
		--Ϩʱʱʱ֮󣬵ָʾ
		sys.timer_start(ledblinkon,ledofftime)
	end	
end

--[[
procled
  ָʾ״̬ԼϨʱ
  
ֵ
]]
function procled()
	print("procled",ledflg,ledstate,flymode,usersckconnect,userscksslconnect,cgatt,state)
	--ָʾƹ
	if ledflg then
		local newstate,newontime,newofftime = "IDLE",ledidleon,ledidleoff
		--ģʽ
		if flymode then
			newstate,newontime,newofftime = "FLYMODE",ledflymodeon,ledflymodeoff
		elseif simerrsta then
			newstate,newontime,newofftime = "SIMERR",ledsimerron,ledsimerroff
		--ûsocketӵ˺̨
		elseif usersckconnect or userscksslconnect then
			newstate,newontime,newofftime = "SCK",ledsckon,ledsckoff
		--GPRS
		elseif cgatt then
			newstate,newontime,newofftime = "CGATT",ledcgatton,ledcgattoff
		--עGSM
		elseif state=="REGISTERED" then
			newstate,newontime,newofftime = "CREG",ledcregon,ledcregoff		
		end
		--ָʾ״̬仯
		if newstate~=ledstate then
			ledstate,ledontime,ledofftime = newstate,newontime,newofftime
			ledblinkoff()
		end
	end
end

--[[
usersckind
  ڲϢUSER_SOCKET_CONNECTĴ
  
		vʾûsocketǷϺ̨
ֵ
]]
local function usersckind(v)
	print("usersckind",v)
	if usersckconnect~=v then
		usersckconnect = v
		procled()
	end
end

local function userscksslind(v)
	print("userscksslind",v)
	if userscksslconnect~=v then
		userscksslconnect = v
		procled()
	end
end

--[[
cgattind
  ڲϢNET_GPRS_READYĴ
  
		vʾǷGPRS
ֵ
]]
local function cgattind(v)
	print("cgattind",v)
	if cgatt~=v then
		cgatt = v
		procled()
	end
	return true
end

--[[
setled
  ָʾƹ
  
		vָʾƿأtrueΪΪر
		pinָʾƿţѡ
		validֵƽָʾƣ1Ϊߣ0Ϊͣѡ
		flymodeon,flymodeoff,simerron,simerroff,idleon,idleoff,cregon,cregoff,cgatton,cgattoff,sckon,sckoffFLYMODE,SIMERR,IDLE,CREG,CGATT,SCK״ָ̬ʾƵĵϨʱ()ѡ
ֵ
]]
function setled(v,pin,valid,flymodeon,flymodeoff,simerron,simerroff,idleon,idleoff,cregon,cregoff,cgatton,cgattoff,sckon,sckoff)
	local c1 = (ledflg~=v or ledpin~=(pin or ledpin) or ledvalid~=(valid or ledvalid))
	local c2 = (ledidleon~=(idleon or ledidleon) or ledidleoff~=(idleoff or ledidleoff) or flymodeon~=(flymodeon or ledflymodeon) or flymodeoff~=(flymodeoff or ledflymodeoff))
	local c3 = (ledcregon~=(cregon or ledcregon) or ledcregoff~=(cregoff or ledcregoff) or ledcgatton~=(cgatton or ledcgatton) or simerron~=(simerron or ledsimerron))
	local c4 = (ledcgattoff~=(cgattoff or ledcgattoff) or ledsckon~=(sckon or ledsckon) or ledsckoff~=(sckoff or ledsckoff) or simerroff~=(simerroff or ledsimerroff))
	--ֵ仯 仯
	if c1 or c2 or c3 or c4 then
		local oldledflg = ledflg
		ledflg = v
		--
		if v then
			ledpin,ledvalid,ledidleon,ledidleoff,ledcregon,ledcregoff = pin or ledpin,valid or ledvalid,idleon or ledidleon,idleoff or ledidleoff,cregon or ledcregon,cregoff or ledcregoff
			ledcgatton,ledcgattoff,ledsckon,ledsckoff = cgatton or ledcgatton,cgattoff or ledcgattoff,sckon or ledsckon,sckoff or ledsckoff
			ledflymodeon,ledflymodeoff,ledsimerron,ledsimerroff = flymodeon or ledflymodeon,flymodeoff or ledflymodeoff,simerron or ledsimerron,simerroff or ledsimerroff
			if not oldledflg then pio.pin.setdir(pio.OUTPUT,ledpin) end
			procled()
		--ر
		else
			sys.timer_stop(ledblinkon)
			sys.timer_stop(ledblinkoff)
			if oldledflg then
				pio.pin.setval(ledvalid==1 and 0 or 1,ledpin)
				pio.pin.close(ledpin)
			end
			ledstate = "INIT"
		end		
	end
end

--ģעڲϢ
local procer =
{
	SIM_IND = simind,
	FLYMODE_IND = flyind,
	SYS_WORKMODE_IND = workmodeind,
	USER_SOCKET_CONNECT = usersckind,
	USER_SOCKETSSL_CONNECT = userscksslind,
	NET_GPRS_READY = cgattind,
	CELL_INFO_IND = cellinfoind,
}
--עϢ
sys.regapp(procer)
--ע+CREG+CENG֪ͨĴ
ril.regurc("+CREG",neturc)
ril.regurc("+CENG",neturc)
--עAT+CCSQAT+CENG?Ӧ
ril.regrsp("+CSQ",rsp)
ril.regrsp("+CENG",rsp)
--AT
req("AT+CREG=2")
req("AT+CREG?")
req("AT+CENG=1,1")
--8ѯһcsq
sys.timer_start(startcsqtimer,8*1000)
resetcellinfo()
setled(true)
