海萤物联网ntp服务上线

欢迎前往社区交流:海萤物联网社区

开源

介绍

基于Golang编写,在海萤物联网提供校时服务。

本机地址是:

0x2141000000000404

服务

服务号|服务| —|— 1|读取时间1 2|读取时间2.返回的是结构体

读取时间服务1

  • CON请求:空或者带符号的1个字节。

当CON请求为空时,则默认为读取的是北京时间(时区8)。

也可以带1个字节表示时区号。这个字节是有符号的int8。

小技巧,可以使用0x100减去正值即负值。比如8对应的无符号数是0x100-8=248。

  • ACK应答:当前时间的字符串

当前时间字符串的格式:2006-01-02 15:04:05 -0700 MST

读取时间服务2.返回的是结构体

  • CON请求:格式与读取时间服务1一致

  • ACK应答:

    struct {
      // 时区
      uint8 TimeZone
      uint16 Year
      uint8 Month
      uint8 Day
      uint8 Hour
      uint8 Minute
      uint8 Second
      // 星期
      uint8 Weekday
    }
    

自定义错误码

错误码|含义 —|— 0x40|内部错误 0x41|接收格式错误

示例

读取时间

resp, err := tziot.Call(pipe, 0x2141000000000004, 1, 1000, []uint8{})
fmt.Println("err:", err, "time:", string(resp))

输出:

err: 0 time: 2021-03-20 06:34:18 +0800 CST

读取时区为2的时间

resp, err := tziot.Call(pipe, 0x2141000000000004, 1, 1000, []uint8{2})
fmt.Println("err:", err, "time:", string(resp))

输出:

err: 0 time: 2021-03-20 00:36:31 +0200 CST

读取时区为-6的时间

resp, err := tziot.Call(pipe, 0x2141000000000004, 1, 1000, []uint8{0x100-6})
fmt.Println("err:", err, "time:", string(resp))

输出:

err: 0 time: 2021-03-19 16:36:06 -0600 CST

读取结构体格式时间

resp, _ := tziot.Call(pipe, 0x2141000000000004, 2, 3000, []uint8{8})
var ack AckRidGetTime2
_ = dcom.BytesToStruct(resp, &ack)
fmt.Println(ack)

输出:

{8 2021 3 30 12 11 28 2}

源码

最新源码请查看仓库。

main.go

// Copyright 2021-2021 The jdh99 Authors. All rights reserved.
// 网络校时服务
// Authors: jdh99 <jdh821@163.com>

package main

import (
	"github.com/jdhxyy/dcom"
	"github.com/jdhxyy/lagan"
	"github.com/jdhxyy/tziot"
	"ntp/config"
	"time"
)

const tag = "ntp"

// 应用错误码
const (
	// 内部错误
	errorCodeInternalError = 0x40
	// 接收格式错误
	errorCodeRxFormat = 0x41
)

// rid号
const (
	// 读取时间.返回的是字符串
	ridGetTime1 = 1
	// 读取时间.返回的是结构体
	ridGetTime2 = 2
)

// ACK格式
type AckRidGetTime2 struct {
	// 时区
	TimeZone uint8
	Year     uint16
	Month    uint8
	Day      uint8
	Hour     uint8
	Minute   uint8
	Second   uint8
	// 星期
	Weekday uint8
}

func main() {
	err := lagan.Load(0)
	if err != nil {
		panic(err)
	}
	lagan.EnableColor(true)
	lagan.SetFilterLevel(lagan.LevelInfo)

	_, err = tziot.BindPipeNet(config.LocalIA, config.LocalPwd, config.LocalIP, config.LocalPort)
	if err != nil {
		panic(err)
		return
	}
	tziot.Register(ridGetTime1, ntpService1)
	tziot.Register(ridGetTime2, ntpService2)

	select {}
}

// ntpService1 校时服务
// 返回值是应答和错误码.错误码为0表示回调成功,否则是错误码
func ntpService1(pipe uint64, srcIA uint64, req []uint8) ([]uint8, int) {
	addr := dcom.PipeToAddr(pipe)

	var timeZone int
	if len(req) == 0 {
		timeZone = 8
	} else if len(req) == 1 {
		timeZone = int(int8(req[0]))
	} else {
		lagan.Warn(tag, "addr:%v ia:0x%x ntp failed.len is wrong:%d", addr, srcIA, len(req))
		return nil, errorCodeRxFormat
	}

	t := getTime(timeZone)
	lagan.Info(tag, "addr:%v ia:0x%x ntp time:%v", addr, srcIA, t)
	return []uint8(t.Format("2006-01-02 15:04:05 -0700 MST")), 0
}

func getTime(timeZone int) time.Time {
	t := time.Now().UTC()
	secondsEastOfUTC := int((time.Duration(timeZone) * time.Hour).Seconds())
	loc := time.FixedZone("CST", secondsEastOfUTC)
	t = t.In(loc)
	return t
}

// ntpService2 校时服务
// 返回值是应答和错误码.错误码为0表示回调成功,否则是错误码
func ntpService2(pipe uint64, srcIA uint64, req []uint8) ([]uint8, int) {
	addr := dcom.PipeToAddr(pipe)

	var timeZone int
	if len(req) == 0 {
		timeZone = 8
	} else if len(req) == 1 {
		timeZone = int(int8(req[0]))
	} else {
		lagan.Warn(tag, "addr:%v ia:0x%x ntp failed.len is wrong:%d", addr, srcIA, len(req))
		return nil, errorCodeRxFormat
	}

	t := getTime(timeZone)
	lagan.Info(tag, "addr:%v ia:0x%x ntp time:%v", addr, srcIA, t)

	var ack AckRidGetTime2
	ack.TimeZone = uint8(timeZone)
	ack.Year = uint16(t.Year())
	ack.Month = uint8(t.Month())
	ack.Day = uint8(t.Day())
	ack.Hour = uint8(t.Hour())
	ack.Minute = uint8(t.Minute())
	ack.Second = uint8(t.Second())
	ack.Weekday = uint8(t.Weekday())

	data, err := dcom.StructToBytes(ack)
	if err != nil {
		lagan.Error(tag, "addr:%v ia:0x%x ntp failed.struct to bytes error:%v", addr, srcIA, err)
		return nil, errorCodeInternalError
	}
	return data, 0
}

config.go

// Copyright 2021-2021 The jdh99 Authors. All rights reserved.
// 配置文件
// Authors: jdh99 <jdh821@163.com>

package config

import "fmt"

// 系统参数
const (
	LocalIA   = 0x2141000000000004
	LocalIP   = "0.0.0.0"
	LocalPort = 12930
)

var LocalPwd string

func init() {
	fmt.Println("please input password:")
	_, err := fmt.Scanln(&LocalPwd)
	if err != nil {
		panic(err)
	}
}