Adds CharacterDevice base class for SerialPort.

This commit is contained in:
Felix Queißner 2016-06-26 16:55:42 +02:00
parent 99a53601b7
commit 236ea33c61
10 changed files with 358 additions and 11 deletions

View file

@ -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/

View 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);
};

View file

@ -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();
};

View 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);
}
}

View file

@ -0,0 +1,12 @@
##
# Build libchardev.
##
include ../config.mk
LIBRARY = libchardev.a
all: builddir $(LIBRARY)
include ../common.mk
include ../library.mk

View 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);
}

View file

@ -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);

View file

@ -5,7 +5,7 @@
include ../config.mk
KERNEL = video.ker
LIBS = -lboot -lvideo -lserial
LIBS += -lboot -lvideo -lchardev -lserial -lbase -lgcc
all: builddir $(KERNEL)

View file

@ -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);
}