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  }