github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/serial-rtt.go (about) 1 //go:build baremetal && serial.rtt 2 3 // Implement Segger RTT support. 4 // This is mostly useful for targets that only have a debug connection 5 // available, and no serial output (or input). It is somewhat like semihosting, 6 // but not unusably slow. 7 // It was originally specified by Segger, but support is available in OpenOCD 8 // for at least the DAPLink debuggers so I assume it works on any SWD debugger. 9 10 package machine 11 12 import ( 13 "runtime/interrupt" 14 "runtime/volatile" 15 "unsafe" 16 ) 17 18 // This symbol name is known by the compiler, see monitor.go. 19 var rttSerialInstance rttSerial 20 21 var Serial = &rttSerialInstance 22 23 func InitSerial() { 24 Serial.Configure(UARTConfig{}) 25 } 26 27 const ( 28 // Some constants, see: 29 // https://github.com/SEGGERMicro/RTT/blob/master/RTT/SEGGER_RTT.h 30 31 rttMaxNumUpBuffers = 1 32 rttMaxNumDownBuffers = 1 33 rttBufferSizeUp = 1024 34 rttBufferSizeDown = 16 35 36 rttModeNoBlockSkip = 0 37 rttModeNoBlockTrim = 1 38 rttModeBlockIfFifoFull = 2 39 ) 40 41 // The debugger knows about the layout of this struct, so it must not change. 42 // This is SEGGER_RTT_CB. 43 type rttControlBlock struct { 44 id [16]volatile.Register8 45 maxNumUpBuffers int32 46 maxNumDownBuffers int32 47 buffersUp [rttMaxNumUpBuffers]rttBuffer 48 buffersDown [rttMaxNumDownBuffers]rttBuffer 49 } 50 51 // Up or down buffer. 52 // This is SEGGER_RTT_BUFFER_UP and SEGGER_RTT_BUFFER_DOWN. 53 type rttBuffer struct { 54 name *byte 55 buffer *volatile.Register8 56 bufferSize uint32 57 writeOffset volatile.Register32 58 readOffset volatile.Register32 59 flags uint32 60 } 61 62 // Static buffers, for the default up and down buffer. 63 var ( 64 rttBufferUpData [rttBufferSizeUp]volatile.Register8 65 rttBufferDownData [rttBufferSizeDown]volatile.Register8 66 ) 67 68 type rttSerial struct { 69 rttControlBlock 70 } 71 72 func (s *rttSerial) Configure(config UARTConfig) error { 73 s.maxNumUpBuffers = rttMaxNumUpBuffers 74 s.maxNumDownBuffers = rttMaxNumDownBuffers 75 76 s.buffersUp[0].name = &[]byte("Terminal\x00")[0] 77 s.buffersUp[0].buffer = &rttBufferUpData[0] 78 s.buffersUp[0].bufferSize = rttBufferSizeUp 79 s.buffersUp[0].flags = rttModeNoBlockSkip 80 81 s.buffersDown[0].name = &[]byte("Terminal\x00")[0] 82 s.buffersDown[0].buffer = &rttBufferDownData[0] 83 s.buffersDown[0].bufferSize = rttBufferSizeDown 84 s.buffersDown[0].flags = rttModeNoBlockSkip 85 86 id := "SEGGER RTT" 87 for i := 0; i < len(id); i++ { 88 s.id[i].Set(id[i]) 89 } 90 91 return nil 92 } 93 94 func (b *rttBuffer) writeByte(c byte) { 95 state := interrupt.Disable() 96 readOffset := b.readOffset.Get() 97 writeOffset := b.writeOffset.Get() 98 newWriteOffset := writeOffset + 1 99 if newWriteOffset == b.bufferSize { 100 newWriteOffset = 0 101 } 102 if newWriteOffset != readOffset { 103 unsafe.Slice(b.buffer, b.bufferSize)[writeOffset].Set(c) 104 b.writeOffset.Set(newWriteOffset) 105 } 106 interrupt.Restore(state) 107 } 108 109 func (b *rttBuffer) readByte() byte { 110 readOffset := b.readOffset.Get() 111 writeOffset := b.writeOffset.Get() 112 for readOffset == writeOffset { 113 readOffset = b.readOffset.Get() 114 } 115 c := unsafe.Slice(b.buffer, b.bufferSize)[readOffset].Get() 116 b.readOffset.Set(readOffset + 1) 117 return c 118 } 119 120 func (b *rttBuffer) buffered() int { 121 readOffset := b.readOffset.Get() 122 writeOffset := b.writeOffset.Get() 123 return int((writeOffset - readOffset) % rttBufferSizeDown) 124 } 125 126 func (s *rttSerial) WriteByte(b byte) error { 127 s.buffersUp[0].writeByte(b) 128 return nil 129 } 130 131 func (s *rttSerial) ReadByte() (byte, error) { 132 return s.buffersDown[0].readByte(), errNoByte 133 } 134 135 func (s *rttSerial) Buffered() int { 136 return s.buffersDown[0].buffered() 137 } 138 139 func (s *rttSerial) Write(data []byte) (n int, err error) { 140 for _, v := range data { 141 s.WriteByte(v) 142 } 143 return len(data), nil 144 }