diff --git a/.gitignore b/.gitignore index c2485fd..99205a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -usbtest/usbtest \ No newline at end of file +.idea/ +stRttLogger/stRttLogger diff --git a/accessport.go b/accessport.go index 4771b99..e362184 100644 --- a/accessport.go +++ b/accessport.go @@ -50,16 +50,13 @@ func (h *StLinkHandle) usbInitAccessPort(apNum byte) error { log.Debugf("init ap_num = %d", apNum) - h.usbInitBuffer(transferRxEndpoint, 16) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ - h.cmdbuf[h.cmdidx] = debugApiV2InitAccessPort - h.cmdidx++ - h.cmdbuf[h.cmdidx] = apNum - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugApiV2InitAccessPort) + ctx.cmdBuffer.WriteByte(apNum) - retVal := h.usbTransferErrCheck(h.databuf, 2) + retVal := h.usbTransferErrCheck(ctx, 2) if retVal != nil { return errors.New("could not init access port on device") diff --git a/constants.go b/constants.go index ceb5d76..bfd444a 100644 --- a/constants.go +++ b/constants.go @@ -136,40 +136,40 @@ const ( cmdGetTargetVoltage = 0xF7 ) -const ( - //STLINK_DEBUG_GETSTATUS = 0x01 - //STLINK_DEBUG_FORCEDEBUG = 0x02 - //STLINK_DEBUG_APIV1_RESETSYS = 0x03 - //STLINK_DEBUG_APIV1_READALLREGS = 0x04 - //STLINK_DEBUG_APIV1_READREG = 0x05 - //STLINK_DEBUG_APIV1_WRITEREG = 0x06 +// ST-Link debug commands +const ( + //debugEnterJTag = 0x00 + //debugGetStatus = 0x01 + //debugForceDebug = 0x02 + //debugApiV1ResetSys = 0x03 + //debugApiV1ReadAllRegs = 0x04 + //debugApiV1ReadReg = 0x05 + //debugApiV1WriteReg = 0x06 debugReadMem32Bit = 0x07 debugWriteMem32Bit = 0x08 - //STLINK_DEBUG_RUNCORE = 0x09 - //STLINK_DEBUG_STEPCORE = 0x0a - //STLINK_DEBUG_APIV1_SETFP = 0x0b + //debugRunCore = 0x09 + //debugStepCore = 0x0a + //debugApiV1SetFP = 0x0b debugReadMem8Bit = 0x0c debugWriteMem8Bit = 0x0d - //STLINK_DEBUG_APIV1_CLEARFP = 0x0e - //STLINK_DEBUG_APIV1_WRITEDEBUGREG = 0x0f - //STLINK_DEBUG_APIV1_SETWATCHPOINT = 0x10 - //STLINK_DEBUG_ENTER_JTAG_RESET = 0x00 - debugEnterSwdNoReset = 0xa3 - debugEnterJTagNoReset = 0xa4 + //debugApiV1ClearFP = 0x0e + //debugApiV1WriteDebugReg = 0x0f + //debugApiV1SetWatchPoint = 0x10 debugApiV1Enter = 0x20 debugExit = 0x21 debugReadCoreId = 0x22 debugApiV2Enter = 0x30 debugApiV2ReadIdCodes = 0x31 - //STLINK_DEBUG_APIV2_RESETSYS = 0x32 - //STLINK_DEBUG_APIV2_READREG = 0x33 - //STLINK_DEBUG_APIV2_WRITEREG = 0x34 - //STLINK_DEBUG_APIV2_WRITEDEBUGREG = 0x35 - //STLINK_DEBUG_APIV2_READDEBUGREG = 0x36 - //STLINK_DEBUG_APIV2_READALLREGS = 0x3A - debugApiV2GetLastRWStatus = 0x3B - debugApiV2DriveNrst = 0x3C - debugApiV2GetLastRWStatus2 = 0x3E + //debugApiV2ResetSys = 0x32 + //debugApiV2ReadReg = 0x33 + //debugApiV2WriteReg = 0x34 + //debugApiV2WriteDebugReg = 0x35 + //debugApiV2ReadDebugReg = 0x36 + //debugApiV2ReadAllRegs = 0x3A + debugApiV2GetLastRWStatus = 0x3B + debugApiV2DriveNrst = 0x3C + debugApiV2GetLastRWStatus2 = 0x3E + debugApiV2StartTraceRx = 0x40 debugApiV2StopTraceRx = 0x41 debugApiV2GetTraceNB = 0x42 @@ -181,9 +181,12 @@ const ( debugApiV2WriteMem16Bit = 0x48 debugApiV2InitAccessPort = 0x4B debugApiV2CloseAccessPortDbg = 0x4C - //STLINK_DEBUG_APIV2_DRIVE_NRST_LOW = 0x00 - //STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH = 0x01 - //STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE = 0x02 + //STLINK_DEBUG_APIV2_DRIVE_NRST_LOW = 0x00 + //STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH = 0x01 + //STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE = 0x02 + + debugEnterSwdNoReset = 0xa3 + debugEnterJTagNoReset = 0xa4 debugApiV3SetComFreq = 0x61 debugApiV3GetComFreq = 0x62 diff --git a/cpus.go b/cpus.go new file mode 100644 index 0000000..6f294c5 --- /dev/null +++ b/cpus.go @@ -0,0 +1,37 @@ +// Copyright 2020 Sebastian Lehmann. All rights reserved. +// Use of this source code is governed by a GNU-style +// license that can be found in the LICENSE file. + +// this code is mainly inspired and based on the openocd project source code +// for detailed information see + +// https://sourceforge.net/p/openocd/code + +package gostlink + +type StmCpuInfo struct { + RamStart uint64 + RamSize uint64 +} + +var supportedStmCpus = map[string]StmCpuInfo{ + "STM32F030F4": {0x20000000, 0x1000}, + "STM32F030K6": {0x20000000, 0x1000}, + "STM32F030C6": {0x20000000, 0x1000}, + "STM32F030C8": {0x20000000, 0x2000}, + "STM32F030R8": {0x20000000, 0x2000}, + "STM32F030CC": {0x20000000, 0x8000}, + "STM32F030RC": {0x20000000, 0x8000}, + "STM32F070F6": {0x20000000, 0x2000}, + "STM32F070C6": {0x20000000, 0x2000}, + "STM32F070CB": {0x20000000, 0x4000}, + "STM32F070RB": {0x20000000, 0x4000}, +} + +func GetCpuInformation(cpuId string) *StmCpuInfo { + if val, ok := supportedStmCpus[cpuId]; ok { + return &val + } else { + return nil + } +} diff --git a/errors.go b/errors.go index 799b42a..cb8c02b 100644 --- a/errors.go +++ b/errors.go @@ -31,10 +31,12 @@ func newUsbError(msg string, code usbErrorCode) error { Converts an STLINK status code held in the first byte of a response to an gostlink library error, logs any error/wait status as debug output. */ -func (h *StLinkHandle) usbErrorCheck() error { +func (h *StLinkHandle) usbErrorCheck(ctx* transferCtx) error { + + errorStatus := ctx.dataBuffer.Bytes()[0] if h.stMode == StLinkModeDebugSwim { - switch h.databuf[0] { + switch errorStatus { case swimErrorOk: return nil @@ -42,16 +44,16 @@ func (h *StLinkHandle) usbErrorCheck() error { return newUsbError("swim is busy", usbErrorWait) default: - return newUsbError(fmt.Sprintf("unknown/unexpected STLINK status code 0x%x", h.databuf[0]), usbErrorFail) + return newUsbError(fmt.Sprintf("unknown/unexpected STLINK status code 0x%x", errorStatus), usbErrorFail) } } /* TODO: no error checking yet on api V1 */ if h.version.jtagApi == jTagApiV1 { - h.databuf[0] = debugErrorOk + errorStatus = debugErrorOk } - switch h.databuf[0] { + switch errorStatus { case debugErrorOk: return nil @@ -109,6 +111,6 @@ func (h *StLinkHandle) usbErrorCheck() error { return newUsbError("STLINK_BAD_AP_ERROR", usbErrorFail) default: - return newUsbError(fmt.Sprintf("unknown/unexpected STLINK status code 0x%x", h.databuf[0]), usbErrorFail) + return newUsbError(fmt.Sprintf("unknown/unexpected STLINK status code 0x%x", errorStatus), usbErrorFail) } } diff --git a/go.mod b/go.mod index 3cbde53..20175e0 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,9 @@ go 1.14 require ( github.com/boljen/go-bitmap v0.0.0-20151001105940-23cd2fb0ce7d github.com/google/gousb v2.1.0+incompatible + github.com/mattn/go-colorable v0.1.7 // indirect + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/sirupsen/logrus v1.6.0 + github.com/x-cray/logrus-prefixed-formatter v0.5.2 + golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de // indirect ) diff --git a/go.sum b/go.sum index bebeb1d..6624d74 100644 --- a/go.sum +++ b/go.sum @@ -6,9 +6,27 @@ github.com/google/gousb v2.1.0+incompatible h1:ApzMDjF3FeO219QwWybJxYfFhXQzPLOEy github.com/google/gousb v2.1.0+incompatible/go.mod h1:Tl4HdAs1ThE3gECkNwz+1MWicX6FXddhJEw7L8jRDiI= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/logger.go b/logger.go index 1267978..81e593d 100644 --- a/logger.go +++ b/logger.go @@ -8,11 +8,21 @@ import ( "os" "github.com/sirupsen/logrus" + "github.com/x-cray/logrus-prefixed-formatter" ) const MaxLogLevel = logrus.DebugLevel func init() { + formatter := &prefixed.TextFormatter{ + DisableColors: false, + TimestampFormat: "15:04:05", + FullTimestamp: true, + ForceFormatting: true, + } + + logrus.SetFormatter(formatter) + logrus.SetOutput(os.Stdout) logrus.SetLevel(MaxLogLevel) } diff --git a/memory.go b/memory.go index fe19bda..e39c35d 100644 --- a/memory.go +++ b/memory.go @@ -22,33 +22,27 @@ func (h *StLinkHandle) usbReadMem8(addr uint32, len uint16, buffer *bytes.Buffer return newUsbError(fmt.Sprintf("max buffer (%d) length exceeded", h.usbBlock()), usbErrorFail) } - h.usbInitBuffer(transferRxEndpoint, readLen) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugReadMem8Bit) - h.cmdbuf[h.cmdidx] = debugReadMem8Bit - h.cmdidx++ - - uint32ToLittleEndian(h.cmdbuf[h.cmdidx:], addr) - h.cmdidx += 4 - - uint16ToLittleEndian(h.cmdbuf[h.cmdidx:], len) - h.cmdidx += 2 + uint32ToLittleEndian(&ctx.cmdBuffer, addr) + uint16ToLittleEndian(&ctx.cmdBuffer, len) // we need to fix read length for single bytes if readLen == 1 { readLen++ } - err := h.usbTransferNoErrCheck(h.databuf, readLen) + err := h.usbTransferNoErrCheck(ctx, readLen) if err != nil { return newUsbError(fmt.Sprintf("ReadMem8 transfer error occurred"), usbErrorFail) } - buffer.Write(h.databuf[:len]) + buffer.Write(ctx.dataBuffer.Bytes()) return h.usbGetReadWriteStatus() } @@ -64,27 +58,21 @@ func (h *StLinkHandle) usbReadMem16(addr uint32, len uint16, buffer *bytes.Buffe return newUsbError("ReadMem16 Invalid data alignment", usbErrorTargetUnalignedAccess) } - h.usbInitBuffer(transferRxEndpoint, uint32(len)) - - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = debugApiV2ReadMem16Bit - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugApiV2ReadMem16Bit) - uint32ToLittleEndian(h.cmdbuf[h.cmdidx:], addr) - h.cmdidx += 4 + uint32ToLittleEndian(&ctx.cmdBuffer, addr) + uint16ToLittleEndian(&ctx.cmdBuffer, len) - uint16ToLittleEndian(h.cmdbuf[h.cmdidx:], len) - h.cmdidx += 2 - - err := h.usbTransferNoErrCheck(h.databuf, uint32(len)) + err := h.usbTransferNoErrCheck(ctx, uint32(len)) if err != nil { return newUsbError("ReadMem16 transfer error occurred", usbErrorFail) } - buffer.Write(h.databuf[:len]) + buffer.Write(ctx.dataBuffer.Bytes()) return h.usbGetReadWriteStatus() } @@ -96,27 +84,21 @@ func (h *StLinkHandle) usbReadMem32(addr uint32, len uint16, buffer *bytes.Buffe return newUsbError("ReadMem32 Invalid data alignment", usbErrorTargetUnalignedAccess) } - h.usbInitBuffer(transferRxEndpoint, uint32(len)) - - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = debugReadMem32Bit - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugReadMem32Bit) - uint32ToLittleEndian(h.cmdbuf[h.cmdidx:], addr) - h.cmdidx += 4 + uint32ToLittleEndian(&ctx.cmdBuffer, addr) + uint16ToLittleEndian(&ctx.cmdBuffer, len) - uint16ToLittleEndian(h.cmdbuf[h.cmdidx:], len) - h.cmdidx += 2 - - err := h.usbTransferNoErrCheck(h.databuf, uint32(len)) + err := h.usbTransferNoErrCheck(ctx, uint32(len)) if err != nil { return newUsbError("ReadMem32 transfer error occurred", usbErrorFail) } - buffer.Write(h.databuf[:len]) + buffer.Write(ctx.dataBuffer.Bytes()) return h.usbGetReadWriteStatus() } @@ -128,21 +110,17 @@ func (h *StLinkHandle) usbWriteMem8(address uint32, len uint16, buffer []byte) e return newUsbError(fmt.Sprintf("max buffer (%d) length exceeded", h.usbBlock()), usbErrorFail) } - h.usbInitBuffer(transferTxEndpoint, writeLen) - - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx := h.initTransfer(transferTxEndpoint) - h.cmdbuf[h.cmdidx] = debugWriteMem8Bit - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugWriteMem8Bit) - uint32ToLittleEndian(h.cmdbuf[h.cmdidx:], address) - h.cmdidx += 4 + uint32ToLittleEndian(&ctx.cmdBuffer, address) + uint16ToLittleEndian(&ctx.cmdBuffer, len) - uint16ToLittleEndian(h.cmdbuf[h.cmdidx:], len) - h.cmdidx += 2 + ctx.dataBuffer.Write(buffer[:len]) - err := h.usbTransferNoErrCheck(buffer, writeLen) + err := h.usbTransferNoErrCheck(ctx, writeLen) if err != nil { return err @@ -163,21 +141,17 @@ func (h *StLinkHandle) usbWriteMem16(address uint32, len uint16, buffer []byte) return newUsbError("ReadMem16 Invalid data alignment", usbErrorTargetUnalignedAccess) } - h.usbInitBuffer(transferTxEndpoint, writeLen) + ctx := h.initTransfer(transferTxEndpoint) - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugApiV2WriteMem16Bit) - h.cmdbuf[h.cmdidx] = debugApiV2WriteMem16Bit - h.cmdidx++ + uint32ToLittleEndian(&ctx.cmdBuffer, address) + uint16ToLittleEndian(&ctx.cmdBuffer, len) - uint32ToLittleEndian(h.cmdbuf[h.cmdidx:], address) - h.cmdidx += 4 + ctx.dataBuffer.Write(buffer[:len]) - uint16ToLittleEndian(h.cmdbuf[h.cmdidx:], len) - h.cmdidx += 2 - - err := h.usbTransferNoErrCheck(buffer, writeLen) + err := h.usbTransferNoErrCheck(ctx, writeLen) if err != nil { return err @@ -194,21 +168,17 @@ func (h *StLinkHandle) usbWriteMem32(address uint32, len uint16, buffer []byte) return newUsbError("ReadMem32 Invalid data alignment", usbErrorTargetUnalignedAccess) } - h.usbInitBuffer(transferTxEndpoint, writeLen) - - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx := h.initTransfer(transferTxEndpoint) - h.cmdbuf[h.cmdidx] = debugWriteMem32Bit - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugWriteMem32Bit) - uint32ToLittleEndian(h.cmdbuf[h.cmdidx:], address) - h.cmdidx += 4 + uint32ToLittleEndian(&ctx.cmdBuffer, address) + uint16ToLittleEndian(&ctx.cmdBuffer, len) - uint16ToLittleEndian(h.cmdbuf[h.cmdidx:], len) - h.cmdidx += 2 + ctx.dataBuffer.Write(buffer[:len]) - err := h.usbTransferNoErrCheck(buffer, writeLen) + err := h.usbTransferNoErrCheck(ctx, writeLen) if err != nil { return err diff --git a/mode.go b/mode.go index e227cfd..e13420f 100644 --- a/mode.go +++ b/mode.go @@ -26,67 +26,58 @@ func (h *StLinkHandle) usbModeEnter(stMode StLinkMode) error { rxSize = 2 } - h.usbInitBuffer(transferRxEndpoint, rxSize) + ctx := h.initTransfer(transferRxEndpoint) switch stMode { case StLinkModeDebugJtag: - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) if h.version.jtagApi == jTagApiV1 { - h.cmdbuf[h.cmdidx] = debugApiV1Enter + ctx.cmdBuffer.WriteByte(debugApiV1Enter) } else { - h.cmdbuf[h.cmdidx] = debugApiV2Enter + ctx.cmdBuffer.WriteByte(debugApiV2Enter) } - h.cmdidx++ - h.cmdbuf[h.cmdidx] = debugEnterJTagNoReset - h.cmdidx++ + ctx.cmdBuffer.WriteByte(debugEnterJTagNoReset) case StLinkModeDebugSwd: - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) if h.version.jtagApi == jTagApiV1 { - h.cmdbuf[h.cmdidx] = debugApiV1Enter + ctx.cmdBuffer.WriteByte(debugApiV1Enter) } else { - h.cmdbuf[h.cmdidx] = debugApiV2Enter + ctx.cmdBuffer.WriteByte(debugApiV2Enter) } - h.cmdidx++ - h.cmdbuf[h.cmdidx] = debugEnterSwdNoReset - h.cmdidx++ + ctx.cmdBuffer.WriteByte(debugEnterSwdNoReset) case StLinkModeDebugSwim: - h.cmdbuf[h.cmdidx] = cmdSwim - h.cmdidx++ - h.cmdbuf[h.cmdidx] = swimEnter - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdSwim) + ctx.cmdBuffer.WriteByte(swimEnter) /* swim enter does not return any response or status */ - return h.usbTransferNoErrCheck(h.databuf, 0) + return h.usbTransferNoErrCheck(ctx, 0) case StLinkModeDfu: case StLinkModeMass: default: return errors.New("cannot set usb mode from DFU or mass stlink configuration") } - return h.usbCmdAllowRetry(h.databuf, rxSize) + return h.usbCmdAllowRetry(ctx, rxSize) } func (h *StLinkHandle) usbCurrentMode() (byte, error) { - h.usbInitBuffer(transferRxEndpoint, 2) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdGetCurrentMode - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdGetCurrentMode) - err := h.usbTransferNoErrCheck(h.databuf, 2) + err := h.usbTransferNoErrCheck(ctx, 2) if err != nil { return 0, err } else { - return h.databuf[0], nil + return ctx.dataBuffer.Bytes()[0], nil } } @@ -99,7 +90,7 @@ func (h *StLinkHandle) usbInitMode(connectUnderReset bool, initialInterfaceSpeed return err } - log.Debugf("Got usb mode: %d", mode) + log.Debugf("Current usb mode: 0x%02x", mode) var stLinkMode StLinkMode @@ -149,8 +140,6 @@ func (h *StLinkHandle) usbInitMode(connectUnderReset bool, initialInterfaceSpeed } } - log.Debugf("MODE: 0x%02X", mode) - stLinkMode = h.stMode if stLinkMode == StLinkModeUnknown { @@ -159,12 +148,12 @@ func (h *StLinkHandle) usbInitMode(connectUnderReset bool, initialInterfaceSpeed if stLinkMode == StLinkModeDebugJtag { if (h.version.flags & flagHasJtagSetFreq) != 0 { - dumpSpeedMap(jTAGkHzToSpeedMap[:]) + //dumpSpeedMap(jTAGkHzToSpeedMap[:]) h.SetSpeed(initialInterfaceSpeed, false) } } else if stLinkMode == StLinkModeDebugSwd { if (h.version.flags & flagHasJtagSetFreq) != 0 { - dumpSpeedMap(swdKHzToSpeedMap[:]) + //dumpSpeedMap(swdKHzToSpeedMap[:]) h.SetSpeed(initialInterfaceSpeed, false) } } @@ -173,7 +162,7 @@ func (h *StLinkHandle) usbInitMode(connectUnderReset bool, initialInterfaceSpeed var smap = make([]speedMap, v3MaxFreqNb) h.usbGetComFreq(stLinkMode == StLinkModeDebugJtag, &smap) - dumpSpeedMap(smap) + //dumpSpeedMap(smap) h.SetSpeed(initialInterfaceSpeed, false) } @@ -209,32 +198,24 @@ func (h *StLinkHandle) usbInitMode(connectUnderReset bool, initialInterfaceSpeed return err } - log.Debugf("Mode: 0x%02x", mode) - return nil } func (h *StLinkHandle) usbLeaveMode(mode StLinkMode) error { - h.usbInitBuffer(transferRxEndpoint, 0) + ctx := h.initTransfer(transferRxEndpoint) switch mode { case StLinkModeDebugJtag, StLinkModeDebugSwd: - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ - h.cmdbuf[h.cmdidx] = debugExit - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugExit) case StLinkModeDebugSwim: - h.cmdbuf[h.cmdidx] = cmdSwim - h.cmdidx++ - h.cmdbuf[h.cmdidx] = swimExit - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdSwim) + ctx.cmdBuffer.WriteByte(swimExit) case StLinkModeDfu: - h.cmdbuf[h.cmdidx] = cmdDfu - h.cmdidx++ - h.cmdbuf[h.cmdidx] = dfuExit - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDfu) + ctx.cmdBuffer.WriteByte(dfuExit) case StLinkModeMass: return errors.New("unknown stlink mode") @@ -242,7 +223,7 @@ func (h *StLinkHandle) usbLeaveMode(mode StLinkMode) error { return errors.New("unknown stlink mode") } - err := h.usbTransferNoErrCheck(h.databuf, 0) + err := h.usbTransferNoErrCheck(ctx, 0) return err } diff --git a/rtt.go b/rtt.go index 09797de..6f94e4d 100644 --- a/rtt.go +++ b/rtt.go @@ -9,11 +9,13 @@ package gostlink import ( "bytes" "errors" - "fmt" - log "github.com/sirupsen/logrus" "sort" + + log "github.com/sirupsen/logrus" ) +type RttDataCb func(int, []byte) error + const ( DefaultRamStart = 0x20000000 ) @@ -26,7 +28,7 @@ const ( SeggerRttModeBlockIfFifoFull = 2 ) -// hold size of data structs to avoid working with sifeof (from unsafe package) +// hold size of data structs to avoid working with sizeof (from unsafe package) const ( seggerRttBufferSize = 24 seggerRttControlBlockSize = 24 @@ -61,44 +63,51 @@ type seggerRttInfo struct { controlBlock seggerRttControlBlock } -func (h *StLinkHandle) InitializeRtt(ramSizeKb uint32, ramStart uint32) error { - h.seggerRtt.ramStart = ramStart +func (h *StLinkHandle) InitializeRtt(rttSearchRanges [][2]uint64) error { - ramBuffer := bytes.NewBuffer([]byte{}) + for _, r := range rttSearchRanges { + log.Infof("Searching for SeggerRTT in range [%08x, %08x]", r[0], r[0]+r[1]) - log.Debug("Initializing Segger RTT. Read complete RAM...") + ramStart := uint32(r[0]) + rangeSize := uint32(r[1]) - err := h.ReadMem(ramStart, 4, (ramSizeKb*1024)/4, ramBuffer) + h.seggerRtt.ramStart = ramStart + ramBuffer := bytes.NewBuffer([]byte{}) - if err != nil { - return err - } else { - log.Info("Searching for SeggerRTT control block...") - occ := bytes.Index(ramBuffer.Bytes(), []byte("SEGGER RTT")) + err := h.ReadMem(ramStart, 4, rangeSize/4, ramBuffer) + + if err != nil { + return err + } else { + occ := bytes.Index(ramBuffer.Bytes(), []byte("SEGGER RTT")) - if occ != -1 { - h.seggerRtt.offset = uint32(occ) + if occ != -1 { + h.seggerRtt.offset = uint32(occ) - log.Infof("Found RTT control block at address: 0x%08x", h.seggerRtt.ramStart+h.seggerRtt.offset) - parseRttControlBlock(ramBuffer.Bytes()[h.seggerRtt.offset:], &h.seggerRtt.controlBlock) + log.Infof("Found RTT control block at address: 0x%08x", h.seggerRtt.ramStart+h.seggerRtt.offset) + parseRttControlBlock(ramBuffer.Bytes()[h.seggerRtt.offset:], &h.seggerRtt.controlBlock) - if h.seggerRtt.controlBlock.maxNumDownBuffers == 0 || h.seggerRtt.controlBlock.maxNumUpBuffers == 0 { - return errors.New("could not find up or downstream buffers in rtt block") - } else { - log.Debugf("Got AC-ID: %s, MaxNumUpBuffers: %d, MaxNumDownBuffers: %d", - h.seggerRtt.controlBlock.acId, - h.seggerRtt.controlBlock.maxNumUpBuffers, - h.seggerRtt.controlBlock.maxNumDownBuffers) + if h.seggerRtt.controlBlock.maxNumDownBuffers == 0 || h.seggerRtt.controlBlock.maxNumUpBuffers == 0 { + return errors.New("could not find any up or downstream buffers in rtt block") + } else { + log.Debugf("Got AC-ID: %s, MaxNumUpBuffers: %d, MaxNumDownBuffers: %d", + h.seggerRtt.controlBlock.acId, + h.seggerRtt.controlBlock.maxNumUpBuffers, + h.seggerRtt.controlBlock.maxNumDownBuffers) - h.seggerRtt.controlBlock.channels = make([]*seggerRttChannel, h.seggerRtt.controlBlock.maxNumUpBuffers+ - h.seggerRtt.controlBlock.maxNumDownBuffers) + h.seggerRtt.controlBlock.channels = make([]*seggerRttChannel, h.seggerRtt.controlBlock.maxNumUpBuffers+ + h.seggerRtt.controlBlock.maxNumDownBuffers) - return nil + return nil + } + } else { + log.Warn("Could not find Segger RTT control block id in this range") } - } else { - return errors.New("could not find SEGGER RTT control block id") } } + + return errors.New("could not find any rtt control block in given ranges") + } func (h *StLinkHandle) UpdateRttChannels(readChannelNames bool) error { @@ -157,7 +166,7 @@ func (h *StLinkHandle) UpdateRttChannels(readChannelNames bool) error { return nil } -func (h *StLinkHandle) ReadRttChannels() error { +func (h *StLinkHandle) ReadRttChannels(callback RttDataCb) error { if h.seggerRtt.controlBlock.maxNumUpBuffers == 0 { return errors.New("no channels for reading configured on target") } @@ -213,8 +222,7 @@ func (h *StLinkHandle) ReadRttChannels() error { channelData := bytes.NewBuffer([]byte{}) h.readDataFromRttChannelBuffer(uint32(i), ramBuffer.Bytes(), channelData) - fmt.Printf("%s", channelData.Bytes()) - + callback(i, channelData.Bytes()) } } @@ -227,7 +235,6 @@ func (h *StLinkHandle) readDataFromRttChannelBuffer(channelIdx uint32, ramBuffer RdOff := rttBuffer.rdOff // determine buffer index - bufferOffset := uint32(0) for i, channel := range h.seggerRtt.controlBlock.channels { if uint32(i) >= channelIdx { @@ -249,10 +256,10 @@ func (h *StLinkHandle) readDataFromRttChannelBuffer(channelIdx uint32, ramBuffer if data.Len() > 0 { addressRdOff := h.seggerRtt.ramStart + h.seggerRtt.offset + seggerRttControlBlockSize + channelIdx*seggerRttBufferSize + 16 // 20 bytes rdOff pos - wrBuffer := []byte{0, 0, 0, 0} - uint32ToLittleEndian(wrBuffer, RdOff) + wrBuffer := bytes.Buffer{} + uint32ToLittleEndian(&wrBuffer, RdOff) - err := h.WriteMem(addressRdOff, Memory32BitBlock, 1, wrBuffer) + err := h.WriteMem(addressRdOff, Memory32BitBlock, 1, wrBuffer.Bytes()) if err != nil { return -1, err diff --git a/speed.go b/speed.go index 7144753..d3e7522 100644 --- a/speed.go +++ b/speed.go @@ -159,17 +159,14 @@ func (h *StLinkHandle) usbSetSwdClk(clkDivisor uint16) error { return errors.New("cannot change speed on this firmware") } - h.usbInitBuffer(transferRxEndpoint, 2) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ - h.cmdbuf[h.cmdidx] = flagHasSwdSetFreq - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(flagHasSwdSetFreq) - uint16ToLittleEndian(h.cmdbuf[h.cmdidx:], clkDivisor) - h.cmdidx += 2 + uint16ToLittleEndian(&ctx.cmdBuffer, clkDivisor) - err := h.usbCmdAllowRetry(h.databuf, 2) + err := h.usbCmdAllowRetry(ctx, 2) return err } @@ -177,33 +174,30 @@ func (h *StLinkHandle) usbSetSwdClk(clkDivisor uint16) error { func (h *StLinkHandle) usbGetComFreq(isJtag bool, smap *[]speedMap) error { if h.version.jtagApi != jTagApiV3 { - return errors.New("Unknown command") + return errors.New("unknown command") } - h.usbInitBuffer(transferRxEndpoint, 16) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ - h.cmdbuf[h.cmdidx] = debugApiV3GetComFreq - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugApiV3GetComFreq) if isJtag { - h.cmdbuf[h.cmdidx] = 1 + ctx.cmdBuffer.WriteByte(1) } else { - h.cmdbuf[h.cmdidx] = 0 + ctx.cmdBuffer.WriteByte(0) } - h.cmdidx++ - err := h.usbTransferErrCheck(h.databuf, 52) + err := h.usbTransferErrCheck(ctx, 52) - size := uint32(h.databuf[8]) + size := uint32(ctx.dataBuffer.Bytes()[8]) if size > v3MaxFreqNb { size = v3MaxFreqNb } for i := uint32(0); i < size; i++ { - (*smap)[i].speed = le_to_h_u32(h.databuf[12+4*i:]) + (*smap)[i].speed = le_to_h_u32(ctx.dataBuffer.Bytes()[12+4*i:]) (*smap)[i].speedDivisor = i } @@ -221,26 +215,21 @@ func (h *StLinkHandle) usbSetComFreq(isJtag bool, frequency uint32) error { return errors.New("unknown command") } - h.usbInitBuffer(transferRxEndpoint, 16) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ - h.cmdbuf[h.cmdidx] = debugApiV3SetComFreq - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugApiV3SetComFreq) if isJtag { - h.cmdbuf[h.cmdidx] = 1 + ctx.cmdBuffer.WriteByte(1) } else { - h.cmdbuf[h.cmdidx] = 0 + ctx.cmdBuffer.WriteByte(0) } - h.cmdidx++ - - h.cmdbuf[h.cmdidx] = 0 - h.cmdidx++ + ctx.cmdBuffer.WriteByte(0) - uint32ToLittleEndian(h.cmdbuf[4:], frequency) + uint32ToLittleEndian(&ctx.cmdBuffer, frequency) - err := h.usbTransferErrCheck(h.databuf, 8) + err := h.usbTransferErrCheck(ctx, 8) return err } diff --git a/stRttLogger/main.go b/stRttLogger/main.go new file mode 100644 index 0000000..80a75a5 --- /dev/null +++ b/stRttLogger/main.go @@ -0,0 +1,193 @@ +// Copyright 2020 Sebastian Lehmann. All rights reserved. +// Use of this source code is governed by a GNU-style +// license that can be found in the LICENSE file. + +package main + +import ( + "flag" + "fmt" + "math" + "os" + "os/signal" + "strings" + "syscall" + "time" + + "github.com/bbnote/gostlink" + "github.com/sirupsen/logrus" + log "github.com/sirupsen/logrus" +) + +var ( + exitProgram chan bool + flagLogFile string + flagChannel *int + fileHandle *os.File +) + +func rttDataHandler(channel int, data []byte) error { + if channel != *flagChannel { + return nil + } + + if fileHandle != nil { + fileHandle.Write(data) + } else { + fmt.Print(data) + } + + return nil +} + +func setUpSignalHandler() { + signals := make(chan os.Signal, 1) + exitProgram = make(chan bool, 1) + + signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) + + go func() { + <-signals + exitProgram <- true + }() + +} + +func main() { + log.Info("Welcome to goST-Link library rtt logger...") + + flagLogLevel := flag.Int("LogLevel", int(logrus.DebugLevel), "Logging verbosity [0 - 7]") + flagDevice := flag.String("Device", "", "STM32-Device type") + flagSpeed := flag.Int("Speed", 4000, "Interface speed to target device") + flagInterface := flag.String("if", "SWD", "Interface connecting to target") + flagChannel = flag.Int("RTTChannel", 0, "RTT channel to interface with") + flagRTTAddress := flag.Uint64("RTTAddress", 0, "Sets RTT address to RTTAddress") + flagRTTSearchRanges := flag.String("RTTSearchRanges", "", "RTTSearchRanges [, , ..]") + + flag.Parse() + + log.SetLevel(log.Level(*flagLogLevel)) + + var rttSearchRanges [][2]uint64 + fileHandle = nil + + if len(flag.Args()) == 1 { + flagLogFile = flag.Args()[0] + + file, err := os.OpenFile(flag.Args()[0], os.O_APPEND|os.O_RDWR, 0600) + + if err != nil { + fileHandle = nil + log.Fatal(err) + } + + file.Truncate(0) + file.Seek(0, 0) + + fileHandle = file + + defer fileHandle.Close() + } + + if *flagDevice != "" { + cpuInfo := gostlink.GetCpuInformation(*flagDevice) + + if cpuInfo != nil { + log.Infof("Found device information for %s [0x%x, 0x%x]", *flagDevice, cpuInfo.RamStart, cpuInfo.RamSize) + rttSearchRanges = append(rttSearchRanges, [...]uint64{cpuInfo.RamStart, cpuInfo.RamSize}) + + } else { + log.Errorf("Could not find device information for %s. Looking for RTT command line parameters...", *flagDevice) + os.Exit(-1) + } + } else if *flagRTTAddress != 0 { + rttSearchRanges = append(rttSearchRanges, [...]uint64{*flagRTTAddress, 24}) + + } else if *flagRTTSearchRanges != "" { + + ranges := strings.Split(*flagRTTSearchRanges, ",") + for _, r := range ranges { + var rttStart uint64 = math.MaxUint64 + var rttRange uint64 = math.MaxUint64 + + fmt.Sscanf(r, "%v %v", &rttStart, &rttRange) + + if rttStart != math.MaxUint64 && rttRange != math.MaxUint64 { + log.Debugf("Adding search range [0x%x, 0x%x]", rttStart, rttRange) + rttSearchRanges = append(rttSearchRanges, [...]uint64{rttStart, rttRange}) + } else { + log.Warnf("Discarding invalid search range '%s'...", r) + } + } + } else { + log.Error("Could not find valid device description") + os.Exit(-1) + } + + err := gostlink.InitializeUSB() + if err != nil { + log.Panic(err) + } + + log.Debugf("Opening target %s (%s, %d kHz) on channel %d...", *flagDevice, *flagInterface, + *flagSpeed, *flagChannel) + + setUpSignalHandler() + + config := gostlink.NewStLinkConfig(gostlink.AllSupportedVIds, gostlink.AllSupportedPIds, + gostlink.StLinkModeDebugSwd, "", uint32(*flagSpeed), false) + + stLink, err := gostlink.NewStLink(config) + + if stLink == nil { + log.Fatal("Could not find any st-link on your computer") + } + + code, err := stLink.GetIdCode() + + if err == nil { + log.Infof("Got id code: %08x", code) + } + + err = stLink.InitializeRtt(rttSearchRanges) + if err != nil { + log.Error("Error during initialization of Rtt: ", err) + + stLink.Close() + gostlink.CloseUSB() + + os.Exit(-1) + } else { + + } + + exitLoop := false + + for exitLoop == false { + + err := stLink.UpdateRttChannels(false) + + if err != nil { + log.Error(err) + + } + + err = stLink.ReadRttChannels(rttDataHandler) + + if err != nil { + log.Error(err) + } + + select { + case <-exitProgram: + exitLoop = true + default: + + } + + time.Sleep(50 * 1000 * 1000) + } + + stLink.Close() + gostlink.CloseUSB() +} diff --git a/stlink.go b/stlink.go index dd8131f..d69a8a6 100644 --- a/stlink.go +++ b/stlink.go @@ -12,9 +12,10 @@ package gostlink import ( "bytes" "errors" + "time" + "github.com/google/gousb" log "github.com/sirupsen/logrus" - "time" ) const AllSupportedVIds = 0xFFFF @@ -71,13 +72,7 @@ type StLinkHandle struct { reconnectPending bool // reconnect is needed next time we try to query the status - cmdbuf []byte - - cmdidx uint8 - - databuf []byte - - max_mem_packet uint32 + maxMemPacket uint32 } type StLinkInterfaceConfig struct { @@ -111,10 +106,6 @@ func NewStLink(config *StLinkInterfaceConfig) (*StLinkHandle, error) { handle := &StLinkHandle{} handle.stMode = config.mode - // initialize data buffers for tx and rx - handle.cmdbuf = make([]byte, cmdBufferSize) - handle.databuf = make([]byte, dataBufferSize) - if config.vid == AllSupportedVIds && config.pid == AllSupportedPIds { devices, err = usbFindDevices(goStLinkSupportedVIds, goStLinkSupportedPIds) @@ -182,8 +173,7 @@ func NewStLink(config *StLinkInterfaceConfig) (*StLinkHandle, error) { switch handle.usbDevice.Desc.Product { case stLinkV1Pid: - handle.version.stlink = 1 - handle.txEndpoint, errorTx = handle.usbInterface.OutEndpoint(usbTxEndpointNo) + return nil, errors.New("st-link V1 api not supported by gostlink") case stLinkV3UsbLoaderPid, stLinkV3EPid, stLinkV3SPid, stLinkV32VcpPid: handle.version.stlink = 3 @@ -255,7 +245,7 @@ func NewStLink(config *StLinkInterfaceConfig) (*StLinkHandle, error) { } */ - handle.max_mem_packet = 1 << 10 + handle.maxMemPacket = 1 << 10 err = handle.usbInitAccessPort(0) @@ -275,11 +265,11 @@ func NewStLink(config *StLinkInterfaceConfig) (*StLinkHandle, error) { if i == 4 || i == 3 { /* Cortex-M3/M4 has 4096 bytes autoincrement range */ log.Debug("Set mem packet layout according to Cortex M3/M4") - handle.max_mem_packet = 1 << 12 + handle.maxMemPacket = 1 << 12 } } - log.Debugf("Using TAR autoincrement: %d", handle.max_mem_packet) + log.Debugf("Using TAR autoincrement: %d", handle.maxMemPacket) return handle, nil } @@ -303,20 +293,19 @@ func (h *StLinkHandle) GetTargetVoltage() (float32, error) { return -1.0, errors.New("device does not support voltage measurement") } - h.usbInitBuffer(transferRxEndpoint, 8) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdGetTargetVoltage - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdGetTargetVoltage) - err := h.usbTransferNoErrCheck(h.databuf, 8) + err := h.usbTransferNoErrCheck(ctx, 8) if err != nil { return -1.0, err } /* convert result */ - adcResults[0] = le_to_h_u32(h.databuf) - adcResults[1] = le_to_h_u32(h.databuf[4:]) + adcResults[0] = le_to_h_u32(ctx.dataBuffer.Bytes()) + adcResults[1] = le_to_h_u32(ctx.dataBuffer.Bytes()[4:]) var targetVoltage float32 = 0.0 @@ -337,22 +326,19 @@ func (h *StLinkHandle) GetIdCode() (uint32, error) { return 0, nil } - h.usbInitBuffer(transferRxEndpoint, 12) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) if h.version.jtagApi == jTagApiV1 { - h.cmdbuf[h.cmdidx] = debugReadCoreId - h.cmdidx++ + ctx.cmdBuffer.WriteByte(debugReadCoreId) - retVal = h.usbTransferNoErrCheck(h.databuf, 4) + retVal = h.usbTransferNoErrCheck(ctx, 4) offset = 0 } else { - h.cmdbuf[h.cmdidx] = debugApiV2ReadIdCodes - h.cmdidx++ + ctx.cmdBuffer.WriteByte(debugApiV2ReadIdCodes) - retVal = h.usbTransferErrCheck(h.databuf, 12) + retVal = h.usbTransferErrCheck(ctx, 12) offset = 4 } @@ -360,7 +346,7 @@ func (h *StLinkHandle) GetIdCode() (uint32, error) { return 0, retVal } else { - idCode := le_to_h_u32(h.databuf[offset:]) + idCode := le_to_h_u32(ctx.dataBuffer.Bytes()[offset:]) return idCode, nil } @@ -447,7 +433,7 @@ func (h *StLinkHandle) ReadMem(addr uint32, bitLength MemoryBlockSize, count uin for count > 0 { if bitLength != Memory8BitBlock { - bytesRemaining = h.maxBlockSize(h.max_mem_packet, addr) + bytesRemaining = h.maxBlockSize(h.maxMemPacket, addr) } else { bytesRemaining = h.usbBlock() } @@ -549,7 +535,7 @@ func (h *StLinkHandle) WriteMem(address uint32, bitLength MemoryBlockSize, count for count > 0 { if bitLength != Memory8BitBlock { - bytesRemaining = h.maxBlockSize(h.max_mem_packet, address) + bytesRemaining = h.maxBlockSize(h.maxMemPacket, address) } else { bytesRemaining = h.usbBlock() } @@ -649,21 +635,18 @@ func (h *StLinkHandle) WriteMem(address uint32, bitLength MemoryBlockSize, count func (h *StLinkHandle) PollTrace(buffer []byte, size *uint32) error { if h.trace.enabled == true && (h.version.flags&flagHasTrace) != 0 { - h.usbInitBuffer(transferRxEndpoint, 10) - - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = debugApiV2GetTraceNB - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugApiV2GetTraceNB) - err := h.usbTransferNoErrCheck(h.databuf, 2) + err := h.usbTransferNoErrCheck(ctx, 2) if err != nil { return err } - bytesAvailable := uint32(le_to_h_u16(h.databuf)) + bytesAvailable := uint32(le_to_h_u16(ctx.dataBuffer.Bytes())) if bytesAvailable < *size { *size = bytesAvailable diff --git a/trace.go b/trace.go index 524a4ca..a2f2dd1 100644 --- a/trace.go +++ b/trace.go @@ -54,12 +54,12 @@ func (h *StLinkHandle) usbTraceDisable() error { log.Debug("tracing: disable") - h.usbInitBuffer(transferRxEndpoint, 2) - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ - h.cmdbuf[h.cmdidx] = debugApiV2StopTraceRx + ctx := h.initTransfer(transferRxEndpoint) - err := h.usbTransferErrCheck(h.databuf, 2) + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugApiV2StopTraceRx) + + err := h.usbTransferErrCheck(ctx, 2) if err == nil { h.trace.enabled = false @@ -72,20 +72,15 @@ func (h *StLinkHandle) usbTraceDisable() error { func (h *StLinkHandle) usbTraceEnable() error { if (h.version.flags & flagHasTrace) != 0 { - h.usbInitBuffer(transferRxEndpoint, 10) - - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ - h.cmdbuf[h.cmdidx] = debugApiV2StartTraceRx - h.cmdidx++ + ctx := h.initTransfer(transferRxEndpoint) - uint16ToLittleEndian(h.cmdbuf[h.cmdidx:], traceSize) - h.cmdidx += 2 + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugApiV2StartTraceRx) - uint32ToLittleEndian(h.cmdbuf[h.cmdidx:], h.trace.sourceHz) - h.cmdidx += 4 + uint16ToLittleEndian(&ctx.cmdBuffer, traceSize) + uint32ToLittleEndian(&ctx.cmdBuffer, h.trace.sourceHz) - err := h.usbTransferErrCheck(h.databuf, 2) + err := h.usbTransferErrCheck(ctx , 2) if err == nil { h.trace.enabled = true diff --git a/transfer.go b/transfer.go index 3572d78..368e644 100644 --- a/transfer.go +++ b/transfer.go @@ -10,136 +10,132 @@ package gostlink import ( + "bytes" "errors" "fmt" "time" - - log "github.com/sirupsen/logrus" ) -func (h *StLinkHandle) usbInitBuffer(endpoint usbTransferEndpoint, size uint32) { - h.transferEndpoint = endpoint - h.cmdidx = 0 +type transferCtx struct { + cmdBuffer bytes.Buffer + dataBuffer bytes.Buffer - memset(h.cmdbuf, cmdBufferSize, 0) - memset(h.databuf, dataBufferSize, 0) + direction usbTransferEndpoint - if h.version.stlink == 1 { - h.usbTransferV1CreateCmd(endpoint, size) - } + cmdSize uint32 +} + +func (h *StLinkHandle) initTransfer(endpoint usbTransferEndpoint) *transferCtx { + context := &transferCtx{} + + context.direction = endpoint + context.cmdBuffer.Grow(cmdBufferSize) + context.dataBuffer.Grow(dataBufferSize) + context.cmdSize = 0 + + return context } -func (h *StLinkHandle) usbTransferNoErrCheck(buffer []byte, size uint32) error { - var cmdSize int = cmdSizeV2 +func (h *StLinkHandle) usbTransferNoErrCheck(ctx *transferCtx, dataLength uint32) error { + ctx.cmdSize = cmdSizeV2 if h.version.stlink == 1 { - cmdSize = cmdBufferSize - h.cmdbuf[14] = h.cmdidx - 15 + ctx.cmdSize = cmdBufferSize + ctx.cmdBuffer.Bytes()[14] = uint8(ctx.cmdBuffer.Len() - 15) } - err := h.usbTransferReadWrite(cmdSize, buffer, size) + err := h.usbTransferReadWrite(ctx, dataLength) if err != nil { return err } if h.version.stlink == 1 { - err := h.usbTransferV1GetStatus() + err := h.usbTransferV1GetStatus(ctx) - if err == nil { - if h.cmdbuf[12] == 1 { - log.Debug("Check sense") - - err = h.usbTransferV1GetSense() - if err != nil { - return err - } - } + if err != nil { + return err } } return nil } -func (h *StLinkHandle) usbTransferErrCheck(buffer []byte, size uint32) error { +func (h *StLinkHandle) usbTransferErrCheck(ctx *transferCtx, dataLength uint32) error { - err := h.usbTransferNoErrCheck(buffer, size) + err := h.usbTransferNoErrCheck(ctx, dataLength) if err != nil { return err } - return h.usbErrorCheck() + return h.usbErrorCheck(ctx) } -func (h *StLinkHandle) usbTransferReadWrite(cmdSize int, buffer []byte, size uint32) error { +func (h *StLinkHandle) usbTransferReadWrite(ctx *transferCtx, dataLength uint32) error { - _, err := usbWrite(h.txEndpoint, h.cmdbuf[:cmdSize]) + _, err := usbWrite(h.txEndpoint, ctx.cmdBuffer.Bytes()[:ctx.cmdSize]) if err != nil { return err } - if h.transferEndpoint == transferTxEndpoint && size > 0 { + if ctx.direction == transferTxEndpoint && dataLength > 0 { + time.Sleep(time.Millisecond * 10) - _, err = usbWrite(h.txEndpoint, buffer[:size]) + _, err = usbWrite(h.txEndpoint, ctx.dataBuffer.Bytes()[:dataLength]) if err != nil { return err } - } else if h.transferEndpoint == transferRxEndpoint && size > 0 { + } else if h.transferEndpoint == transferRxEndpoint && dataLength > 0 { + + readBuffer := make([]byte, dataLength) - _, err = usbRead(h.rxEndpoint, buffer[:size]) + _, err = usbRead(h.rxEndpoint, readBuffer) if err != nil { return err } + + ctx.dataBuffer.Write(readBuffer) } return nil } -func (h *StLinkHandle) usbTransferV1CreateCmd(endpoint usbTransferEndpoint, size uint32) { - h.cmdbuf[0] = 'U' - h.cmdbuf[1] = 'S' - h.cmdbuf[2] = 'B' - h.cmdbuf[3] = 'C' - h.cmdidx += 4 +func (h *StLinkHandle) usbTransferV1CreateCmd(ctx *transferCtx, cmdLength uint32) { + ctx.cmdBuffer.WriteByte('U') + ctx.cmdBuffer.WriteByte('S') + ctx.cmdBuffer.WriteByte('B') + ctx.cmdBuffer.WriteByte('C') - buf_set_u32(h.cmdbuf[:h.cmdidx], 0, 32, 0) - h.cmdidx += 4 - - buf_set_u32(h.cmdbuf[:h.cmdidx], 0, 32, size) - h.cmdidx += 4 + addU32ToBuffer(&ctx.cmdBuffer,0,32,0) + addU32ToBuffer(&ctx.cmdBuffer,0,32, cmdLength) /* cbw flags */ - if endpoint == transferRxEndpoint { - h.cmdbuf[h.cmdidx] = usbEndpointIn + if ctx.direction == transferRxEndpoint { + ctx.cmdBuffer.WriteByte(usbEndpointIn) } else { - h.cmdbuf[h.cmdidx] = usbEndpointOut + ctx.cmdBuffer.WriteByte(usbEndpointOut) } - h.cmdidx++ - - h.cmdbuf[h.cmdidx] = 0 /* lun */ - h.cmdidx++ - /* cdb clength (is filled in at xfer) */ - h.cmdbuf[h.cmdidx] = 0 - h.cmdidx++ + ctx.cmdBuffer.WriteByte(0) /* lun */ + ctx.cmdBuffer.WriteByte(0) /* cdb clength (is filled in at xfer) */ } -func (h *StLinkHandle) usbTransferV1GetStatus() error { - memset(h.cmdbuf, cmdBufferSize, 0) +func (h *StLinkHandle) usbTransferV1GetStatus(ctx *transferCtx) error { + ctx.cmdBuffer.Truncate(0) - bytesRead, err := usbRead(h.rxEndpoint, h.cmdbuf) + bytesRead, err := usbRead(h.rxEndpoint, ctx.cmdBuffer.Bytes()) if err != nil || bytesRead != 13 { return errors.New("ST-Link V1 status read error") } - t1 := buf_get_u32(h.cmdbuf, 0, 32) + t1 := buf_get_u32(ctx.cmdBuffer.Bytes(), 0, 32) /* check for USBS */ if t1 != 0x53425355 { @@ -152,56 +148,29 @@ func (h *StLinkHandle) usbTransferV1GetStatus() error { * 1 command failure * 2 phase error */ - if h.cmdbuf[12] != 0 { - return errors.New(fmt.Sprintf("got CSW status error %d", h.cmdbuf[12])) + if ctx.cmdBuffer.Bytes()[12] != 0 { + return errors.New(fmt.Sprintf("got CSW status error %d", ctx.cmdBuffer.Bytes()[12])) } return nil } -func (h *StLinkHandle) usbTransferV1GetSense() error { - - h.usbInitBuffer(transferRxEndpoint, 16) - - h.cmdbuf[h.cmdidx] = cmdRequestSense - h.cmdidx++ - h.cmdbuf[h.cmdidx] = 0 - h.cmdidx++ - h.cmdbuf[h.cmdidx] = 0 - h.cmdidx++ - h.cmdbuf[h.cmdidx] = 0 - h.cmdidx++ - h.cmdbuf[h.cmdidx] = requestSenseLength - - err := h.usbTransferReadWrite(requestSenseLength, h.databuf, 16) - - if err != nil { - return err - } else { - return h.usbTransferV1GetStatus() - } -} - func (h *StLinkHandle) usbGetReadWriteStatus() error { if h.version.jtagApi == jTagApiV1 { return nil } - h.usbInitBuffer(transferRxEndpoint, 2) - - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ + ctx := h.initTransfer(transferRxEndpoint) + ctx.cmdBuffer.WriteByte(cmdDebug) if (h.version.flags & flagHasGetLastRwStatus2) != 0 { - h.cmdbuf[h.cmdidx] = debugApiV2GetLastRWStatus2 - h.cmdidx++ + ctx.cmdBuffer.WriteByte(debugApiV2GetLastRWStatus2) - return h.usbTransferErrCheck(h.databuf, 12) + return h.usbTransferErrCheck(ctx, 12) } else { - h.cmdbuf[h.cmdidx] = debugApiV2GetLastRWStatus - h.cmdidx++ + ctx.cmdBuffer.WriteByte(debugApiV2GetLastRWStatus) - return h.usbTransferErrCheck(h.databuf, 2) + return h.usbTransferErrCheck(ctx, 2) } } diff --git a/usb.go b/usb.go index c0f95f2..3bda8ce 100644 --- a/usb.go +++ b/usb.go @@ -84,10 +84,6 @@ func usbWrite(endpoint *gousb.OutEndpoint, buffer []byte) (int, error) { } -type contextReader interface { - ReadContext(context.Context, []byte) (int, error) -} - func usbRead(endpoint *gousb.InEndpoint, buffer []byte) (int, error) { opCtx := context.Background() @@ -108,25 +104,24 @@ func usbRead(endpoint *gousb.InEndpoint, buffer []byte) (int, error) { func (h *StLinkHandle) usbGetVersion() error { var v, x, y, jtag, swim, msd, bridge byte = 0, 0, 0, 0, 0, 0, 0 - h.usbInitBuffer(transferRxEndpoint, 6) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdGetVersion - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdGetVersion) - err := h.usbTransferNoErrCheck(h.databuf, 6) + err := h.usbTransferNoErrCheck(ctx, 6) if err != nil { return err } - version := be_to_h_u16(h.databuf) + version := be_to_h_u16(ctx.dataBuffer.Bytes()) v = byte((version >> 12) & 0x0f) x = byte((version >> 6) & 0x3f) y = byte(version & 0x3f) - h.vid = gousb.ID(le_to_h_u16(h.databuf[2:])) - h.pid = gousb.ID(le_to_h_u16(h.databuf[4:])) + h.vid = gousb.ID(le_to_h_u16(ctx.dataBuffer.Bytes()[2:])) + h.pid = gousb.ID(le_to_h_u16(ctx.dataBuffer.Bytes()[4:])) switch h.pid { case stLinkV21Pid, stLinkV21NoMsdPid: @@ -148,24 +143,23 @@ func (h *StLinkHandle) usbGetVersion() error { /* STLINK-V3 requires a specific command */ if v == 3 && x == 0 && y == 0 { - h.usbInitBuffer(transferRxEndpoint, 16) + ctxV3 := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = debugApiV3GetVersionEx - h.cmdidx++ + ctxV3.cmdBuffer.WriteByte(debugApiV3GetVersionEx) - err := h.usbTransferNoErrCheck(h.databuf, 12) + err := h.usbTransferNoErrCheck(ctx, 12) if err != nil { return err } - v = h.databuf[0] - swim = h.databuf[1] - jtag = h.databuf[2] - msd = h.databuf[3] - bridge = h.databuf[4] - h.vid = gousb.ID(le_to_h_u16(h.databuf[8:])) - h.pid = gousb.ID(le_to_h_u16(h.databuf[10:])) + v = ctxV3.dataBuffer.Bytes()[0] + swim = ctxV3.dataBuffer.Bytes()[1] + jtag = ctxV3.dataBuffer.Bytes()[2] + msd = ctxV3.dataBuffer.Bytes()[3] + bridge = ctxV3.dataBuffer.Bytes()[4] + h.vid = gousb.ID(le_to_h_u16(ctxV3.dataBuffer.Bytes()[8:])) + h.pid = gousb.ID(le_to_h_u16(ctxV3.dataBuffer.Bytes()[10:])) } h.version.stlink = int(v) @@ -301,12 +295,12 @@ func (h *StLinkHandle) usbGetVersion() error { Returns an openocd result code. */ -func (h *StLinkHandle) usbCmdAllowRetry(buffer []byte, size uint32) error { +func (h *StLinkHandle) usbCmdAllowRetry(ctx *transferCtx, size uint32) error { var retries int = 0 for true { if (h.stMode != StLinkModeDebugSwim) || retries > 0 { - err := h.usbTransferNoErrCheck(buffer, size) + err := h.usbTransferNoErrCheck(ctx, size) if err != nil { return err } @@ -321,7 +315,7 @@ func (h *StLinkHandle) usbCmdAllowRetry(buffer []byte, size uint32) error { } }*/ - err := h.usbErrorCheck() + err := h.usbErrorCheck(ctx) if err != nil { usbError := err.(*usbError) @@ -357,16 +351,13 @@ func (h *StLinkHandle) usbAssertSrst(srst byte) error { return errors.New("could not find rsrt command on target") } - h.usbInitBuffer(transferRxEndpoint, 2) + ctx := h.initTransfer(transferRxEndpoint) - h.cmdbuf[h.cmdidx] = cmdDebug - h.cmdidx++ - h.cmdbuf[h.cmdidx] = debugApiV2DriveNrst - h.cmdidx++ - h.cmdbuf[h.cmdidx] = srst - h.cmdidx++ + ctx.cmdBuffer.WriteByte(cmdDebug) + ctx.cmdBuffer.WriteByte(debugApiV2DriveNrst) + ctx.cmdBuffer.WriteByte(srst) - return h.usbCmdAllowRetry(h.databuf, 2) + return h.usbCmdAllowRetry(ctx, 2) } func (h *StLinkHandle) maxBlockSize(tarAutoIncrBlock uint32, address uint32) uint32 { diff --git a/usbtest/main.go b/usbtest/main.go deleted file mode 100644 index 6d7b923..0000000 --- a/usbtest/main.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2020 Sebastian Lehmann. All rights reserved. -// Use of this source code is governed by a GNU-style -// license that can be found in the LICENSE file. - -package main - -import ( - "github.com/bbnote/gostlink" - log "github.com/sirupsen/logrus" - "os" - "os/signal" - "syscall" - "time" -) - -func main() { - log.Info("Starting usb stlink test-software...") - - err := gostlink.InitializeUSB() - - if err != nil { - log.Panic(err) - } - - config := gostlink.NewStLinkConfig(gostlink.AllSupportedVIds, gostlink.AllSupportedPIds, - gostlink.StLinkModeDebugSwd, "", 10000, false) - - stlink, err := gostlink.NewStLink(config) - - if stlink != nil { - log.Info("Found ST-Link on your computer! :)") - } else { - log.Fatal("Could not find any st-link on your computer") - } - - code, err := stlink.GetIdCode() - - if err == nil { - log.Infof("Got id code: %08x", code) - } - - err = stlink.InitializeRtt(16, gostlink.DefaultRamStart) - - sigs := make(chan os.Signal, 1) - done := make(chan bool, 1) - - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) - - go func() { - <-sigs - done <- true - }() - - exiting := false - - if err == nil { - - for i := 0; i < 30000 && exiting == false; i++ { - - err := stlink.UpdateRttChannels(false) - - if err != nil { - log.Error(err) - - } - - err = stlink.ReadRttChannels() - - if err != nil { - log.Error(err) - } - - select { - case <-done: - exiting = true - default: - - } - - time.Sleep(50 * 1000 * 1000) - } - - } else { - log.Error(err) - } - - stlink.Close() - gostlink.CloseUSB() -} diff --git a/utils.go b/utils.go index 3623ba6..b87f316 100644 --- a/utils.go +++ b/utils.go @@ -4,7 +4,11 @@ package gostlink -import "github.com/google/gousb" +import ( + "bytes" + "github.com/google/gousb" + "log" +) func idExists(slice []gousb.ID, item gousb.ID) bool { for _, element := range slice { @@ -22,21 +26,28 @@ func memset(a []uint8, size int, v uint8) { } } -func buf_set_u32(buffer []uint8, first uint, num uint, value uint32) { - if (num == 32) && (first == 0) { - buffer[3] = uint8((value >> 24) & 0xff) - buffer[2] = uint8((value >> 16) & 0xff) - buffer[1] = uint8((value >> 8) & 0xff) - buffer[0] = uint8((value >> 0) & 0xff) +// Adds an uint32 to current buffer +// it's also possible to determine bit position in buffer and amount of bits to be set + +func addU32ToBuffer(buffer* bytes.Buffer, firstBit uint, numBits uint, value uint32) { + + if (numBits == 32) && (firstBit == 0) { + buffer.WriteByte(uint8((value >> 0) & 0xff)) + buffer.WriteByte(uint8((value >> 8) & 0xff)) + buffer.WriteByte(uint8((value >> 16) & 0xff)) + buffer.WriteByte(uint8((value >> 24) & 0xff)) + } else { - for i := first; i < first+num; i++ { - if ((value >> (i - first)) & 1) == 1 { + log.Panic("Implement bit position setting in addU32ToBuffer") + /* + for i := firstBit; i < firstBit+numBits; i++ { + if ((value >> (i - firstBit)) & 1) == 1 { buffer[i/8] |= 1 << (i % 8) } else { buffer[i/8] &= ^(1 << (i % 8)) } - } + }*/ } } @@ -69,14 +80,16 @@ func le_to_h_u32(buffer []byte) uint32 { return uint32(buffer[0]) | uint32(buffer[1])<<8 | uint32(buffer[2])<<16 | uint32(buffer[3])<<24 } -func uint32ToLittleEndian(buffer []byte, value uint32) { - buffer[3] = byte(value >> 24) - buffer[2] = byte(value >> 16) - buffer[1] = byte(value >> 8) - buffer[0] = byte(value >> 0) + + +func uint32ToLittleEndian(buffer *bytes.Buffer, value uint32) { + buffer.WriteByte(byte(value >> 0)) + buffer.WriteByte(byte(value >> 8)) + buffer.WriteByte(byte(value >> 16)) + buffer.WriteByte(byte(value >> 24)) } -func uint16ToLittleEndian(buffer []byte, value uint16) { - buffer[1] = byte(value >> 8) - buffer[0] = byte(value >> 0) +func uint16ToLittleEndian(buffer *bytes.Buffer, value uint16) { + buffer.WriteByte(byte(value >> 0)) + buffer.WriteByte(byte(value >> 8)) }