pax_global_header00006660000000000000000000000064151461060160014512gustar00rootroot0000000000000052 comment=4141bde386ed9d13548abdbb96b8b411773ba923 marcinbor85-gohex-4141bde/000077500000000000000000000000001514610601600153615ustar00rootroot00000000000000marcinbor85-gohex-4141bde/.gitignore000066400000000000000000000004231514610601600173500ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.dll *.so *.dylib # Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 .glide/ marcinbor85-gohex-4141bde/.project000066400000000000000000000006431514610601600170330ustar00rootroot00000000000000 gohex com.googlecode.goclipse.goBuilder clean,full,incremental, com.googlecode.goclipse.core.goNature marcinbor85-gohex-4141bde/.travis.yml000066400000000000000000000000701514610601600174670ustar00rootroot00000000000000language: go go: - 1.x - 1.6 - 1.7.x - master marcinbor85-gohex-4141bde/LICENSE000066400000000000000000000020601514610601600163640ustar00rootroot00000000000000MIT License Copyright (c) 2018 Marcin Borowicz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. marcinbor85-gohex-4141bde/README.md000066400000000000000000000024511514610601600166420ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/marcinbor85/gohex.svg?branch=master)](https://travis-ci.org/marcinbor85/gohex) # gohex A Go library for parsing Intel HEX files ## Documentation: https://godoc.org/github.com/marcinbor85/gohex ## Features: * robust intelhex parsing (full test coverage) * support i32hex format * two-way converting hex<->bin * trivial but powerful api (only the most commonly used functions) * interface-based IO functions ## Examples: ### Loading IntelHex file: ```go package main import ( "fmt" "github.com/marcinbor85/gohex" "os" ) func main() { file, err := os.Open("example.hex") if err != nil { panic(err) } defer file.Close() mem := gohex.NewMemory() err = mem.ParseIntelHex(file) if err != nil { panic(err) } for _, segment := range mem.GetDataSegments() { fmt.Printf("%+v\n", segment) } bytes := mem.ToBinary(0xFFF0, 128, 0x00) fmt.Printf("%v\n", bytes) } ``` ### Dumping IntelHex file: ```go package main import ( "github.com/marcinbor85/gohex" "os" ) func main() { file, err := os.Create("output.hex") if err != nil { panic(err) } defer file.Close() mem := gohex.NewMemory() mem.SetStartAddress(0x80008000) mem.AddBinary(0x10008000, []byte{0x01,0x02,0x03,0x04}) mem.AddBinary(0x20000000, make([]byte, 256)) mem.DumpIntelHex(file, 16) } ```marcinbor85-gohex-4141bde/VERSION000066400000000000000000000000061514610601600164250ustar00rootroot000000000000000.1.0 marcinbor85-gohex-4141bde/errors.go000066400000000000000000000014061514610601600172250ustar00rootroot00000000000000package gohex import ( "fmt" ) type parseErrorType uint const ( _SYNTAX_ERROR parseErrorType = 1 _RECORD_ERROR parseErrorType = 2 _DATA_ERROR parseErrorType = 3 _CHECKSUM_ERROR parseErrorType = 4 ) type parseError struct { errorType parseErrorType message string lineNum uint } func (e *parseError) Error() string { var str string = "error" switch e.errorType { case _SYNTAX_ERROR: str = "syntax error" case _RECORD_ERROR: str = "record error" case _DATA_ERROR: str = "data error" case _CHECKSUM_ERROR: str = "checksum error" } return fmt.Sprintf("%s: %s at line %d", str, e.message, e.lineNum) } func newParseError(et parseErrorType, msg string, line uint) error { return &parseError{errorType: et, message: msg, lineNum: line} } marcinbor85-gohex-4141bde/example/000077500000000000000000000000001514610601600170145ustar00rootroot00000000000000marcinbor85-gohex-4141bde/example/dumper/000077500000000000000000000000001514610601600203105ustar00rootroot00000000000000marcinbor85-gohex-4141bde/example/dumper/dumper.go000066400000000000000000000005531514610601600221360ustar00rootroot00000000000000package main import ( "github.com/marcinbor85/gohex" "os" ) func main() { file, err := os.Create("output.hex") if err != nil { panic(err) } defer file.Close() mem := gohex.NewMemory() mem.SetStartAddress(0x80008000) mem.AddBinary(0x10008000, []byte{0x01,0x02,0x03,0x04}) mem.AddBinary(0x20000000, make([]byte, 256)) mem.DumpIntelHex(file, 16) }marcinbor85-gohex-4141bde/example/dumper/output.hex000066400000000000000000000014241514610601600223570ustar00rootroot00000000000000:0400000580008000F7 :020000041000EA :048000000102030472 :020000042000DA :1000000000000000000000000000000000000000F0 :1000100000000000000000000000000000000000E0 :1000200000000000000000000000000000000000D0 :1000300000000000000000000000000000000000C0 :1000400000000000000000000000000000000000B0 :1000500000000000000000000000000000000000A0 :100060000000000000000000000000000000000090 :100070000000000000000000000000000000000080 :100080000000000000000000000000000000000070 :100090000000000000000000000000000000000060 :1000A0000000000000000000000000000000000050 :1000B0000000000000000000000000000000000040 :1000C0000000000000000000000000000000000030 :1000D0000000000000000000000000000000000020 :1000E0000000000000000000000000000000000010 :1000F0000000000000000000000000000000000000 :00000001FF marcinbor85-gohex-4141bde/example/loader/000077500000000000000000000000001514610601600202625ustar00rootroot00000000000000marcinbor85-gohex-4141bde/example/loader/example.hex000066400000000000000000000002051514610601600224200ustar00rootroot00000000000000:04FFFC0001020304F7 :020000040001F9 :1000000005060708090A0B0C0D0E0F101112131428 :040010001516171892 :0400400001020304B2 :00000001FF marcinbor85-gohex-4141bde/example/loader/loader.go000066400000000000000000000006451514610601600220640ustar00rootroot00000000000000package main import ( "fmt" "github.com/marcinbor85/gohex" "os" ) func main() { file, err := os.Open("example.hex") if err != nil { panic(err) } defer file.Close() mem := gohex.NewMemory() err = mem.ParseIntelHex(file) if err != nil { panic(err) } for _, segment := range mem.GetDataSegments() { fmt.Printf("%+v\n", segment) } bytes := mem.ToBinary(0xFFF0, 128, 0x00) fmt.Printf("%v\n", bytes) } marcinbor85-gohex-4141bde/go.mod000066400000000000000000000000561514610601600164700ustar00rootroot00000000000000module github.com/marcinbor85/gohex go 1.25.0marcinbor85-gohex-4141bde/gohex.go000066400000000000000000000225141514610601600170260ustar00rootroot00000000000000package gohex import ( "bufio" "encoding/hex" "io" "sort" ) // Constants definitions of IntelHex record types const ( _DATA_RECORD byte = 0 // Record with data bytes _EOF_RECORD byte = 1 // Record with end of file indicator _ADR_20_RECORD byte = 2 // Record with extended 20-bit linear address _ADR_32_RECORD byte = 4 // Record with extended 32-bit linear address _START_RECORD byte = 5 // Record with start linear address ) // Structure with binary data segment fields type DataSegment struct { Address uint32 // Starting address of data segment Data []byte // Data segment bytes } // Helper type for data segments sorting operations type sortByAddress []*DataSegment func (segs sortByAddress) Len() int { return len(segs) } func (segs sortByAddress) Swap(i, j int) { segs[i], segs[j] = segs[j], segs[i] } func (segs sortByAddress) Less(i, j int) bool { return segs[i].Address < segs[j].Address } // Main structure with private fields of IntelHex parser type Memory struct { dataSegments []*DataSegment // Slice with pointers to DataSegments startAddress uint32 // Start linear address extendedAddress uint32 // Extended linear address eofFlag bool // End of file record exist flag startFlag bool // Start address record exist flag lineNum uint // Parser input line number firstAddressFlag bool // Dump first address line } // Constructor of Memory structure func NewMemory() *Memory { m := new(Memory) m.Clear() return m } // Method to getting start address from IntelHex data func (m *Memory) GetStartAddress() (adr uint32, ok bool) { if m.startFlag { return m.startAddress, true } return 0, false } // Method to setting start address to IntelHex data func (m *Memory) SetStartAddress(adr uint32) { m.startAddress = adr m.startFlag = true } // Method to getting data segments address from IntelHex data func (m *Memory) GetDataSegments() []DataSegment { segs := []DataSegment{} for _, s := range m.dataSegments { segs = append(segs, *s) } return segs } // Method to clear memory structure func (m *Memory) Clear() { m.startAddress = 0 m.extendedAddress = 0 m.lineNum = 0 m.dataSegments = []*DataSegment{} m.startFlag = false m.eofFlag = false m.firstAddressFlag = false } func (seg *DataSegment) isOverlap(adr uint32, size uint32) bool { if ((adr >= seg.Address) && (adr < seg.Address+uint32(len(seg.Data)))) || ((adr < seg.Address) && (adr+size) > seg.Address) { return true } return false } func (m *Memory) removeSegment(index int) { size := len(m.dataSegments) if size == 0 { return } else if size == 1 { m.dataSegments = []*DataSegment{} } else { if index == 0 { m.dataSegments = m.dataSegments[1:] } else if index == size-1 { m.dataSegments = m.dataSegments[:index] } else { m.dataSegments = append(m.dataSegments[:index], m.dataSegments[index+1:]...) } } } func (m *Memory) findDataSegment(adr uint32) (seg *DataSegment, offset uint32, index int) { for i, s := range m.dataSegments { if s.isOverlap(adr, 1) == true { return s, adr - s.Address, i } } return nil, 0, 0 } // Method to add binary data to memory (auto segmented and sorted) func (m *Memory) AddBinary(adr uint32, bytes []byte) error { var segBefore *DataSegment = nil var segAfter *DataSegment = nil var segAfterIndex int for i, s := range m.dataSegments { if s.isOverlap(adr, uint32(len(bytes))) == true { return newParseError(_DATA_ERROR, "data segments overlap", m.lineNum) } if adr == s.Address+uint32(len(s.Data)) { segBefore = s } if adr+uint32(len(bytes)) == s.Address { segAfter, segAfterIndex = s, i } } if segBefore != nil && segAfter != nil { segBefore.Data = append(segBefore.Data, bytes...) segBefore.Data = append(segBefore.Data, segAfter.Data...) m.dataSegments = append(m.dataSegments[:segAfterIndex], m.dataSegments[segAfterIndex+1:]...) } else if segBefore != nil && segAfter == nil { segBefore.Data = append(segBefore.Data, bytes...) } else if segBefore == nil && segAfter != nil { segAfter.Address = adr segAfter.Data = append(bytes, segAfter.Data...) } else { data := make([]byte, len(bytes)) copy(data, bytes) m.dataSegments = append(m.dataSegments, &DataSegment{Address: adr, Data: data}) } sort.Sort(sortByAddress(m.dataSegments)) return nil } // Method to set binary data to memory (data overlapped will change, auto segmented and sorted) func (m *Memory) SetBinary(adr uint32, bytes []byte) { for a, b := range bytes { currentAdr := adr + uint32(a) seg, offset, _ := m.findDataSegment(currentAdr) if seg != nil { seg.Data[offset] = b } else { m.AddBinary(currentAdr, []byte{b}) } } } // Method to remove binary data from memory (auto segmented and sorted) func (m *Memory) RemoveBinary(adr uint32, size uint32) { adrEnd := adr + size for currentAdr := adr; currentAdr < adrEnd; currentAdr++ { seg, offset, index := m.findDataSegment(currentAdr) if seg == nil { continue } if offset == 0 { seg.Address += 1 if len(seg.Data) > 1 { seg.Data = seg.Data[1:] } else { m.removeSegment(index) } } else if offset == uint32(len(seg.Data)-1) { if len(seg.Data) > 1 { seg.Data = seg.Data[:offset] } else { m.removeSegment(index) } } else { newSeg := DataSegment{Address: seg.Address + offset + 1, Data: seg.Data[offset+1:]} seg.Data = seg.Data[:offset] m.dataSegments = append(m.dataSegments, &newSeg) } } sort.Sort(sortByAddress(m.dataSegments)) } func (m *Memory) parseIntelHexRecord(bytes []byte) error { if len(bytes) < 5 { return newParseError(_DATA_ERROR, "not enought data bytes", m.lineNum) } err := checkSum(bytes) if err != nil { return newParseError(_CHECKSUM_ERROR, err.Error(), m.lineNum) } err = checkRecordSize(bytes) if err != nil { return newParseError(_DATA_ERROR, err.Error(), m.lineNum) } switch record_type := bytes[3]; record_type { case _DATA_RECORD: a, data := getDataLine(bytes) adr := uint32(a) + m.extendedAddress err = m.AddBinary(adr, data) if err != nil { return err } case _EOF_RECORD: err = checkEOF(bytes) if err != nil { return newParseError(_RECORD_ERROR, err.Error(), m.lineNum) } m.eofFlag = true case _ADR_20_RECORD: fallthrough case _ADR_32_RECORD: m.extendedAddress, err = getExtendedAddress(bytes) if err != nil { return newParseError(_RECORD_ERROR, err.Error(), m.lineNum) } case _START_RECORD: if m.startFlag == true { return newParseError(_DATA_ERROR, "multiple start address lines", m.lineNum) } m.startAddress, err = getStartAddress(bytes) if err != nil { return newParseError(_RECORD_ERROR, err.Error(), m.lineNum) } m.startFlag = true } return nil } func (m *Memory) parseIntelHexLine(line string) error { if len(line) == 0 { return nil } if line[0] != ':' { return newParseError(_SYNTAX_ERROR, "no colon char on the first line character", m.lineNum) } bytes, err := hex.DecodeString(line[1:]) if err != nil { return newParseError(_SYNTAX_ERROR, err.Error(), m.lineNum) } return m.parseIntelHexRecord(bytes) } // Method to parsing IntelHex data and add into memory func (m *Memory) ParseIntelHex(reader io.Reader) error { scanner := bufio.NewScanner(reader) m.Clear() for scanner.Scan() { m.lineNum++ line := scanner.Text() err := m.parseIntelHexLine(line) if err != nil { return err } } if err := scanner.Err(); err != nil { return newParseError(_SYNTAX_ERROR, err.Error(), m.lineNum) } if m.eofFlag == false { return newParseError(_DATA_ERROR, "no end of file line", m.lineNum) } return nil } func (m *Memory) dumpDataSegment(writer io.Writer, s *DataSegment, lineLength byte) error { lineAdr := s.Address lineData := []byte{} for byteAdr := s.Address; byteAdr < s.Address+uint32(len(s.Data)); byteAdr++ { if ((byteAdr & 0xFFFF0000) != m.extendedAddress) || (m.firstAddressFlag == false) { m.firstAddressFlag = true if len(lineData) != 0 { err := writeDataLine(writer, &lineAdr, byteAdr, &lineData) if err != nil { return err } } m.extendedAddress = (byteAdr & 0xFFFF0000) writeExtendedAddressLine(writer, m.extendedAddress) } if len(lineData) >= int(lineLength) { err := writeDataLine(writer, &lineAdr, byteAdr, &lineData) if err != nil { return err } } lineData = append(lineData, s.Data[byteAdr-s.Address]) } if len(lineData) != 0 { return writeDataLine(writer, &lineAdr, 0, &lineData) } return nil } // Method to dumping IntelHex data previously loaded into memory func (m *Memory) DumpIntelHex(writer io.Writer, lineLength byte) error { if m.startFlag { err := writeStartAddressLine(writer, m.startAddress) if err != nil { return err } } m.firstAddressFlag = false m.extendedAddress = 0 for _, s := range m.dataSegments { err := m.dumpDataSegment(writer, s, lineLength) if err != nil { return err } } return writeEofLine(writer) } // Method to load binary data previously loaded into memory func (m *Memory) ToBinary(address uint32, size uint32, padding byte) []byte { data := make([]byte, size) i := uint32(0) for i < size { ok := false for _, s := range m.dataSegments { if (address >= s.Address) && (address < s.Address+uint32(len(s.Data))) { data[i] = s.Data[address-s.Address] i++ address++ ok = true break } } if ok == false { data[i] = padding i++ address++ } } return data } marcinbor85-gohex-4141bde/gohex_test.go000066400000000000000000000573101514610601600200670ustar00rootroot00000000000000package gohex import ( "bytes" "reflect" "strings" "testing" ) func TestConstructor(t *testing.T) { m := NewMemory() if a, ok := m.GetStartAddress(); ok != false || a != 0 { t.Error("incorrect initial start Address") } if len(m.GetDataSegments()) != 0 { t.Error("incorrect initial data segments") } if m.extendedAddress != 0 { t.Error("incorrect initial data segments") } } func parseIntelHex(m *Memory, str string) error { return m.ParseIntelHex(strings.NewReader(str)) } func checkErrorType(t *testing.T, err error, et parseErrorType, msg string) { if err != nil { perr, ok := err.(*parseError) if ok == true { if perr.errorType != et { t.Error(perr.Error()) t.Error(err) } } else { t.Error(err) } } else { t.Error(msg) } } func assertParseError(t *testing.T, m *Memory, input string, et parseErrorType, err string) { e := parseIntelHex(m, input) checkErrorType(t, e, et, err) } func TestSyntaxError(t *testing.T) { m := NewMemory() assertParseError(t, m, "00000001FF\n", _SYNTAX_ERROR, "no colon error") assertParseError(t, m, ":qw00000001FF\n", _SYNTAX_ERROR, "no ascii hex error") assertParseError(t, m, ":0000001FF\n", _SYNTAX_ERROR, "no odd/even hex error") } func TestDataError(t *testing.T) { m := NewMemory() assertParseError(t, m, ":000000FF\n", _DATA_ERROR, "no line length error") assertParseError(t, m, ":02000000FE\n", _DATA_ERROR, "no data length error") assertParseError(t, m, "\n", _DATA_ERROR, "no end of file line error") assertParseError(t, m, ":000000FF01\n", _DATA_ERROR, "no end of file line error") assertParseError(t, m, ":0400000501000000F6\n", _DATA_ERROR, "no end of file line error") assertParseError(t, m, ":0400000501000000F6\n:0400000502000000F5\n:00000001FF\n", _DATA_ERROR, "no multiple start Address lines error") assertParseError(t, m, ":048000000102030472\n:04800300050607085F\n:00000001FF\n", _DATA_ERROR, "no segments overlap error") assertParseError(t, m, ":048000000102030472\n:047FFD000506070866\n:00000001FF\n", _DATA_ERROR, "no segments overlap error") } func TestChecksumError(t *testing.T) { m := NewMemory() assertParseError(t, m, ":00000101FF\n", _CHECKSUM_ERROR, "no checksum error") assertParseError(t, m, ":00000001FE\n", _CHECKSUM_ERROR, "no checksum error") assertParseError(t, m, ":0000000001\n", _CHECKSUM_ERROR, "no checksum error") assertParseError(t, m, ":000000FF02\n", _CHECKSUM_ERROR, "no checksum error") } func TestRecordsError(t *testing.T) { m := NewMemory() assertParseError(t, m, ":00000101FE\n", _RECORD_ERROR, "no eof record error") assertParseError(t, m, ":00010001FE\n", _RECORD_ERROR, "no eof record error") assertParseError(t, m, ":0100000100FE\n", _RECORD_ERROR, "no eof record error") assertParseError(t, m, ":020001040101F7\n", _RECORD_ERROR, "no extended Address record error") assertParseError(t, m, ":020100040101F7\n", _RECORD_ERROR, "no extended Address record error") assertParseError(t, m, ":03000004010100F7\n", _RECORD_ERROR, "no extended Address record error") assertParseError(t, m, ":0400010501010101F2\n", _RECORD_ERROR, "no start Address record error") assertParseError(t, m, ":0401000501010101F2\n", _RECORD_ERROR, "no start Address record error") assertParseError(t, m, ":050000050101010100F2\n", _RECORD_ERROR, "no start Address record error") } func TestAddress(t *testing.T) { m := NewMemory() err := parseIntelHex(m, ":020000041234B4\n:0400000501020304ED\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if m.lineNum != 3 { t.Error("incorrect lines number") } if m.extendedAddress != 0x12340000 { t.Errorf("incorrect extended Address: %08X", m.extendedAddress) } if a, ok := m.GetStartAddress(); a != 0x01020304 && ok == true { t.Errorf("incorrect start Address: %08X", m.startAddress) } if len(m.GetDataSegments()) != 0 { t.Error("incorrect data segments") } if m.eofFlag != true { t.Error("incorrect eof flag state") } if m.startFlag != true { t.Error("incorrect start flag state") } err = parseIntelHex(m, ":020000049ABCA4\n:0400000591929394AD\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if m.extendedAddress != 0x9ABC0000 { t.Errorf("incorrect extended Address: %08X", m.extendedAddress) } if a, ok := m.GetStartAddress(); a != 0x91929394 && ok == true { t.Errorf("incorrect start Address: %08X", m.startAddress) } err = parseIntelHex(m, ":020000041234B4\n:02000004234592\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if m.extendedAddress != 0x23450000 { t.Errorf("incorrect extended Address: %08X", m.extendedAddress) } } func TestDataSegments(t *testing.T) { m := NewMemory() err := parseIntelHex(m, ":048000000102030472\n:04800400050607085E\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 1 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg := m.GetDataSegments()[0] p := DataSegment{Address: 0x8000, Data: []byte{1, 2, 3, 4, 5, 6, 7, 8}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } err = parseIntelHex(m, ":048000000102030472\n:047FFC000506070867\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 1 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0x7FFC, Data: []byte{5, 6, 7, 8, 1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } err = parseIntelHex(m, ":048000000102030472\n:04800800050607085A\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0x8000, Data: []byte{1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x8008, Data: []byte{5, 6, 7, 8}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } err = parseIntelHex(m, ":04800800050607085A\n:048000000102030472\n\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0x8000, Data: []byte{1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x8008, Data: []byte{5, 6, 7, 8}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } err = parseIntelHex(m, ":020000041000EA\n:048000000102030472\n:04800800050607085A\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0x10008000, Data: []byte{1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x10008008, Data: []byte{5, 6, 7, 8}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } err = parseIntelHex(m, ":020000042000DA\n:048000000506070862\n:020000041000EA\n:048000000102030472\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0x10008000, Data: []byte{1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x20008000, Data: []byte{5, 6, 7, 8}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } } func TestClear(t *testing.T) { m := NewMemory() err := parseIntelHex(m, ":020000049ABCA4\n:0400000591929394AD\n:048000000102030472\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } m.Clear() if m.lineNum != 0 { t.Error("incorrect lines number") } if len(m.GetDataSegments()) != 0 { t.Error("incorrect data segments") } if m.extendedAddress != 0 { t.Errorf("incorrect extended Address: %08X", m.extendedAddress) } if a, _ := m.GetStartAddress(); a != 0 { t.Errorf("incorrect start Address: %08X", m.extendedAddress) } if m.eofFlag != false { t.Error("incorrect eof flag state") } if m.startFlag != false { t.Error("incorrect start flag state") } } func TestAddBinary(t *testing.T) { m := NewMemory() err := m.AddBinary(0x20000, []byte{1, 2, 3, 4}) err = m.AddBinary(0x20004, []byte{5, 6, 7, 8}) if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 1 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg := m.GetDataSegments()[0] p := DataSegment{Address: 0x20000, Data: []byte{1, 2, 3, 4, 5, 6, 7, 8}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } err = m.AddBinary(0x10000, []byte{1, 2, 3, 4}) err = m.AddBinary(0xFFFC, []byte{5, 6, 7, 8}) if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0xFFFC, Data: []byte{5, 6, 7, 8, 1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x20000, Data: []byte{1, 2, 3, 4, 5, 6, 7, 8}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } err = m.AddBinary(0x15000, []byte{1, 2, 3, 4}) err = m.AddBinary(0x14FF8, []byte{5, 6, 7, 8, 9, 10, 11, 12}) if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 3 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0xFFFC, Data: []byte{5, 6, 7, 8, 1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x14FF8, Data: []byte{5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[2] p = DataSegment{Address: 0x20000, Data: []byte{1, 2, 3, 4, 5, 6, 7, 8}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } err = m.AddBinary(0x15000, []byte{1, 2, 3, 4}) m.Clear() err = m.AddBinary(0x0008, []byte{9, 10, 11, 12}) err = m.AddBinary(0x0000, []byte{1, 2, 3, 4}) err = m.AddBinary(0x0004, []byte{5, 6, 7, 8}) if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 1 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0x0000, Data: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } } func TestDataOverlaps(t *testing.T) { m := NewMemory() err := m.AddBinary(0x0004, []byte{1, 2, 3, 4}) if err != nil { t.Error("unexpected error: ", err.Error()) } err = m.AddBinary(0x0000, []byte{5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) checkErrorType(t, err, _DATA_ERROR, "no data segments overlaps error") err = m.AddBinary(0x0005, []byte{5, 6}) checkErrorType(t, err, _DATA_ERROR, "no data segments overlaps error") err = m.AddBinary(0x0002, []byte{1, 2, 3, 4}) checkErrorType(t, err, _DATA_ERROR, "no data segments overlaps error") err = m.AddBinary(0x0006, []byte{1, 2, 3, 4}) checkErrorType(t, err, _DATA_ERROR, "no data segments overlaps error") err = m.AddBinary(0x0008, []byte{5}) if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 1 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg := m.GetDataSegments()[0] p := DataSegment{Address: 0x0004, Data: []byte{1, 2, 3, 4, 5}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } } func TestSetStartMemory(t *testing.T) { m := NewMemory() m.SetStartAddress(0x12345678) if a, ok := m.GetStartAddress(); a != 0x12345678 || ok != true { t.Errorf("wrong start address: %v", a) } err := parseIntelHex(m, ":020000049ABCA4\n:048000000102030472\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if a, ok := m.GetStartAddress(); a != 0 || ok != false { t.Errorf("wrong start address: %v", a) } err = parseIntelHex(m, ":020000049ABCA4\n:0400000591929394AD\n:048000000102030472\n:00000001FF\n") if err != nil { t.Error("unexpected error: ", err.Error()) } if a, ok := m.GetStartAddress(); a != 0x91929394 || ok != true { t.Errorf("wrong start address: %v", a) } m.SetStartAddress(0x23456789) if a, ok := m.GetStartAddress(); a != 0x23456789 || ok != true { t.Errorf("wrong start address: %v", a) } } func TestMultiSegmentsParse(t *testing.T) { m := NewMemory() err := parseIntelHex(m, ":020000025000AC\n" + ":10000000A5A9AEFC5FAAB488B8A8860F8BC79C943C\n" + ":0200000260009C\n" + ":10000000F384980CA450DC26572ECE667CAF34DFE8\n" + ":0200000460009A\n" + ":10000000F384980CA450DC26572ECE667CAF34DEE9\n" + ":00000001FF\n"); if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 3 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg := m.GetDataSegments()[0] p := DataSegment{Address: 0x00050000, Data: []byte{0xA5, 0xA9, 0xAE, 0xFC, 0x5F, 0xAA, 0xB4, 0x88, 0xB8, 0xA8, 0x86, 0x0F, 0x8B, 0xC7, 0x9C, 0x94}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x00060000, Data: []byte{0xF3, 0x84, 0x98, 0x0C, 0xA4, 0x50, 0xDC, 0x26, 0x57, 0x2E, 0xCE, 0x66, 0x7C, 0xAF, 0x34, 0xDF}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[2] p = DataSegment{Address: 0x60000000, Data: []byte{0xF3, 0x84, 0x98, 0x0C, 0xA4, 0x50, 0xDC, 0x26, 0x57, 0x2E, 0xCE, 0x66, 0x7C, 0xAF, 0x34, 0xDE}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } } func TestExtendedAddressIntelHex(t *testing.T) { m := NewMemory() oks := ":020000020000FC\n" + ":0C0000000102030405060708090A0B0CA6\n" + ":020000023000CC\n" + ":048000000102030472\n" + ":00000001FF\n" err := parseIntelHex(m, oks) if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg := m.GetDataSegments()[0] p := DataSegment{Address: 0x0000, Data: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x38000, Data: []byte{1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } } func TestDumpIntelHex(t *testing.T) { m := NewMemory() m.SetStartAddress(0x12345678) m.AddBinary(0x18000, []byte{1, 2, 3, 4}) m.AddBinary(0x20000000, []byte{11, 12, 13, 14}) m.AddBinary(0x8, []byte{9, 10, 11, 12}) m.AddBinary(0x0, []byte{1, 2, 3, 4}) m.AddBinary(0x4, []byte{5, 6, 7, 8}) buf := bytes.Buffer{} m.DumpIntelHex(&buf, 16) dump := buf.String() oks := ":0400000512345678E3\n" + ":020000040000FA\n" + ":0C0000000102030405060708090A0B0CA6\n" + ":020000040001F9\n" + ":048000000102030472\n" + ":020000042000DA\n" + ":040000000B0C0D0ECA\n" + ":00000001FF\n" if buf.String() != oks { t.Errorf("wrong hex dump:\n%v", dump) } m.Clear() err := parseIntelHex(m, buf.String()) if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 3 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg := m.GetDataSegments()[0] p := DataSegment{Address: 0x0000, Data: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x18000, Data: []byte{1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[2] p = DataSegment{Address: 0x20000000, Data: []byte{11, 12, 13, 14}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } m.Clear() m.AddBinary(0xFFFC, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}) m.AddBinary(0x10040, []byte{1, 2, 3, 4}) buf = bytes.Buffer{} m.DumpIntelHex(&buf, 16) dump = buf.String() oks = ":020000040000FA\n" + ":04FFFC0001020304F7\n" + ":020000040001F9\n" + ":1000000005060708090A0B0C0D0E0F101112131428\n" + ":040010001516171892\n" + ":0400400001020304B2\n" + ":00000001FF\n" if buf.String() != oks { t.Errorf("wrong hex dump:\n%v", dump) } m.Clear() err = parseIntelHex(m, buf.String()) if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0xFFFC, Data: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } seg = m.GetDataSegments()[1] p = DataSegment{Address: 0x10040, Data: []byte{1, 2, 3, 4}} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } m.Clear() d := make([]byte, 512) m.AddBinary(0x2FF20, d) buf = bytes.Buffer{} m.DumpIntelHex(&buf, 64) dump = buf.String() oks = ":020000040002F8\n" + ":40FF200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A1\n" + ":40FF60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061\n" + ":40FFA0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021\n" + ":20FFE000000000000000000000000000000000000000000000000000000000000000000001\n" + ":020000040003F7\n" + ":4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0\n" + ":400040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080\n" + ":400080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040\n" + ":4000C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n" + ":200100000000000000000000000000000000000000000000000000000000000000000000DF\n" + ":00000001FF\n" if buf.String() != oks { t.Errorf("wrong hex dump:\n%v", dump) } m.Clear() err = parseIntelHex(m, buf.String()) if err != nil { t.Error("unexpected error: ", err.Error()) } if len(m.GetDataSegments()) != 1 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } seg = m.GetDataSegments()[0] p = DataSegment{Address: 0x2FF20, Data: make([]byte, 512)} if reflect.DeepEqual(seg, p) == false { t.Errorf("incorrect segment: %v != %v", seg, p) } } func TestToBinary(t *testing.T) { m := NewMemory() m.AddBinary(0x20000000, []byte{11, 12, 13, 14}) m.AddBinary(0xA, []byte{9, 10, 11, 12}) m.AddBinary(0x4, []byte{5, 6, 7, 8}) data := m.ToBinary(0, 16, 0xFF) org := []byte{0xFF, 0xFF, 0xFF, 0xFF, 5, 6, 7, 8, 0xFF, 0xFF, 9, 10, 11, 12, 0xFF, 0xFF} if reflect.DeepEqual(data, org) == false { t.Errorf("incorrect binary data: %v", data) } data = m.ToBinary(0x1FFFFFFF, 8, 0) org = []byte{0, 11, 12, 13, 14, 0, 0, 0} if reflect.DeepEqual(data, org) == false { t.Errorf("incorrect binary data: %v", data) } } func TestSetBinary(t *testing.T) { m := NewMemory() m.AddBinary(0x00, []byte{0, 1, 2, 3}) m.AddBinary(0x08, []byte{8, 9, 10, 11}) m.AddBinary(0x10, []byte{16, 17, 18, 19}) m.SetBinary(0x02, []byte{102, 103, 4, 5, 6, 7, 108, 109, 110, 111, 12, 13}) data := m.ToBinary(0, 20, 0xFF) org := []byte{0, 1, 102, 103, 4, 5, 6, 7, 108, 109, 110, 111, 12, 13, 0xFF, 0xFF, 16, 17, 18, 19} if reflect.DeepEqual(data, org) == false { t.Errorf("incorrect binary data: %v", data) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } } func TestRemoveBinary(t *testing.T) { m := NewMemory() m.AddBinary(0x00, []byte{0, 1, 2, 3, 4, 5, 6, 7}) m.AddBinary(0x0A, []byte{0, 1, 2, 3}) m.AddBinary(0x10, []byte{8, 9, 10, 11}) m.RemoveBinary(0x02, 4) m.RemoveBinary(0x0C, 6) data := m.ToBinary(0, 20, 0xFF) org := []byte{0, 1, 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 0xFF, 0xFF, 0, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 10, 11} if reflect.DeepEqual(data, org) == false { t.Errorf("incorrect binary data: %v", data) } if len(m.GetDataSegments()) != 4 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } m.Clear() m.AddBinary(0x00, []byte{0, 1, 2, 3, 4, 5, 6, 7}) m.AddBinary(0x0A, []byte{0, 1, 2, 3}) m.AddBinary(0x10, []byte{8, 9, 10, 11}) m.RemoveBinary(0x00, 4) m.RemoveBinary(0x0A, 4) data = m.ToBinary(0, 20, 0xFF) org = []byte{0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 8, 9, 10, 11} if reflect.DeepEqual(data, org) == false { t.Errorf("incorrect binary data: %v", data) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } m.Clear() m.AddBinary(0x00, []byte{0, 1}) m.RemoveBinary(0x00, 2) data = m.ToBinary(0, 4, 0xFF) org = []byte{0xFF, 0xFF, 0xFF, 0xFF} if reflect.DeepEqual(data, org) == false { t.Errorf("incorrect binary data: %v", data) } if len(m.GetDataSegments()) != 0 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } m.Clear() m.AddBinary(0x00, []byte{0, 1, 2, 3, 4, 5, 6, 7}) m.AddBinary(0x0A, []byte{0, 1, 2, 3}) m.AddBinary(0x10, []byte{8, 9, 10, 11}) m.RemoveBinary(0x0A, 4) data = m.ToBinary(0, 20, 0xFF) org = []byte{0, 1, 2, 3, 4, 5, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 8, 9, 10, 11} if reflect.DeepEqual(data, org) == false { t.Errorf("incorrect binary data: %v", data) } if len(m.GetDataSegments()) != 2 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } m.AddBinary(0x0A, []byte{0, 1, 2, 3}) data = m.ToBinary(0, 20, 0xFF) org = []byte{0, 1, 2, 3, 4, 5, 6, 7, 0xFF, 0xFF, 0, 1, 2, 3, 0xFF, 0xFF, 8, 9, 10, 11} if reflect.DeepEqual(data, org) == false { t.Errorf("incorrect binary data: %v", data) } if len(m.GetDataSegments()) != 3 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } m.Clear() m.AddBinary(0x00, []byte{0, 1}) m.RemoveBinary(0x02, 2) data = m.ToBinary(0, 4, 0xFF) org = []byte{0, 1, 0xFF, 0xFF} if reflect.DeepEqual(data, org) == false { t.Errorf("incorrect binary data: %v", data) } if len(m.GetDataSegments()) != 1 { t.Errorf("incorrect number of data segments: %v", len(m.GetDataSegments())) } } marcinbor85-gohex-4141bde/helper.go000066400000000000000000000057701514610601600172000ustar00rootroot00000000000000package gohex import ( "encoding/binary" "encoding/hex" "errors" "fmt" "io" "strings" ) func calcSum(bytes []byte) byte { sum := 0 for _, b := range bytes { sum += int(b) } sum %= 256 sum = 256 - sum return byte(sum) } func checkSum(bytes []byte) error { sum := calcSum(bytes[:len(bytes)-1]) last := bytes[len(bytes)-1] if sum != last { return errors.New("incorrect checksum (sum = " + fmt.Sprintf("%02X != %02X", sum, last) + ")") } return nil } func checkRecordSize(bytes []byte) error { if (int(bytes[0]) + 5) != len(bytes) { return errors.New("incorrect data length") } return nil } func checkEOF(bytes []byte) error { if bytes[0] != 0 { return errors.New("incorrect data length field in eof line") } if binary.BigEndian.Uint16(bytes[1:3]) != 0 { return errors.New("incorrect address field in eof line") } return nil } func getExtendedAddress(bytes []byte) (adr uint32, err error) { if bytes[0] != 2 { return 0, errors.New("incorrect data length field in extended linear address line") } if binary.BigEndian.Uint16(bytes[1:3]) != 0 { return 0, errors.New("incorrect address field in extended linear address line") } adr = uint32(binary.BigEndian.Uint16(bytes[4:6])) << (1 << bytes[3]) return adr, nil } func getDataLine(bytes []byte) (adr uint16, data []byte) { size := bytes[0] adr = binary.BigEndian.Uint16(bytes[1:3]) data = bytes[4 : size+4] return adr, data } func getStartAddress(bytes []byte) (adr uint32, err error) { if bytes[0] != 4 { return 0, errors.New("incorrect data length field in start address line") } if binary.BigEndian.Uint16(bytes[1:3]) != 0 { return 0, errors.New("incorrect address field in start address line") } adr = binary.BigEndian.Uint32(bytes[4:8]) return adr, nil } func makeDataLine(adr uint16, recordType byte, data []byte) []byte { line := make([]byte, 5+len(data)) line[0] = byte(len(data)) binary.BigEndian.PutUint16(line[1:3], adr) line[3] = recordType copy(line[4:], data) line[len(line)-1] = calcSum(line[:len(line)-1]) return line } func writeDataLine(writer io.Writer, lineAdr *uint32, byteAdr uint32, lineData *[]byte) error { s := strings.ToUpper(hex.EncodeToString(makeDataLine(uint16(*lineAdr&0x0000FFFF), _DATA_RECORD, *lineData))) _, err := fmt.Fprintf(writer, ":%s\n", s) *lineAdr = byteAdr *lineData = []byte{} return err } func writeStartAddressLine(writer io.Writer, startAdr uint32) error { a := make([]byte, 4) binary.BigEndian.PutUint32(a, startAdr) s := strings.ToUpper(hex.EncodeToString(makeDataLine(0, _START_RECORD, a))) _, err := fmt.Fprintf(writer, ":%s\n", s) return err } func writeExtendedAddressLine(writer io.Writer, extAdr uint32) { a := make([]byte, 2) binary.BigEndian.PutUint16(a, uint16(extAdr>>16)) s := strings.ToUpper(hex.EncodeToString(makeDataLine(0, _ADR_32_RECORD, a))) fmt.Fprintf(writer, ":%s\n", s) } func writeEofLine(writer io.Writer) error { s := strings.ToUpper(hex.EncodeToString(makeDataLine(0, _EOF_RECORD, []byte{}))) _, err := fmt.Fprintf(writer, ":%s\n", s) return err }