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