Refactor and enhance handling of payloads and data structures
Added support for handling various payload types, including GPS and alarms, with new structures and constants. Introduced helper methods for JSON marshalling/unmarshalling of GPS data and modularized the handling of certificates, configurations, and alarms. Implemented foundational server code for testing and expanded several package functionalities.
This commit is contained in:
parent
f3083820dc
commit
16da4affa8
@ -23,7 +23,7 @@ const (
|
|||||||
|
|
||||||
type CertificateConnectRequest struct {
|
type CertificateConnectRequest struct {
|
||||||
Net NetConnectionType `json:"NET"`
|
Net NetConnectionType `json:"NET"`
|
||||||
SerialNumber string `json:"DNSO"`
|
SerialNumber string `json:"DSNO"`
|
||||||
DeviceName string `json:"DEVNAME"`
|
DeviceName string `json:"DEVNAME"`
|
||||||
ChannelsNumber uint `json:"CHANNEL"`
|
ChannelsNumber uint `json:"CHANNEL"`
|
||||||
LicensePlate string `json:"CARNUM"`
|
LicensePlate string `json:"CARNUM"`
|
||||||
@ -35,6 +35,25 @@ type CertificateConnectRequest struct {
|
|||||||
EvidenceSupport string `json:"EV"`
|
EvidenceSupport string `json:"EV"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CertificateConnectResponse struct {
|
||||||
|
ErrorCode uint `json:"ERRORCODE"`
|
||||||
|
ErrorCause string `json:"ERRORCAUSE"`
|
||||||
|
CommandMask uint `json:"MASKCMD"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandMaskParameters uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
CommandMaskAlarm = 1 << iota
|
||||||
|
CommandMaskScanningGun
|
||||||
|
CommandMaskPassengerFlow
|
||||||
|
CommandMaskFaceContrast
|
||||||
|
CommandMaskCard
|
||||||
|
CommandMaskShutdownReport
|
||||||
|
CommandMaskGPSReport
|
||||||
|
CommandMaskAll = 0b1111111
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
func (e *Package) RequestConnect(session string, serial string, numOfCams int) {
|
func (e *Package) RequestConnect(session string, serial string, numOfCams int) {
|
||||||
e.Payload = map[string]any{
|
e.Payload = map[string]any{
|
||||||
|
174
cmd/dev-server/main.go
Normal file
174
cmd/dev-server/main.go
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"gitea.unprism.ru/KRBL/n9m"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 handle(conn net.Conn) {
|
||||||
|
var err error
|
||||||
|
var rn int
|
||||||
|
|
||||||
|
var serial string
|
||||||
|
|
||||||
|
packS := n9m.Package{}
|
||||||
|
tmp := make([]byte, 1024)
|
||||||
|
|
||||||
|
for {
|
||||||
|
rn, err = conn.Read(tmp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
packS.AddToAccum(tmp[:rn])
|
||||||
|
|
||||||
|
for packS.ReadPackage() {
|
||||||
|
switch packS.PayloadType {
|
||||||
|
case n9m.PayloadTypeData:
|
||||||
|
combined := packS.Payload.Module + ":" + packS.Payload.Operation
|
||||||
|
|
||||||
|
switch combined {
|
||||||
|
case "CERTIFICATE:CONNECT":
|
||||||
|
var params n9m.CertificateConnectRequest
|
||||||
|
|
||||||
|
if err = packS.GetParametersAs(¶ms); err != nil {
|
||||||
|
fmt.Println(combined, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = n9m.CertificateConnectResponse{
|
||||||
|
ErrorCode: 0,
|
||||||
|
CommandMask: n9m.CommandMaskAll,
|
||||||
|
}
|
||||||
|
|
||||||
|
packS.SetResponse(response)
|
||||||
|
|
||||||
|
if _, err = conn.Write(packS.PackPackage()); err != nil {
|
||||||
|
fmt.Println(combined, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Connected:", params.SerialNumber)
|
||||||
|
serial = params.SerialNumber
|
||||||
|
|
||||||
|
var request n9m.ConfigModelGetRequest
|
||||||
|
request.MDVR = "?"
|
||||||
|
packS.Payload.Module = "CONFIGMODEL"
|
||||||
|
packS.Payload.Operation = "GET"
|
||||||
|
packS.SetParameters(request)
|
||||||
|
|
||||||
|
conn.Write(packS.PackPackage())
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
*/
|
||||||
|
case "CERTIFICATE:KEEPALIVE":
|
||||||
|
packS.SetResponse(nil)
|
||||||
|
if _, err = conn.Write(packS.PackPackage()); err != nil {
|
||||||
|
fmt.Println(combined, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Connection is still alive!")
|
||||||
|
case "EVEM:GGALARMING":
|
||||||
|
fmt.Println(string(packS.RawPayload))
|
||||||
|
|
||||||
|
var response n9m.EventModelGetAlarmingResponse
|
||||||
|
if err = packS.GetResponseAs(&response); err != nil {
|
||||||
|
fmt.Println(combined, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%+v\n", response)
|
||||||
|
case "CONFIGMODEL:GET":
|
||||||
|
os.WriteFile(fmt.Sprintf("./%s.json", serial), packS.RawPayload, 0644)
|
||||||
|
case "EVEM:SENDALARMINFO":
|
||||||
|
var params n9m.SendAlarmInfoParameters
|
||||||
|
var response n9m.SendAlarmInfoResponse
|
||||||
|
|
||||||
|
if err = packS.GetParametersAs(¶ms); err != nil {
|
||||||
|
fmt.Printf("Error: %s\nData: %s", err, packS.RawPayload)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
response.ErrorCode = 0
|
||||||
|
response.AlarmType = params.AlarmType
|
||||||
|
response.CommandType = params.CommandType
|
||||||
|
response.AlarmUID = params.AlarmUID
|
||||||
|
response.NumberOfRestarts = params.NumberOfRestarts
|
||||||
|
response.InstructionSerial = params.InstructionSerial
|
||||||
|
|
||||||
|
switch params.AlarmType {
|
||||||
|
case n9m.AlarmTypeMotionDetection:
|
||||||
|
break
|
||||||
|
case n9m.AlarmTypeVideoLoss, n9m.AlarmTypeCameraCovered:
|
||||||
|
var cameraParams n9m.SendAlarmInfoCameraParameters
|
||||||
|
|
||||||
|
if err = packS.GetParametersAs(&cameraParams); err != nil {
|
||||||
|
fmt.Printf("Error: %s\nData: %s", err, packS.RawPayload)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%+v\n", cameraParams)
|
||||||
|
|
||||||
|
packS.SetResponse(response)
|
||||||
|
conn.Write(packS.PackPackage())
|
||||||
|
default:
|
||||||
|
fmt.Println("Unknown alarm type:", params.AlarmType)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Println("Strange operation:", combined)
|
||||||
|
}
|
||||||
|
|
||||||
|
case n9m.PayloadTypeSpecial:
|
||||||
|
switch packS.SSRC {
|
||||||
|
case n9m.SpecialPayloadTypeGPS:
|
||||||
|
fmt.Printf("%+v\n", packS.GPS)
|
||||||
|
default:
|
||||||
|
fmt.Println("Unhandled special operation:", packS.SSRC)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Println("Unhandled operation:", packS.PayloadType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,37 +28,41 @@ func (e *Package) SetParameters(params map[string]any, serial int, session strin
|
|||||||
}
|
}
|
||||||
// log.Println(e.Payload)
|
// log.Println(e.Payload)
|
||||||
} // end of 'SetParameters' function
|
} // end of 'SetParameters' function
|
||||||
|
*/
|
||||||
|
|
||||||
// todo al1
|
type ConfigModelSetRequest struct {
|
||||||
func (e *Package) ConfigeModel(Sid string) {
|
MDVR Setting `json:"MDVR"`
|
||||||
e.Payload = map[string]any{
|
|
||||||
"MODULE": "CONFIGMODEL",
|
|
||||||
"OPERATION": "SET",
|
|
||||||
"PARAMETER": map[string]any{
|
|
||||||
"MDVR": map[string]any{
|
|
||||||
"KEYS": map[string]any{ // KEY parameters
|
|
||||||
"GV": 1, // GPS version
|
|
||||||
},
|
|
||||||
"PGDSM": map[string]any{ // Network monitoring status parameters
|
|
||||||
"PGPS": map[string]any{ // GPS position
|
|
||||||
"EN": 1, // Real-time position monitoring
|
|
||||||
"TM": 10, // Time interval
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"PSI": map[string]any{ // Platform basic information
|
|
||||||
"CG": map[string]any{ // Call information
|
|
||||||
"AS": 0, // Automatic answer
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"SUBSTRNET": map[string]any{
|
|
||||||
"SM": 1, // 0-Smooth .. 4-Clear
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// main server util
|
type ConfigModelGetRequest struct {
|
||||||
|
MDVR interface{} `json:"MDVR"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigModelSetResponse struct {
|
||||||
|
MDVR Setting `json:"MDVR"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Package) InitialConfigModelSetRequest() {
|
||||||
|
e.SetParameters(ConfigModelSetRequest{
|
||||||
|
MDVR: Setting{
|
||||||
|
KEYS: KEYS{
|
||||||
|
GV: 1, // GPS version
|
||||||
|
},
|
||||||
|
PGDSM: PGDSM{
|
||||||
|
PGPS: PGPS{
|
||||||
|
EN: 1, // Real-time position monitoring
|
||||||
|
MODE: 0b10, // Enable timer
|
||||||
|
TM: 10, // Time interval
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SUBSTRNET: SUBSTRNET{
|
||||||
|
SM: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func (e *Package) ResponseConfigModelSet(Sid string) {
|
func (e *Package) ResponseConfigModelSet(Sid string) {
|
||||||
e.Payload = map[string]any{
|
e.Payload = map[string]any{
|
||||||
"MODULE": "CONFIGMODUL", // it's not error
|
"MODULE": "CONFIGMODUL", // it's not error
|
||||||
|
169
evem.go
169
evem.go
@ -1,5 +1,174 @@
|
|||||||
package n9m
|
package n9m
|
||||||
|
|
||||||
|
// 3.4.1.3
|
||||||
|
type EventModelGetAlarmStatusInfoResponse struct {
|
||||||
|
ErrorCode uint `json:"ERRORCODE"`
|
||||||
|
ErrorCause string `json:"ERRORCAUSE"`
|
||||||
|
StorageErrors []StorageErrorStatus `json:"ST"`
|
||||||
|
AnotherStorageErrors []AnotherStorageErrorStatus `json:"VS"`
|
||||||
|
VideoLossErrors []VideoLossErrorStatus `json:"VL"`
|
||||||
|
GPSError GPSErrorStatus `json:"GFA"`
|
||||||
|
GPSAntennaError GPSAntennaErrorStatus `json:"GPSS"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.4.1.4.21
|
||||||
|
type StorageErrorStatus struct {
|
||||||
|
CameraCovered uint `json:"ISA"`
|
||||||
|
ChannelBind uint `json:"LHC"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.4.1.4.4
|
||||||
|
type AnotherStorageErrorStatus struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.4.1.4.5
|
||||||
|
type VideoLossErrorStatus struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.4.1.4.44
|
||||||
|
type GPSErrorStatus struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.4.1.4.46
|
||||||
|
type GPSAntennaErrorStatus struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.4.1.5
|
||||||
|
// Alarm upload
|
||||||
|
type SendAlarmInfoParameters struct {
|
||||||
|
AlarmType AlarmType `json:"ALARMTYPE"`
|
||||||
|
CommandType uint `json:"CMDTYPE"`
|
||||||
|
AlarmUID uint `json:"ALARMUID"`
|
||||||
|
NumberOfRestarts uint `json:"RUN"`
|
||||||
|
AlarmLevel AlarmLevel `json:"ALARMAS"`
|
||||||
|
AlarmCount uint `json:"ALARMCOUNT"`
|
||||||
|
TriggerType TriggerType `json:"TRIGGERTYPE"`
|
||||||
|
ContinueTime uint `json:"CONTINUETIME"`
|
||||||
|
CurrentTime uint `json:"CURRENTTIME"`
|
||||||
|
Language Language `json:"L"`
|
||||||
|
GPSData GPSData `json:"P"`
|
||||||
|
RealTimeUpload uint `json:"REAL"`
|
||||||
|
InstructionSerial uint `json:"CMDNO"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.4.1.5
|
||||||
|
// Alarm upload
|
||||||
|
type SendAlarmInfoResponse struct {
|
||||||
|
ErrorCode uint `json:"ERRORCODE"`
|
||||||
|
AlarmType AlarmType `json:"ALARMTYPE"`
|
||||||
|
ErrorCause string `json:"ERRORCAUSE"`
|
||||||
|
CommandType uint `json:"CMDTYPE"`
|
||||||
|
AlarmUID uint `json:"ALARMUID"`
|
||||||
|
NumberOfRestarts uint `json:"RUN"`
|
||||||
|
InstructionSerial uint `json:"CMDNO"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.4.1.5.1
|
||||||
|
type SendAlarmInfoCameraParameters struct {
|
||||||
|
SendAlarmInfoParameters
|
||||||
|
|
||||||
|
Channel uint `json:"CHANNEL"`
|
||||||
|
ChannelMask uint `json:"CHANNELMASK"`
|
||||||
|
LCH []uint `json:"LCH"`
|
||||||
|
Push uint `json:"PUSH"`
|
||||||
|
AlarmName string `json:"ALARMNAME"`
|
||||||
|
AlarmAbbreviation string `json:"SER"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AlarmType uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
AlarmTypeVideoLoss AlarmType = iota
|
||||||
|
AlarmTypeCameraCovered
|
||||||
|
AlarmTypeMotionDetection
|
||||||
|
AlarmTypeStorageAbnormal
|
||||||
|
AlarmTypeUserDefined
|
||||||
|
AlarmTypeSentriesInspection
|
||||||
|
AlarmTypeViolation
|
||||||
|
AlarmTypeEmergency
|
||||||
|
AlarmTypeSpeedAlarm
|
||||||
|
AlarmTypeLowVoltage
|
||||||
|
AlarmTypeOutOfFence = iota + 7
|
||||||
|
AlarmTypeAccAlarm
|
||||||
|
AlarmTypePeripheralsDropped
|
||||||
|
AlarmTypeStopAnnouncement
|
||||||
|
AlarmTypeGpsAntenna
|
||||||
|
AlarmTypeDayNightSwitch
|
||||||
|
AlarmTypeProhibitDriving
|
||||||
|
AlarmTypeSerialAlarm = iota + 15
|
||||||
|
AlarmTypeFatigueAlarm
|
||||||
|
AlarmTypeTakeOutParking
|
||||||
|
AlarmTypeGestureAlarm
|
||||||
|
AlarmTypeGreenDriving
|
||||||
|
AlarmTypeIllegalIgnition
|
||||||
|
AlarmTypeIllegalShutdown
|
||||||
|
AlarmTypeCustomExternal
|
||||||
|
AlarmTypeThinkingLKJ
|
||||||
|
AlarmTypeTAX3
|
||||||
|
AlarmTypeOilAlarm
|
||||||
|
AlarmTypeBusLineOccupation
|
||||||
|
AlarmTypeForgottenAlarm
|
||||||
|
AlarmTypeSpecialCustomerFault
|
||||||
|
AlarmTypeTemperatureAbnormal
|
||||||
|
AlarmTypeTemperatureChangeAbnormal
|
||||||
|
AlarmTypeSmokeAlarm
|
||||||
|
AlarmTypeGBox
|
||||||
|
AlarmTypeLicensePlateRecognition
|
||||||
|
AlarmTypeAnotherSpeedAlarm
|
||||||
|
AlarmTypeWirelessSignalAbnormal
|
||||||
|
AlarmTypeArming
|
||||||
|
AlarmTypePhoneCall
|
||||||
|
AlarmTypeGPSFault
|
||||||
|
AlarmTypeDSMFault
|
||||||
|
AlarmTypeFireBox
|
||||||
|
)
|
||||||
|
|
||||||
|
type AlarmLevel uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
AlarmLevelImportant AlarmLevel = iota
|
||||||
|
AlarmLevelGeneral
|
||||||
|
AlarmLevelEmergency
|
||||||
|
)
|
||||||
|
|
||||||
|
type TriggerType uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
TriggerTypeManual TriggerType = iota
|
||||||
|
TriggerTypeAutomatic
|
||||||
|
)
|
||||||
|
|
||||||
|
type Language uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
LanguageSimplifiedChinese Language = iota
|
||||||
|
LanguageEnglish
|
||||||
|
LanguageKorean
|
||||||
|
LanguageItalian
|
||||||
|
LanguageGerman
|
||||||
|
LanguageThai
|
||||||
|
LanguageTurkey
|
||||||
|
LanguagePortugal
|
||||||
|
LanguageSpain
|
||||||
|
LanguageRomania
|
||||||
|
LanguageGreece
|
||||||
|
LanguageFrench
|
||||||
|
LanguageRussian
|
||||||
|
LanguageDutch
|
||||||
|
LanguageHebrew
|
||||||
|
LanguageChineseTraditional
|
||||||
|
)
|
||||||
|
|
||||||
|
type EventModelGetAlarmingResponse struct {
|
||||||
|
CameraCoveredChannelMask uint `json:"VS_CH"`
|
||||||
|
CameraCoveredAlarmMask uint `json:"VS_AT"`
|
||||||
|
CameraCoveredStatusMask uint `json:"VS_AS"`
|
||||||
|
|
||||||
|
VideoLossChannelMask uint `json:"VL_CH"`
|
||||||
|
VideoLossAlarmMask uint `json:"VL_AT"`
|
||||||
|
VideoLossStatusMask uint `json:"VL_AS"`
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// main server util
|
// main server util
|
||||||
func (e *Package) ResponseAlarm(alarmType int64, alarmUID int64, cmdno int64, cmdtype int64, run int64, serial string, Sid string) {
|
func (e *Package) ResponseAlarm(alarmType int64, alarmUID int64, cmdno int64, cmdtype int64, run int64, serial string, Sid string) {
|
||||||
|
53
io.go
53
io.go
@ -2,10 +2,12 @@ package n9m
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"fmt"
|
||||||
|
|
||||||
"github.com/icza/bitio"
|
"github.com/icza/bitio"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Read package
|
// Read package
|
||||||
@ -20,7 +22,7 @@ func (e *Package) ReadPackage() bool {
|
|||||||
e.CompressFlag = r.TryReadBool()
|
e.CompressFlag = r.TryReadBool()
|
||||||
e.CSRCCount = uint8(r.TryReadBits(4))
|
e.CSRCCount = uint8(r.TryReadBits(4))
|
||||||
e.PayloadType = PayloadType(r.TryReadBits(8))
|
e.PayloadType = PayloadType(r.TryReadBits(8))
|
||||||
e.SSRC = uint16(r.TryReadBits(16))
|
e.SSRC = SpecialPayloadType((r.TryReadBits(8) | (r.TryReadBits(8) << 8)))
|
||||||
|
|
||||||
if e.EncryptionFlag && e.CompressFlag {
|
if e.EncryptionFlag && e.CompressFlag {
|
||||||
// TODO: get snippet, that use this code
|
// TODO: get snippet, that use this code
|
||||||
@ -60,11 +62,34 @@ func (e *Package) ReadPackage() bool {
|
|||||||
|
|
||||||
e.Accum = e.Accum[12+e.payloadLen:]
|
e.Accum = e.Accum[12+e.payloadLen:]
|
||||||
|
|
||||||
if e.PayloadType == PayloadTypeData {
|
switch e.PayloadType {
|
||||||
|
case PayloadTypeData:
|
||||||
if err := json.Unmarshal(e.RawPayload, &e.Payload); err != nil {
|
if err := json.Unmarshal(e.RawPayload, &e.Payload); err != nil {
|
||||||
log.Printf("Error parsing JSON payload: %v", err)
|
log.Printf("Error parsing JSON payload: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case PayloadTypeSpecial:
|
||||||
|
switch e.SSRC {
|
||||||
|
case SpecialPayloadTypeGPS:
|
||||||
|
e.GPS.GPSStatus = e.RawPayload[0]
|
||||||
|
e.GPS.Expand = e.RawPayload[1]
|
||||||
|
e.GPS.Real = e.RawPayload[2]
|
||||||
|
|
||||||
|
e.GPS.Longitude = float64(binary.BigEndian.Uint32(e.RawPayload[4:8])) / 1e6
|
||||||
|
e.GPS.Latitude = float64(binary.BigEndian.Uint32(e.RawPayload[8:12])) / 1e6
|
||||||
|
e.GPS.Speed = float64(binary.BigEndian.Uint32(e.RawPayload[12:16])) / 100
|
||||||
|
e.GPS.Direction = float64(binary.BigEndian.Uint32(e.RawPayload[16:20])) / 100
|
||||||
|
e.GPS.Altitude = int32(binary.BigEndian.Uint32(e.RawPayload[20:24]))
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if e.GPS.Time, err = time.Parse("20060102150405", string(e.RawPayload[24:38])); err != nil {
|
||||||
|
log.Printf("Error parsing time: %v", err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Println("N9M parser warning: unknown special payload type", e.SSRC)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Println("N9M parser warning: unknown payload type", e.PayloadType)
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.TryError != nil {
|
if r.TryError != nil {
|
||||||
@ -141,3 +166,23 @@ func (e *Package) GetParametersAs(parameters any) error {
|
|||||||
|
|
||||||
return json.Unmarshal(marshal, parameters)
|
return json.Unmarshal(marshal, parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Package) SetParameters(parameters any) {
|
||||||
|
e.Payload.Response = struct{}{}
|
||||||
|
e.Payload.Parameter = parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Package) GetResponseAs(response any) error {
|
||||||
|
marshal, err := json.Marshal(e.Payload.Response)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Unmarshal(marshal, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Package) SetResponse(response any) {
|
||||||
|
e.Payload.Parameter = struct{}{}
|
||||||
|
e.Payload.Response = response
|
||||||
|
}
|
||||||
|
92
params.go
92
params.go
@ -1,5 +1,6 @@
|
|||||||
package n9m
|
package n9m
|
||||||
|
|
||||||
|
// 7.2
|
||||||
type RIP struct {
|
type RIP struct {
|
||||||
DEVID string // ID номер устройства
|
DEVID string // ID номер устройства
|
||||||
BN string // бортовой номер
|
BN string // бортовой номер
|
||||||
@ -218,7 +219,8 @@ type DNS struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type KEYS struct {
|
type KEYS struct {
|
||||||
MAC string // MAC-адрес
|
MAC string `json:"MAC,omitempty"` // MAC-адрес
|
||||||
|
GV uint `json:"GV,omitempty"` // GPS version
|
||||||
}
|
}
|
||||||
|
|
||||||
type WIFI struct {
|
type WIFI struct {
|
||||||
@ -267,29 +269,67 @@ type SP struct {
|
|||||||
MUPORT int // UDP-порт медиасервера
|
MUPORT int // UDP-порт медиасервера
|
||||||
}
|
}
|
||||||
|
|
||||||
type Setting struct {
|
// 7.30
|
||||||
RIP RIP
|
type PGDSM struct {
|
||||||
VS VS
|
PGPS PGPS `json:"PGPS,omitempty"`
|
||||||
GSP GSP
|
PDSM PDSM `json:"PDSM,omitempty"`
|
||||||
TIMEP TIMEP
|
}
|
||||||
ETHERNET ETHERNET
|
|
||||||
KEYS KEYS
|
// 7.30.1
|
||||||
WIFI WIFI
|
// GPS (position) status parameter
|
||||||
M3G M3G
|
type PGPS struct {
|
||||||
MCMS MCMS
|
EN uint // Enable
|
||||||
ATP ATP
|
MODE uint
|
||||||
SSP SSP
|
SEP uint `json:"SEP,omitempty"`
|
||||||
SWUS SWUS
|
TM uint `json:"TM,omitempty"`
|
||||||
UMP UMP
|
NUM uint `json:"NUM,omitempty"`
|
||||||
SUBSTRNET SUBSTRNET
|
}
|
||||||
DOSD DOSD
|
|
||||||
AR AR
|
// 7.30.2
|
||||||
EOSD []EOSD
|
type PDSM struct {
|
||||||
MAIN []VEC
|
}
|
||||||
IOP []IOP
|
|
||||||
SAP SAP
|
// 7.39.3.9
|
||||||
UAP UAP
|
// Platform basic information
|
||||||
PVLAS PVLAS
|
type PSI struct {
|
||||||
PMDAS PMDAS
|
CG CG `json:"CG,omitempty"`
|
||||||
DSM DSM
|
}
|
||||||
|
|
||||||
|
// 7.39.3.8
|
||||||
|
// Total record information for call
|
||||||
|
type CG struct {
|
||||||
|
ECL uint // The maximum calling time
|
||||||
|
ECML uint // The maximum calling time per month
|
||||||
|
AS uint // Terminal phonecall answering strategy
|
||||||
|
AT uint // Answer automatically when exceed time
|
||||||
|
}
|
||||||
|
|
||||||
|
type Setting struct {
|
||||||
|
KEYS KEYS `json:"KEYS,omitempty"`
|
||||||
|
RIP RIP `json:"RIP,omitempty"`
|
||||||
|
TIMEP TIMEP `json:"TIMEP,omitempty"`
|
||||||
|
ATP ATP `json:"ATP,omitempty"`
|
||||||
|
SSP SSP `json:"SSP,omitempty"`
|
||||||
|
GSP GSP `json:"GSP,omitempty"`
|
||||||
|
UMP UMP `json:"UMP,omitempty"`
|
||||||
|
ETHERNET ETHERNET `json:"ETHERNET,omitempty"`
|
||||||
|
WIFI WIFI `json:"WIFI,omitempty"`
|
||||||
|
M3G M3G `json:"M3G,omitempty"`
|
||||||
|
MCMS MCMS `json:"MCMS,omitempty"`
|
||||||
|
SUBSTRNET SUBSTRNET `json:"SUBSTRNET,omitempty"`
|
||||||
|
DOSD DOSD `json:"DOSD,omitempty"`
|
||||||
|
AR AR `json:"AR,omitempty"`
|
||||||
|
MAIN []VEC `json:"MAIN,omitempty"`
|
||||||
|
EOSD []EOSD `json:"EOSD,omitempty"`
|
||||||
|
IOP []IOP `json:"IOP,omitempty"`
|
||||||
|
SAP SAP `json:"SAP,omitempty"`
|
||||||
|
UAP UAP `json:"UAP,omitempty"`
|
||||||
|
PGDSM PGDSM `json:"PGDSM,omitempty"`
|
||||||
|
PVLAS PVLAS `json:"PVLAS,omitempty"`
|
||||||
|
PMDAS PMDAS `json:"PMDAS,omitempty"`
|
||||||
|
VS VS `json:"VS,omitempty"`
|
||||||
|
PSI PSI `json:"PSI,omitempty"`
|
||||||
|
|
||||||
|
SWUS SWUS `json:"SWUS,omitempty"`
|
||||||
|
DSM DSM `json:"DSM,omitempty"`
|
||||||
}
|
}
|
||||||
|
99
scheme.go
99
scheme.go
@ -1,5 +1,12 @@
|
|||||||
package n9m
|
package n9m
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type PayloadType uint8
|
type PayloadType uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -13,10 +20,28 @@ const (
|
|||||||
PayloadTypeTransmissionSubStream PayloadType = 15
|
PayloadTypeTransmissionSubStream PayloadType = 15
|
||||||
PayloadTypeRecordingSubStream PayloadType = 16
|
PayloadTypeRecordingSubStream PayloadType = 16
|
||||||
PayloadTypeBlackBox PayloadType = 17
|
PayloadTypeBlackBox PayloadType = 17
|
||||||
PayloadTypeGPS PayloadType = 22
|
PayloadTypeSpecial PayloadType = 22
|
||||||
PayloadTypeMaintainData PayloadType = 30
|
PayloadTypeMaintainData PayloadType = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SpecialPayloadType uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
SpecialPayloadTypeHeartbeat SpecialPayloadType = iota
|
||||||
|
SpecialPayloadTypeHeartbeatWithoutBody
|
||||||
|
SpecialPayloadTypeGPS
|
||||||
|
SpecialPayloadTypeMileage
|
||||||
|
SpecialPayloadTypeEnvironmentalQuality
|
||||||
|
SpecialPayloadTypeDrivingPosture
|
||||||
|
SpecialPayloadTypeScanningGun
|
||||||
|
SpecialPayloadTypeOil
|
||||||
|
SpecialPayloadTypeGDS
|
||||||
|
SpecialPayloadTypeGPSToBWS
|
||||||
|
SpecialPayloadTypeCANBOX
|
||||||
|
SpecialPayloadTypeGSenor
|
||||||
|
SpecialPayloadTypeAckGPS
|
||||||
|
)
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Module string `json:"MODULE"`
|
Module string `json:"MODULE"`
|
||||||
Session string `json:"SESSION"`
|
Session string `json:"SESSION"`
|
||||||
@ -25,6 +50,74 @@ type Message struct {
|
|||||||
Response interface{} `json:"RESPONSE,omitempty"`
|
Response interface{} `json:"RESPONSE,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3.4.5.27.1
|
||||||
|
type GPSData struct {
|
||||||
|
GPSStatus uint8
|
||||||
|
Expand uint8
|
||||||
|
Real uint8
|
||||||
|
Longitude float64
|
||||||
|
Latitude float64
|
||||||
|
Speed float64
|
||||||
|
Direction float64
|
||||||
|
Altitude int32
|
||||||
|
Time time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GPSData) MarshalJSON() ([]byte, error) {
|
||||||
|
var alias struct {
|
||||||
|
GPSStatus uint8 `json:"V"`
|
||||||
|
Longitude string `json:"J"`
|
||||||
|
Latitude string `json:"W"`
|
||||||
|
Speed uint `json:"S"`
|
||||||
|
Direction uint `json:"C"`
|
||||||
|
Altitude int32 `json:"H"`
|
||||||
|
Time string `json:"T"`
|
||||||
|
}
|
||||||
|
|
||||||
|
alias.GPSStatus = g.GPSStatus
|
||||||
|
alias.Longitude = fmt.Sprintf("%.6f", g.Longitude)
|
||||||
|
alias.Latitude = fmt.Sprintf("%.6f", g.Latitude)
|
||||||
|
alias.Speed = uint(g.Speed * 100)
|
||||||
|
alias.Direction = uint(g.Direction * 100)
|
||||||
|
alias.Altitude = g.Altitude
|
||||||
|
alias.Time = g.Time.Format("20060102150405")
|
||||||
|
|
||||||
|
return json.Marshal(alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GPSData) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
var alias struct {
|
||||||
|
GPSStatus uint8 `json:"V"`
|
||||||
|
Longitude string `json:"J"`
|
||||||
|
Latitude string `json:"W"`
|
||||||
|
Speed uint `json:"S"`
|
||||||
|
Direction uint `json:"C"`
|
||||||
|
Altitude int32 `json:"H"`
|
||||||
|
Time string `json:"T"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal(data, &alias); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.GPSStatus = alias.GPSStatus
|
||||||
|
|
||||||
|
if g.Longitude, err = strconv.ParseFloat(alias.Longitude, 64); err != nil {
|
||||||
|
return fmt.Errorf("invalid longitude: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.Latitude, err = strconv.ParseFloat(alias.Latitude, 64); err != nil {
|
||||||
|
return fmt.Errorf("invalid latitude: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Speed = float64(alias.Speed) / 100.0
|
||||||
|
g.Direction = float64(alias.Direction) / 100.0
|
||||||
|
g.Altitude = alias.Altitude
|
||||||
|
g.Time, _ = time.Parse("20060102150405", alias.Time)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
EncryptionFlag bool
|
EncryptionFlag bool
|
||||||
@ -32,10 +125,12 @@ type Package struct {
|
|||||||
CSRCCount uint8
|
CSRCCount uint8
|
||||||
|
|
||||||
PayloadType PayloadType
|
PayloadType PayloadType
|
||||||
SSRC uint16
|
SSRC SpecialPayloadType
|
||||||
Reserved uint64
|
Reserved uint64
|
||||||
CSRC [16]uint64
|
CSRC [16]uint64
|
||||||
|
|
||||||
|
GPS GPSData
|
||||||
|
|
||||||
payloadLen uint64
|
payloadLen uint64
|
||||||
Payload Message
|
Payload Message
|
||||||
RawPayload []byte
|
RawPayload []byte
|
||||||
|
Loading…
Reference in New Issue
Block a user