SatCat5
file_display.cc
1 // Copyright 2024-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <hal_posix/file_display.h>
7 
9 
10 // Workaround to ensure C++11 allocates static constants.
11 // See also: https://stackoverflow.com/questions/8452952/
12 constexpr satcat5::gui::LogColors FileDisplay::LOG_COLORS;
13 
14 // Other useful constants.
15 static constexpr u8 DATA_BLANK[] = {' '};
16 static constexpr u8 DATA_NEWLINE[] = {'\r', '\n'};
17 
18 // Create a "display" using the specified file.
19 FileDisplay::FileDisplay(const char* filename, u16 rows, u16 cols)
20  : satcat5::gui::Display(rows, cols)
21  , m_file(0)
22 {
23  // Open the file in binary mode to avoid \n vs \r\n confusion.
24  m_file = fopen(filename, "wb");
25  if (!m_file) return;
26 
27  // Fill the "display" with blank lines.
28  for (u16 r = 0 ; r < rows ; ++r) {
29  for (u16 c = 0 ; c < cols ; ++c) {
30  fwrite(DATA_BLANK, sizeof(DATA_BLANK), 1, m_file);
31  }
32  fwrite(DATA_NEWLINE, sizeof(DATA_NEWLINE), 1, m_file);
33  }
34 }
35 
36 FileDisplay::~FileDisplay() {
37  if (m_file) fclose(m_file);
38  m_file = 0;
39 }
40 
41 bool FileDisplay::draw(const Cursor& cursor, const DrawCmd& cmd) {
42  // Abort immediately if I/O is impossible.
43  if (!m_file) return false;
44 
45  // Discard commands that go out of bounds.
46  if (cursor.c + cmd.width() > width()) return true;
47 
48  // Calculate the number of bytes per row.
49  u32 row_len = u32(width()) + sizeof(DATA_NEWLINE);
50 
51  // Draw/overwrite each "pixel" affected by this command.
52  for (u16 r = 0 ; r < cmd.height() ; ++r) {
53  // At the start of each row, seek to the write position.
54  u32 rr = (r + cursor.r) % u32(height());
55  u32 posn = row_len * rr + u32(cursor.c);
56  fseek(m_file, posn, SEEK_SET);
57  // Write one character for each column.
58  for (u16 c = 0 ; c < cmd.width() ; ++c) {
59  u8 pixel = cmd.rc(r, c) ? u8(cursor.fg) : u8(cursor.bg);
60  fwrite(&pixel, 1, 1, m_file);
61  }
62  }
63 
64  // The operation always succeeds.
65  return true;
66 }
Required API for display devices.
Definition: gui_display.h:105
u16 width() const
Total size of the display, in pixels.
Definition: gui_display.h:124
u16 height() const
Total size of the display, in pixels.
Definition: gui_display.h:123
Each "draw command" updates a rectangular region of pixels.
Definition: gui_display.h:61
u16 width() const
Size of the rectangular update region.
Definition: gui_display.cc:92
u16 height() const
Size of the rectangular update region.
Definition: gui_display.cc:77
bool rc(u16 r, u16 c) const
Get the new pixel value at the designated row and column.
Definition: gui_display.cc:52
Implement the gui::Display API using a temporary file.
Definition: file_display.h:24
bool draw(const satcat5::gui::Cursor &cursor, const satcat5::gui::DrawCmd &cmd) override
Implement the required draw() method.
Definition: file_display.cc:41
Cursor object tracks position and foreground/background colors.
Definition: gui_display.h:33
u32 fg
Foreground color (format defined by display)
Definition: gui_display.h:36
u16 r
Row coordinate (0 = top)
Definition: gui_display.h:34
u32 bg
Background color (format defined by display)
Definition: gui_display.h:37
u16 c
Column coordinate (0 = left)
Definition: gui_display.h:35
Color parameters for the LogToDisplay class.
Definition: gui_display.h:237