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:
		| @@ -23,7 +23,7 @@ const ( | ||||
|  | ||||
| type CertificateConnectRequest struct { | ||||
| 	Net               NetConnectionType       `json:"NET"` | ||||
| 	SerialNumber      string                  `json:"DNSO"` | ||||
| 	SerialNumber      string                  `json:"DSNO"` | ||||
| 	DeviceName        string                  `json:"DEVNAME"` | ||||
| 	ChannelsNumber    uint                    `json:"CHANNEL"` | ||||
| 	LicensePlate      string                  `json:"CARNUM"` | ||||
| @@ -35,6 +35,25 @@ type CertificateConnectRequest struct { | ||||
| 	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) { | ||||
| 	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) | ||||
| } // end of 'SetParameters' function | ||||
| */ | ||||
|  | ||||
| // todo al1 | ||||
| func (e *Package) ConfigeModel(Sid string) { | ||||
| 	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 | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| type ConfigModelSetRequest struct { | ||||
| 	MDVR Setting `json:"MDVR"` | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	e.Payload = map[string]any{ | ||||
| 		"MODULE":    "CONFIGMODUL", // it's not error | ||||
|   | ||||
							
								
								
									
										169
									
								
								evem.go
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								evem.go
									
									
									
									
									
								
							| @@ -1,5 +1,174 @@ | ||||
| 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 | ||||
| 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 ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"encoding/json" | ||||
| 	"log" | ||||
|  | ||||
| 	"fmt" | ||||
| 	"github.com/icza/bitio" | ||||
| 	"log" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Read package | ||||
| @@ -20,7 +22,7 @@ func (e *Package) ReadPackage() bool { | ||||
| 	e.CompressFlag = r.TryReadBool() | ||||
| 	e.CSRCCount = uint8(r.TryReadBits(4)) | ||||
| 	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 { | ||||
| 		// TODO: get snippet, that use this code | ||||
| @@ -60,11 +62,34 @@ func (e *Package) ReadPackage() bool { | ||||
|  | ||||
| 	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 { | ||||
| 			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 { | ||||
| @@ -141,3 +166,23 @@ func (e *Package) GetParametersAs(parameters any) error { | ||||
|  | ||||
| 	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 | ||||
|  | ||||
| // 7.2 | ||||
| type RIP struct { | ||||
| 	DEVID string // ID номер устройства | ||||
| 	BN    string // бортовой номер | ||||
| @@ -218,7 +219,8 @@ type DNS struct { | ||||
| } | ||||
|  | ||||
| type KEYS struct { | ||||
| 	MAC string // MAC-адрес | ||||
| 	MAC string `json:"MAC,omitempty"` // MAC-адрес | ||||
| 	GV  uint   `json:"GV,omitempty"`  // GPS version | ||||
| } | ||||
|  | ||||
| type WIFI struct { | ||||
| @@ -267,29 +269,67 @@ type SP struct { | ||||
| 	MUPORT int    // UDP-порт медиасервера | ||||
| } | ||||
|  | ||||
| type Setting struct { | ||||
| 	RIP       RIP | ||||
| 	VS        VS | ||||
| 	GSP       GSP | ||||
| 	TIMEP     TIMEP | ||||
| 	ETHERNET  ETHERNET | ||||
| 	KEYS      KEYS | ||||
| 	WIFI      WIFI | ||||
| 	M3G       M3G | ||||
| 	MCMS      MCMS | ||||
| 	ATP       ATP | ||||
| 	SSP       SSP | ||||
| 	SWUS      SWUS | ||||
| 	UMP       UMP | ||||
| 	SUBSTRNET SUBSTRNET | ||||
| 	DOSD      DOSD | ||||
| 	AR        AR | ||||
| 	EOSD      []EOSD | ||||
| 	MAIN      []VEC | ||||
| 	IOP       []IOP | ||||
| 	SAP       SAP | ||||
| 	UAP       UAP | ||||
| 	PVLAS     PVLAS | ||||
| 	PMDAS     PMDAS | ||||
| 	DSM       DSM | ||||
| // 7.30 | ||||
| type PGDSM struct { | ||||
| 	PGPS PGPS `json:"PGPS,omitempty"` | ||||
| 	PDSM PDSM `json:"PDSM,omitempty"` | ||||
| } | ||||
|  | ||||
| // 7.30.1 | ||||
| // GPS (position) status parameter | ||||
| type PGPS struct { | ||||
| 	EN   uint // Enable | ||||
| 	MODE uint | ||||
| 	SEP  uint `json:"SEP,omitempty"` | ||||
| 	TM   uint `json:"TM,omitempty"` | ||||
| 	NUM  uint `json:"NUM,omitempty"` | ||||
| } | ||||
|  | ||||
| // 7.30.2 | ||||
| type PDSM struct { | ||||
| } | ||||
|  | ||||
| // 7.39.3.9 | ||||
| // Platform basic information | ||||
| type PSI struct { | ||||
| 	CG CG `json:"CG,omitempty"` | ||||
| } | ||||
|  | ||||
| // 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 | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type PayloadType uint8 | ||||
|  | ||||
| const ( | ||||
| @@ -13,10 +20,28 @@ const ( | ||||
| 	PayloadTypeTransmissionSubStream PayloadType = 15 | ||||
| 	PayloadTypeRecordingSubStream    PayloadType = 16 | ||||
| 	PayloadTypeBlackBox              PayloadType = 17 | ||||
| 	PayloadTypeGPS                   PayloadType = 22 | ||||
| 	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"` | ||||
| @@ -25,6 +50,74 @@ type Message struct { | ||||
| 	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 | ||||
| @@ -32,10 +125,12 @@ type Package struct { | ||||
| 	CSRCCount      uint8 | ||||
|  | ||||
| 	PayloadType PayloadType | ||||
| 	SSRC        uint16 | ||||
| 	SSRC        SpecialPayloadType | ||||
| 	Reserved    uint64 | ||||
| 	CSRC        [16]uint64 | ||||
|  | ||||
| 	GPS GPSData | ||||
|  | ||||
| 	payloadLen uint64 | ||||
| 	Payload    Message | ||||
| 	RawPayload []byte | ||||
|   | ||||
		Reference in New Issue
	
	Block a user