-
Notifications
You must be signed in to change notification settings - Fork 1
Development #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Development #58
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,203 @@ | ||
#include "Serial.h" | ||
#include "Io.h" | ||
|
||
#define COM1 0x3f8 // COM1 | ||
// Serial port register offsets | ||
#define SERIAL_DATA_REG 0 // Data register (DLAB=0) | ||
#define SERIAL_IER_REG 1 // Interrupt Enable Register (DLAB=0) | ||
#define SERIAL_DIVISOR_LOW 0 // Divisor low byte (DLAB=1) | ||
#define SERIAL_DIVISOR_HIGH 1 // Divisor high byte (DLAB=1) | ||
#define SERIAL_FIFO_REG 2 // FIFO Control Register | ||
#define SERIAL_LCR_REG 3 // Line Control Register | ||
#define SERIAL_MCR_REG 4 // Modem Control Register | ||
#define SERIAL_LSR_REG 5 // Line Status Register | ||
#define SERIAL_MSR_REG 6 // Modem Status Register | ||
|
||
void SerialInit(void) { | ||
outb(COM1 + 1, 0x00); // Disable all interrupts | ||
outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor) | ||
outb(COM1 + 0, 0x03); // Set divisor to 3 (lo byte) -> 38400 baud | ||
outb(COM1 + 1, 0x00); // (hi byte) | ||
outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit | ||
// FIFO: enable (bit0), clear RX (bit1), clear TX (bit2), trigger=14 bytes (bits 6-7=11) | ||
outb(COM1 + 2, 0xC7); | ||
// Modem Control: DTR | RTS | OUT2 (keeps IRQ line enabled at PIC; actual serial IRQs still disabled since IER=0) | ||
outb(COM1 + 4, 0x0B); | ||
// Line Control Register bits | ||
#define SERIAL_LCR_DLAB 0x80 // Divisor Latch Access Bit | ||
#define SERIAL_LCR_8BITS 0x03 // 8 data bits | ||
#define SERIAL_LCR_1STOP 0x00 // 1 stop bit | ||
#define SERIAL_LCR_NOPARITY 0x00 // No parity | ||
|
||
// Line Status Register bits | ||
#define SERIAL_LSR_DATA_READY 0x01 // Data available | ||
#define SERIAL_LSR_TRANSMIT_EMPTY 0x20 // Transmit buffer empty | ||
#define SERIAL_LSR_IDLE 0x40 // Transmitter idle | ||
|
||
// FIFO Control Register bits | ||
#define SERIAL_FIFO_ENABLE 0x01 | ||
#define SERIAL_FIFO_CLEAR_RX 0x02 | ||
#define SERIAL_FIFO_CLEAR_TX 0x04 | ||
#define SERIAL_FIFO_TRIGGER_14 0xC0 | ||
|
||
// Modem Control Register bits | ||
#define SERIAL_MCR_DTR 0x01 | ||
#define SERIAL_MCR_RTS 0x02 | ||
#define SERIAL_MCR_OUT2 0x08 | ||
|
||
static uint16_t serial_port = COM1; | ||
static int serial_initialized = 0; | ||
|
||
int SerialInit(void) { | ||
return SerialInitPort(COM1); | ||
} | ||
|
||
int SerialInitPort(uint16_t port) { | ||
serial_port = port; | ||
|
||
// Test if serial port exists by writing to scratch register | ||
outb(port + 7, 0xAE); | ||
if (inb(port + 7) != 0xAE) { | ||
return -1; // Port doesn't exist | ||
} | ||
|
||
// Disable all interrupts | ||
outb(port + SERIAL_IER_REG, 0x00); | ||
|
||
// Enable DLAB to set baud rate | ||
outb(port + SERIAL_LCR_REG, SERIAL_LCR_DLAB); | ||
|
||
// Set divisor to 3 (38400 baud) | ||
outb(port + SERIAL_DIVISOR_LOW, 0x03); | ||
outb(port + SERIAL_DIVISOR_HIGH, 0x00); | ||
|
||
// Configure: 8 bits, no parity, 1 stop bit | ||
outb(port + SERIAL_LCR_REG, SERIAL_LCR_8BITS | SERIAL_LCR_NOPARITY | SERIAL_LCR_1STOP); | ||
|
||
// Enable and configure FIFO | ||
outb(port + SERIAL_FIFO_REG, SERIAL_FIFO_ENABLE | SERIAL_FIFO_CLEAR_RX | | ||
SERIAL_FIFO_CLEAR_TX | SERIAL_FIFO_TRIGGER_14); | ||
|
||
// Enable DTR, RTS, and OUT2 | ||
outb(port + SERIAL_MCR_REG, SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT2); | ||
|
||
// Test serial chip (loopback test) | ||
outb(port + SERIAL_MCR_REG, SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT2 | 0x10); | ||
outb(port + SERIAL_DATA_REG, 0xAE); | ||
|
||
if (inb(port + SERIAL_DATA_REG) != 0xAE) { | ||
return -2; // Serial chip failed | ||
} | ||
|
||
// Restore normal operation | ||
outb(port + SERIAL_MCR_REG, SERIAL_MCR_DTR | SERIAL_MCR_RTS | SERIAL_MCR_OUT2); | ||
|
||
serial_initialized = 1; | ||
return 0; // Success | ||
} | ||
int is_transmit_empty(void) { | ||
return inb(COM1 + 5) & 0x20; | ||
|
||
int SerialTransmitEmpty(void) { | ||
if (!serial_initialized) return 0; | ||
return inb(serial_port + SERIAL_LSR_REG) & SERIAL_LSR_TRANSMIT_EMPTY; | ||
} | ||
|
||
int SerialDataAvailable(void) { | ||
if (!serial_initialized) return 0; | ||
return inb(serial_port + SERIAL_LSR_REG) & SERIAL_LSR_DATA_READY; | ||
} | ||
|
||
void SerialWriteChar(const char a) { | ||
int SerialWriteChar(const char a) { | ||
if (!serial_initialized) return -1; | ||
|
||
// Timeout counter to prevent infinite loops | ||
int timeout = 65536; | ||
|
||
// If newline, emit CR first, then LF | ||
if (a == '\n') { | ||
while ((inb(COM1 + 5) & 0x20) == 0) {} | ||
outb(COM1, '\r'); | ||
while (!SerialTransmitEmpty() && --timeout > 0); | ||
if (timeout <= 0) return -1; | ||
outb(serial_port + SERIAL_DATA_REG, '\r'); | ||
timeout = 65536; // Reset timeout | ||
} | ||
|
||
while (!SerialTransmitEmpty() && --timeout > 0); | ||
if (timeout <= 0) return -1; | ||
|
||
outb(serial_port + SERIAL_DATA_REG, a); | ||
return 0; | ||
} | ||
|
||
int SerialReadChar(void) { | ||
if (!serial_initialized) return -1; | ||
|
||
if (!SerialDataAvailable()) { | ||
return -1; // No data available | ||
} | ||
while ((inb(COM1 + 5) & 0x20) == 0) {} | ||
outb(COM1, a); | ||
|
||
return inb(serial_port + SERIAL_DATA_REG); | ||
} | ||
|
||
void SerialWrite(const char* str) { | ||
int SerialWrite(const char* str) { | ||
if (!str || !serial_initialized) return -1; | ||
|
||
for (int i = 0; str[i] != '\0'; i++) { | ||
SerialWriteChar(str[i]); | ||
if (SerialWriteChar(str[i]) < 0) { | ||
return -1; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
void SerialWriteHex(uint64_t value) { | ||
if (!serial_initialized) return; | ||
|
||
const char hex[] = "0123456789ABCDEF"; | ||
char buffer[17]; | ||
buffer[16] = '\0'; | ||
|
||
for (int i = 15; i >= 0; i--) { | ||
buffer[15-i] = hex[(value >> (i * 4)) & 0xF]; | ||
} | ||
|
||
SerialWrite(buffer); | ||
} | ||
|
||
void SerialWriteDec(uint64_t value) { | ||
if (!serial_initialized) return; | ||
|
||
if (value == 0) { | ||
SerialWriteChar('0'); | ||
return; | ||
} | ||
|
||
char buffer[21]; // Max digits for uint64_t | ||
int pos = 0; | ||
|
||
while (value > 0) { | ||
buffer[pos++] = '0' + (value % 10); | ||
value /= 10; | ||
} | ||
|
||
// Reverse the string | ||
for (int i = pos - 1; i >= 0; i--) { | ||
SerialWriteChar(buffer[i]); | ||
} | ||
} | ||
|
||
// Read a line from serial (with basic line editing) | ||
int SerialReadLine(char* buffer, int max_length) { | ||
if (!buffer || !serial_initialized || max_length <= 0) return -1; | ||
|
||
int pos = 0; | ||
int c; | ||
|
||
while (pos < max_length - 1) { | ||
c = SerialReadChar(); | ||
if (c < 0) continue; // No data, keep waiting | ||
|
||
if (c == '\r' || c == '\n') { | ||
SerialWriteChar('\n'); // Echo newline | ||
break; | ||
} else if (c == '\b' || c == 0x7F) { // Backspace or DEL | ||
if (pos > 0) { | ||
pos--; | ||
SerialWrite("\b \b"); // Erase character on terminal | ||
} | ||
} else if (c >= 32 && c < 127) { // Printable characters | ||
buffer[pos++] = c; | ||
SerialWriteChar(c); // Echo character | ||
} | ||
} | ||
|
||
buffer[pos] = '\0'; | ||
return pos; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,39 @@ | ||
#ifndef VOIDFRAME_SERIAL_H | ||
#define VOIDFRAME_SERIAL_H | ||
#include "stdint.h" | ||
|
||
void SerialInit(void); | ||
void SerialWriteChar(char c); | ||
void SerialWrite(const char* str); | ||
#include <stdint.h> | ||
|
||
#define COM1 0x3f8 // COM1 | ||
#define COM2 0x2f8 // COM2 | ||
#define COM3 0x3e8 // COM3 | ||
#define COM4 0x2e8 // COM4 | ||
|
||
// Serial port addresses | ||
#define SERIAL_COM1 0x3F8 | ||
#define SERIAL_COM2 0x2F8 | ||
#define SERIAL_COM3 0x3E8 | ||
#define SERIAL_COM4 0x2E8 | ||
|
||
// Initialize serial port (defaults to COM1) | ||
int SerialInit(void); | ||
|
||
// Initialize specific serial port | ||
int SerialInitPort(uint16_t port); | ||
|
||
// Status functions | ||
int SerialTransmitEmpty(void); | ||
int SerialDataAvailable(void); | ||
|
||
// Character I/O | ||
int SerialWriteChar(const char c); | ||
int SerialReadChar(void); | ||
|
||
// String I/O | ||
int SerialWrite(const char* str); | ||
int SerialReadLine(char* buffer, int max_length); | ||
|
||
// Number output | ||
void SerialWriteHex(uint64_t value); | ||
void SerialWriteDec(uint64_t value); | ||
|
||
#endif // VOIDFRAME_SERIAL_H | ||
#endif // VOIDFRAME_SERIAL_H |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Return-type inconsistency hampers error handling
All other I/O functions now return
int
for status;SerialWriteHex
/SerialWriteDec
still returnvoid
, so callers cannot detect transmit time-outs or un-initialised port.Propagate the return codes inside the implementations for uniform API.
📝 Committable suggestion
🤖 Prompt for AI Agents