Adds CharacterDevice base class for SerialPort.
This commit is contained in:
parent
99a53601b7
commit
236ea33c61
10 changed files with 358 additions and 11 deletions
|
@ -7,4 +7,6 @@ CC=/opt/bin/i686-elf-gcc
|
|||
CXX=/opt/bin/i686-elf-g++
|
||||
LD=/opt/i686-elf/bin/ld
|
||||
AR=/opt/i686-elf/bin/ar
|
||||
AS=/opt/bin/i686-elf-gcc
|
||||
AS=/opt/bin/i686-elf-gcc
|
||||
|
||||
LIBS += -L/opt/lib/gcc/i686-elf/6.1.0/
|
94
prototypes-rework/include/chardev.hpp
Normal file
94
prototypes-rework/include/chardev.hpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
template<typename T>
|
||||
struct NumericFormat
|
||||
{
|
||||
T value;
|
||||
uint32_t base;
|
||||
|
||||
/**
|
||||
* Applies a padding to the number.
|
||||
* A positive number will apply padding the right side,
|
||||
* a negative number will pad the left side.
|
||||
*/
|
||||
int32_t padding = 0;
|
||||
|
||||
char padchar = ' ';
|
||||
|
||||
NumericFormat(T value) : value(value), base(10) { }
|
||||
NumericFormat(T value, uint32_t base) : value(value), base(base) { }
|
||||
};
|
||||
|
||||
namespace utils
|
||||
{
|
||||
template<typename T>
|
||||
auto hex(T value) { return NumericFormat<T>(value, 16); }
|
||||
|
||||
template<typename T>
|
||||
auto dec(T value) { return NumericFormat<T>(value, 10); }
|
||||
|
||||
template<typename T>
|
||||
auto oct(T value) { return NumericFormat<T>(value, 8); }
|
||||
|
||||
template<typename T>
|
||||
auto bin(T value) { return NumericFormat<T>(value, 2); }
|
||||
|
||||
template<typename T>
|
||||
auto nbase(T value, uint32_t base) { return NumericFormat<T>(value, base); }
|
||||
|
||||
template<typename T>
|
||||
auto pad(NumericFormat<T> value, int32_t padding, char c = ' ') {
|
||||
value.padding = padding;
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto pad(T value, int32_t padding, char c = ' ') {
|
||||
return pad(NumericFormat<T>(value), padding, c);
|
||||
}
|
||||
}
|
||||
|
||||
class CharacterDevice
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Prints the prefix for a given numeric base.
|
||||
* @returns the prefix length.
|
||||
*/
|
||||
uint32_t printNumericPrefix(uint32_t base);
|
||||
|
||||
/**
|
||||
* Prints a character several times.
|
||||
*/
|
||||
void putrep(char c, uint32_t repetitions);
|
||||
public:
|
||||
virtual void write(char c) = 0;
|
||||
|
||||
inline CharacterDevice & operator << (char c)
|
||||
{
|
||||
this->write(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CharacterDevice & operator << (const char *str)
|
||||
{
|
||||
while(*str) {
|
||||
*this << *str++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CharacterDevice & operator << (uint32_t value);
|
||||
|
||||
CharacterDevice & operator << (int32_t value);
|
||||
|
||||
CharacterDevice & operator << (void *value);
|
||||
|
||||
CharacterDevice & operator << (bool value);
|
||||
|
||||
template<typename T>
|
||||
CharacterDevice & operator << (const NumericFormat<T> &fmt);
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <chardev.hpp>
|
||||
|
||||
#define SERIAL_COM1 0x3F8
|
||||
#define SERIAL_COM2 0x2F8
|
||||
|
@ -16,7 +17,8 @@ enum class Partiy
|
|||
Low = 0x7,
|
||||
};
|
||||
|
||||
class SerialPort
|
||||
class SerialPort :
|
||||
public CharacterDevice
|
||||
{
|
||||
private:
|
||||
uint16_t mBase;
|
||||
|
@ -31,7 +33,7 @@ public:
|
|||
|
||||
bool isReceiveEmpty() const;
|
||||
|
||||
void write(uint8_t c);
|
||||
void write(char c) override;
|
||||
|
||||
uint8_t read();
|
||||
char read();
|
||||
};
|
133
prototypes-rework/libbase/numeric.cpp
Normal file
133
prototypes-rework/libbase/numeric.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
#include <numeric.hpp>
|
||||
|
||||
static char getDigit(uint32_t i)
|
||||
{
|
||||
if(i >= 0 && i <= 9) {
|
||||
return '0' + i;
|
||||
}
|
||||
return 'A' + (i-10);
|
||||
}
|
||||
|
||||
size_t Numeric::toString(
|
||||
char *buffer,
|
||||
size_t length,
|
||||
uint32_t number,
|
||||
uint32_t radix)
|
||||
{
|
||||
if(length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if(number == 0) {
|
||||
buffer[0] = '0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
while(number > 0)
|
||||
{
|
||||
buffer[len++] = getDigit(number % radix);
|
||||
if(len >= length)
|
||||
break;
|
||||
number /= radix;
|
||||
}
|
||||
|
||||
int half = len / 2;
|
||||
for(int i = 0; i < half; i++)
|
||||
{
|
||||
char c = buffer[i];
|
||||
buffer[i] = buffer[len - i - 1];
|
||||
buffer[len - i - 1] = c;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t Numeric::toString(
|
||||
char *buffer,
|
||||
size_t length,
|
||||
int32_t number,
|
||||
uint32_t radix)
|
||||
{
|
||||
if(length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if(number == 0) {
|
||||
buffer[0] = '0';
|
||||
return 1;
|
||||
}
|
||||
if(number < 0) {
|
||||
buffer[0] = '-';
|
||||
length -= 1;
|
||||
if(length == 0) {
|
||||
return 0;
|
||||
}
|
||||
return Numeric::toString(&buffer[1], length, static_cast<uint32_t>(-number), radix) + 1;
|
||||
}
|
||||
else {
|
||||
return Numeric::toString(buffer, length, static_cast<uint32_t>(number), radix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
size_t Numeric::toString(
|
||||
char *buffer,
|
||||
size_t length,
|
||||
uint64_t number,
|
||||
uint32_t radix)
|
||||
{
|
||||
if(length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if(number == 0) {
|
||||
buffer[0] = '0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
while(number > 0)
|
||||
{
|
||||
buffer[len++] = getDigit(number % radix);
|
||||
if(len >= length)
|
||||
break;
|
||||
number /= radix;
|
||||
}
|
||||
|
||||
int half = len / 2;
|
||||
for(int i = 0; i < half; i++)
|
||||
{
|
||||
char c = buffer[i];
|
||||
buffer[i] = buffer[len - i - 1];
|
||||
buffer[len - i - 1] = c;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t Numeric::toString(
|
||||
char *buffer,
|
||||
size_t length,
|
||||
int64_t number,
|
||||
uint32_t radix)
|
||||
{
|
||||
if(length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if(number == 0) {
|
||||
buffer[0] = '0';
|
||||
return 1;
|
||||
}
|
||||
if(number < 0) {
|
||||
buffer[0] = '-';
|
||||
length -= 1;
|
||||
if(length == 0) {
|
||||
return 0;
|
||||
}
|
||||
return Numeric::toString(&buffer[1], length, static_cast<uint64_t>(-number), radix) + 1;
|
||||
}
|
||||
else {
|
||||
return Numeric::toString(buffer, length, static_cast<uint64_t>(number), radix);
|
||||
}
|
||||
}
|
12
prototypes-rework/libchardev/Makefile
Normal file
12
prototypes-rework/libchardev/Makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
##
|
||||
# Build libchardev.
|
||||
##
|
||||
|
||||
include ../config.mk
|
||||
|
||||
LIBRARY = libchardev.a
|
||||
|
||||
all: builddir $(LIBRARY)
|
||||
|
||||
include ../common.mk
|
||||
include ../library.mk
|
105
prototypes-rework/libchardev/chardev.cpp
Normal file
105
prototypes-rework/libchardev/chardev.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
#include <chardev.hpp>
|
||||
|
||||
#include <numeric.hpp>
|
||||
|
||||
|
||||
CharacterDevice & CharacterDevice::operator << (uint32_t value)
|
||||
{
|
||||
char buffer[12];
|
||||
size_t len = Numeric::toString(buffer, sizeof(buffer), value, 10);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
this->write(buffer[i]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CharacterDevice & CharacterDevice::operator << (int32_t value)
|
||||
{
|
||||
char buffer[13];
|
||||
size_t len = Numeric::toString(buffer, sizeof(buffer), value, 10);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
this->write(buffer[i]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CharacterDevice & CharacterDevice::operator << (void *value)
|
||||
{
|
||||
char buffer[13];
|
||||
size_t len = Numeric::toString(buffer, sizeof(buffer), reinterpret_cast<uint32_t>(value), 16);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
this->write(buffer[i]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CharacterDevice & CharacterDevice::operator << (bool value)
|
||||
{
|
||||
if(value == true) {
|
||||
*this << "true";
|
||||
} else {
|
||||
*this << "false";
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
#define NUMERIC_FMT_HANDLER char buffer[13]; \
|
||||
size_t prefixlen = this->printNumericPrefix(fmt.base); \
|
||||
size_t len = Numeric::toString(buffer, sizeof(buffer), fmt.value, fmt.base); \
|
||||
int delta = prefixlen + len; \
|
||||
if(fmt.padding < 0 && delta < -fmt.padding) { \
|
||||
this->putrep(fmt.padchar, -fmt.padding - delta); \
|
||||
} \
|
||||
for(size_t i = 0; i < len; i++) { \
|
||||
this->write(buffer[i]); \
|
||||
} \
|
||||
if(fmt.padding > 0 && delta < fmt.padding) { \
|
||||
this->putrep(fmt.padchar, fmt.padding - delta); \
|
||||
} \
|
||||
return *this
|
||||
|
||||
template<>
|
||||
CharacterDevice & CharacterDevice::operator << <uint32_t>(const NumericFormat<uint32_t> & fmt)
|
||||
{
|
||||
NUMERIC_FMT_HANDLER;
|
||||
}
|
||||
|
||||
template<>
|
||||
CharacterDevice & CharacterDevice::operator << <int32_t>(const NumericFormat<int32_t> & fmt)
|
||||
{
|
||||
NUMERIC_FMT_HANDLER;
|
||||
}
|
||||
|
||||
template<>
|
||||
CharacterDevice & CharacterDevice::operator << <uint64_t>(const NumericFormat<uint64_t> & fmt)
|
||||
{
|
||||
NUMERIC_FMT_HANDLER;
|
||||
}
|
||||
|
||||
template<>
|
||||
CharacterDevice & CharacterDevice::operator << <int64_t>(const NumericFormat<int64_t> & fmt)
|
||||
{
|
||||
NUMERIC_FMT_HANDLER;
|
||||
}
|
||||
|
||||
uint32_t CharacterDevice::printNumericPrefix(uint32_t base)
|
||||
{
|
||||
switch(base) {
|
||||
case 2: *this << "0b"; return 2;
|
||||
case 8: *this << "0o"; return 2;
|
||||
case 10: return 0;
|
||||
case 16: *this << "0x"; return 2;
|
||||
default:
|
||||
*this << "[" << base << "]x";
|
||||
if(base < 10) return 4;
|
||||
if(base < 100) return 5;
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterDevice::putrep(char c, uint32_t repetitions)
|
||||
{
|
||||
for(uint32_t i = 0; i < repetitions; i++)
|
||||
this->write(c);
|
||||
}
|
|
@ -53,13 +53,13 @@ bool SerialPort::isReceiveEmpty() const
|
|||
return (inb(this->mBase + LSR) & 1) == 0;
|
||||
}
|
||||
|
||||
void SerialPort::write(uint8_t c)
|
||||
void SerialPort::write(char c)
|
||||
{
|
||||
while (this->isTransmitEmpty() == false);
|
||||
outb(this->mBase, c);
|
||||
}
|
||||
|
||||
uint8_t SerialPort::read()
|
||||
char SerialPort::read()
|
||||
{
|
||||
while (this->isReceiveEmpty());
|
||||
return inb(this->mBase);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
include ../config.mk
|
||||
|
||||
KERNEL = video.ker
|
||||
LIBS = -lboot -lvideo -lserial
|
||||
LIBS += -lboot -lvideo -lchardev -lserial -lbase -lgcc
|
||||
|
||||
all: builddir $(KERNEL)
|
||||
|
||||
|
|
|
@ -8,10 +8,7 @@
|
|||
extern "C" void init(multiboot::Structure const & data)
|
||||
{
|
||||
SerialPort serial(SERIAL_COM1);
|
||||
|
||||
serial.write('H');
|
||||
serial.write('i');
|
||||
serial.write('\n');
|
||||
serial << "Hi!\n";
|
||||
|
||||
VideoScreen video(*data.vbe.modeInfo);
|
||||
for(uint32_t y = 0; y < video.height(); y++)
|
||||
|
@ -22,5 +19,7 @@ extern "C" void init(multiboot::Structure const & data)
|
|||
}
|
||||
}
|
||||
|
||||
serial << "w=" << video.width() << " h=" << video.height() << "\n";
|
||||
|
||||
while(true);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue