Related
I'm in the process of working on a kernel program to handle printing capabilities of input for a custom OS. I'm following Poncho's 2nd YouTube Video series found here, I'm currently on Video 4 in the series where he starts to add numerical types as inputs to the renderer's print function. Now, my code isn't exactly like his as I made some modifications.
-Note- This won't compile directly as there is no main function. _start is being called or invoked by a bootloader that isn't shown here, I will however, add it to the bottom of this question.
When I use the class's print function like this within my kernel:
#include "BasicRenderer.h"
extern "C" void _start(Framebuffer* framebuffer, PSF1_FONT** fonts) {
BasicRenderer = renderer(framebuffer, fonts);
renderer.Print("This is some text");
renderer.Print('\n');
renderer.Print(uint64_t(123456789));
renderer.Print('\n');
renderer.Print(int64_t(-123456789));
return;
}
And I run the kernel in emu. I'm getting the following output displayed:
This is some text
123456789
-123456789
The above is correct, however, when I try to incorporate the ability to parse a newline set of characters being either \n or \0 within of a const char* that acts as a string as seen in the following example:
#include "BasicRenderer.h"
extern "C" void _start(Framebuffer* framebuffer, PSF1_FONT** fonts) {
BasicRenderer = renderer(framebuffer, fonts);
renderer.Print("This is some text\n");
renderer.Print(uint64_t(123456789));
renderer.Print('\n');
renderer.Print(int64_t(-123456789));
return;
}
And now the displayed output is:
This is some text
123456789
-123456789
Here, the output in the second line has a space preceding the numerical value to be displayed after the call to Print() that has a \n within its string. I'm not sure what is causing this in my code. Does it have to do with the while condition or how I'm incrementing and indexing into the character string within BasicRenderer::Print(const char* str)? Or is it coming from BasicRender::PutChar(char c)? Or is it within one of the to_string() functions?
Here is the relevant implementation code...
BasicRenderer.cpp
#include "BasicRenderer.h"
void BasicRenderer::Print(const char* str) {
char* chr = (char*)str;
while(*chr != 0) {
if ( (*chr == '\\') && ((*chr+1 == 'n') || (*chr+1 == '0')) ) {
PutChar('\n');
chr++;
chr++;
} else {
PutChar(*chr);
cursor_position_.x += 8;
if (cursor_position_.x + 8 > framebuffer_->Width) {
cursor_position_.x = 0;
cursor_position_.y += 16;
}
chr++;
}
}
}
void BasicRenderer::Print(uint64_t val) {
const char* str = to_string(val);
Print(str);
}
void BasicRenderer::Print(int64_t val) {
const char* str = to_string(val);
Print(str);
}
void BasicRenderer::PutChar(char c) {
if (c == '\n' || c == '\0') {
cursor_position_.x = 0;
cursor_position_.y += 16;
} else {
unsigned int* pixPtr = (unsigned int*)framebuffer_->BaseAddress;
char* fontPtr = (char*)selected_font_->glyphBuffer + (c * selected_font_->psf1_Header->charsize);
for (unsigned long y = cursor_position_.y; y < cursor_position_.y + 16; y++) {
for (unsigned long x = cursor_position_.x; x < cursor_position_.x + 8; x++) {
if ((*fontPtr & (0b10000000 >> (x - cursor_position_.x))) > 0) {
*(unsigned int*)(pixPtr + x + (y * framebuffer_->PixelsPerScanLine)) = font_color_;
}
}
fontPtr++;
}
}
}
cstr.cpp
#include "cstr.h"
const char* to_string(uint64_t value) {
static char output_uint_buffer[128];
uint8_t size = 0;
uint64_t sizeTest = value;
while (sizeTest / 10 > 0) {
sizeTest /= 10;
size++;
}
uint8_t idx = 0;
while (value / 10 > 0) {
uint8_t remainder = value % 10;
value /= 10;
output_uint_buffer[size - idx] = remainder + '0';
idx++;
}
uint8_t remainder = value % 10;
output_uint_buffer[size-idx] = remainder + '0';
output_uint_buffer[size + 1] = 0;
return output_uint_buffer;
}
const char* to_string(int64_t value) {
static char output_int_buffer[128];
uint8_t isNegative = 0;
if (value < 0) {
isNegative = 1;
value *= -1;
output_int_buffer[0] = '-';
}
uint8_t size = 0;
uint64_t sizeTest = value;
while (sizeTest / 10 > 0) {
sizeTest /= 10;
size++;
}
uint8_t idx = 0;
while (value / 10 > 0) {
uint8_t remainder = value % 10;
value /= 10;
output_int_buffer[isNegative + size - idx] = remainder + '0';
idx++;
}
uint8_t remainder = value % 10;
output_int_buffer[isNegative + size - idx] = remainder + '0';
output_int_buffer[isNegative + size + 1] = 0;
return output_int_buffer;
}
And here is the rest of the declarations...
BasicRender.h
#pragma once
#include "cstr.h"
#include "math.h"
#include "framebuffer.h"
#include "SimpleFonts.h"
class BasicRenderer {
public:
BasicRenderer(Framebuffer* framebuffer, PSF1_FONT** fonts) :
framebuffer_{framebuffer},
fonts_{fonts},
cursor_position_({0,0}),
selected_font_{fonts_[0]},
font_color_{0xFFFFFFFF}
{}
void Print(const char* str);
void Print(char c) { PutChar(c); }
void Print(uint64_t val);
void Print(int64_t val);
private:
void PutChar(char c);
Framebuffer* framebuffer_;
Point cursor_position_;
PSF1_FONT** fonts_;
PSF1_FONT* selected_font_;
unsigned int font_color_;
};
cstr.h
#pragma once
#include <stdint.h>
const char* to_string(uint64_t value);
const char* to_string(int64_t value);
math.h
#pragma once
struct Point {
unsigned int x;
unsigned int y;
};
Framebuffer.h
#pragma once
#include <stddef.h>
struct Framebuffer {
void* BaseAddress;
size_t BufferSize;
unsigned int Width;
unsigned int Height;
unsigned int PixelsPerScanLine;
};
SimpleFonts.h
#pragma once
struct PSF1_HEADER {
unsigned char magic[2];
unsigned char mode;
unsigned char charsize;
};
struct PSF1_FONT {
PSF1_HEADER* psf1_Header;
void* glyphBuffer;
};
Here is the bootloader application that invokes the above kernel.
main.c
#include <efi.h>
#include <efilib.h>
#include <elf.h>
#define PSF1_MAGIC0 0x36
#define PSF1_MAGIC1 0x04
typedef unsigned long long size_t;
typedef struct {
unsigned char magic[2];
unsigned char mode;
unsigned char charsize;
} PSF1_HEADER;
typedef struct {
PSF1_HEADER* psf1_Header;
void* glyphBuffer;
} PSF1_FONT;
typedef struct {
void* BaseAddress;
size_t BufferSize;
unsigned int Width;
unsigned int Height;
unsigned int PixelsPerScanLine;
} Framebuffer; Framebuffer framebuffer;
Framebuffer* InitializeGOP() {
EFI_GUID gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL* gop;
EFI_STATUS status;
status = uefi_call_wrapper(BS->LocateProtocol, 3, &gopGuid, NULL, (void**)&gop);
if (EFI_ERROR(status)) {
Print(L"Unable to locate GOP\n\r");
return NULL;
} else {
Print(L"GOP located\n\r");
}
framebuffer.BaseAddress = (void*)gop->Mode->FrameBufferBase;
framebuffer.BufferSize = gop->Mode->FrameBufferSize;
framebuffer.Width = gop->Mode->Info->HorizontalResolution;
framebuffer.Height = gop->Mode->Info->VerticalResolution;
framebuffer.PixelsPerScanLine = gop->Mode->Info->PixelsPerScanLine;
return &framebuffer;
}
EFI_FILE* LoadFile(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
EFI_FILE* LoadedFile;
EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
SystemTable->BootServices->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (void**)&LoadedImage);
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileSystem;
SystemTable->BootServices->HandleProtocol(LoadedImage->DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (void**)&FileSystem);
if (Directory == NULL) {
FileSystem->OpenVolume(FileSystem, &Directory);
}
EFI_STATUS s = Directory->Open(Directory, &LoadedFile, Path, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY);
if (s != EFI_SUCCESS) {
return NULL;
}
return LoadedFile;
}
PSF1_FONT* LoadPSF1Font(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
EFI_FILE* font = LoadFile(Directory, Path, ImageHandle, SystemTable);
if (font == NULL) return NULL;
PSF1_HEADER* fontHeader;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(PSF1_HEADER), (void**)&fontHeader);
UINTN size = sizeof(PSF1_HEADER);
font->Read(font, &size, fontHeader);
if (fontHeader->magic[0] != PSF1_MAGIC0 || fontHeader->magic[1] != PSF1_MAGIC1) return NULL;
UINTN glyphBufferSize = fontHeader->charsize * 256;
if (fontHeader->mode == 1) { // 512 glyph mode
glyphBufferSize *= 2;
}
void* glyphBuffer;
font->SetPosition(font, sizeof(PSF1_HEADER));
SystemTable->BootServices->AllocatePool(EfiLoaderData, glyphBufferSize, (void**)&glyphBuffer);
font->Read(font, &glyphBufferSize, glyphBuffer);
PSF1_FONT* finishedFont;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(PSF1_FONT), (void**)&finishedFont);
finishedFont->psf1_Header = fontHeader;
finishedFont->glyphBuffer = glyphBuffer;
return finishedFont;
}
int memcmp(const void* aptr, const void* bptr, size_t n) {
const unsigned char* a = aptr, *b = bptr;
for (size_t i = 0; i < n; i++) {
if (a[i] < b[i]) return -1;
else if(a[i] > b[i]) return 1;
}
return 0;
}
EFI_STATUS efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
InitializeLib(ImageHandle, SystemTable);
Print(L"Hello World!\n\r");
EFI_FILE* Kernel = LoadFile(NULL, L"kernel.elf", ImageHandle, SystemTable);
if ( Kernel == NULL) {
Print(L"Could not load kernel \n\r");
} else {
Print(L"Kernel Loaded Successfully \n\r");
}
Elf64_Ehdr header;
{
UINTN FileInfoSize;
EFI_FILE_INFO* FileInfo;
Kernel->GetInfo(Kernel, &gEfiFileInfoGuid, &FileInfoSize, NULL);
SystemTable->BootServices->AllocatePool(EfiLoaderData, FileInfoSize, (void**)&FileInfo);
Kernel->GetInfo(Kernel, &gEfiFileInfoGuid, &FileInfoSize, (void**)&FileInfo);
UINTN size = sizeof(header);
Kernel->Read(Kernel, &size, &header);
}
if (
memcmp(&header.e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0 ||
header.e_ident[EI_CLASS] != ELFCLASS64 ||
header.e_ident[EI_DATA] != ELFDATA2LSB ||
header.e_type != ET_EXEC ||
header.e_machine != EM_X86_64 ||
header.e_version != EV_CURRENT
) {
Print(L"kernel format is bad\r\n");
} else {
Print(L"kernel header successfully verified\r\n");
}
Elf64_Phdr* phdrs;
{
Kernel->SetPosition(Kernel, header.e_phoff);
UINTN size = header.e_phnum * header.e_phentsize;
SystemTable->BootServices->AllocatePool(EfiLoaderData, size, (void**)&phdrs);
Kernel->Read(Kernel, &size, phdrs);
}
for (
Elf64_Phdr* phdr = phdrs;
(char*)phdr < (char*)phdrs + header.e_phnum * header.e_phentsize;
phdr = (Elf64_Phdr*)((char*)phdr + header.e_phentsize)
) {
switch(phdr->p_type) {
case PT_LOAD: {
int pages = (phdr->p_memsz + 0x1000 - 1) / 0x1000;
Elf64_Addr segment = phdr->p_paddr;
SystemTable->BootServices->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment);
Kernel->SetPosition(Kernel, phdr->p_offset);
UINTN size = phdr->p_filesz;
Kernel->Read(Kernel, &size, (void*)segment);
break;
}
}
}
Print(L"Kernel Loaded\n\r");
void (*KernelStart)(Framebuffer*, PSF1_FONT**) = ((__attribute__((sysv_abi)) void(*)(Framebuffer*, PSF1_FONT**) ) header.e_entry);
PSF1_FONT* newFont = LoadPSF1Font(NULL, L"zap-light16.psf", ImageHandle, SystemTable);
if (newFont == NULL) {
Print(L"Font is not valid or is not found\n\r");
} else {
Print(L"Font found, char size = %d\n\r", newFont->psf1_Header->charsize);
}
PSF1_FONT* newFontExt = LoadPSF1Font(NULL, L"zap-ext-light16.psf", ImageHandle, SystemTable);
if (newFont == NULL) {
Print(L"Font is not valid or is not found\n\r");
} else {
Print(L"Font found, char size = %d\n\r", newFont->psf1_Header->charsize);
}
PSF1_FONT* fonts[] = {newFont, newFontExt};
Framebuffer* newBuffer = InitializeGOP();
Print(L"Base: 0x%x\n\rSize: 0x%x\n\rWidth: %d\n\rHeight: %d\n\rPixelsPerScanline: %d\n\r",
newBuffer->BaseAddress,
newBuffer->BufferSize,
newBuffer->Width,
newBuffer->Height,
newBuffer->PixelsPerScanLine);
KernelStart(newBuffer, fonts);
return EFI_SUCCESS; // Exit the UEFI application
}
The problem is here:
if ( (*chr == '\\') && ((*chr+1 == 'n') || (*chr+1 == '0')) ) {
PutChar('\n');
chr++;
chr++;
}
...
You should not be parsing out \n since this will be present in the string as a linefeed character. What you want instead is:
if (*chr == '\n') {
PutChar('\n');
chr++;
}
...
Summarize The Problem
I'm building an operating system using C++ on Linux Mint in Parallels Desktop Mac.
I just added keyboard support except there was a problem...
When I press one key on the keyboard, it will create around 5 or more characters. This is an image of the problem:
Describe What you've tried
All of the sources were talking about Linux kernel so I couldn't find anything. I didn't try anything.
Show some code
print.h
#ifndef PRINT_H
#define PRINT_H
#include "types.h"
#include "colours.h"
class print {
public:
void printf(char *str);
void printf(int num);
void itoa(int num, char *number);
uint32_t digit_count(int num);
uint32_t strlen(const char *str);
void print_char(char ch);
void newLine();
void init_vga(uint8_t fore_color, uint8_t back_color);
void clear_vga_buffer(uint16_t **buffer, uint8_t fore_color, uint8_t back_color);
uint16_t vga_entry(unsigned char ch, uint8_t fore_color, uint8_t back_color);
void setTextColors(uint8_t foreColor, uint8_t back_color);
print *getPrinter();
void setPrinter(print *printer1);
private:
print *ksafdkjlasdlfk;
//index for video buffer array
uint32_t vga_index;
//counter to store new lines
uint32_t next_line_index = 1;
//fore & back color values
uint8_t g_fore_color = WHITE, g_back_color = BLUE;
//digit ascii code for printing integers
int digit_ascii_codes[10] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
#define VGA_ADDRESS 0xB8000
#define BUFSIZE 2200
uint16_t *vga_buffer;
#define NULL 0
};
#endif
print.cpp
#include "print.h"
void print::printf(char *str) {
uint32_t index = 0;
while (str[index]) {
print_char(str[index]);
index++;
}
}
void print::printf(int num) {
char str_num[digit_count(num) + 1];
itoa(num, str_num);
printf(str_num);
}
void print::itoa(int num, char *number) {
int dgcount = digit_count(num);
int index = dgcount - 1;
char x;
if (num == 0 && dgcount == 1) {
number[0] = '0';
number[1] = '\0';
} else {
while (num != 0) {
x = num % 10;
number[index] = x + '0';
index--;
num = num / 10;
}
number[dgcount] = '\0';
}
}
uint32_t print::digit_count(int num) {
uint32_t count = 0;
if (num == 0)
return 1;
while (num > 0) {
count++;
num = num / 10;
}
return count;
}
uint32_t print::strlen(const char *str) {
uint32_t length = 0;
while (str[length])
length++;
return length;
}
void print::print_char(char ch) {
vga_buffer[vga_index] = vga_entry(ch, g_fore_color, g_back_color);
vga_index++;
}
void print::newLine() {
if (next_line_index >= 55) {
next_line_index = 0;
clear_vga_buffer(&vga_buffer, g_fore_color, g_back_color);
}
vga_index = 80 * next_line_index;
next_line_index++;
}
void print::init_vga(uint8_t fore_color, uint8_t back_color) {
vga_buffer = (uint16_t *) VGA_ADDRESS;
clear_vga_buffer(&vga_buffer, fore_color, back_color);
g_fore_color = fore_color;
g_back_color = back_color;
}
void print::clear_vga_buffer(uint16_t **buffer, uint8_t fore_color, uint8_t back_color) {
uint32_t i;
for (i = 0; i < BUFSIZE; i++) {
(*buffer)[i] = vga_entry(NULL, fore_color, back_color);
}
next_line_index = 1;
vga_index = 0;
}
uint16_t print::vga_entry(unsigned char ch, uint8_t fore_color, uint8_t back_color) {
uint16_t ax = 0;
uint8_t ah = 0, al = 0;
ah = back_color;
ah <<= 4;
ah |= fore_color;
ax = ah;
ax <<= 8;
al = ch;
ax |= al;
return ax;
}
void print::setTextColors(uint8_t foreColor, uint8_t back_color) {
g_fore_color = foreColor;
g_back_color = back_color;
}
print *print::getPrinter() {
return ksafdkjlasdlfk;
}
void print::setPrinter(print *printer1) {
ksafdkjlasdlfk = printer1;
}
keyboard.h
#ifndef APOS_KEYBOARD_H
#define APOS_KEYBOARD_H
#include "../../utils/types.h"
#include "../../utils/print.h"
#include "char.h"
class keyboard {
public:
void enableKeyboard();
void test_input();
void sleep(uint32_t timer_count);
void wait_for_io(uint32_t timer_count);
char get_input_keycode();
void outb(uint16_t port, uint8_t data);
uint8_t inb(uint16_t port);
};
#endif //APOS_KEYBOARD_H
keyboard.cpp
#include "keyboard.h"
uint8_t keyboard::inb(uint16_t port) {
uint8_t ret;
asm volatile("inb %1, %0" : "=a"(ret) : "d"(port));
return ret;
}
void keyboard::outb(uint16_t port, uint8_t data) {
asm volatile("outb %0, %1" : "=a"(data) : "d"(port));
}
char keyboard::get_input_keycode() {
char ch = 0;
while ((ch = inb(KEYBOARD_PORT)) != 0) {
if (ch > 0)
return ch;
}
return ch;
}
/*
keep the cpu busy for doing nothing(nop)
so that io port will not be processed by cpu
here timer can also be used, but lets do this in looping counter
*/
void keyboard::wait_for_io(uint32_t timer_count) {
while (1) {
asm volatile("nop");
timer_count--;
if (timer_count <= 0)
break;
}
}
void keyboard::sleep(uint32_t timer_count) {
wait_for_io(timer_count);
}
void keyboard::test_input() {
char ch = 0;
char keycode = 0;
do {
keycode = get_input_keycode();
if (keycode == KEY_ENTER) {
print printt;
printt.getPrinter()->newLine();
} else {
ch = get_ascii_char(keycode);
print printt;
printt.getPrinter()->print_char(ch);
}
sleep(0x02FFFFFF);
} while (ch > 0);
}
void keyboard::enableKeyboard() {
test_input();
}
The kernel.cpp just has the test_intput command and prints a few things.
There are a few files there, but that main ones are the kernel.cpp, hardware/keyboard/all the files there.
Either use a seperate Thread to handle the input reckognition function, that way you can use a sleep without blocking the main Thread. You could also save the current pressed key and save it as a previous key and check if it has changed, if not the button has not been released yet. so you can avoid multiples.
Me and and a friend of mine are building a robot which contains a gps for arduino. We built the following circuit, to test the gps:
We're trying the following code to test the gps:
#include <SoftwareSerial.h>
#include <TinyGPS.h>
long lat,lon; // create variable for latitude and longitude object
SoftwareSerial gpsSerial(2, 3); // create gps sensor connection
TinyGPS gps; // create gps object
void setup(){
Serial.begin(9600); // connect serial
gpsSerial.begin(4800); // connect gps sensor
}
void loop(){
Serial.print("test"); //I implemented this test
while(gpsSerial.available()){ // check for gps data
Serial.print("test2"); //I implemented this test
if(gps.encode(gpsSerial.read())){ // encode gps data
Serial.print("test3"); //I implemented this test
gps.get_position(&lat,&lon); // get latitude and longitude
// display position
Serial.print("Position: ");
Serial.print("lat: ");Serial.print(lat);Serial.print(" ");// print latitude
Serial.print("lon: ");Serial.println(lon); // print longitude
}
}
}
The thing is that the serial monitor does output test number 1, but doesn't output test number 2 and number 3. So we expected the circuit we built to fail. But we double checked the wires etc. Does anybody know what the problem could be?
Any inspiration/help is welcome,
Thanks,
Justin van Til
Try this code.
#include <SoftwareSerial.h>
#include <TinyGPS.h>
TinyGPS gps;
static void print_long(long val, long invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);
SoftwareSerial ss(3,4);
void setup()
{
Serial.begin(9600);
ss.begin(9600);
}
void loop()
{
long lat, lon;
int alt;
unsigned short sentences = 0, failed = 0;
gps.get_position(&lat, &lon);
alt=gps.altitude();
Serial.print("CURRENT LATITUDE & LONGITUDE:");
Serial.print(lat);
Serial.print(",");
Serial.println(lon);
Serial.print("CURRENT ALTITUDE:");
Serial.println(alt);
smartdelay(1000);
}
static void smartdelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
static void print_long (long val, long invalid, int len, int prec)
{
if (val == invalid)
{
while (len-- > 1)
Serial.print('*');
Serial.print(' ');
}
else
{
Serial.print(val, prec);
int vi = abs((int)val);
int flen = prec + (val < 0.0 ? 2 : 1); // . and -
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i=flen; i<len; ++i)
Serial.print(' ');
}
smartdelay(0);
}
static void print_int(unsigned long val, unsigned long invalid, int len)
{
char sz[32];
if (val == invalid)
strcpy(sz, "*******");
else
sprintf(sz, "%ld", val);
sz[len] = 0;
for (int i=strlen(sz); i<len; ++i)
sz[i] = ' ';
if (len > 0)
sz[len-1] = ' ';
Serial.print(sz);
smartdelay(0);
}
static void print_str(const char *str, int len)
{
int slen = strlen(str);
for (int i=0; i<len; ++i)
Serial.print(i<slen ? str[i] : ' ');
smartdelay(0);
}
I'm fiddling with an Arduino project where I've got these structs in my main file:
struct gpsCoord_t {
long latitude;
long longitude;
};
struct track_t {
char code[4];
gpsCoord_t bounds[4];
gpsCoord_t points[4];
};
Next to that I've got a function to dump variables of this type to the serial bus in that same file:
void dumpTrack(track_t track) {
Serial.print("\nTrack: ");
Serial.print(track.code);
Serial.print("\nTrack bounds: ");
Serial.print("\n- 1 lat: ");
Serial.print(track.bounds[0].latitude);
Serial.print("\n- 1 lon: ");
Serial.print(track.bounds[0].longitude);
}
The compiler produces 2 errors without line numbers from which I believe the first one is caused by the second one:
error: variable or field 'dumpTrack' declared void
error: 'track_t' was not declared in this scope
EDIT here's the complete file:
#include <Wire.h> //I2C library
#include <I2C_eeprom.h>
#include <SoftwareSerial.h>
#include <TinyGPS.h>
I2C_eeprom ee(0x50);
const int baseTrackAddress = 3;
const int trackSize = 68;
const int maxTracks = 480;
int powerOnLED = 2;
int gpsFixLED = 3;
int trackFoundLED = 4;
int errorLED = 6;
int gpsSensor = 7;
TinyGPS gps;
SoftwareSerial nss(gpsSensor, 255);
int calcTrackAddress(int trackId) {
return (trackId*trackSize) + baseTrackAddress;
}
struct gpsCoord_t {
long latitude;
long longitude;
};
struct track_t {
char code[4];
gpsCoord_t bounds[4];
gpsCoord_t points[4];
};
track_t tracks[maxTracks];
void setup()
{
Serial.begin(115200);
Serial.flush();
Serial.print("Demo I2C eeprom library ");
Serial.print(I2C_EEPROM_VERSION);
Serial.println("\n");
strcpy(tracks[0].code, "X11");
tracks[0].bounds[0].latitude = 0;
tracks[0].bounds[0].longitude = 0;
tracks[0].points[0].latitude = 0;
tracks[0].points[0].longitude = 0;
ee.writeBlock(3, (uint8_t*)&tracks[0], trackSize);
}
void loop()
{
Serial.println("\nTEST: 64 byte page boundary writeBlock");
dumpEEPROM(0, 255);
while(1);
}
void dumpTrack(track_t track) {
Serial.print("\nTrack: ");
Serial.print(track.code);
Serial.print("\nTrack bounds: ");
Serial.print("\n- 1 lat: ");
Serial.print(track.bounds[0].latitude);
Serial.print("\n- 1 lon: ");
Serial.print(track.bounds[0].longitude);
}
void readTrack(int trackId) {
track_t track;
ee.readBlock(60, (uint8_t*)&track, 10);
}
void readTracks() {
}
void dumpEEPROM(unsigned int addr, unsigned int length)
{
// block to 10
addr = addr / 10 * 10;
length = (length + 9)/10 * 10;
byte b = ee.readByte(addr);
for (int i = 0; i < length; i++)
{
if (addr % 10 == 0)
{
Serial.println();
Serial.print(addr);
Serial.print(":\t");
}
Serial.print(b);
b = ee.readByte(++addr);
Serial.print(" ");
}
Serial.println();
}
void ProcessCommand(char* command) {
//switch(*command==)
}
char* ReadSerialCommand() {
int i=0;
char commandbuffer[100];
if(Serial.available()){
delay(100);
while( Serial.available() && i< 99) {
commandbuffer[i++] = Serial.read();
}
commandbuffer[i++]='\0';
}
if(i>0)
return (char*)commandbuffer;
else
return 0L;
}
When I put the entire dumpTrack function in comment, the errors go away. I've checked a couple of times for a typo but failed to find any.
It seems you are compiling this code as C.
Instead of
struct track_t {
char code[4];
gpsCoord_t bounds[4];
gpsCoord_t points[4];
};
write
typedef struct {
char code[4];
gpsCoord_t bounds[4];
gpsCoord_t points[4];
} track_t;
I suspect somewhere in a header there is a variable called dumpTrack. Why don't you just rename the function to something else?
Also in general it is good to avoid using reserved words as function names; "loop" is not a good choice for a function name.
Edit: the latter is probably the reason for your problem.
I have an issue where my Arduino program hangs for no reason. I run my program, and at some undetermined point, the Serial Monitor stops printing output. Here's what I've tested so far:
In my "com.init_drone()" method, I've commented everything out except for the last line, which signals that the method returned. When I do this, my program hangs somewhere else but still it doesn't get to the infinite while loop.
I've been outputting memory usage, and I'm getting numbers no lower than 450 -- this tells me that I'm not using an absurd amount of memory.
I've tried removing the Timer1 instantiation, interrupt attach/detach, bu that has had no effect on the program.
My .ino file(and Command) is located here for anyone that wants a fuller picture and doesn't want to scroll through all this code I'm going to post below.
Here's my log output so far. Notice the truncation!:
AT&F
AT+NMAC=00:1d:c9:10:39:6f
AT+WM=0
AT+NDHCP=1
AT+WA=ardrone_279440
AT+NCUDP=192.168.1.1,5556
S0AT*CONFIG=1,"general:navdata_demo","TRUE"
EAT*CONFIG=1,"general:navdata_demo","TRUE"
638
S0AT*CONFIG=2,"control:altitude_max","2000"
EAT*CONFIG=2,"control:altitude_max","2000"
638
S0AT*CONFIG=3,"control:euler_angle_max","0.35"
EAT*CONFIG=3,"control:euler_angle_max","0.35"
586
S0AT*CONFIG=4,"control:outdoor","FALSE"
EAT*CONFIG=4,"control:outdoor","FALSE"
635
S0AT*CONFIG=5,"control:flight_without_shell","FALSE"
EAT*CONFIG=5,"control:flight_without_shell","FALSE"
574
S0AT*CTRL=6,4,0
EAT*CTRL=6,4,0
629
S0AT*CTRL=7,0,0
EAT*CTRL=7,0,0
629
S0AT*CTRL=8,4,0
EAT*CTRL=8,4,0
629
S0AT*COMWDG=9
EAT*COMWDG=9
629
S0AT*COMWDG=10
EAT*COMWDG=10
629
S0AT*COMWDG=11
EAT*COMWDG=11
629
S0AT*COMWDG=12
EAT*COMWDG=12
629
S0AT*COMWDG=13
EAT*COMWDG=13
629
S0AT*FTRIM=14
EAT*FTRIM=14
629
Here is my .ino file:
#include "Command.h"
#include "Streaming.h"
int debug = 1;
extern ring_buffer rx_buf;
extern resultint_ resultint;
Command com;
int sequenceNumber = 1;
String atcmd = "";
#include "TimerOne.h"
#define LEDpin 13
void setup()
{
PCsrl.begin(9600);
com.start_wifi_connection();
com.drone_is_init = com.init_drone();
Timer1.initialize(COMWDG_INTERVAL_USEC);
Timer1.attachInterrupt(watchdog_timer);
}
void watchdog_timer() {
com.sendwifi(com.makeComwdg());
}
void loop()
{
if (com.drone_is_init == 0) {
if (debug) {
// never use three ! together in arduino code
PCsrl.println("Drone wasn't initlized before loop() was called. Initalizing now.\r\n");
}
} else {
com.drone_takeoff();
com.drone_takeoff();
com.sendwifi(com.makePcmd(1,0,0,0,0));
com.sendwifi(com.makePcmd(1,0,0,0,0));
delay(5000);
com.moveForward(1);
com.moveRotate(180);
com.moveForward(1);
com.moveRotate(180);
delay(500);
com.drone_landing();
com.drone_landing();
delay(500);
//end of program
Timer1.detachInterrupt();
PCsrl.println("Program finished");
while (1){};
}
}
And my Command.cpp
#ifndef GAINSPAN
#define GAINSPAN
#include "Command.h"
extern int sequenceNumber;
extern int debug;
ring_buffer rx_buf= {{0}, 0, 0};
resultint_ resultint;
Command::Command()
{
at = "";
command = "";
s2ip_running = 0;
drone_is_init = 0;
drone_is_hover = 0;
emergency = 0;
}
void Command::sendwifi(String s) {
WIFIsrl.write(27); //esc
WIFIsrl.print("S0"); //choose connection CID 0
WIFIsrl.print(s);
WIFIsrl.write(27);
WIFIsrl.print("E");
if(debug) PCsrl.println(s);
WIFIsrl.println(memoryTest());
}
int Command::start_wifi_connection()
{
WIFIsrl.begin(9600);
WIFIsrl.println("");
WIFIsrl.println("AT&F");
//WIFIsrl.println("ATE0"); //turn off echo
WIFIsrl.print("AT+NMAC=00:1d:c9:10:39:6f\r"); //set MAC address
WIFIsrl.println("AT+WM=0");
WIFIsrl.println("AT+NDHCP=1");
/* drone's network profile, change if needed*/
WIFIsrl.println("AT+WA=ardrone_279440");
WIFIsrl.println("AT+NCUDP=192.168.1.1,5556");
readARsrl();
delay(3000); //need 3 seconds for connection to establish
return 0;
}
String Command::makeComwdg()
{
at = "AT*COMWDG=";
command = at + getSequenceNumber() + "\r\n";
return command;
}
void Command::sendComwdg_t(int msec)
{
for (int i = 0; i < msec; i+=20) {
sendwifi(makeComwdg());
delay(20);
}
}
void Command::sendFtrim()
{
at = "AT*FTRIM=";
command = at + getSequenceNumber() + "\r\n";
sendwifi(command);
}
void Command::sendConfig(String option, String value)
{
at = "AT*CONFIG=";
command = at + getSequenceNumber() + ",\"" + option + "\",\"" + value + "\"\r\n";
sendwifi(command);
}
void Command::sendRef(flying_status fs)
{
at = "AT*REF=";
if(fs == TAKEOFF){
command = at + getSequenceNumber() + ",290718208\r\n"; //takeoff
}
else if(fs == LANDING){
command = at + getSequenceNumber() + ",290717696\r\n"; //landing
} else if (fs == EMERGENCY_TOGGLE){
command = at + getSequenceNumber() + ",290717952\r\n"; //landing
}
// emergency -> 290717952
sendwifi(command);
}
void Command::send_control_commands(){
at = "AT*CTRL=";
sendwifi(at+getSequenceNumber()+",4,0\r\n");
sendwifi(at+getSequenceNumber()+",0,0\r\n");
sendwifi(at+getSequenceNumber()+",4,0\r\n");
}
void Command::drone_emergency_reset()
{
at = "AT*REF=";
command = at + getSequenceNumber() + ",290717952\r\n";
sendwifi(command);
}
/** Movement functions **/
int Command::moveForward(float distanceInMeters)
{
float i = 0;
String moveForward = makePcmd(1, 0, -.855, 0, 0);
delay(1000*distanceInMeters);
sendPcmd(moveForward);
return 1;
}
int Command::moveRotate(float yawInDegrees)
{
int i = 0;
while (i < yawInDegrees) {
String stayRotate = makePcmd(1, 0, 0, 0, 0.17);
sendPcmd(stayRotate);
delay(150);
i += 8;
}
return 1;
}
String Command::makePcmd(int enable, float roll, float pitch, float gaz, float yaw)
{
at = "AT*PCMD=";
command = at + getSequenceNumber() + "," + enable + "," + fl2int(roll) + "," + fl2int(pitch) + "," + fl2int(gaz) + "," + fl2int(yaw) + "\r";
return command;
}
void Command::sendPcmd(String command)
{
previousCommand = command;
sendwifi(command);
}
void Command::sendPcmd(int enable, float roll, float pitch, float gaz, float yaw)
{
at = "AT*PCMD=";
command = at + getSequenceNumber() + "," + enable + "," + fl2int(roll) + "," + fl2int(pitch) + "," + fl2int(gaz) + "," + fl2int(yaw) + "\r";
sendwifi(command);
}
String Command::makeAnim(anim_mayday_t anim, int time)
{
at = "AT*ANIM=";
command = at + getSequenceNumber() + "," + anim + "," + time + "\r\n";
return command;
}
void Command::doLEDAnim(int animseq, int duration)
{
PCsrl << "calling LEDAnim" << endl;
at = "AT*LED=";
command = at + getSequenceNumber() + "," + animseq + ",1073741824," + duration + "\r\n";
sendwifi(command);
}
int Command::start_s2ip()
{
char temp;
//delay(20000); //wait for drone to start
readARsrl();
if (debug) {
PCsrl << "trying to start s2ip" << endl;
}
ARsrl.print("\r\n");
delay(500);
ARsrl.print("\r\n");
delay(500);
ARsrl << "cd ~" << endl;
if (debug) {
readARsrl();
}
delay(500);
ARsrl << "cd data/video/apps/" << endl;
delay(500);
ARsrl << "./s2ip.arm" << endl;
while ((int) temp != 2) {
temp = ARsrl.read();
if (temp == 2) {
PCsrl << "s2ip is running" << endl;
ARsrl << "bullshit\r\n"; //to fix a delay bug
break;
}
//PCsrl << "s2ip not running" << endl;
}
if (debug) {
while (ARsrl.available()) {
PCsrl.write(ARsrl.read());
}
}
return 1;
}
void Command::quit_s2ip()
{
ARsrl.println("EXIT");
while (ARsrl.available()) {
PCsrl.write(ARsrl.read());
}
}
int Command::init_drone()
{
sendConfig("general:navdata_demo","TRUE");
sendConfig("control:altitude_max","2000");
sendConfig("control:euler_angle_max","0.35");
sendConfig("control:outdoor","FALSE");
sendConfig("control:flight_without_shell","FALSE");
send_control_commands();
sendComwdg_t(90);
sendFtrim();
drone_emergency_reset(); //clear emergency flag
return 1;
}
int Command::drone_takeoff()
{
sendRef(TAKEOFF);
int i = 0;
return 1;
}
int Command::drone_hover(int msec)
{
int i = 0;
while (i < msec) {
sendwifi(makePcmd(1, 0, 0, 0, 0));
delay(100);
i += 100;
}
return 1;
}
int Command::drone_landing()
{
sendRef(LANDING);
return 1;
}
int Command::drone_move_up(int centimeter)
{
int i = 0;
while (i < centimeter) {
ARsrl << makePcmd(1, 0, 0, 0.6, 0);
delay(100);
i += 10;
}
return 1;
}
int Command::drone_move_down(int centimeter)
{
int i = 0;
while (i < centimeter) {
sendwifi(makePcmd(1, 0, 0, -0.5, 0));
delay(100);
i += 10;
}
return 1;
}
long Command::fl2int(float value)
{
resultint.i = 0;
if (value < -1 || value > 1) {
resultint.f = 1;
} else {
resultint.f=value;
}
return resultint.i;
}
void Command::readARsrl()
{
while (ARsrl.available()) {
if (debug) {
PCsrl.write(ARsrl.read());
}
}
}
//Memory test code from : http://www.faludi.com/2007/04/18/arduino-available-memory-test/
int Command::memoryTest() {
int byteCounter = 0; // initialize a counter
byte *byteArray; // create a pointer to a byte array
// More on pointers here: http://en.wikipedia.org/wiki/Pointer#C_pointers
// use the malloc function to repeatedly attempt
// allocating a certain number of bytes to memory
// More on malloc here: http://en.wikipedia.org/wiki/Malloc
while ( (byteArray = (byte*) malloc (byteCounter * sizeof(byte))) != NULL ) {
byteCounter++; // if allocation was successful, then up the count for the next try
free(byteArray); // free memory after allocating it
}
free(byteArray); // also free memory after the function finishes
return byteCounter; // send back the highest number of bytes successfully allocated
}
int Command::getSequenceNumber(){
return sequenceNumber++;
}
// Volatile, since it is modified in an ISR.
volatile boolean inService = false;
void SrlRead()
{
if (inService) {
PCsrl.println("timer kicked too fast");
return;
}
interrupts();
inService = true;
while(ARsrl.available()) {
unsigned char k = ARsrl.read();
store_char(k, &rx_buf);
}
inService = false;
}
void read_rx_buf()
{
while (rx_buf.tail != rx_buf.head) {
if (debug) {
PCsrl.write(rx_buf.buffer[rx_buf.tail]);
}
rx_buf.tail = (unsigned int) (rx_buf.tail+ 1) % SERIAL_BUFFER_SIZE;
}
}
inline void store_char(unsigned char c, ring_buffer *buffer)
{
int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != buffer->tail) {
buffer->buffer[buffer->head] = c;
buffer->head = i;
}
else {
Serial.println("ring buffer is too small");
}
}
#endif
I know it sounds weird but, sometimes this happens when arduino is not getting enough power supply. Try connecting the arduino to a power source different from USB.
As soon as I started to put things in prog memory my program started to clear up it's hiccups. It seems it was a memory issue.
I had the same problem, but the issue was with Timer1.initialize(). Try this:
com.drone_is_init = com.init_drone();
Serial.println("One");
Serial.println("Two");
Serial.println("Three");
Timer1.initialize(COMWDG_INTERVAL_USEC);
Timer1.attachInterrupt(watchdog_timer);
Open serial monitor and see... it will show until "Two", and then Arduino will hang.
The issue was I calling some functions of the LiquidCrystal_I2C library, that need interrupt routines. Check if your timer ISR is using some interrupts. If so, you should move this code to another place in your project.