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++
|
CXX=/opt/bin/i686-elf-g++
|
||||||
LD=/opt/i686-elf/bin/ld
|
LD=/opt/i686-elf/bin/ld
|
||||||
AR=/opt/i686-elf/bin/ar
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <chardev.hpp>
|
||||||
|
|
||||||
#define SERIAL_COM1 0x3F8
|
#define SERIAL_COM1 0x3F8
|
||||||
#define SERIAL_COM2 0x2F8
|
#define SERIAL_COM2 0x2F8
|
||||||
|
@ -16,7 +17,8 @@ enum class Partiy
|
||||||
Low = 0x7,
|
Low = 0x7,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SerialPort
|
class SerialPort :
|
||||||
|
public CharacterDevice
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
uint16_t mBase;
|
uint16_t mBase;
|
||||||
|
@ -31,7 +33,7 @@ public:
|
||||||
|
|
||||||
bool isReceiveEmpty() const;
|
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;
|
return (inb(this->mBase + LSR) & 1) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialPort::write(uint8_t c)
|
void SerialPort::write(char c)
|
||||||
{
|
{
|
||||||
while (this->isTransmitEmpty() == false);
|
while (this->isTransmitEmpty() == false);
|
||||||
outb(this->mBase, c);
|
outb(this->mBase, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SerialPort::read()
|
char SerialPort::read()
|
||||||
{
|
{
|
||||||
while (this->isReceiveEmpty());
|
while (this->isReceiveEmpty());
|
||||||
return inb(this->mBase);
|
return inb(this->mBase);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
include ../config.mk
|
include ../config.mk
|
||||||
|
|
||||||
KERNEL = video.ker
|
KERNEL = video.ker
|
||||||
LIBS = -lboot -lvideo -lserial
|
LIBS += -lboot -lvideo -lchardev -lserial -lbase -lgcc
|
||||||
|
|
||||||
all: builddir $(KERNEL)
|
all: builddir $(KERNEL)
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,7 @@
|
||||||
extern "C" void init(multiboot::Structure const & data)
|
extern "C" void init(multiboot::Structure const & data)
|
||||||
{
|
{
|
||||||
SerialPort serial(SERIAL_COM1);
|
SerialPort serial(SERIAL_COM1);
|
||||||
|
serial << "Hi!\n";
|
||||||
serial.write('H');
|
|
||||||
serial.write('i');
|
|
||||||
serial.write('\n');
|
|
||||||
|
|
||||||
VideoScreen video(*data.vbe.modeInfo);
|
VideoScreen video(*data.vbe.modeInfo);
|
||||||
for(uint32_t y = 0; y < video.height(); y++)
|
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);
|
while(true);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue