86 lines
2.2 KiB
Go
86 lines
2.2 KiB
Go
package gb32960
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"time"
|
|
|
|
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
|
|
)
|
|
|
|
var ErrResponseFrameTooShort = errors.New("gb32960 response frame too short")
|
|
|
|
const (
|
|
responseSuccess = byte(0x01)
|
|
responseError = byte(0x02)
|
|
responseCommand = byte(0xfe)
|
|
encryptNone = byte(0x01)
|
|
)
|
|
|
|
// AutoResponse builds the protocol ACK for accepted upstream GB/T 32960 frames.
|
|
// The ACK is written only after the caller has durably published the frame.
|
|
func AutoResponse(raw []byte, env envelope.FrameEnvelope) ([]byte, bool, error) {
|
|
if env.ParseStatus == envelope.ParseBadFrame {
|
|
return nil, false, nil
|
|
}
|
|
if len(raw) < headerLen+1 {
|
|
return nil, false, ErrResponseFrameTooShort
|
|
}
|
|
if raw[3] != responseCommand {
|
|
return nil, false, nil
|
|
}
|
|
command := raw[2]
|
|
if !shouldRespond(command) {
|
|
return nil, false, nil
|
|
}
|
|
|
|
body := []byte(nil)
|
|
if timestamp := responseTime(raw, command); !timestamp.IsZero() {
|
|
body = encodeGBTime(timestamp)
|
|
}
|
|
responseFlag := responseSuccess
|
|
if command == 0x05 && env.AuthenticationEnforced && env.AuthenticationStatus != "accepted" {
|
|
responseFlag = responseError
|
|
}
|
|
return buildResponse(raw[0], command, responseFlag, raw[4:21], body), true, nil
|
|
}
|
|
|
|
func shouldRespond(command byte) bool {
|
|
switch command {
|
|
case 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func responseTime(raw []byte, command byte) time.Time {
|
|
bodyLen := len(raw) - headerLen - 1
|
|
if bodyLen >= 6 {
|
|
return parseGBTime(raw[headerLen : headerLen+6])
|
|
}
|
|
return time.Now().In(time.FixedZone("Asia/Shanghai", 8*3600))
|
|
}
|
|
|
|
func encodeGBTime(t time.Time) []byte {
|
|
local := t.In(time.FixedZone("Asia/Shanghai", 8*3600))
|
|
return []byte{
|
|
byte(local.Year() - 2000),
|
|
byte(local.Month()),
|
|
byte(local.Day()),
|
|
byte(local.Hour()),
|
|
byte(local.Minute()),
|
|
byte(local.Second()),
|
|
}
|
|
}
|
|
|
|
func buildResponse(start byte, command byte, responseFlag byte, vin17 []byte, body []byte) []byte {
|
|
out := make([]byte, 0, headerLen+len(body)+1)
|
|
out = append(out, start, start, command, responseFlag)
|
|
out = append(out, vin17[:17]...)
|
|
out = append(out, encryptNone, 0, 0)
|
|
binary.BigEndian.PutUint16(out[22:24], uint16(len(body)))
|
|
out = append(out, body...)
|
|
return append(out, bcc(out[2:]))
|
|
}
|