Introduced `SpiParameters` and related structs to process SPI data. Added JSON marshaling/unmarshaling logic and a handler for the "SPI" command in the server. This enables parsing and transforming SPI data effectively for device communication.
190 lines
3.9 KiB
Go
190 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"gitea.unprism.ru/KRBL/n9m/v2"
|
|
"io"
|
|
"net"
|
|
"os"
|
|
"syscall"
|
|
)
|
|
|
|
func main() {
|
|
ln, err := net.Listen("tcp", "0.0.0.0:5556")
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for {
|
|
var conn net.Conn
|
|
|
|
conn, err = ln.Accept()
|
|
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
go handle(conn)
|
|
}
|
|
}
|
|
|
|
func handleSpecialPackages(_ *n9m.SmartPackage, pack n9m.Package) error {
|
|
switch pack.SSRC {
|
|
case n9m.SpecialPayloadTypeGPS:
|
|
fmt.Printf("%+v\n", pack.GPS)
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("unhandled special operation: %d", pack.SSRC)
|
|
}
|
|
}
|
|
|
|
func handleCertificateConnect(sPack *n9m.SmartPackage, pack n9m.Package) (err error) {
|
|
var params n9m.CertificateConnectRequest
|
|
|
|
if err = pack.GetParametersAs(¶ms); err != nil {
|
|
return fmt.Errorf("failed to get parameters: %w", err)
|
|
}
|
|
|
|
var response = n9m.CertificateConnectResponse{
|
|
ErrorCode: 0,
|
|
CommandMask: n9m.CommandMaskAll,
|
|
}
|
|
|
|
pack.SetResponse(response)
|
|
|
|
if _, err = sPack.Write(pack.PackPackage()); err != nil {
|
|
return fmt.Errorf("failed to write package: %w", err)
|
|
}
|
|
|
|
fmt.Println("Connected:", params.SerialNumber)
|
|
sPack.Storage["serial"] = params.SerialNumber
|
|
|
|
var request n9m.ConfigModelGetRequest
|
|
request.MDVR = "?"
|
|
|
|
pack.Payload.Module = "CONFIGMODEL"
|
|
pack.Payload.Operation = "GET"
|
|
pack.SetParameters(request)
|
|
|
|
sPack.Write(pack.PackPackage())
|
|
|
|
return
|
|
}
|
|
|
|
func handleKeepAlive(sPack *n9m.SmartPackage, pack n9m.Package) (err error) {
|
|
serial := sPack.Storage["serial"]
|
|
fmt.Println(serial, "still alive!")
|
|
|
|
pack.SetResponse(nil)
|
|
sPack.Write(pack.PackPackage())
|
|
|
|
return
|
|
}
|
|
|
|
func handleGetConfig(sPack *n9m.SmartPackage, pack n9m.Package) (err error) {
|
|
serial := sPack.Storage["serial"]
|
|
|
|
os.WriteFile(fmt.Sprintf("./%s.json", serial), pack.RawPayload, 0644)
|
|
|
|
var request n9m.ConfigModelSetRequest
|
|
|
|
if err = pack.GetParametersAs(&request); err != nil {
|
|
fmt.Println(err)
|
|
return err
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func handleUselessAlarms(sPack *n9m.SmartPackage, pack n9m.Package, response n9m.SendAlarmInfoResponse) (err error) {
|
|
return nil
|
|
}
|
|
|
|
func handleVideoLossAlarm(sPack *n9m.SmartPackage, pack n9m.Package, response n9m.SendAlarmInfoResponse) (err error) {
|
|
fmt.Println("Video loss alarm!")
|
|
return nil
|
|
}
|
|
|
|
func handleCameraCoveredAlarm(sPack *n9m.SmartPackage, pack n9m.Package, response n9m.SendAlarmInfoResponse) (err error) {
|
|
fmt.Println("Camera covered alarm!")
|
|
return nil
|
|
}
|
|
|
|
func handleSPI(_ *n9m.SmartPackage, pack n9m.Package) (err error) {
|
|
var params n9m.SpiParameters
|
|
|
|
if err = pack.GetParametersAs(¶ms); err != nil {
|
|
return
|
|
}
|
|
|
|
fmt.Printf("%+v\n", params)
|
|
|
|
return
|
|
}
|
|
|
|
func createSmartPackage(conn net.Conn) (pack *n9m.SmartPackage) {
|
|
pack = n9m.NewSmartPackage(conn)
|
|
|
|
pack.AddPayloadHandler(n9m.PayloadTypeSpecial, handleSpecialPackages)
|
|
|
|
pack.AddJSONHandler("CERTIFICATE", "CONNECT", handleCertificateConnect)
|
|
pack.AddJSONHandler("CERTIFICATE", "KEEPALIVE", handleKeepAlive)
|
|
pack.AddJSONHandler("CONFIGMODEL", "GET", handleGetConfig)
|
|
pack.AddJSONHandler("DEVEMM", "SPI", handleSPI)
|
|
|
|
pack.AddAlarmHandler(n9m.AlarmTypeMotionDetection, handleUselessAlarms)
|
|
|
|
pack.AddAlarmHandler(n9m.AlarmTypeVideoLoss, handleVideoLossAlarm)
|
|
pack.AddAlarmHandler(n9m.AlarmTypeCameraCovered, handleCameraCoveredAlarm)
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
go func() {
|
|
pack := packS
|
|
pack.Payload.Module = "EVEM"
|
|
pack.Payload.Operation = "GALARMING"
|
|
|
|
ticker := time.NewTicker(5 * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
for range ticker.C {
|
|
fmt.Println("Sent!")
|
|
if _, err := conn.Write(pack.PackPackage()); err != nil {
|
|
fmt.Println("Failed to send GALARMING:", err)
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
*/
|
|
|
|
func isNetConnClosedErr(err error) bool {
|
|
switch {
|
|
case
|
|
errors.Is(err, net.ErrClosed),
|
|
errors.Is(err, io.EOF),
|
|
errors.Is(err, syscall.EPIPE):
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func handle(conn net.Conn) {
|
|
pack := createSmartPackage(conn)
|
|
|
|
var err error
|
|
for {
|
|
if err = pack.Handle(); err != nil {
|
|
fmt.Println("Error:", err)
|
|
|
|
if isNetConnClosedErr(err) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|