远程门禁


概述

用于小区智能门禁的实际案例,启动后连接服务器;连接上以后发送注册包到服务器,包含门锁的参数;每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;
    }
}