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.
Related
Hello my goal is to design an embedded system for the Nios II processor and DE1-SoC development board that will control a servo motor to sweep between two angles. The embedded system should contain a custom IP that creates the appropriate Pulse-Width Modulation (PWM) signal to sweep the servo-motor’s arm. The system also contains 8 switches for entering the start and stop angles, 2 pushbuttons for “locking” in the angles and 5 seven-segment displays for displaying the start and stop angles. I am experimenting with the custom servo motor component in Nios and I am not sure how to proceed. I have made the component to accept inputs from the switches, but in previous trials I could not get the servo motor to move.
Any help would be appreciated
Here is my code:
#include "sys/alt_stdio.h"
#include "io.h"
#include <stdio.h>
#include "system.h"
#include "alt_types.h"
#include "sys/alt_irq.h"
#include "altera_avalon_pio_regs.h"
#define HEXZERO 0x40
#define HEXONE 0x79
#define HEXTWO 0x24
#define HEXTHREE 0x30
#define HEXFOUR 0x19
#define HEXFIVE 0x12
#define HEXSIX 0x02
#define HEXSEVEN 0x78
#define HEXEIGHT 0x00
#define HEXNINE 0x10
//array
char hexArray0 [] = { HEXZERO, HEXONE, HEXTWO, HEXTHREE, HEXFOUR, HEXFIVE, HEXSIX, HEXSEVEN, HEXEIGHT, HEXNINE };
char hexArray1 [] = { HEXZERO, HEXONE, HEXTWO, HEXTHREE, HEXFOUR, HEXFIVE, HEXSIX, HEXSEVEN, HEXEIGHT, HEXNINE };
char hexArray2 [] = { HEXZERO, HEXONE, HEXTWO, HEXTHREE, HEXFOUR, HEXFIVE, HEXSIX, HEXSEVEN, HEXEIGHT, HEXNINE };
char hexArray4 [] = { HEXZERO, HEXONE, HEXTWO, HEXTHREE, HEXFOUR, HEXFIVE, HEXSIX, HEXSEVEN, HEXEIGHT, HEXNINE };
char hexArray5 [] = { HEXZERO, HEXONE, HEXTWO, HEXTHREE, HEXFOUR, HEXFIVE, HEXSIX, HEXSEVEN, HEXEIGHT, HEXNINE };
// create standard embedded type definitions
typedef signed char sint8; // signed 8 bit values
typedef unsigned char uint8; // unsigned 8 bit values
typedef signed short sint16; // signed 16 bit values
typedef unsigned short uint16; // unsigned 16 bit values
typedef signed long sint32; // signed 32 bit values
typedef unsigned long uint32; // unsigned 32 bit values
typedef float real32; // 32 bit real values
//set up pointers to peripherals
//uint32* TimerPtr = (uint32*)TIMER_0_BASE;
uint32* JtagUartPtr = (uint32*)JTAG_UART_0_BASE;
uint32* CustomIpPtr = (uint32*)SERVO_CONTROLLER_0_BASE;
unsigned char* switchesBase_ptr = (unsigned char*)SWITCHES_BASE;
unsigned char* hex_ptr0 = (unsigned char*)HEX0_BASE;
unsigned char* hex_ptr1 = (unsigned char*)HEX1_BASE;
unsigned char* hex_ptr2 = (unsigned char*)HEX2_BASE;
unsigned char* hex_ptr4 = (unsigned char*)HEX4_BASE;
unsigned char* hex_ptr5 = (unsigned char*)HEX5_BASE;
unsigned char* buttons_ptr = (unsigned char*)PUSHBUTTONS_BASE;
int arrayCounter=0;
unsigned int read_push=0 ;
unsigned int read_switch=0 ;
unsigned int isr_flag=0 ; //if flag=0 means miniumum angle / flag=1 means maximum angle
int servo_input_min=0;
int servo_input_max=0;
int key3,key2 =0;
int hex0_index, hex1_index, hex2_index,hex4_index,hex5_index;
int fortySix= 0b00101110; //binary
int fortySix_n= 0x0000C57A; //fortySix*1099;
int oneThreeFour= 0b10000110; //binary
int oneThreeFour_n= 0x00018464; //oneThreeSix*742;
int eighty= 0b01010000; //binary
int eighty_n=0x00010F40; // eighty*868 ;
int hundred= 0b01100100; //binary
int hundred_n= 0x00013A74; //hundred*805;
int fortyFive= 0b00101101; //binary
int fortyFive_n= 0x0000C350 ;//fortyFive*1110;
int ninety= 0b01011010; //binary
int ninety_n=0x000124F8;// ninety* 833;
int oneThreeFive=0b10000111; //binary
int oneThreeFive_n= 0x000186A0; //oneThreeFive*740;
void button_isr(void *context)
/*****************************************************************************/
/* Interrupt Service Routine */
/* Determines what caused the interrupt and calls the appropriate */
/* subroutine. */
/* */
/*****************************************************************************/
{
unsigned char current_val;
//clear timer interrupt
//*TimerPtr = 0;
current_val= *buttons_ptr;
if(current_val==0b1000){
key3=1;
}
else if(current_val==0b0100){
key2=1;
}
*(buttons_ptr + 12)= 1;
return;
}
void servo_isr(void *context){
*(CustomIpPtr ) = servo_input_min;
*(CustomIpPtr + 1) = servo_input_max;
return;
}
int main()
{
printf("Hello from Nips II!\n");
uint32 i;
servo_input_min=fortyFive_n;
servo_input_max=oneThreeFive_n;
*hex_ptr0 = hexArray0[5]; //5
*hex_ptr1 = hexArray1[3]; //3
*hex_ptr2 = hexArray2[1]; //1
*hex_ptr4 = hexArray4[5]; //5
*hex_ptr5 = hexArray5[4]; //4
alt_ic_isr_register(SERVO_CONTROLLER_0_IRQ_INTERRUPT_CONTROLLER_ID, SERVO_CONTROLLER_0_IRQ, servo_isr,CustomIpPtr,0);
*(CustomIpPtr ) = servo_input_min;
*(CustomIpPtr + 1) = servo_input_max;
alt_ic_isr_register(PUSHBUTTONS_IRQ_INTERRUPT_CONTROLLER_ID,PUSHBUTTONS_IRQ,button_isr,0,0);
*(buttons_ptr + 8)= 0x0C; //key 3,2
while (1) { //start loop
*buttons_ptr &= 0x0C;
*switchesBase_ptr &= 0xFF;
read_push = *buttons_ptr;
read_switch = *switchesBase_ptr;
if (read_switch == fortySix) {
servo_input_min = fortySix_n;
isr_flag = 0; //key3
} else if (read_switch == oneThreeFour) {
servo_input_max = oneThreeFour_n;
isr_flag = 1; //key2
} else if (read_switch == eighty) {
servo_input_min = eighty_n;
isr_flag = 0; //key3
} else if (read_switch == hundred) {
servo_input_max = hundred_n;
isr_flag = 1; //key2
} else if (read_switch == ninety) {
servo_input_min = ninety_n;
servo_input_max = ninety_n;
isr_flag = 1; //key 3,2
}
if (isr_flag == 1 && key2 == 1) { //max angle
while (read_push == 13) { //while button is still pressed stay in loop
*buttons_ptr &= 0x0C;
read_push = *buttons_ptr;
}
if (servo_input_max == oneThreeFour_n) { //134
hex2_index = 1;
hex1_index = 3;
hex0_index = 4;
} else if (servo_input_max == hundred_n) { //100
hex2_index = 1;
hex1_index = 0;
hex0_index = 0;
} else if (servo_input_max == ninety_n) { //90
hex2_index = 9;
hex1_index = 0;
hex0_index = 0;
}
*hex_ptr2 = hexArray0[hex2_index];
*hex_ptr1 = hexArray0[hex1_index];
*hex_ptr0 = hexArray0[hex0_index];
while (read_push != 15) { //while button is still unpressed stay in loop 15=0
*buttons_ptr &= 0x0C;
read_push = *buttons_ptr;
}
} else if (isr_flag == 0 && key3 == 1) { //min angle
while (read_push != 13) { //while button is still unpressed stay in loop 15=0
*buttons_ptr &= 0x0C;
read_push = *buttons_ptr;
}
if (servo_input_max == fortySix_n) { //46
hex5_index = 4;
hex4_index = 6;
} else if (servo_input_max == eighty_n) { //80
hex5_index = 8;
hex4_index = 0;
} else if (servo_input_max == ninety_n) { //90
hex5_index = 9;
hex4_index = 0;
}
*hex_ptr5 = hexArray0[hex5_index];
*hex_ptr4 = hexArray0[hex4_index];
while (read_push != 15) { //while button is still unpressed stay in loop 15=0
*buttons_ptr &= 0x0C;
read_push = *buttons_ptr;
}
}
}
return 0;
}
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++;
}
...
PROBLEM
I'm starting to play with Arduino IoT (ESP32). I read the GPIO configuration from a file on the SD card. I have a problem with external interrupts. I need to count the number of interrupts on a given GPIO.
I wrote a class that stores the GPIO configuration, and put the objects of this class in a global array. How can I count interrupts on a given pin, so that the result is available by using the appropriate object method?
I tried different solutions, but the problem lies in the ISR method, which must be static. This method has no access to object fields, so I do not know where and how to increment the counter of interrupts.
I divided the code into several files. I attach only the necessary to solve this problem.
This holds up my project. Please help.
Main file:
#define GPIO_CONFIG_FILE "cfg/gpio.txt"
#define WIFI_AP_CONFIG_FILE "cfg/ap.txt"
#define WIFI_STA_CONFIG_FILE "cfg/sta.txt"
#define AVAILABLE_GPIO_CNT 7
#define LED_BUILTIN_OLIMEX 33
#define BTN_BUILTIN_OLIMEX 34
#include "FS.h"
#include "SD_MMC.h"
#include "GPIO_CONFIG.h"
GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];
uint32_t gpio_int_cnt[AVAILABLE_GPIO_CNT] = {0};
void setup() {
if (checkSdCard()) {
setUpPinsFromFile(GPIO_CONFIG_FILE);
}
}
void loop() {
}
GPIO_CONFIG.h
#ifndef GPIO_CONFIG_h
#define GPIO_CONFIG_h
#include "Arduino.h"
#define ID_LENGTH 7
class GPIO_CONFIG {
public:
GPIO_CONFIG();
void setUp(const char * key);
void printConfig();
uint8_t number();
uint8_t mode();
uint16_t multiplier();
bool inversion();
char * id();
static void isr();
static uint32_t int_cnt();
private:
uint8_t gp_number;
uint8_t gp_mode;
uint16_t gp_multiplier;
uint32_t gp_init_value;
bool gp_inversion;
char gp_id[ID_LENGTH];
// const uint8_t gp_mode_array[4] = {INPUT, OUTPUT, INPUT_PULLUP};
};
#endif
GPIO_CONFIG.cpp
#include "GPIO_CONFIG.h"
GPIO_CONFIG::GPIO_CONFIG() {
gp_number = 0;
gp_multiplier = 1;
gp_inversion = false;
gp_init_value = 0;
}
void GPIO_CONFIG::setUp(const char * key) {
//nr|id|name|mode|multi|inv|init
char cfg[sizeof(key)];
for (uint8_t b = 0; b < sizeof(key); ++b) {
cfg[b] = key[b];
}
//PIN_NUMBER
char * tok = strtok(cfg, "|");
gp_number = atoi(tok);
//ID
tok = strtok(NULL, "|");
for (int b = 0; b < sizeof(tok); b++) {
if (b < ID_LENGTH) {
gp_id[b] = tok[b];
} else {
break;
}
}
gp_id[ID_LENGTH - 1] = '\0';
//NAME
strtok(NULL, "|");
//MODE
tok = strtok(NULL, "|");
gp_mode = atoi(tok);
//MULTIPLIER
tok = strtok(NULL, "|");
gp_multiplier = atoi(tok);
//INVERSION
tok = strtok(NULL, "|");
gp_inversion = (atoi(tok) > 0);
//INITIAL VALUE
tok = strtok(NULL, "|");
gp_init_value = atoi(tok);
//0-in; 1-out; 2-int
if (gp_mode != 1) {
if (gp_inversion) { //sterowanie podstawowe przez vcc
pinMode(gp_number, INPUT_PULLUP);
} else {
pinMode(gp_number, INPUT);
}
if (gp_mode > 2) {
attachInterrupt(digitalPinToInterrupt(gp_number), isr, FALLING);
}
} else {
pinMode(gp_number, OUTPUT);
}
}
void GPIO_CONFIG::printConfig() {
#ifdef DEBUG
Serial.print("GPIO_CONFIG:");
Serial.print(" -no:");
Serial.print(gp_number);
Serial.print(" -id:");
Serial.print(gp_id);
Serial.print(" -mode:");
Serial.print(gp_mode);
Serial.print(" -multi:");
Serial.print(gp_multiplier);
Serial.print(" -inv:");
Serial.print(gp_inversion);
Serial.println("");
#endif
}
uint8_t GPIO_CONFIG::number() {
return gp_number;
}
uint8_t GPIO_CONFIG::mode() {
return gp_mode;
}
uint16_t GPIO_CONFIG::multiplier() {
return gp_multiplier;
}
bool GPIO_CONFIG::inversion() {
return gp_inversion;
}
char * GPIO_CONFIG::id() {
return gp_id;
}
void GPIO_CONFIG::isr() {
// gpio_int_cnt[0]++;
}
uint32_t GPIO_CONFIG::int_cnt() {
// return gpio_int_cnt[0];
}
#EDIT 2018/01/04 08:10
I add some changes to files:
Main .ino file
isr_ptr isrptr[AVAILABLE_GPIO_CNT];
GPIO_CONFIG.h
#define AVAILABLE_GPIO_CNT 7
class GPIO_CONFIG;
typedef /*static*/ void (*isr_ptr)();
extern isr_ptr isrptr[AVAILABLE_GPIO_CNT];
extern GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];
(...)
public:
void setIndex(const uint8_t * i);
uint8_t index();
(...)
private:
uint8_t gp_index;
uint32_t gp_cnt_value;
GPIO_CONFIG.cpp
void GPIO_CONFIG::setIndex(const uint8_t * i){
gp_index = *i;
isrptr[gp_index] = &isr;
}
uint8_t GPIO_CONFIG::index(){
return gp_index;
}
void GPIO_CONFIG::setUp(const char * key) {
(...)
attachInterrupt(digitalPinToInterrupt(gp_number), isrptr[gp_index], FALLING);
(...)
}
void GPIO_CONFIG::isr() {
for(uint8_t i=0; i<AVAILABLE_GPIO_CNT; ++i){
if(&isrptr[i] == &gpio[i].isr()){ //here is my actualy problem. how can i compare this?
gpio[i].increment_cnt_value();
break;
}
}
}
uint32_t GPIO_CONFIG::int_cnt() {
return gp_cnt_value;
}
SOLUTION
Here I place short fragments which have to be modified:
GPIO_CONFIG.cpp
From isrptr[gp_index] = &isr; to isrptr[gp_index] = isr;
From if(&isrptr[i] == &gpio[i].isr){ to if(isrptr[i] == gpio[i].isr){
I've looked over your code several times and can't find your ISR(s). I know how to handle this sort of problem in simple C code: You just define an array with one element for each interrupt pin, and increment that element from its respective ISR. I don't know how to relate that to what you've shown.
The part that often causes trouble is that you usually need to define variables shared between the main code and ISR as volatile. Failing to do this can cause problems that are really hard to find, due to the compiler optimizing away things that it decides aren't changed (in the ISR or the main code).
Best regards,
i have difficulties in using LZMA SDK in my application.
I would like to create a kind of single file compression tool. I dont need any directory support, just need only the LZMA2 stream. But i have no idea on how LZMA SDK is to be used for this.
Please can anyone give me a little example on how the LZMA SDK can be used under C++?
I think that it's a properly little example to use LZMA SDK.
/* LzmaUtil.c -- Test application for LZMA compression
2008-08-05
Igor Pavlov
public domain */
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../LzmaDec.h"
#include "../LzmaEnc.h"
#include "../Alloc.h"
const char *kCantReadMessage = "Can not read input file";
const char *kCantWriteMessage = "Can not write output file";
const char *kCantAllocateMessage = "Can not allocate memory";
const char *kDataErrorMessage = "Data error";
static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
static void SzFree(void *p, void *address) { p = p; MyFree(address); }
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
#define kInBufferSize (1 << 15)
#define kOutBufferSize (1 << 15)
unsigned char g_InBuffer[kInBufferSize];
unsigned char g_OutBuffer[kOutBufferSize];
size_t MyReadFile(FILE *file, void *data, size_t size)
{ return fread(data, 1, size, file); }
int MyReadFileAndCheck(FILE *file, void *data, size_t size)
{ return (MyReadFile(file, data, size) == size); }
size_t MyWriteFile(FILE *file, const void *data, size_t size)
{
if (size == 0)
return 0;
return fwrite(data, 1, size, file);
}
int MyWriteFileAndCheck(FILE *file, const void *data, size_t size)
{ return (MyWriteFile(file, data, size) == size); }
long MyGetFileLength(FILE *file)
{
long length;
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
return length;
}
void PrintHelp(char *buffer)
{
strcat(buffer, "\nLZMA Utility 4.58 Copyright (c) 1999-2008 Igor Pavlov 2008-04-11\n"
"\nUsage: lzma <e|d> inputFile outputFile\n"
" e: encode file\n"
" d: decode file\n");
}
int PrintError(char *buffer, const char *message)
{
strcat(buffer, "\nError: ");
strcat(buffer, message);
strcat(buffer, "\n");
return 1;
}
int PrintErrorNumber(char *buffer, SRes val)
{
sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
return 1;
}
int PrintUserError(char *buffer)
{
return PrintError(buffer, "Incorrect command");
}
#define IN_BUF_SIZE (1 << 16)
#define OUT_BUF_SIZE (1 << 16)
static int Decode(FILE *inFile, FILE *outFile, char *rs)
{
UInt64 unpackSize;
int thereIsSize; /* = 1, if there is uncompressed size in headers */
int i;
int res = 0;
CLzmaDec state;
/* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
unsigned char header[LZMA_PROPS_SIZE + 8];
/* Read and parse header */
if (!MyReadFileAndCheck(inFile, header, sizeof(header)))
return PrintError(rs, kCantReadMessage);
unpackSize = 0;
thereIsSize = 0;
for (i = 0; i < 8; i++)
{
unsigned char b = header[LZMA_PROPS_SIZE + i];
if (b != 0xFF)
thereIsSize = 1;
unpackSize += (UInt64)b << (i * 8);
}
LzmaDec_Construct(&state);
res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
if (res != SZ_OK)
return res;
{
Byte inBuf[IN_BUF_SIZE];
Byte outBuf[OUT_BUF_SIZE];
size_t inPos = 0, inSize = 0, outPos = 0;
LzmaDec_Init(&state);
for (;;)
{
if (inPos == inSize)
{
inSize = MyReadFile(inFile, inBuf, IN_BUF_SIZE);
inPos = 0;
}
{
SizeT inProcessed = inSize - inPos;
SizeT outProcessed = OUT_BUF_SIZE - outPos;
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
ELzmaStatus status;
if (thereIsSize && outProcessed > unpackSize)
{
outProcessed = (SizeT)unpackSize;
finishMode = LZMA_FINISH_END;
}
res = LzmaDec_DecodeToBuf(&state, outBuf + outPos, &outProcessed,
inBuf + inPos, &inProcessed, finishMode, &status);
inPos += (UInt32)inProcessed;
outPos += outProcessed;
unpackSize -= outProcessed;
if (outFile != 0)
MyWriteFile(outFile, outBuf, outPos);
outPos = 0;
if (res != SZ_OK || thereIsSize && unpackSize == 0)
break;
if (inProcessed == 0 && outProcessed == 0)
{
if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
res = SZ_ERROR_DATA;
break;
}
}
}
}
LzmaDec_Free(&state, &g_Alloc);
return res;
}
typedef struct _CFileSeqInStream
{
ISeqInStream funcTable;
FILE *file;
} CFileSeqInStream;
static SRes MyRead(void *p, void *buf, size_t *size)
{
if (*size == 0)
return SZ_OK;
*size = MyReadFile(((CFileSeqInStream*)p)->file, buf, *size);
/*
if (*size == 0)
return SZE_FAIL;
*/
return SZ_OK;
}
typedef struct _CFileSeqOutStream
{
ISeqOutStream funcTable;
FILE *file;
} CFileSeqOutStream;
static size_t MyWrite(void *pp, const void *buf, size_t size)
{
return MyWriteFile(((CFileSeqOutStream *)pp)->file, buf, size);
}
static SRes Encode(FILE *inFile, FILE *outFile, char *rs)
{
CLzmaEncHandle enc;
SRes res;
CFileSeqInStream inStream;
CFileSeqOutStream outStream;
CLzmaEncProps props;
enc = LzmaEnc_Create(&g_Alloc);
if (enc == 0)
return SZ_ERROR_MEM;
inStream.funcTable.Read = MyRead;
inStream.file = inFile;
outStream.funcTable.Write = MyWrite;
outStream.file = outFile;
LzmaEncProps_Init(&props);
res = LzmaEnc_SetProps(enc, &props);
if (res == SZ_OK)
{
Byte header[LZMA_PROPS_SIZE + 8];
size_t headerSize = LZMA_PROPS_SIZE;
UInt64 fileSize;
int i;
res = LzmaEnc_WriteProperties(enc, header, &headerSize);
fileSize = MyGetFileLength(inFile);
for (i = 0; i < 8; i++)
header[headerSize++] = (Byte)(fileSize >> (8 * i));
if (!MyWriteFileAndCheck(outFile, header, headerSize))
return PrintError(rs, "writing error");
if (res == SZ_OK)
res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
NULL, &g_Alloc, &g_Alloc);
}
LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
return res;
}
int main2(int numArgs, const char *args[], char *rs)
{
FILE *inFile = 0;
FILE *outFile = 0;
char c;
int res;
int encodeMode;
if (numArgs == 1)
{
PrintHelp(rs);
return 0;
}
if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)
return PrintUserError(rs);
c = args[1][0];
encodeMode = (c == 'e' || c == 'E');
if (!encodeMode && c != 'd' && c != 'D')
return PrintUserError(rs);
{
size_t t4 = sizeof(UInt32);
size_t t8 = sizeof(UInt64);
if (t4 != 4 || t8 != 8)
return PrintError(rs, "LZMA UTil needs correct UInt32 and UInt64");
}
inFile = fopen(args[2], "rb");
if (inFile == 0)
return PrintError(rs, "Can not open input file");
if (numArgs > 3)
{
outFile = fopen(args[3], "wb+");
if (outFile == 0)
return PrintError(rs, "Can not open output file");
}
else if (encodeMode)
PrintUserError(rs);
if (encodeMode)
{
res = Encode(inFile, outFile, rs);
}
else
{
res = Decode(inFile, outFile, rs);
}
if (outFile != 0)
fclose(outFile);
fclose(inFile);
if (res != SZ_OK)
{
if (res == SZ_ERROR_MEM)
return PrintError(rs, kCantAllocateMessage);
else if (res == SZ_ERROR_DATA)
return PrintError(rs, kDataErrorMessage);
else
return PrintErrorNumber(rs, res);
}
return 0;
}
int MY_CDECL main(int numArgs, const char *args[])
{
char rs[800] = { 0 };
int res = main2(numArgs, args, rs);
printf(rs);
return res;
}
Also you can see it at:
http://read.pudn.com/downloads151/sourcecode/zip/656407/7z460/C/LzmaUtil/LzmaUtil.c__.htm
http://read.pudn.com/downloads157/sourcecode/zip/698262/LZMA/LzmaUtil.c__.htm
I recently found a nice example, written in C++. Credit goes to GH user Treeki who published the original gist:
// note: -D_7ZIP_ST is required when compiling on non-Windows platforms
// g++ -o lzma_sample -std=c++14 -D_7ZIP_ST lzma_sample.cpp LzmaDec.c LzmaEnc.c LzFind.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <memory>
#include "LzmaEnc.h"
#include "LzmaDec.h"
static void *_lzmaAlloc(ISzAllocPtr, size_t size) {
return new uint8_t[size];
}
static void _lzmaFree(ISzAllocPtr, void *addr) {
if (!addr)
return;
delete[] reinterpret_cast<uint8_t *>(addr);
}
static ISzAlloc _allocFuncs = {
_lzmaAlloc, _lzmaFree
};
std::unique_ptr<uint8_t[]> lzmaCompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
std::unique_ptr<uint8_t[]> result;
// set up properties
CLzmaEncProps props;
LzmaEncProps_Init(&props);
if (inputSize >= (1 << 20))
props.dictSize = 1 << 20; // 1mb dictionary
else
props.dictSize = inputSize; // smaller dictionary = faster!
props.fb = 40;
// prepare space for the encoded properties
SizeT propsSize = 5;
uint8_t propsEncoded[5];
// allocate some space for the compression output
// this is way more than necessary in most cases...
// but better safe than sorry
// (a smarter implementation would use a growing buffer,
// but this requires a bunch of fuckery that is out of
/// scope for this simple example)
SizeT outputSize64 = inputSize * 1.5;
if (outputSize64 < 1024)
outputSize64 = 1024;
auto output = std::make_unique<uint8_t[]>(outputSize64);
int lzmaStatus = LzmaEncode(
output.get(), &outputSize64, input, inputSize,
&props, propsEncoded, &propsSize, 0,
NULL,
&_allocFuncs, &_allocFuncs);
*outputSize = outputSize64 + 13;
if (lzmaStatus == SZ_OK) {
// tricky: we have to generate the LZMA header
// 5 bytes properties + 8 byte uncompressed size
result = std::make_unique<uint8_t[]>(outputSize64 + 13);
uint8_t *resultData = result.get();
memcpy(resultData, propsEncoded, 5);
for (int i = 0; i < 8; i++)
resultData[5 + i] = (inputSize >> (i * 8)) & 0xFF;
memcpy(resultData + 13, output.get(), outputSize64);
}
return result;
}
std::unique_ptr<uint8_t[]> lzmaDecompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
if (inputSize < 13)
return NULL; // invalid header!
// extract the size from the header
UInt64 size = 0;
for (int i = 0; i < 8; i++)
size |= (input[5 + i] << (i * 8));
if (size <= (256 * 1024 * 1024)) {
auto blob = std::make_unique<uint8_t[]>(size);
ELzmaStatus lzmaStatus;
SizeT procOutSize = size, procInSize = inputSize - 13;
int status = LzmaDecode(blob.get(), &procOutSize, &input[13], &procInSize, input, 5, LZMA_FINISH_END, &lzmaStatus, &_allocFuncs);
if (status == SZ_OK && procOutSize == size) {
*outputSize = size;
return blob;
}
}
return NULL;
}
void hexdump(const uint8_t *buf, int size) {
int lines = (size + 15) / 16;
for (int i = 0; i < lines; i++) {
printf("%08x | ", i * 16);
int lineMin = i * 16;
int lineMax = lineMin + 16;
int lineCappedMax = (lineMax > size) ? size : lineMax;
for (int j = lineMin; j < lineCappedMax; j++)
printf("%02x ", buf[j]);
for (int j = lineCappedMax; j < lineMax; j++)
printf(" ");
printf("| ");
for (int j = lineMin; j < lineCappedMax; j++) {
if (buf[j] >= 32 && buf[j] <= 127)
printf("%c", buf[j]);
else
printf(".");
}
printf("\n");
}
}
void testIt(const uint8_t *input, int size) {
printf("Test Input:\n");
hexdump(input, size);
uint32_t compressedSize;
auto compressedBlob = lzmaCompress(input, size, &compressedSize);
if (compressedBlob) {
printf("Compressed:\n");
hexdump(compressedBlob.get(), compressedSize);
} else {
printf("Nope, we screwed it\n");
return;
}
// let's try decompressing it now
uint32_t decompressedSize;
auto decompressedBlob = lzmaDecompress(compressedBlob.get(), compressedSize, &decompressedSize);
if (decompressedBlob) {
printf("Decompressed:\n");
hexdump(decompressedBlob.get(), decompressedSize);
} else {
printf("Nope, we screwed it (part 2)\n");
return;
}
printf("----------\n");
}
void testIt(const char *string) {
testIt((const uint8_t *)string, strlen(string));
}
int main(int argc, char **argv) {
testIt("a");
testIt("here is a cool string");
testIt("here's something that should compress pretty well: abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef");
return 0;
}
You can refer to this file on how to use lzma2。
https://github.com/Tencent/libpag/blob/aab6391e455193c8ec5b8e2031b495b3fe77b034/test/framework/utils/LzmaUtil.cpp
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making libpag available.
//
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// unless required by applicable law or agreed to in writing, software distributed under the
// license is distributed on an "as is" basis, without warranties or conditions of any kind,
// either express or implied. see the license for the specific language governing permissions
// and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
#include "LzmaUtil.h"
#include "test/framework/lzma/Lzma2DecMt.h"
#include "test/framework/lzma/Lzma2Enc.h"
namespace pag {
static void* LzmaAlloc(ISzAllocPtr, size_t size) {
return new uint8_t[size];
}
static void LzmaFree(ISzAllocPtr, void* address) {
if (!address) {
return;
}
delete[] reinterpret_cast<uint8_t*>(address);
}
static ISzAlloc gAllocFuncs = {LzmaAlloc, LzmaFree};
class SequentialOutStream {
public:
virtual ~SequentialOutStream() = default;
virtual bool write(const void* data, size_t size) = 0;
};
class SequentialInStream {
public:
virtual ~SequentialInStream() = default;
virtual bool read(void* data, size_t size, size_t* processedSize) = 0;
};
struct CSeqInStreamWrap {
ISeqInStream vt;
std::unique_ptr<SequentialInStream> inStream;
};
struct CSeqOutStreamWrap {
ISeqOutStream vt;
std::unique_ptr<SequentialOutStream> outStream;
};
class BuffPtrInStream : public SequentialInStream {
public:
explicit BuffPtrInStream(const uint8_t* buffer, size_t bufferSize)
: buffer(buffer), bufferSize(bufferSize) {
}
bool read(void* data, size_t size, size_t* processedSize) override {
if (processedSize) {
*processedSize = 0;
}
if (size == 0 || position >= bufferSize) {
return true;
}
auto remain = bufferSize - position;
if (remain > size) {
remain = size;
}
memcpy(data, static_cast<const uint8_t*>(buffer) + position, remain);
position += remain;
if (processedSize) {
*processedSize = remain;
}
return true;
}
private:
const uint8_t* buffer = nullptr;
size_t bufferSize = 0;
size_t position = 0;
};
class VectorOutStream : public SequentialOutStream {
public:
explicit VectorOutStream(std::vector<uint8_t>* buffer) : buffer(buffer) {
}
bool write(const void* data, size_t size) override {
auto oldSize = buffer->size();
buffer->resize(oldSize + size);
memcpy(&(*buffer)[oldSize], data, size);
return true;
}
private:
std::vector<uint8_t>* buffer;
};
class BuffPtrSeqOutStream : public SequentialOutStream {
public:
BuffPtrSeqOutStream(uint8_t* buffer, size_t size) : buffer(buffer), bufferSize(size) {
}
bool write(const void* data, size_t size) override {
auto remain = bufferSize - position;
if (remain > size) {
remain = size;
}
if (remain != 0) {
memcpy(buffer + position, data, remain);
position += remain;
}
return remain != 0 || size == 0;
}
private:
uint8_t* buffer = nullptr;
size_t bufferSize = 0;
size_t position = 0;
};
static const size_t kStreamStepSize = 1 << 31;
static SRes MyRead(const ISeqInStream* p, void* data, size_t* size) {
CSeqInStreamWrap* wrap = CONTAINER_FROM_VTBL(p, CSeqInStreamWrap, vt);
auto curSize = (*size < kStreamStepSize) ? *size : kStreamStepSize;
if (!wrap->inStream->read(data, curSize, &curSize)) {
return SZ_ERROR_READ;
}
*size = curSize;
return SZ_OK;
}
static size_t MyWrite(const ISeqOutStream* p, const void* buf, size_t size) {
auto* wrap = CONTAINER_FROM_VTBL(p, CSeqOutStreamWrap, vt);
if (wrap->outStream->write(buf, size)) {
return size;
}
return 0;
}
class Lzma2Encoder {
public:
Lzma2Encoder() {
encoder = Lzma2Enc_Create(&gAllocFuncs, &gAllocFuncs);
}
~Lzma2Encoder() {
Lzma2Enc_Destroy(encoder);
}
std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
if (encoder == nullptr || inputData == nullptr || inputData->size() == 0) {
return nullptr;
}
auto inputSize = inputData->size();
CLzma2EncProps lzma2Props;
Lzma2EncProps_Init(&lzma2Props);
lzma2Props.lzmaProps.dictSize = inputSize;
lzma2Props.lzmaProps.level = 9;
lzma2Props.numTotalThreads = 4;
Lzma2Enc_SetProps(encoder, &lzma2Props);
std::vector<uint8_t> outBuf;
outBuf.resize(1 + 8);
outBuf[0] = Lzma2Enc_WriteProperties(encoder);
for (int i = 0; i < 8; i++) {
outBuf[1 + i] = static_cast<uint8_t>(inputSize >> (8 * i));
}
CSeqInStreamWrap inWrap = {};
inWrap.vt.Read = MyRead;
inWrap.inStream = std::make_unique<BuffPtrInStream>(
static_cast<const uint8_t*>(inputData->data()), inputSize);
CSeqOutStreamWrap outStream = {};
outStream.vt.Write = MyWrite;
outStream.outStream = std::make_unique<VectorOutStream>(&outBuf);
auto status =
Lzma2Enc_Encode2(encoder, &outStream.vt, nullptr, nullptr, &inWrap.vt, nullptr, 0, nullptr);
if (status != SZ_OK) {
return nullptr;
}
return Data::MakeWithCopy(&outBuf[0], outBuf.size());
}
private:
CLzma2EncHandle encoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Compress(const std::shared_ptr<Data>& pixelData) {
Lzma2Encoder encoder;
return encoder.code(pixelData);
}
class Lzma2Decoder {
public:
Lzma2Decoder() {
decoder = Lzma2DecMt_Create(&gAllocFuncs, &gAllocFuncs);
}
~Lzma2Decoder() {
if (decoder) {
Lzma2DecMt_Destroy(decoder);
}
}
std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
if (decoder == nullptr || inputData == nullptr || inputData->size() == 0) {
return nullptr;
}
auto input = static_cast<const uint8_t*>(inputData->data());
auto inputSize = inputData->size() - 9;
Byte prop = static_cast<const Byte*>(input)[0];
CLzma2DecMtProps props;
Lzma2DecMtProps_Init(&props);
props.inBufSize_ST = inputSize;
props.numThreads = 1;
UInt64 outBufferSize = 0;
for (int i = 0; i < 8; i++) {
outBufferSize |= (input[1 + i] << (i * 8));
}
auto outBuffer = new uint8_t[outBufferSize];
CSeqInStreamWrap inWrap = {};
inWrap.vt.Read = MyRead;
inWrap.inStream = std::make_unique<BuffPtrInStream>(input + 9, inputSize);
CSeqOutStreamWrap outWrap = {};
outWrap.vt.Write = MyWrite;
outWrap.outStream = std::make_unique<BuffPtrSeqOutStream>(outBuffer, outBufferSize);
UInt64 inProcessed = 0;
int isMT = false;
auto res = Lzma2DecMt_Decode(decoder, prop, &props, &outWrap.vt, &outBufferSize, 1, &inWrap.vt,
&inProcessed, &isMT, nullptr);
if (res == SZ_OK && inputSize == inProcessed) {
return Data::MakeAdopted(outBuffer, outBufferSize, Data::DeleteProc);
}
delete[] outBuffer;
return nullptr;
}
private:
CLzma2DecMtHandle decoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Decompress(const std::shared_ptr<Data>& data) {
Lzma2Decoder decoder;
return decoder.code(data);
}
} // namespace pag
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.