Xyris  0.5
rs232.cpp
Go to the documentation of this file.
1 /**
2  * @file rs232.cpp
3  * @author Keeton Feavel ([email protected])
4  * @brief
5  * @version 0.3
6  * @date 2020-06-29
7  *
8  * @copyright Copyright the Xyris Contributors (c) 2020
9  *
10  * TODO: Make this module robust enough for fast transmission of binary data
11  * currently it adequately supports slow, character transmission.
12  *
13  */
14 
15 #include <Arch/Arch.hpp>
16 #include <Devices/Serial/rs232.hpp>
17 #include <Library/RingBuffer.hpp>
18 #include <Library/stdio.hpp>
19 #include <Library/string.hpp>
20 #include <Locking/RAII.hpp>
21 #include <Logger.hpp>
22 #include <Memory/heap.hpp>
23 #include <stdarg.h>
24 
25 #define RS_232_COM1_IRQ 0x04
26 #define RS_232_COM3_IRQ 0x04
27 #define RS_232_COM2_IRQ 0x03
28 #define RS_232_COM4_IRQ 0x03
29 
30 #define RS_232_DATA_REG 0x0
31 #define RS_232_INTERRUPT_ENABLE_REG 0x1
32 #define RS_232_INTERRUPT_IDENTIFICATION_REG 0x2
33 #define RS_232_LINE_CONTROL_REG 0x3
34 #define RS_232_MODEM_CONTROL_REG 0x4
35 #define RS_232_LINE_STATUS_REG 0x5
36 #define RS_232_MODEM_STATUS_REG 0x6
37 #define RS_232_SCRATCH_REG 0x7
38 
39 namespace RS232 {
40 
41 static uint16_t rs_232_port_base;
42 static RingBuffer<char, 1024> ring;
43 static Mutex mutex_rs232("rs232");
44 
45 static int received();
46 static int is_transmit_empty();
47 static char read_byte();
48 static void callback(struct registers* regs);
49 
50 static int received()
51 {
52  return readByte(rs_232_port_base + RS_232_LINE_STATUS_REG) & 1;
53 }
54 
55 static int is_transmit_empty()
56 {
57  return readByte(rs_232_port_base + RS_232_LINE_STATUS_REG) & 0x20;
58 }
59 
60 static char read_byte()
61 {
62  lockedRegion([]() {
63  while (received() == 0)
64  ;
65  },
66  mutex_rs232);
67  return readByte(rs_232_port_base + RS_232_DATA_REG);
68 }
69 
70 static int vprintf_helper(unsigned c, void** ptr)
71 {
72  // Unfortunately very hacky...
73  (void)ptr;
74  char buf = (char)c;
75  write(&buf, 1);
76  return 0;
77 }
78 
79 int vprintf(const char* fmt, va_list args)
80 {
81  int retval;
82  retval = printf_helper(fmt, args, vprintf_helper, NULL);
83  return retval;
84 }
85 
86 int printf(const char* format, ...)
87 {
88  va_list args;
89  int ret_val;
90 
91  va_start(args, format);
92  ret_val = vprintf(format, args);
93  va_end(args);
94  return ret_val;
95 }
96 
97 static void callback(struct registers* regs)
98 {
99  (void)regs;
100  // Grab the input character
101  char in = read_byte();
102  // Change carriage returns to newlines
103  if (in == '\r') {
104  in = '\n';
105  }
106  printf("%c", in);
107  // Add the character to the circular buffer
108  ring.Enqueue(in);
109 }
110 
111 // FIXME: Use separate ring buffers for COM1 & COM2
112 void init(uint16_t com_id)
113 {
114  // Register the IRQ callback
115  rs_232_port_base = com_id;
116  uint8_t IRQ = 0x20 + (com_id == RS_232_COM1 ? RS_232_COM1_IRQ : RS_232_COM2_IRQ);
117  Interrupts::registerHandler(IRQ, callback);
118  // Write the port data to activate the device
119  // disable interrupts
120  writeByte(rs_232_port_base + RS_232_INTERRUPT_ENABLE_REG, 0x00);
121  writeByte(rs_232_port_base + RS_232_LINE_CONTROL_REG, 0x80);
122  writeByte(rs_232_port_base + RS_232_DATA_REG, 0x03);
123  writeByte(rs_232_port_base + RS_232_INTERRUPT_ENABLE_REG, 0x00);
124  writeByte(rs_232_port_base + RS_232_LINE_CONTROL_REG, 0x03);
125  writeByte(rs_232_port_base + RS_232_INTERRUPT_IDENTIFICATION_REG, 0xC7);
126  writeByte(rs_232_port_base + RS_232_MODEM_CONTROL_REG, 0x0B);
127  writeByte(rs_232_port_base + RS_232_LINE_CONTROL_REG, 0x00);
128  // re-enable interrupts
129  writeByte(rs_232_port_base + RS_232_INTERRUPT_ENABLE_REG, 0x01);
130 
133  "\033[93m\n"
134  " _ __ _ _____\n"
135  " | |/ /_ _______(_)____ _ _|__ /\n"
136  " | / / / / ___/ / ___/ | | / //_ <\n"
137  " / / /_/ / / / (__ ) | |/ /__/ /\n"
138  "/_/|_\\__, /_/ /_/____/ |___/____/\n"
139  " /____/\n"
140  "\n\033[0m"
141  "Xyris Serial Output Debugger\n\n");
142 }
143 
144 size_t read(char* buf, size_t count)
145 {
146  size_t bytes = 0;
147  mutex_rs232.lock();
148  for (size_t idx = 0; idx < count && !ring.IsEmpty(); idx++) {
149  buf[idx] = ring.Dequeue();
150  bytes++;
151  }
152  mutex_rs232.unlock();
153  return bytes;
154 }
155 
156 size_t write(const char* buf, size_t count)
157 {
158  // Wait for previous transfer to complete
159  while (is_transmit_empty() == 0);
160  size_t bytes = 0;
161  for (size_t idx = 0; idx < count; idx++) {
162  writeByte(rs_232_port_base + RS_232_DATA_REG, buf[idx]);
163  bytes++;
164  }
165  return bytes;
166 }
167 
168 int close()
169 {
170  return 0;
171 }
172 
173 } // !namespace RS232
RS_232_LINE_STATUS_REG
#define RS_232_LINE_STATUS_REG
Definition: rs232.cpp:35
Mutex::unlock
bool unlock()
Release the mutex.
Definition: Mutex.cpp:38
stdio.hpp
RAII.hpp
Resource Acquisition Is Initialization mutex. Locks when constructed and unlocks when destructed.
RingBuffer.hpp
A ring buffer is a buffer method where the same memory used to contain data is reused....
RS_232_MODEM_CONTROL_REG
#define RS_232_MODEM_CONTROL_REG
Definition: rs232.cpp:34
RS232::write
size_t write(const char *buf, size_t count)
Write bytes to the serial device.
Definition: rs232.cpp:156
RS_232_COM1_IRQ
#define RS_232_COM1_IRQ
Definition: rs232.cpp:25
string.hpp
Standard string and memory utility library.
registers
A structure definining values for all x86 registers. Cannot be namespaced due to C linkage and ASM in...
Definition: regs.hpp:19
RS232::read
size_t read(char *buf, size_t count)
Reads bytes from the serial buffer.
Definition: rs232.cpp:144
Interrupts::registerHandler
void registerHandler(uint8_t interrupt, InterruptHandler_t handler)
Definition: isr.cpp:98
Mutex
Definition: Mutex.hpp:16
Mutex::lock
bool lock()
Aquire the mutex.
Definition: Mutex.cpp:20
RS232::vprintf
int vprintf(const char *fmt, va_list args)
Prints a formatted string to serial output using a va_list of arguments.
Definition: rs232.cpp:79
rs232.hpp
A simple, write-only driver for the RS232 serial device standard. Code mostly ported from Panix-Archi...
RS_232_INTERRUPT_ENABLE_REG
#define RS_232_INTERRUPT_ENABLE_REG
Definition: rs232.cpp:31
Arch.hpp
Architecture control and initialization.
RS_232_COM2_IRQ
#define RS_232_COM2_IRQ
Definition: rs232.cpp:27
Logger::addWriter
static bool addWriter(LogWriter writer)
Definition: Logger.cpp:119
RS_232_INTERRUPT_IDENTIFICATION_REG
#define RS_232_INTERRUPT_IDENTIFICATION_REG
Definition: rs232.cpp:32
RS232::close
int close()
Closes the serial input buffer and frees all of the data contained within.
Definition: rs232.cpp:168
lockedRegion
void lockedRegion(Function lockedWork, Mutex &mutex)
Mutex protected region lambda function. Executed the provided function after locking the provided mut...
Definition: RAII.hpp:55
Logger::Print
static void Print(const char *fmt,...)
Definition: Logger.cpp:111
RS232::init
void init(uint16_t com_id)
Activates the RS232 serial driver.
Definition: rs232.cpp:112
RS_232_DATA_REG
#define RS_232_DATA_REG
Definition: rs232.cpp:30
writeByte
void writeByte(uint16_t port, uint8_t data)
Writes a byte (8 bits) to the CPU bus at a given port address.
Definition: ports.cpp:19
RS_232_COM1
#define RS_232_COM1
Definition: rs232.hpp:18
RS232
Definition: rs232.cpp:39
heap.hpp
Liballoc heap implementation.
printf_helper
int printf_helper(const char *fmt, va_list args, printf_cb_fnptr_t fn, void *ptr)
Perform all printf operations on the format string using the provided argument list and uses the call...
Definition: printf.cpp:105
RingBuffer
Definition: RingBuffer.hpp:19
readByte
uint8_t readByte(uint16_t port)
Reads a byte (8 bits) off the CPU bus at a given port address.
Definition: ports.cpp:13
RS_232_LINE_CONTROL_REG
#define RS_232_LINE_CONTROL_REG
Definition: rs232.cpp:33
RS232::printf
int printf(const char *format,...)
Prints a formatted string to serial output.
Definition: rs232.cpp:86
Logger.hpp