teltonikaparser

package module
v0.0.0-...-24bbb64 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2022 License: BSD-3-Clause Imports: 9 Imported by: 0

README

Package teltonikaparser provides GO parser and validator for Teltonika Codec 8 and Codec 8 Extended

Certain purpose:

Package teltonikaparser was created for parsing data structures from Teltonika UDP packets. Package can return a raw data and human readable data, see examples.

Package teltonikaparser is a very fast, low-level implementation, it can decode over one milion packets per second per core. See GO Concurrency Example

Performace: Decode() 788 ns/op 592 B/op 4 allocs/op
Human() 4082 ns/op 4722 B/op 49 allocs/op

First stage - basic decoding

When a binary packet arrived it is necessary to parse the data out and create a structure which represents a parsed data.

type Decoded
type Decoded struct {
    IMEI     string    // IMEI number, if len==15 also validated by checksum
    CodecID  byte      // 0x08 (codec 8) or 0x8E (codec 8 extended)
    NoOfData uint8     // Number of Data
    Data     []AvlData // Slice with avl data
    Data     []AvlData // Slice with avl data
    Response []byte    // Slice with a response to a packet
}
type AvlData

AvlData represent one block of data.

type AvlData struct {
    UtimeMs    uint64      // Utime in mili seconds
    Utime      uint64      // Utime in seconds
    Priority   uint8       // Priority, [0 Low, 1 High, 2 Panic]
    Lat        int32       // Latitude (between 850000000 and -850000000), fit int32
    Lng        int32       // Longitude (between 1800000000 and -1800000000), fit int32
    Altitude   int16       // Altitude In meters above sea level, 2 bytes
    Angle      uint16      // Angle In degrees, 0 is north, increasing clock-wise, 2 bytes
    VisSat     uint8       // Satellites Number of visible satellites
    Speed      uint16      // Speed in km/h
    EventID    uint16      // Event generated (0 – data generated not on event)
    Elements []Element // Slice containing parsed IO Elements
}
type Element

Element represents one IO element parsed from a binary packet.

type Element struct {
   Length uint16 // Length of element, this should be uint16 because Codec 8 extended has 2Byte of IO len
   IOID   uint16 // IO element ID
   Value  []byte // Value of the element represented by slice of bytes
}
func Decode

Decode is used for basic decoding as see in the example. It takes a pointer to a byte slice and return Decoded struct and error. FULL DOCUMENTATION

Performance per core: 849 ns/op 720 B/op 3 allocs/op

Example Decode
package main

import (
   "fmt"
   "log"

    "github.com/filipkroca/teltonikaparser"
)

func main() {
    // Example packet Teltonika UDP Codec 8 007CCAFE0133000F33353230393430383136373231373908020000016C32B488A0000A7A367C1D30018700000000000000F1070301001500EF000342318BCD42DCCE606401F1000059D9000000016C32B48C88000A7A367C1D3001870000000000000015070301001501EF0003423195CD42DCCE606401F1000059D90002

    var bs = []byte{00, 0x7C, 0xCA, 0xFE, 0x01, 0x33, 0x00, 0x0F, 0x33, 0x35, 0x32, 0x30, 0x39, 0x34, 0x30, 0x38, 0x31, 0x36, 0x37, 0x32, 0x31, 0x37, 0x39, 0x08, 0x02, 0x00, 0x00, 0x01, 0x6C, 0x32, 0xB4, 0x88, 0xA0, 0x00, 0x0A, 0x7A, 0x36, 0x7C, 0x1D, 0x30, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0x07, 0x03, 0x01, 0x00, 0x15, 0x00, 0xEF, 0x00, 0x03, 0x42, 0x31, 0x8B, 0xCD, 0x42, 0xDC, 0xCE, 0x60, 0x64, 0x01, 0xF1, 0x00, 0x00, 0x59, 0xD9, 0x00, 0x00, 0x00, 0x01, 0x6C, 0x32, 0xB4, 0x8C, 0x88, 0x00, 0x0A, 0x7A, 0x36, 0x7C, 0x1D, 0x30, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x07, 0x03, 0x01, 0x00, 0x15, 0x01, 0xEF, 0x00, 0x03, 0x42, 0x31, 0x95, 0xCD, 0x42, 0xDC, 0xCE, 0x60, 0x64, 0x01, 0xF1, 0x00, 0x00, 0x59, 0xD9, 0x00, 0x02}

    // decode a raw data byte slice
    parsedData, err := teltonikaparser.Decode(&bs)
    if err != nil {
        log.Panicf("Error when decoding a bs, %v\n", err)
    }
    fmt.Printf("%+v", parsedData)
}

Output:

{IMEI:352094081672179 CodecID:8 NoOfData:2 Data:[{UtimeMs:1564218788000 Utime:1564218788 Priority:0 Lat:175781500 Lng:489685383 Altitude:0 Angle:0 VisSat:0 Speed:0 EventID:241 Elements:[{Length:1 IOID:1 Value:[0]} {Length:1 IOID:21 Value:[0]} {Length:1 IOID:239 Value:[0]} {Length:2 IOID:66 Value:[49 139]} {Length:2 IOID:205 Value:[66 220]} {Length:2 IOID:206 Value:[96 100]} {Length:4 IOID:241 Value:[0 0 89 217]}]} {UtimeMs:1564218789000 Utime:1564218789 Priority:0 Lat:175781500 Lng:489685383 Altitude:0 Angle:0 VisSat:0 Speed:0 EventID:21 Elements:[{Length:1 IOID:1 Value:[0]} {Length:1 IOID:21 Value:[1]} {Length:1 IOID:239 Value:[0]} {Length:2 IOID:66 Value:[49 149]} {Length:2 IOID:205 Value:[66 220]} {Length:2 IOID:206 Value:[96 100]} {Length:4 IOID:241 Value:[0 0 89 217]}]}]}

Second stage - human readable

This package also provides method (h *HAvlData) GetFinalValue() which can convert values to human-readable form. It can be primary used for diagnostic purposes.

Currently are implemented AVLs lists for FMBXY, FMB64, FM36 and FM11XY devices family.

type HumanDecoder

HumanDecoder is responsible for decoding, value of type HumanDecoder should be created becase it is needed to load files with encoding JSON maps from ./teltonikajson/*.go

type HumanDecoder struct {
    elements map[string]map[uint16]AvlEncodeKey
}
type HAvlData

HAvlData represent human readable set of a pointer to an AvlEncodeKey Decoding key and a pointer to IO element with RAW data

type HAvlData struct {
    AvlEncodeKey *AvlEncodeKey
    Element      *Element
}
type AvlEncodeKey

AvlEncodeKey represent parsed element values from JSON

type AvlEncodeKey struct {
    No              string `json:"No"`
    PropertyName    string `json:"PropertyName"`
    Bytes           string `json:"Bytes"`
    Type            string `json:"Type"`
    Min             string `json:"Min"`
    Max             string `json:"Max"`
    Multiplier      string `json:"Multiplier"`
    Units           string `json:"Units"`
    Description     string `json:"Description"`
    HWSupport       string `json:"HWSupport"`
    ParametrGroup   string `json:"Parametr Group"`
    FinalConversion string `json:"FinalConversion"`
}
Example HumanDecoder

Have a binary packet bs which is Teltonika UDP Codec 8 Extended

package main

import (
   "fmt"
   "log"
    "encoding/hex"
    "github.com/filipkroca/teltonikaparser"
)

func main() {
    // Example packet Teltonika UDP Codec 8 Extended 0086cafe0101000f3335323039333038353639383230368e0100000167efa919800200000000000000000000000000000000fc0013000800ef0000f00000150500c80000450200010000710000fc00000900b5000000b600000042305600cd432a00ce6064001100090012ff22001303d1000f0000000200f1000059d900100000000000000000010086cafe0191000f3335323039333038353639383230368e0100000167efad92080200000000000000000000000000000000fc0013000800ef0000f00000150500c80000450200010000715800fc01000900b5000000b600000042039d00cd432a00ce60640011015f0012fd930013036f000f0000000200f1000059d900100000000000000000010086cafe01a0000f3335323039333038353639383230368e01000000f9cebaeac80200000000000000000000000000000000fc0013000800ef0000f00000150000c80000450200010000710000fc00000900b5000000b600000042305400cd000000ce0000001103570012fe8900130196000f0000000200f10000000000100000000000000000010083cafe0101000f3335323039333038353639383230368e0100000167f1aeec00000a750e8f1d43443100f800b210000000000012000700ef0000f00000150500c800004501000100007142000900b5000600b6000500422fb300cd432a00ce60640011000700120007001303ec000f0000000200f1000059d90010000000000000000001

    // test with Codec8 Extended packet
    stringData := `0086cafe0101000f3335323039333038353639383230368e0100000167efa919800200000000000000000000000000000000fc0013000800ef0000f00000150500c80000450200010000710000fc00000900b5000000b600000042305600cd432a00ce6064001100090012ff22001303d1000f0000000200f1000059d900100000000000000000010086cafe0191000f3335323039333038353639383230368e0100000167efad92080200000000000000000000000000000000fc0013000800ef0000f00000150500c80000450200010000715800fc01000900b5000000b600000042039d00cd432a00ce60640011015f0012fd930013036f000f0000000200f1000059d900100000000000000000010086cafe01a0000f3335323039333038353639383230368e01000000f9cebaeac80200000000000000000000000000000000fc0013000800ef0000f00000150000c80000450200010000710000fc00000900b5000000b600000042305400cd000000ce0000001103570012fe8900130196000f0000000200f10000000000100000000000000000010083cafe0101000f3335323039333038353639383230368e0100000167f1aeec00000a750e8f1d43443100f800b210000000000012000700ef0000f00000150500c800004501000100007142000900b5000600b6000500422fb300cd432a00ce60640011000700120007001303ec000f0000000200f1000059d90010000000000000000001`

    bs, _ := hex.DecodeString(stringData)

    // decode a raw data byte slice
    parsedData, err := Decode(&bs)
    if err != nil {
        log.Panicf("Error when decoding a bs, %v\n", err)
    }

    // initialize a human decoder
    humanDecoder := teltonikaparser.HumanDecoder{}

    // loop over raw data
    for _, val := range parsedData.Data {
        // loop over Elements
        for _, ioel := range val.Elements {
            // decode to human readable format
            decoded, err := humanDecoder.Human(&ioel, "FMBXY") // second parameter - device family type ["FMBXY", "FM64"]
            if err != nil {
                log.Panicf("Error when converting human, %v\n", err)
            }

            // get final decoded value to value which is specified in ./teltonikajson/ in paramether FinalConversion
            if val, err := (*decoded).GetFinalValue(); err != nil {
                log.Panicf("Unable to GetFinalValue() %v", err)
            } else if val != nil {
                // print output
                fmt.Printf("Property Name: %v, Value: %v\n", decoded.AvlEncodeKey.PropertyName, val)
            }
        }
    }
}

Output:

Property Name: Ignition, Value: 0  
Property Name: Movement, Value: 0  
Property Name: GSM Signal, Value: 5  
Property Name: Sleep Mode, Value: 0  
Property Name: GNSS Status, Value: 2  
Property Name: Digital Input 1, Value: false  
Property Name: Battery Level, Value: 0  
Property Name: Unplug, Value: 0  
Property Name: GNSS PDOP, Value: 0  
Property Name: GNSS HDOP, Value: 0  
Property Name: External Voltage, Value: 12374  
Property Name: GSM Cell ID, Value: 17194  
Property Name: GSM Area Code, Value: 24676  
Property Name: Axis X, Value: 9  
Property Name: Axis Y, Value: -222  
Property Name: Axis Z, Value: 977  
Property Name: Eco Score, Value: 0  
Property Name: Active GSM Operator, Value: 23001  
Property Name: Total Odometer, Value: 0  

Full documentation HERE

Example usage of concurrency pattern

This example was created for testing purpose. It uses a concurrency pattern and load all data from a SQL database to the memory and then uses all CPUs to decoding.
It was tested on a bundle of 58 milions - 12GiB real world Teltonika UPD data from devices FMA110, FMB920, FMB110, FMB120, FMB640.

package main

import (
    "database/sql"
    "fmt"
    "log"
    "runtime"
    "sync"
    "sync/atomic"
    "time"

    "github.com/filipkroca/teltonikaparser"
    _ "github.com/go-sql-driver/mysql"
)

var data []byte

func main() {
    // init counters for total counting, this is used by atomic operations
    var errcounter int64
    var counter int64

    // make a slice for storing all 58254304 byte slices
    arr := make([][]byte, 58254304) //58254304

    // connect to a database
    db, err := sql.Open("mysql", "root:password@/binarylogdb")
    defer db.Close()
    if err != nil {
        fmt.Println("error when connecting", err)
    }

    /*    MySQL structure:
                CREATE TABLE `binLog` (
                `utime` int(10) NOT NULL,
                `bin` blob NOT NULL
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
                ALTER TABLE `binLog`
                  ADD KEY `utime` (`utime`);
    */

    // select 58254304 rows from SQL
    rows, err := db.Query("SELECT bin FROM `binlog_archiv` LIMIT 58254304")
    if err != nil {
        log.Fatal(err)
    }
    // defer databse closing
    defer rows.Close()

    // load all data into memory
    i := 0
    for rows.Next() {
        err := rows.Scan(&arr[i])
        if err != nil {
            log.Fatal(err)
        }
        i++
    }
    err = rows.Err()
    if err != nil {
        log.Fatal(err)
    }

    // init start time
    now := time.Now()
    start := now.Unix()

    // init WaitGroup used for synchronization
    var waitgroup sync.WaitGroup

    // make a channel used for avoiding RACE CONDITION and workers synchronization
    queue := make(chan int, 10)

    // run 16 workers on different threads and CPUs
    for i := 0; i < 16; i++ {
        // fire goroutine with goParse function
        go goParse(&waitgroup, &arr, queue, &counter, &errcounter)
    }

    // feed workers by the channel
    for ind := range arr {
        waitgroup.Add(1)
        queue <- ind
    }

    // block until all workers will be done with parsing
    waitgroup.Wait()

    // close the channel
    close(queue)

    // init end timer
    now = time.Now()
    stop := now.Unix()

    // print output
    fmt.Printf("takes: %v seconds\n", stop-start)
    fmt.Printf("total: %v packets\nerrors: %v invalid packets", atomic.LoadInt64(&counter), atomic.LoadInt64(&errcounter))

}

func goParse(waitgroup *sync.WaitGroup, bs *[][]byte, queue chan int, counter *int64, errcounter *int64) {
    // wait for a work comming by the channel, range is blocking operation
    for element := range queue {

        // increment total packet counter by atomic operation to avoid RACE CONDITION
        atomic.AddInt64(counter, 1)
        runtime.Gosched()

        // decode packet
        _, err := teltonikaparser.Decode(&(*bs)[element])
        // trash ping packets 0xFF
        if err != nil && err.Error() != "Minimum packet size is 45 Bytes, got 1" {
            // increment error counter
            atomic.AddInt64(errcounter, 1)
            runtime.Gosched()
        }
        // synchro
        waitgroup.Done()
    }
}
}
Output:
takes:  31 seconds
total:  58254304 packets
errors: 6641 invalid packets

Result:
On Intel Core i7-7700K CPU @ 4.20Ghz takes one run 31 seconds and it parsed 58254304 packets. So the throughput is about 1,8milions of packets per second.

Documentation

Overview

Package teltonikaparser is an implementation of https://wiki.teltonika.lt/view/Codec Codec12 for UDP packets in GO Lang implemented https://wiki.teltonika-gps.com/view/Codec#Codec_12

Package teltonikaparser is an implementation of https://wiki.teltonika.lt/view/Codec Codec08 and Codec08Extended for UDP packets in GO Lang implemented https://wiki.teltonika.lt/view/Codec#Codec_8 implemented https://wiki.teltonika.lt/view/Codec#Codec_8_Extended

Index

Examples

Constants

View Source
const (
	CodecID             = 0x0C
	RequestPreamble     = 0x00000000
	ResponsePreamble    = 0x00000000
	CommandTypeRequest  = 0x05
	CommandTypeResponse = 0x06
)

Variables

This section is empty.

Functions

func EncodeCommandRequest

func EncodeCommandRequest(command string) ([]byte, error)

Types

type AvlData

type AvlData struct {
	UtimeMs  uint64    // Utime in mili seconds
	Utime    uint64    // Utime in seconds
	Priority uint8     // Priority, 	[0	Low, 1	High, 2	Panic]
	Lat      int32     // Latitude (between 850000000 and -850000000), fit int32
	Lng      int32     // Longitude (between 1800000000 and -1800000000), fit int32
	Altitude int16     // Altitude In meters above sea level, 2 bytes
	Angle    uint16    // Angle In degrees, 0 is north, increasing clock-wise, 2 bytes
	VisSat   uint8     // Satellites Number of visible satellites
	Speed    uint16    // Speed in km/h
	EventID  uint16    // Event generated (0 – data generated not on event)
	Elements []Element // Slice containing parsed IO Elements
}

AvlData represent one block of data

type AvlEncodeKey

type AvlEncodeKey struct {
	No              string `json:"No"`
	PropertyName    string `json:"PropertyName"`
	Bytes           string `json:"Bytes"`
	Type            string `json:"Type"`
	Min             string `json:"Min"`
	Max             string `json:"Max"`
	Multiplier      string `json:"Multiplier"`
	Units           string `json:"Units"`
	Description     string `json:"Description"`
	HWSupport       string `json:"HWSupport"`
	ParametrGroup   string `json:"Parametr Group"`
	FinalConversion string `json:"FinalConversion"`
}

AvlEncodeKey represent parsed element values from JSON

type CommandRequest

type CommandRequest struct {

	// Command - command  in HEX.
	Command []byte // dynamic long type. Needs to read separately.
	// contains filtered or unexported fields
}

func DecodeCommandRequest

func DecodeCommandRequest(rawCommand *[]byte) (CommandRequest, error)

type CommandResponse

type CommandResponse struct {

	// Response – response in HEX.
	Response []byte // dynamic long type. Needs to read separately.
	// contains filtered or unexported fields
}

func DecodeCommandResponse

func DecodeCommandResponse(rawResponse *[]byte) (CommandResponse, error)

type Decoded

type Decoded struct {
	IMEI     string    // IMEI number, if len==15 also validated by checksum
	CodecID  byte      // 0x08 (codec 8) or 0x8E (codec 8 extended)
	NoOfData uint8     // Number of Data
	Data     []AvlData // Slice with avl data
	Response []byte    // Slice with a response
}

Decoded struct represent decoded Teltonika data structure with all AVL data as return from function Decode

func Decode

func Decode(bs *[]byte) (Decoded, error)

Decode takes a pointer to a slice of bytes with raw data and return Decoded struct

Example
stringData := `01e4cafe0128000f333532303934303839333937343634080400000163c803eb02010a2524c01d4a377d00d3012f130032421b0a4503f00150051503ef01510052005900be00c1000ab50008b60006426fd8cd3d1ece605a5400005500007300005a0000c0000007c70000000df1000059d910002d33c65300000000570000000064000000f7bf000000000000000163c803e6e8010a2530781d4a316f00d40131130031421b0a4503f00150051503ef01510052005900be00c1000ab50008b60005426fcbcd3d1ece605a5400005500007300005a0000c0000007c70000000ef1000059d910002d33b95300000000570000000064000000f7bf000000000000000163c803df18010a2536961d4a2e4f00d50134130033421b0a4503f00150051503ef01510052005900be00c1000ab50008b6000542702bcd3d1ece605a5400005500007300005a0000c0000007c70000001ef1000059d910002d33aa5300000000570000000064000000f7bf000000000000000163c8039ce2010a25d8d41d49f42c00dc0123120058421b0a4503f00150051503ef01510052005900be00c1000ab50009b60005427031cd79d8ce605a5400005500007300005a0000c0000007c700000019f1000059d910002d32505300000000570000000064000000f7bf000000000004`

bs, _ := hex.DecodeString(stringData)
// decode a raw data byte slice
parsedData, err := Decode(&bs)
if err != nil {
	log.Panicf("Error when decoding a bs, %v\n", err)
}
fmt.Printf("Decoded packet codec 8:\n%+v\n", parsedData)

// test with Codec8 Extended packet
stringData = `0086cafe0101000f3335323039333038353639383230368e0100000167efa919800200000000000000000000000000000000fc0013000800ef0000f00000150500c80000450200010000710000fc00000900b5000000b600000042305600cd432a00ce6064001100090012ff22001303d1000f0000000200f1000059d900100000000000000000010086cafe0191000f3335323039333038353639383230368e0100000167efad92080200000000000000000000000000000000fc0013000800ef0000f00000150500c80000450200010000715800fc01000900b5000000b600000042039d00cd432a00ce60640011015f0012fd930013036f000f0000000200f1000059d900100000000000000000010086cafe01a0000f3335323039333038353639383230368e01000000f9cebaeac80200000000000000000000000000000000fc0013000800ef0000f00000150000c80000450200010000710000fc00000900b5000000b600000042305400cd000000ce0000001103570012fe8900130196000f0000000200f10000000000100000000000000000010083cafe0101000f3335323039333038353639383230368e0100000167f1aeec00000a750e8f1d43443100f800b210000000000012000700ef0000f00000150500c800004501000100007142000900b5000600b6000500422fb300cd432a00ce60640011000700120007001303ec000f0000000200f1000059d90010000000000000000001`

bs, _ = hex.DecodeString(stringData)

// decode a raw data byte slice
parsedData, err = Decode(&bs)
if err != nil {
	log.Panicf("Error when decoding a bs, %v\n", err)
}
fmt.Printf("Decoded packet codec 8 extended:\n%+v\n", parsedData)
Output:

Decoded packet codec 8:
{IMEI:352094089397464 CodecID:8 NoOfData:4 Data:[{UtimeMs:1528069090050 Utime:1528069090 Priority:1 Lat:491403133 Lng:170206400 Altitude:211 Angle:303 VisSat:19 Speed:50 EventID:66 Elements:[{Length:1 IOID:69 Value:[3]} {Length:1 IOID:240 Value:[1]} {Length:1 IOID:80 Value:[5]} {Length:1 IOID:21 Value:[3]} {Length:1 IOID:239 Value:[1]} {Length:1 IOID:81 Value:[0]} {Length:1 IOID:82 Value:[0]} {Length:1 IOID:89 Value:[0]} {Length:1 IOID:190 Value:[0]} {Length:1 IOID:193 Value:[0]} {Length:2 IOID:181 Value:[0 8]} {Length:2 IOID:182 Value:[0 6]} {Length:2 IOID:66 Value:[111 216]} {Length:2 IOID:205 Value:[61 30]} {Length:2 IOID:206 Value:[96 90]} {Length:2 IOID:84 Value:[0 0]} {Length:2 IOID:85 Value:[0 0]} {Length:2 IOID:115 Value:[0 0]} {Length:2 IOID:90 Value:[0 0]} {Length:2 IOID:192 Value:[0 0]} {Length:4 IOID:199 Value:[0 0 0 13]} {Length:4 IOID:241 Value:[0 0 89 217]} {Length:4 IOID:16 Value:[0 45 51 198]} {Length:4 IOID:83 Value:[0 0 0 0]} {Length:4 IOID:87 Value:[0 0 0 0]} {Length:4 IOID:100 Value:[0 0 0 247]} {Length:4 IOID:191 Value:[0 0 0 0]}]} {UtimeMs:1528069089000 Utime:1528069089 Priority:1 Lat:491401583 Lng:170209400 Altitude:212 Angle:305 VisSat:19 Speed:49 EventID:66 Elements:[{Length:1 IOID:69 Value:[3]} {Length:1 IOID:240 Value:[1]} {Length:1 IOID:80 Value:[5]} {Length:1 IOID:21 Value:[3]} {Length:1 IOID:239 Value:[1]} {Length:1 IOID:81 Value:[0]} {Length:1 IOID:82 Value:[0]} {Length:1 IOID:89 Value:[0]} {Length:1 IOID:190 Value:[0]} {Length:1 IOID:193 Value:[0]} {Length:2 IOID:181 Value:[0 8]} {Length:2 IOID:182 Value:[0 5]} {Length:2 IOID:66 Value:[111 203]} {Length:2 IOID:205 Value:[61 30]} {Length:2 IOID:206 Value:[96 90]} {Length:2 IOID:84 Value:[0 0]} {Length:2 IOID:85 Value:[0 0]} {Length:2 IOID:115 Value:[0 0]} {Length:2 IOID:90 Value:[0 0]} {Length:2 IOID:192 Value:[0 0]} {Length:4 IOID:199 Value:[0 0 0 14]} {Length:4 IOID:241 Value:[0 0 89 217]} {Length:4 IOID:16 Value:[0 45 51 185]} {Length:4 IOID:83 Value:[0 0 0 0]} {Length:4 IOID:87 Value:[0 0 0 0]} {Length:4 IOID:100 Value:[0 0 0 247]} {Length:4 IOID:191 Value:[0 0 0 0]}]} {UtimeMs:1528069087000 Utime:1528069087 Priority:1 Lat:491400783 Lng:170210966 Altitude:213 Angle:308 VisSat:19 Speed:51 EventID:66 Elements:[{Length:1 IOID:69 Value:[3]} {Length:1 IOID:240 Value:[1]} {Length:1 IOID:80 Value:[5]} {Length:1 IOID:21 Value:[3]} {Length:1 IOID:239 Value:[1]} {Length:1 IOID:81 Value:[0]} {Length:1 IOID:82 Value:[0]} {Length:1 IOID:89 Value:[0]} {Length:1 IOID:190 Value:[0]} {Length:1 IOID:193 Value:[0]} {Length:2 IOID:181 Value:[0 8]} {Length:2 IOID:182 Value:[0 5]} {Length:2 IOID:66 Value:[112 43]} {Length:2 IOID:205 Value:[61 30]} {Length:2 IOID:206 Value:[96 90]} {Length:2 IOID:84 Value:[0 0]} {Length:2 IOID:85 Value:[0 0]} {Length:2 IOID:115 Value:[0 0]} {Length:2 IOID:90 Value:[0 0]} {Length:2 IOID:192 Value:[0 0]} {Length:4 IOID:199 Value:[0 0 0 30]} {Length:4 IOID:241 Value:[0 0 89 217]} {Length:4 IOID:16 Value:[0 45 51 170]} {Length:4 IOID:83 Value:[0 0 0 0]} {Length:4 IOID:87 Value:[0 0 0 0]} {Length:4 IOID:100 Value:[0 0 0 247]} {Length:4 IOID:191 Value:[0 0 0 0]}]} {UtimeMs:1528069070050 Utime:1528069070 Priority:1 Lat:491385900 Lng:170252500 Altitude:220 Angle:291 VisSat:18 Speed:88 EventID:66 Elements:[{Length:1 IOID:69 Value:[3]} {Length:1 IOID:240 Value:[1]} {Length:1 IOID:80 Value:[5]} {Length:1 IOID:21 Value:[3]} {Length:1 IOID:239 Value:[1]} {Length:1 IOID:81 Value:[0]} {Length:1 IOID:82 Value:[0]} {Length:1 IOID:89 Value:[0]} {Length:1 IOID:190 Value:[0]} {Length:1 IOID:193 Value:[0]} {Length:2 IOID:181 Value:[0 9]} {Length:2 IOID:182 Value:[0 5]} {Length:2 IOID:66 Value:[112 49]} {Length:2 IOID:205 Value:[121 216]} {Length:2 IOID:206 Value:[96 90]} {Length:2 IOID:84 Value:[0 0]} {Length:2 IOID:85 Value:[0 0]} {Length:2 IOID:115 Value:[0 0]} {Length:2 IOID:90 Value:[0 0]} {Length:2 IOID:192 Value:[0 0]} {Length:4 IOID:199 Value:[0 0 0 25]} {Length:4 IOID:241 Value:[0 0 89 217]} {Length:4 IOID:16 Value:[0 45 50 80]} {Length:4 IOID:83 Value:[0 0 0 0]} {Length:4 IOID:87 Value:[0 0 0 0]} {Length:4 IOID:100 Value:[0 0 0 247]} {Length:4 IOID:191 Value:[0 0 0 0]}]}] Response:[0 5 202 254 1 40 4]}
Decoded packet codec 8 extended:
{IMEI:352093085698206 CodecID:142 NoOfData:1 Data:[{UtimeMs:1545914096000 Utime:1545914096 Priority:2 Lat:0 Lng:0 Altitude:0 Angle:0 VisSat:0 Speed:0 EventID:252 Elements:[{Length:1 IOID:239 Value:[0]} {Length:1 IOID:240 Value:[0]} {Length:1 IOID:21 Value:[5]} {Length:1 IOID:200 Value:[0]} {Length:1 IOID:69 Value:[2]} {Length:1 IOID:1 Value:[0]} {Length:1 IOID:113 Value:[0]} {Length:1 IOID:252 Value:[0]} {Length:2 IOID:181 Value:[0 0]} {Length:2 IOID:182 Value:[0 0]} {Length:2 IOID:66 Value:[48 86]} {Length:2 IOID:205 Value:[67 42]} {Length:2 IOID:206 Value:[96 100]} {Length:2 IOID:17 Value:[0 9]} {Length:2 IOID:18 Value:[255 34]} {Length:2 IOID:19 Value:[3 209]} {Length:2 IOID:15 Value:[0 0]} {Length:4 IOID:241 Value:[0 0 89 217]} {Length:4 IOID:16 Value:[0 0 0 0]}]}] Response:[0 5 202 254 1 1 1]}

type Element

type Element struct {
	Length uint16 // Length of element, this should be uint16 because Codec 8 extended has 2Byte of IO len
	IOID   uint16 // IO element ID
	Value  []byte // Value of the element represented by slice of bytes
}

Element represent one IO element, before storing in a db do a conversion to IO datatype (1B, 2B, 4B, 8B)

func DecodeElements

func DecodeElements(bs *[]byte, start int, codecID byte) ([]Element, int, error)

DecodeElements take pointer to a byte slice with raw data, start Byte position and Codec ID, and returns slice of Element

type HAvlData

type HAvlData struct {
	AvlEncodeKey *AvlEncodeKey
	Element      *Element
}

HAvlData represent human readable set of a pointer to an AvlEncodeKey Decoding key and a pointer to IO element with RAW data

func (*HAvlData) GetFinalValue

func (h *HAvlData) GetFinalValue() (interface{}, error)

GetFinalValue return decimal value, if necesarry with float, return should be empty interface because there is many values to return

type HumanDecoder

type HumanDecoder struct {
	// contains filtered or unexported fields
}

HumanDecoder is responsible for decoding

func (*HumanDecoder) AvlDataToHuman

func (h *HumanDecoder) AvlDataToHuman(data *[]AvlData) ([][][]string, error)

AvlDataToHuman takes a pointer to a slice of AvlData and return a slice with data

Example
// test with Codec8 Extended packet
stringData := `01e4cafe0126000f333532303934303839333937343634080400000163c803b420010a259e1a1d4a057d00da0128130057421b0a4503f00150051503ef01510052005900be00c1000ab50008b60005427025cd79d8ce605a5400005500007300005a0000c0000007c700000018f1000059d910002d32c85300000000570000000064000000f7bf000000000000000163c803ac50010a25a9d21d4a01b600db0128130056421b0a4503f00150051503ef01510052005900be00c1000ab50008b6000542702ecd79d8ce605a5400005500007300005a0000c0000007c700000017f1000059d910002d32b05300000000570000000064000000f7bf000000000000000163c803a868010a25b5581d49fe5400db0127130057421b0a4503f00150051503ef01510052005900be00c1000ab50008b60005427039cd79d8ce605a5400005500007300005a0000c0000007c700000017f1000059d910002d32995300000000570000000064000000f7bf000000000000000163c803a4b2010a25cc861d49f75c00db0124130058421b0a4503f00150051503ef01510052005900be00c1000ab50008b6000542703ccd79d8ce605a5400005500007300005a0000c0000007c700000018f1000059d910002d32695300000000570000000064000000f7bf000000000004`

bs, _ := hex.DecodeString(stringData)

// decode a raw data byte slice
parsedData, err := Decode(&bs)
if err != nil {
	log.Panicf("Error when decoding a bs, %v\n", err)
}

// initialize a human decoder
humanDecoder := HumanDecoder{}

decoded, err := humanDecoder.AvlDataToHuman(&parsedData.Data)

fmt.Printf("Property Name: %v\n", decoded)
Output:

func (*HumanDecoder) Human

func (h *HumanDecoder) Human(el *Element, device string) (*HAvlData, error)

Human takes a pointer to Element, device type ["FMBXY", "FM64", "FM36", "FM11XY"] and return a pointer to decoding key

Example
// test with Codec8 Extended packet
stringData := `01e4cafe0126000f333532303934303839333937343634080400000163c803b420010a259e1a1d4a057d00da0128130057421b0a4503f00150051503ef01510052005900be00c1000ab50008b60005427025cd79d8ce605a5400005500007300005a0000c0000007c700000018f1000059d910002d32c85300000000570000000064000000f7bf000000000000000163c803ac50010a25a9d21d4a01b600db0128130056421b0a4503f00150051503ef01510052005900be00c1000ab50008b6000542702ecd79d8ce605a5400005500007300005a0000c0000007c700000017f1000059d910002d32b05300000000570000000064000000f7bf000000000000000163c803a868010a25b5581d49fe5400db0127130057421b0a4503f00150051503ef01510052005900be00c1000ab50008b60005427039cd79d8ce605a5400005500007300005a0000c0000007c700000017f1000059d910002d32995300000000570000000064000000f7bf000000000000000163c803a4b2010a25cc861d49f75c00db0124130058421b0a4503f00150051503ef01510052005900be00c1000ab50008b6000542703ccd79d8ce605a5400005500007300005a0000c0000007c700000018f1000059d910002d32695300000000570000000064000000f7bf000000000004`

/*01e4cafe0126000f333532303934303839333937343634080400000163c803b420010a259e1a1d4a057d00da0128130057421b0a4503f00150051503ef01510052005900be00c1000ab50008b60005427025cd79d8ce605a5400005500007300005a0000c0000007c700000018f1000059d910002d32c85300000000570000000064000000f7bf000000000000000163c803ac50010a25a9d21d4a01b600db0128130056421b0a4503f00150051503ef01510052005900be00c1000ab50008b6000542702ecd79d8ce605a5400005500007300005a0000c0000007c700000017f1000059d910002d32b05300000000570000000064000000f7bf000000000000000163c803a868010a25b5581d49fe5400db0127130057421b0a4503f00150051503ef01510052005900be00c1000ab50008b60005427039cd79d8ce605a5400005500007300005a0000c0000007c700000017f1000059d910002d32995300000000570000000064000000f7bf000000000000000163c803a4b2010a25cc861d49f75c00db0124130058421b0a4503f00150051503ef01510052005900be00c1000ab50008b6000542703ccd79d8ce605a5400005500007300005a0000c0000007c700000018f1000059d910002d32695300000000570000000064000000f7bf000000000004*/

bs, _ := hex.DecodeString(stringData)

// decode a raw data byte slice
parsedData, err := Decode(&bs)
if err != nil {
	log.Panicf("Error when decoding a bs, %v\n", err)
}

// initialize a human decoder
humanDecoder := HumanDecoder{}

// loop over raw data
for _, val := range parsedData.Data {
	// loop over Elements
	for _, ioel := range val.Elements {
		// decode to human readable format
		decoded, err := humanDecoder.Human(&ioel, "FM11XY") // second parameter - device family type ["FMBXY", "FM64", "FM36", "FM11XY"]
		if err != nil {
			log.Panicf("Error when converting human, %v\n", err)
		}

		// get final decoded value to value which is specified in ./teltonikajson/ in paramether FinalConversion
		if val, err := (*decoded).GetFinalValue(); err != nil {
			log.Panicf("Unable to GetFinalValue() %v", err)
		} else if val != nil {
			// print output
			fmt.Printf("Property Name: %v, Value: %v\n", decoded.AvlEncodeKey.PropertyName, val)
		}
	}
}
Output:

Property Name: GPS Status, Value: 3
Property Name: Movement Sensor, Value: 1
Property Name: Data Mode, Value: 5
Property Name: GSM level, Value: 3
Property Name: Ignition, Value: 1
Property Name: LVCAN Speed, Value: 0
Property Name: LVCAN Accelerator Pedal Position, Value: 0
Property Name: LVCAN Fuel Level (percentage), Value: 0
Property Name: LVC CNG Status, Value: 0
Property Name: LVC Oil level, Value: 0
Property Name: PDOP, Value: 8
Property Name: HDOP, Value: 5
Property Name: External Power Voltage, Value: 28709
Property Name: Cell ID, Value: 31192
Property Name: Area Code, Value: 24666
Property Name: LVCAN Fuel Level (liters), Value: 0
Property Name: LVCAN Engine RPM, Value: 0
Property Name: LVC Engine Temperature, Value: 0
Property Name: LVCAN Door Status, Value: 0
Property Name: LVC CNG Level, Value: 0
Property Name: Odometer/Trip Distance, Value: 24
Property Name: GSM Operator Code, Value: 23001
Property Name: Total distance, Value: 2962120
Property Name: LVCAN Total Fuel Used, Value: 0
Property Name: LVCAN Vehicle Distance, Value: 0
Property Name: LVCAN Program Number, Value: 247
Property Name: LVC CNG Used, Value: 0
Property Name: GPS Status, Value: 3
Property Name: Movement Sensor, Value: 1
Property Name: Data Mode, Value: 5
Property Name: GSM level, Value: 3
Property Name: Ignition, Value: 1
Property Name: LVCAN Speed, Value: 0
Property Name: LVCAN Accelerator Pedal Position, Value: 0
Property Name: LVCAN Fuel Level (percentage), Value: 0
Property Name: LVC CNG Status, Value: 0
Property Name: LVC Oil level, Value: 0
Property Name: PDOP, Value: 8
Property Name: HDOP, Value: 5
Property Name: External Power Voltage, Value: 28718
Property Name: Cell ID, Value: 31192
Property Name: Area Code, Value: 24666
Property Name: LVCAN Fuel Level (liters), Value: 0
Property Name: LVCAN Engine RPM, Value: 0
Property Name: LVC Engine Temperature, Value: 0
Property Name: LVCAN Door Status, Value: 0
Property Name: LVC CNG Level, Value: 0
Property Name: Odometer/Trip Distance, Value: 23
Property Name: GSM Operator Code, Value: 23001
Property Name: Total distance, Value: 2962096
Property Name: LVCAN Total Fuel Used, Value: 0
Property Name: LVCAN Vehicle Distance, Value: 0
Property Name: LVCAN Program Number, Value: 247
Property Name: LVC CNG Used, Value: 0
Property Name: GPS Status, Value: 3
Property Name: Movement Sensor, Value: 1
Property Name: Data Mode, Value: 5
Property Name: GSM level, Value: 3
Property Name: Ignition, Value: 1
Property Name: LVCAN Speed, Value: 0
Property Name: LVCAN Accelerator Pedal Position, Value: 0
Property Name: LVCAN Fuel Level (percentage), Value: 0
Property Name: LVC CNG Status, Value: 0
Property Name: LVC Oil level, Value: 0
Property Name: PDOP, Value: 8
Property Name: HDOP, Value: 5
Property Name: External Power Voltage, Value: 28729
Property Name: Cell ID, Value: 31192
Property Name: Area Code, Value: 24666
Property Name: LVCAN Fuel Level (liters), Value: 0
Property Name: LVCAN Engine RPM, Value: 0
Property Name: LVC Engine Temperature, Value: 0
Property Name: LVCAN Door Status, Value: 0
Property Name: LVC CNG Level, Value: 0
Property Name: Odometer/Trip Distance, Value: 23
Property Name: GSM Operator Code, Value: 23001
Property Name: Total distance, Value: 2962073
Property Name: LVCAN Total Fuel Used, Value: 0
Property Name: LVCAN Vehicle Distance, Value: 0
Property Name: LVCAN Program Number, Value: 247
Property Name: LVC CNG Used, Value: 0
Property Name: GPS Status, Value: 3
Property Name: Movement Sensor, Value: 1
Property Name: Data Mode, Value: 5
Property Name: GSM level, Value: 3
Property Name: Ignition, Value: 1
Property Name: LVCAN Speed, Value: 0
Property Name: LVCAN Accelerator Pedal Position, Value: 0
Property Name: LVCAN Fuel Level (percentage), Value: 0
Property Name: LVC CNG Status, Value: 0
Property Name: LVC Oil level, Value: 0
Property Name: PDOP, Value: 8
Property Name: HDOP, Value: 5
Property Name: External Power Voltage, Value: 28732
Property Name: Cell ID, Value: 31192
Property Name: Area Code, Value: 24666
Property Name: LVCAN Fuel Level (liters), Value: 0
Property Name: LVCAN Engine RPM, Value: 0
Property Name: LVC Engine Temperature, Value: 0
Property Name: LVCAN Door Status, Value: 0
Property Name: LVC CNG Level, Value: 0
Property Name: Odometer/Trip Distance, Value: 24
Property Name: GSM Operator Code, Value: 23001
Property Name: Total distance, Value: 2962025
Property Name: LVCAN Total Fuel Used, Value: 0
Property Name: LVCAN Vehicle Distance, Value: 0
Property Name: LVCAN Program Number, Value: 247
Property Name: LVC CNG Used, Value: 0

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL