远程门禁
概述
用于小区智能门禁的实际案例,启动后连接服务器;连接上以后发送注册包到服务器,包含门锁的参数;每60秒发送一个心跳包;收到服务器开门指令后打开门锁;门锁开关状态有变化时上报服务器。
本节提供两种写法,功能是一致的,前面一种直接用javascript脚本组包,后面一种调用组包库,代码会简单点。
代码
var server = "218.201.154.94";
var port = 10808;
var isConnected = false;
function encodePacket(s)
{
var crc = Coder.crc16(s);
var pk = Bytes.create(s.length + 5);
pk.seti(0xEA);
pk.seti(s.length, 1, "2b");
pk.sets(s, 3);
pk.seti(crc, 3 + s.length, "2b");
return pk;
}
function sendHeartbeat()
{
var pk = Bytes.create(5);
pk.seti(0xEA);
pk.seti(0, 1, "4b");
Net.send(1, pk);
}
function sendBoot()
{
var cmd = {cmd:1,ver:Box.ver()};
cmd.sn = Box.sn();
cmd.devid = Box.ccid();
Net.send(1, encodePacket(JSON.stringify(cmd)));
}
function sendResult(c, r)
{
var cmd = {cmd:c,result:r};
Net.send(1, encodePacket(JSON.stringify(cmd)));
}
function sendStatus(s)
{
var cmd = {cmd:3,status:s};
Net.send(1, encodePacket(JSON.stringify(cmd)));
}
function parseCmd(s)
{
d = JSON.parse(s);
if(d == undefined)
return;
Timer.stop(1);
switch(d.cmd)
{
case 1:
Timer.stop(2);
isConnected = true;
GPIO.listen(GPIO.IN1);
break;
case 2:
GPIO.set(GPIO.OUT1, 1);
GPIO.set(GPIO.DATA, 1);
sendResult(2, 0);
Timer.start(3, 5000);
break;
}
Timer.start(1, 60000);
}
var buf = Bytes.create(255);
var index = 0;
var len = 0;
var crc = 0;
var state = 0;
function handleRecv(d)
{
var i;
for(i = 0; i < d.length; i++)
{
var b = d.geti(i);
switch(state)
{
case 0:
if(b == 0xEA)
state++;
break;
case 1:
len = b;
state++;
break;
case 2:
len <<= 8;
len += b;
if(len > 255)
{
state = 0;
return;
}
else
{
state++;
index = 0;
}
break;
case 3:
buf.seti(b, index);
index++;
if(index >= len)
state++;
break;
case 4:
buf.seti(b, index);
index++;
state++;
break;
case 5:
buf.seti(b, index);
index++;
if(Coder.crc16(buf.sub(0, index)) == 0)
parseCmd(buf.gets(0, index));
state = 0;
break;
}
}
}
function handleNetEvent(m)
{
switch(m.event)
{
case Net.READY:
Net.connect(1, server, port);
break;
case Net.CONN_OK:
sendBoot();
Timer.start(2, 10000);
break;
case Net.CONN_FAIL:
Net.connect(1, server, port);
break;
case Net.CONN_CLOSE:
Timer.stop(1);
Timer.stop(2);
Timer.stop(3);
isConnected = false;
Net.connect(1, server, port);
break;
case Net.RECV:
handleRecv(m.data);
break;
}
}
function handleTimerOut(id)
{
switch(id)
{
case 1: //send heartbeat packet
sendHeartbeat();
Timer.start(1, 60000);
break;
case 2: //send boot packet
sendBoot();
Timer.start(2, 10000);
break;
case 3: //close switch
GPIO.set(GPIO.OUT1, 0);
GPIO.set(GPIO.DATA, 0);
break;
}
}
GPIO.set(GPIO.POWER, 1);
Net.init();
while(true)
{
var m = Event.get();
switch(m.msg)
{
case Event.NET_EVENT:
handleNetEvent(m);
break;
case Event.TIMER_OUT:
handleTimerOut(m.id);
break;
case Event.PIO_CHANGE:
if(isConnected)
sendStatus(1 - m.level);
break;
}
}
下面是另一种写法,使用了Packet.Simple对象库,可以忽略组包,解包的细节,也处理了接收数据过程中数据包的粘包和分包情况。
var server = "iot.easelive.cn";
var port = 10808;
var isConnected = false;
function sendHeartbeat()
{
Net.send(1, Packet.Simple.packet(""));
}
function sendBoot()
{
var cmd = {cmd:1,ver:Box.ver(),model:3};
cmd.sn = Box.sn();
cmd.devid = Box.ccid();
Net.send(1, Packet.Simple.packet(JSON.stringify(cmd)));
}
function sendResult(c, r)
{
var cmd = {cmd:c,result:r};
Net.send(1, Packet.Simple.packet(JSON.stringify(cmd)));
}
function sendStatus(s)
{
var cmd = {cmd:3,status:s};
cmd.sn = Box.sn();
Net.send(1, Packet.Simple.packet(JSON.stringify(cmd)));
}
function parseCmd(data)
{
var d = JSON.parse(data.gets());
if(d == undefined)
return;
Timer.stop(1);
print(data.gets());
switch(d["cmd"])
{
case 1:
Timer.stop(2);
isConnected = true;
GPIO.listen(GPIO.IN1);
Net.close(1);
break;
case 2:
GPIO.set(GPIO.OUT1, 1);
GPIO.set(GPIO.DATA, 1);
sendResult(2, 0);
Timer.start(3, 500);
break;
}
Timer.start(1, 60000);
}
var parser = Packet.Simple.Parser.create(parseCmd);
function handleNetEvent(m)
{
switch(m["event"])
{
case Net.READY:
Net.connect(1, server, port);
break;
case Net.CONN_OK:
sendBoot();
Timer.start(2, 10000);
break;
case Net.CONN_FAIL:
Net.connect(1, server, port);
break;
case Net.CONN_CLOSE:
Timer.stop(1);
Timer.stop(2);
Timer.stop(3);
isConnected = false;
Net.connect(1, server, port);
break;
case Net.RECV:
parser.parse(m["data"]);
break;
}
}
function handleTimerOut(id)
{
switch(id)
{
case 1: //send heartbeat packet
sendHeartbeat();
Timer.start(1, 60000);
break;
case 2: //send boot packet
sendBoot();
Timer.start(2, 10000);
break;
case 3: //close switch
GPIO.set(GPIO.OUT1, 0);
GPIO.set(GPIO.DATA, 0);
break;
}
}
GPIO.set(GPIO.POWER, 1);
Net.init();
while(true)
{
var m = Event.get();
switch(m["msg"])
{
case Event.NET_EVENT:
handleNetEvent(m);
break;
case Event.TIMER_OUT:
handleTimerOut(m["id"]);
break;
case Event.PIO_CHANGE:
if(isConnected)
sendStatus(1 - m["level"]);
break;
}
}