Refactor and simplify package structure and interfaces.
Reorganize code by removing unused files, restructuring package organization, and updating import references to new paths. This simplifies handling of smart and protocol-related operations, improves maintainability, and eliminates redundancy.
This commit is contained in:
57
pkg/protocol/alarms.go
Normal file
57
pkg/protocol/alarms.go
Normal file
@ -0,0 +1,57 @@
|
||||
package protocol
|
||||
|
||||
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
|
||||
)
|
192
pkg/protocol/io.go
Normal file
192
pkg/protocol/io.go
Normal file
@ -0,0 +1,192 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/icza/bitio"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Read package
|
||||
func (e *Package) ReadPackage() bool {
|
||||
if len(e.Accum) < 12 {
|
||||
return false
|
||||
}
|
||||
|
||||
r := bitio.NewReader(bytes.NewBuffer(e.Accum))
|
||||
e.Version = uint8(r.TryReadBits(2))
|
||||
e.EncryptionFlag = r.TryReadBool()
|
||||
e.CompressFlag = r.TryReadBool()
|
||||
e.CSRCCount = uint8(r.TryReadBits(4))
|
||||
e.PayloadType = PayloadType(r.TryReadBits(8))
|
||||
e.SSRC = SpecialPayloadType((r.TryReadBits(8) | (r.TryReadBits(8) << 8)))
|
||||
|
||||
if e.EncryptionFlag && e.CompressFlag {
|
||||
// TODO: get snippet, that use this code
|
||||
r.TryReadBits(8 * 4)
|
||||
e.payloadLen = r.TryReadBits(8)
|
||||
r.TryReadBits(3 * 8)
|
||||
|
||||
if uint64(len(e.Accum)) < e.payloadLen+12 {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
e.payloadLen = r.TryReadBits(32)
|
||||
|
||||
// WTF: e.CC is useless
|
||||
for i := uint64(0); i < 1; i++ {
|
||||
e.CSRC[i] = r.TryReadBits(32)
|
||||
}
|
||||
}
|
||||
|
||||
if e.payloadLen > 1e6 {
|
||||
log.Printf("%v\n", e)
|
||||
log.Panicln("CORRUPTED PACKAGE")
|
||||
}
|
||||
|
||||
numOfBytes := 0
|
||||
|
||||
if e.payloadLen != 0 {
|
||||
e.RawPayload = make([]byte, e.payloadLen)
|
||||
numOfBytes = r.TryRead(e.RawPayload)
|
||||
} else {
|
||||
e.RawPayload = []byte{}
|
||||
}
|
||||
|
||||
if numOfBytes != int(e.payloadLen) {
|
||||
return false
|
||||
}
|
||||
|
||||
e.Accum = e.Accum[12+e.payloadLen:]
|
||||
|
||||
switch e.PayloadType {
|
||||
case PayloadTypeData:
|
||||
if err := json.Unmarshal(e.RawPayload, &e.Payload); err != nil {
|
||||
log.Printf("Error parsing JSON payload: %v", err)
|
||||
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 {
|
||||
log.Printf("TryError encountered: %v", r.TryError)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *Package) PackPayload() (err error) {
|
||||
e.RawPayload, err = json.Marshal(e.Payload)
|
||||
e.payloadLen = uint64(len(e.RawPayload))
|
||||
|
||||
if e.payloadLen != 0 {
|
||||
e.RawPayload = append(e.RawPayload, 0)
|
||||
e.payloadLen++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e *Package) PackPackage() []byte {
|
||||
var err error
|
||||
|
||||
if err = e.PackPayload(); err != nil {
|
||||
log.Printf("Error while packing payload: %v", err)
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
return e.PackRawPackage()
|
||||
}
|
||||
|
||||
func (e *Package) PackRawPackage() []byte {
|
||||
var err error
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
w := bitio.NewWriter(b)
|
||||
|
||||
w.TryWriteBits(uint64(e.Version), 2)
|
||||
|
||||
w.TryWriteBool(e.EncryptionFlag)
|
||||
w.TryWriteBool(e.CompressFlag)
|
||||
|
||||
w.TryWriteBits(uint64(e.CSRCCount), 4)
|
||||
w.TryWriteBits(uint64(e.PayloadType), 8)
|
||||
w.TryWriteBits(uint64(e.SSRC), 16)
|
||||
|
||||
w.TryWriteBits(e.payloadLen, 32)
|
||||
|
||||
// WTF: e.CC is useless
|
||||
for i := uint64(0); i < 1; i++ {
|
||||
w.TryWriteBits(e.CSRC[i], 32)
|
||||
}
|
||||
|
||||
if e.payloadLen != 0 {
|
||||
w.TryWrite(e.RawPayload)
|
||||
}
|
||||
|
||||
if err = w.Close(); err != nil {
|
||||
log.Printf("Error while closing writer: %v", err)
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (e *Package) GetParametersAs(parameters any) error {
|
||||
marshal, err := json.Marshal(e.Payload.Parameter)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return json.Unmarshal(marshal, parameters)
|
||||
}
|
||||
|
||||
func (e *Package) SetParameters(parameters any) {
|
||||
e.Payload.Response = nil
|
||||
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 = nil
|
||||
e.Payload.Response = response
|
||||
}
|
||||
|
||||
func (e *Package) AddToAccum(data []byte) {
|
||||
e.Accum = append(e.Accum, data...)
|
||||
}
|
22
pkg/protocol/languages.go
Normal file
22
pkg/protocol/languages.go
Normal file
@ -0,0 +1,22 @@
|
||||
package protocol
|
||||
|
||||
type Language uint
|
||||
|
||||
const (
|
||||
LanguageSimplifiedChinese Language = iota
|
||||
LanguageEnglish
|
||||
LanguageKorean
|
||||
LanguageItalian
|
||||
LanguageGerman
|
||||
LanguageThai
|
||||
LanguageTurkey
|
||||
LanguagePortugal
|
||||
LanguageSpain
|
||||
LanguageRomania
|
||||
LanguageGreece
|
||||
LanguageFrench
|
||||
LanguageRussian
|
||||
LanguageDutch
|
||||
LanguageHebrew
|
||||
LanguageChineseTraditional
|
||||
)
|
139
pkg/protocol/scheme.go
Normal file
139
pkg/protocol/scheme.go
Normal file
@ -0,0 +1,139 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PayloadType uint8
|
||||
|
||||
const (
|
||||
PayloadTypeData PayloadType = 0
|
||||
PayloadTypeLive PayloadType = 2
|
||||
PayloadTypeDownload PayloadType = 3
|
||||
PayloadTypePlayback PayloadType = 4
|
||||
PayloadTypeCapturedPhotos PayloadType = 6
|
||||
PayloadTypeParameterImport PayloadType = 10
|
||||
PayloadTypeParameterExport PayloadType = 11
|
||||
PayloadTypeTransmissionSubStream PayloadType = 15
|
||||
PayloadTypeRecordingSubStream PayloadType = 16
|
||||
PayloadTypeBlackBox PayloadType = 17
|
||||
PayloadTypeSpecial PayloadType = 22
|
||||
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 {
|
||||
Module string `json:"MODULE"`
|
||||
Session string `json:"SESSION"`
|
||||
Operation string `json:"OPERATION"`
|
||||
Parameter interface{} `json:"PARAMETER,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 {
|
||||
Version uint8
|
||||
EncryptionFlag bool
|
||||
CompressFlag bool
|
||||
CSRCCount uint8
|
||||
|
||||
PayloadType PayloadType
|
||||
SSRC SpecialPayloadType
|
||||
Reserved uint64
|
||||
CSRC [16]uint64
|
||||
|
||||
GPS GPSData
|
||||
|
||||
payloadLen uint64
|
||||
Payload Message
|
||||
RawPayload []byte
|
||||
|
||||
Accum []byte
|
||||
}
|
8
pkg/protocol/trigger.go
Normal file
8
pkg/protocol/trigger.go
Normal file
@ -0,0 +1,8 @@
|
||||
package protocol
|
||||
|
||||
type TriggerType uint
|
||||
|
||||
const (
|
||||
TriggerTypeManual TriggerType = iota
|
||||
TriggerTypeAutomatic
|
||||
)
|
Reference in New Issue
Block a user