blob: 7f472c0e6b7f2f5f2a69e9f375b9e03f80f282f4 [file] [log] [blame]
Brian Silverman4787a6e2018-10-06 16:00:54 -07001#include "motors/print/itm.h"
2
Austin Schuh7fe04492022-01-02 13:37:21 -08003#include <cstring>
4
5#include "absl/types/span.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07006
Brian Silverman4787a6e2018-10-06 16:00:54 -07007#include "motors/core/itm.h"
8
9namespace frc971 {
10namespace motors {
11namespace {
12
Austin Schuh7fe04492022-01-02 13:37:21 -080013template <int kPort>
14void WriteToPort(absl::Span<const char> buffer) {
Brian Silverman4787a6e2018-10-06 16:00:54 -070015 // This ignores memory barriers etc, because it will be called by
16 // CreatePrinting which must be called before any interrupts are enabled. That
17 // means the only thing we need to worry about is actually getting it
18 // initialized with a minimal number of cycles.
19 static bool is_initialized = false;
20 if (__builtin_expect(!is_initialized, false)) {
21 is_initialized = true;
22 itm::Initialize();
23 }
24
25 const char *next_address = buffer.data();
26 int remaining_bytes = buffer.size();
27
28 // Write small chunks to make the address even.
29 if (remaining_bytes >= 1 && (reinterpret_cast<uintptr_t>(next_address) & 1)) {
30 uint8_t value;
31 memcpy(&value, next_address, 1);
32 itm::Write8(kPort, value);
33 next_address += 1;
34 remaining_bytes -= 1;
35 }
36 if (remaining_bytes >= 2 && (reinterpret_cast<uintptr_t>(next_address) & 2)) {
37 uint16_t value;
38 memcpy(&value, next_address, 2);
39 itm::Write16(kPort, value);
40 next_address += 2;
41 remaining_bytes -= 2;
42 }
43
44 // Write big chunks while we can.
45 while (remaining_bytes >= 4) {
46 uint32_t value;
47 memcpy(&value, next_address, 4);
48 itm::Write32(kPort, value);
49 next_address += 4;
50 remaining_bytes -= 4;
51 }
52
53 // Write out any remaining uneven bytes on the end.
54 if (remaining_bytes >= 2) {
55 uint16_t value;
56 memcpy(&value, next_address, 2);
57 itm::Write16(kPort, value);
58 next_address += 2;
59 remaining_bytes -= 2;
60 }
61 if (remaining_bytes >= 1) {
62 uint8_t value;
63 memcpy(&value, next_address, 1);
64 itm::Write8(kPort, value);
65 next_address += 1;
66 remaining_bytes -= 1;
67 }
68}
69
70} // namespace
71
72::std::unique_ptr<PrintingImplementation> CreatePrinting(
73 const PrintingParameters & /*parameters*/) {
74 return ::std::unique_ptr<PrintingImplementation>(new ItmPrinting());
75}
76
77extern "C" int _write(const int /*file*/, char *const ptr, const int len) {
Austin Schuh7fe04492022-01-02 13:37:21 -080078 WriteToPort<0>(absl::Span<const char>(ptr, len));
Brian Silverman4787a6e2018-10-06 16:00:54 -070079 return len;
80}
81
82ItmPrinting::ItmPrinting() {
83 // Make sure we run the one-time initialization. It's important to do it here
84 // to ensure it's complete before interrupts are enabled, because it's not
85 // interrupt-safe.
86 _write(0, nullptr, 0);
87}
88
Austin Schuh7fe04492022-01-02 13:37:21 -080089int ItmPrinting::WriteStdout(absl::Span<const char> buffer) {
Brian Silverman4787a6e2018-10-06 16:00:54 -070090 WriteToPort<0>(buffer);
91 return buffer.size();
92}
93
Austin Schuh7fe04492022-01-02 13:37:21 -080094int ItmPrinting::WriteDebug(absl::Span<const char> buffer) {
Brian Silverman4787a6e2018-10-06 16:00:54 -070095 WriteToPort<1>(buffer);
96 return buffer.size();
97}
98
99} // namespace motors
100} // namespace frc971