how to change part of argument passed to a function in C? - c

I have function
Oled_logo(const unsigned char *image)
so if i pass
unsigned char giphy_0 [] = { 0x80, 0x81, 0x03, 0x07,
0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 };
e.g. -
Oled_logo(giphy_0);
it works
but i got 14 such images naming giphy_0 ,giphy_1 ... giphy_14
so i want to run these one by one to get an animation
i just want to pass arguments to Oled_logo like Oled_logo(giphy_0) or Oled_log(giphy_1) or Oleg_logo(giphy_2) ,so instead of doing it for 14 times ,i want to call Oled_logo function in loop and change part of argument giphy_imagenumber in loop.
So instead of writing code to call Oled_logo function for 14 times ,i want a loop where i pass giphy_imagenumber to function Oled_logo and this imagenumber is replaced by loop variable ,so i have to write only few lines in a loop.
following i tried
unsigned char x[] = "giphy_0";
volatile unsigned char y ;
while(1)
{
for(int image_gif = 0 ; image_gif<=14;image_gif++)
{
x[6] = image_gif + 0x30;
Oled_logo(x);
ssd1306_UpdateScreen();
HAL_Delay(4000);
}
}
No error came ,but output is some garbage
I tried with strcat ,converted loop variable to string and concatanate with giphy_ and passed to Oled_logo function
Same problem
What i am doing wrong ?

{ 0x80, 0x81, 0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 }
is different from
"giphy_0"
What you are trying to achieve seems wrong or you are missing a piece.
My guess is you want an array like { giphy_0, giphy_1, ... } and then use the index in this array.

What you're attempting to do is pass in a string with the name of the variable in question an expecting the program to automatically replace this string with the contents of the variable of that name. That's not how C works.
The real problem here is how you've defined the arrays. Rather than having a set of arrays with names containing the array number:
unsigned char giphy_0 [] = { 0x80, 0x81, 0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 };
unsigned char giphy_1 [] = { 0x80, 0x81, 0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 };
unsigned char giphy_2 [] = { 0x80, 0x81, 0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 };
...
unsigned char giphy_14 [] = { 0x80, 0x81, 0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 };
Create an array of arrays:
unsigned char giphy[][11] = {
{ 0x80, 0x81, 0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 },
{ 0x80, 0x81, 0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 },
{ 0x80, 0x81, 0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 },
...
{ 0x80, 0x81, 0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x7f, 0xff, 0 },
};
And pass loop through the outer dimension:
for(int image_gif = 0 ; image_gif<=14; image_gif++)
{
Oled_logo(giphy[image_gif]);
ssd1306_UpdateScreen();
HAL_Delay(4000);
}

Related

How to enable 16 bit color in ili9486?

Wanna use 16 bit color, changed register 3A to 0x55 and when I’m trying to fill out my screen with red color 0xf800, nothing happens. When I use 18 bit color 0x3A = 0x66 red color is correct
UPD: Here is my piece of code that I used for 18 bit and how I rewrite it to use with 16 bit
typedef struct {
uint8_t cmd;
uint8_t data[16];
uint8_t databytes;
} lcd_init_cmd_t;
// 18 bit color
DRAM_ATTR static const lcd_init_cmd_t ili_init_cmds_18b[]={
/* SW reset */
{0x01, {0}, 0},
/* Sleep out, also SW reset */
{0x11, {0}, 0},
{0xc0, {0x0D, 0x0D}, 2},
/* 18 bit - 0x66, 16 bit 0x55 */
{0x3A, {0x66}, 1},
/* Power Control 3 (For Normal Mode) */
{0xC2, {0x44}, 1},
/* VCOM Control */
{0xC5, {0,0,0,0}, 4},
/* Positive gamma correction */
{0xE0, {0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0X98, 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00}, 15},
/* Negative gamma correction */
{0xE1, {0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00}, 15},
/* Display Inversion OFF */
{0x20, {0}, 0},
/* Memory access contorl, MX=MY=0, MV=1, ML=0, BGR=1, MH=0 */
{0x36, {0x28}, 1},
/* Display on */
{0x29, {0}, 0},
};
// 16 bit color
DRAM_ATTR static const lcd_init_cmd_t ili_init_cmds_16b[] = {
{0x01, {0}, 0},
{0x28, {0}, 0},
{0x11, {0}, 0},
{0xC0, {0x0D, 0x0D}, 2},
{0xc1, {0x43, 0x00}, 2},
{0xc2, {0x00}, 1},
{0xC5, {0x00, 0x48}, 2},
{0xB6, {0x00, 0x01, 0x3B}, 3},
{0xE0, {0x0F, 0x24, 0x1C, 0x0A, 0x0F, 0x08, 0x43, 0x88, 0x32, 0x0F, 0x10, 0x06, 0x0F, 0x07, 0x00}, 15},
{0xE1, {0x0F, 0x38, 0x30, 0x09, 0x0F, 0x0F, 0x4E, 0x77, 0x3C, 0x07, 0x10, 0x05, 0x23, 0x1B, 0x00}, 15},
{0x20, {0x00}, 1},
{0x36, {0xE8}, 1},
{0x3A, {0x55}, 1},
{0x2A, {0x00, 0x00, 0x01, 0xDF}, 4},
{0x2B, {0x00, 0x00, 0x01, 0x3F}, 4},
{0x29, {0x00}, 0}
}; // 16-bit color
void lcd_init(){
ili_init_cmds = ili_init_cmds_18b; // <- pseudocode
//Send all the commands
uint8_t len = sizeof(ili_init_cmds)/sizeof(ili_init_cmds[0]);
for (uint8_t i=0; i<len; i++){
lcd_cmd(spi, ili_init_cmds[i].cmd);
lcd_data(spi, ili_init_cmds[i].data, ili_init_cmds[i].databytes & 0x1F);
if (ili_init_cmds[i].cmd == 0x01 || ili_init_cmds[i].cmd == 0x11 || ili_init_cmds[i].cmd == 0x28 || ili_init_cmds[i].cmd == 0x29){
vTaskDelay(100 / portTICK_RATE_MS);
}
}
}
void fill_screen(){
uint16_t color = 0xf800;
uint8_t GRAM_BUFF[1440] = {0}; // width 480 pixels * 3 bytes of color
uint16_t i;
// for 18 bit
for(i=0; i<1440; i+=3){
GRAM_BUFF[i] = RGB_R(color);
GRAM_BUFF[i+1] = RGB_G(color);
GRAM_BUFF[i+2] = RGB_B(color);
}
// for 16 bit
for (i=0; i< 1440; i+=2){
GRAM_BUFF[i] = (uint8_t)(color >> 8);
GRAM_BUFF[i+1] = (uint8_t)(color);
}
for (i=0; i<HEIGHT; i+=3){ // HEIGHT = 320pixels
send_lines(spi, i, GRAM_BUFF);
}

'error: initializer element is not constant'

I'm working on a simple operating system, and I've come across an error I just can't figure out how to get rid of:
kernel.c:100:22: error: initializer element is not constant
100 | static u32 *BUFFER = (u32 *) (modeInfo->PhysBasePtr);
| ^
I tried a few little things to fix this, though I'm not sure how to go about making this work. For a bit of context, I'm trying to get VESA graphics up and running for my OS, and the problematic line is one that establishes a buffer for double buffering (I was struggling with a flickering issue). Here I'll leave kernel.c and a link to my GitHub:
kernel.c:
/*
TODO:
-Filesystem
-Mouse Inputs
-Simple GUI
-3d Viewer
-Maybe Link Downloader and Viewer
*/
#define NULL ((void*)0)
#define true 1
#define false 0
typedef unsigned char uint8_t;
typedef unsigned char u8;
typedef unsigned short uint16_t;
typedef unsigned int u32;
typedef u32 size_t;
typedef unsigned long phys_bytes;
#define SCREEN_WIDTH (int)(modeInfo->XResolution)
#define SCREEN_HEIGHT (int)(modeInfo->YResolution)
#define BPP 32
#define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
#define FPS 30
#define PIT_HERTZ 1193131.666
#define CLOCK_HIT (int)(PIT_HERTZ/FPS)
#define KEY_LEFT 0x4B
#define KEY_UP 0x48
#define KEY_RIGHT 0x4D
#define KEY_DOWN 0x50
void * malloc(size_t len) {
static size_t curoff = 0;
static char space[1 * 1024 * 1024 * 1024];
void *ptr = NULL;
if ((curoff + len) < sizeof(space)) {
ptr = &space[curoff]; curoff += len;
} return ptr;
}
typedef struct VBE_modeInfo{
/* Mandatory information for all VBE revisions */
uint16_t ModeAttributes;
uint8_t WinAAttributes;
uint8_t WinBAttributes;
uint16_t WinGranularity;
uint16_t WinSize;
uint16_t WinASegment;
uint16_t WinBSegment;
phys_bytes WinFuncPtr;
uint16_t BytesPerScanLine;
/* Mandatory information for VBE 1.2 and above */
uint16_t XResolution;
uint16_t YResolution;
uint8_t XCharSize;
uint8_t YCharSize;
uint8_t NumberOfPlanes;
uint8_t BitsPerPixel;
uint8_t NumberOfBanks;
uint8_t MemoryModel;
uint8_t BankSize;
uint8_t NumberOfImagePages;
uint8_t Reserved1;
/* Direct Color fields (required for direct/6 and YUV/7 memory models) */
uint8_t RedMaskSize; /* size of direct color red mask in bits */
uint8_t RedFieldPosition; /* bit position of lsb of red mask */
uint8_t GreenMaskSize; /* size of direct color green mask in bits */
uint8_t GreenFieldPosition; /* bit position of lsb of green mask */
uint8_t BlueMaskSize; /* size of direct color blue mask in bits */
uint8_t BlueFieldPosition; /* bit position of lsb of blue mask */
uint8_t RsvdMaskSize; /* size of direct color reserved mask in bits */
uint8_t RsvdFieldPosition; /* bit position of lsb of reserved mask */
uint8_t DirectColorModeInfo; /* direct color mode attributes */
/* Mandatory information for VBE 2.0 and above */
phys_bytes PhysBasePtr;
uint8_t Reserved2[4];
uint8_t Reserved3[2];
/* Mandatory information for VBE 3.0 and above */
uint16_t LinBytesPerScanLine; /* bytes per scan line for linear modes */
uint8_t BnkNumberOfImagePages; /* number of images for banked modes */
uint8_t LinNumberOfImagePages; /* number of images for linear modes */
uint8_t LinRedMaskSize; /* size of direct color red mask (linear modes) */
uint8_t LinRedFieldPosition; /* bit position of lsb of red mask (linear modes) */
uint8_t LinGreenMaskSize; /* size of direct color green mask (linear modes) */
uint8_t LinGreenFieldPosition; /* bit position of lsb of green mask (linear modes) */
uint8_t LinBlueMaskSize; /* size of direct color blue mask (linear modes) */
uint8_t LinBlueFieldPosition; /* bit position of lsb of blue mask (linear modes ) */
uint8_t LinRsvdMaskSize; /* size of direct color reserved mask (linear modes) */
uint8_t LinRsvdFieldPosition; /* bit position of lsb of reserved mask (linear modes) */
u32 MaxPixelClock; /* maximum pixel clock (in Hz) for graphics mode */
uint8_t Reserved4[190]; /* remainder of ModeInfoBlock */
} VBE_modeInfo;
struct VBE_modeInfo *modeInfoPointer;
#define modeInfo modeInfoPointer
static u32 *BUFFER = (u32 *) (modeInfo->PhysBasePtr);
// double buffers
u32 *_sbuffers;
u32 _sback = 0;
#define SBUF(_y,_x) \
_sbuffers[((_y) * SCREEN_SIZE) + _x]
#define CURRENT &SBUF(0,0)
#define SWAP() (_sback = 1 - _sback)
#define screen_buffer() (_sbuffers[_sback])
static inline void outb(uint16_t port, uint8_t val)
{
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
}
#define bytesPerPixel ((modeInfo->BitsPerPixel + 7) / 8)
void screen_set(u32 color,int x,int y) {
u32 physical_address = modeInfo->PhysBasePtr + y * modeInfo->LinBytesPerScanLine + x * bytesPerPixel;
if (_sbuffers == NULL)
_sbuffers = (u32 *) malloc(sizeof(u32) * 2 * SCREEN_SIZE);
SBUF(_sback,physical_address)=color;
}
static inline uint8_t inb(uint16_t port)
{
uint8_t ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "Nd"(port) );
return ret;
}
const unsigned char font[128-32][8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
/*this bit of code was deleted because it was long/irrelevant */
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F
};
static inline void *memcpy(void *dst, const void *src, size_t n)
{
u8 *d = (u8*)dst;
const u8 *s = (const u8*)src;
while (n-- > 0) {
*d++ = *s++;
}
return d;
}
void screen_swap() {
memcpy(BUFFER, CURRENT, SCREEN_SIZE);
SWAP();
}
unsigned read_pit(void) {
unsigned count = 0;
// al = channel in bits 6 and 7, remaining bits clear
outb(0x43,0b0000000);
count = inb(0x40); // Low byte
count |= inb(0x40)<<8; // High byte
return count;
}
void draw_char(char c, int x, int y, u32 color)
{
const unsigned char *glyph = font[(int)c-32];
for(int cy=0;cy<8;cy++){
for(int cx=0;cx<8;cx++){
if(((int)glyph[cy]&(1<<cx))==(1<<cx)){
screen_set(color,x+cx,y+cy);
}
}
}
}
void draw_string(const char * s, int x, int y, u32 color) {
int i = 0;
while(s[i] != false) {
draw_char(s[i],x+(i*8),y,color);
i++;
}
}
void draw_rect(int pos_x, int pos_y, int w, int h, u32 color) {
for(int y = 0; y<h; y++) {
for(int x = 0; x<w; x++) {
screen_set(color,x+pos_x,y+pos_y);
}
}
}
static void render(int c0, int c1) {
//draw_rect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,0);
//draw_string("Hello, reader. This is written text.", 100, 180, 16777215);
//draw_string("If this is displayed, my code works.", 100+c0, 100+c1, 16777215);
}
void main(struct VBE_modeInfo *vbe) {
modeInfoPointer = vbe;
int clock = 0;
int incC1 = 0;
int incC0 = 0;
while(true) {
uint16_t scancode = (uint16_t) inb(0x60);
clock++;
if(read_pit()!= 0 && clock == CLOCK_HIT) {
if(scancode == KEY_LEFT) {
incC0--;
}else if(scancode == KEY_RIGHT) {
incC0++;
}
if(scancode == KEY_DOWN) {
incC1++;
}else if(scancode == KEY_UP) {
incC1--;
}
clock = 0;
render(incC0,incC1);
screen_swap();
}
}
return;
}
You are only allowed to initialize global variables with:
a constant value
int i = 5;
char* str = "hello world";
int* ptr = &i;
struct my_struct = {6, 1, 7};
int my_arr[] = {4, 5, 6};
a macro expression (only constants and the option below)
#define MY_CONST 5
#define DOUBLE_OF(x) (x * 2)
int my_global_var = MY_CONST;
int many = DOUBLE_OF(1000);
int my_size = sizeof(int);
a combination of the variants above with operators
int my_combination = 8 + MY_CONST + sizeof(float);
The problem with your code is, that the compiler may not know the content of modeInfo->PhysBasePtr (in this case it definitely doesn't know). I don't quite understand what you were trying to do, but maybe you mean:
static u32 *BUFFER = (u32 *) (&modeInfo->PhysBasePtr);
Even if the compiler does not know the content of your buffer, it does know the (relative) memory address of your buffer, because all global variables have a known memory position in their section.
Okay ...
Starting from my answer to your previous question: How can I fix my VBE implementation for my OS?
There are two problems with:
static u32 *BUFFER = (u32 *) (modeInfo->PhysBasePtr);
Because you changed from kernel.cpp to kernel.c, this is valid C++ but not valid C
While it was valid C++ code, [as Eugene pointed out], modeInfo was NULL
The quick fix:
#define BUFFER = ((u32 *) (modeInfo->PhysBasePtr))
However, you still have a problem with double buffering and flicker.
There is the physical frame buffer (i.e.) BUFFER.
But, you have two offscreen buffers with _sbuffers.
Herein, we'll call them _sbuffers[0] and _sbuffers[1] as if we had defined the buffers as:
u32 *_sbuffers[2];
You need/want only one.
_sback is the "current" buffer choice. When writing the buffer using screen_set [and SBUF], it uses _sbuffers[_sback].
However, CURRENT is defined only to use _sbuffers[0].
So, in screen_swap, on every alternate frame, it is using a stale frame (because it only uses _sbuffers[0]).
The effect is a "stutter" or "flicker". If you are creating the frames in order:
f0, f1, f2, f3, f4, f5, f6, f7, ...
What you'll [probably] see displayed is:
f0, f0, f2, f2, f4, f4, f6, f6, ...
When the backing buffer _sbuffers is set with screen_set, it is slow. So, it is desirable to only update the live screen via screen_swap (using memcpy). This is double buffering.
But, we only need/want one backing buffer. Otherwise, we'd need an additional memcpy to update the contents of the "other" backing buffer.
So, the real fix is to change _sbuffers to only have one screen image.
Although macros are often a good thing, the sheer number of them was obscuring the issue.
Here is a git diff. It is made against your b5396d6386356908e88fcd19ec1e6d338f2581b0 commit:
diff --git a/src/kernel.c b/src/kernel.c
index 6215ec4..0d2babd 100644
--- a/src/kernel.c
+++ b/src/kernel.c
## -103,14 +103,6 ## struct VBE_modeInfo *modeInfoPointer;
u32 *_sbuffers;
u32 _sback = 0;
-#define SBUF(_y,_x) \
- _sbuffers[((_y) * SCREEN_SIZE) + _x]
-
-#define CURRENT &SBUF(0,0)
-#define SWAP() (_sback = 1 - _sback)
-
-#define screen_buffer() (_sbuffers[_sback])
-
static inline void outb(uint16_t port, uint8_t val)
{
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
## -119,11 +111,11 ## static inline void outb(uint16_t port, uint8_t val)
#define bytesPerPixel ((modeInfo->BitsPerPixel + 7) / 8)
void screen_set(u32 color,int x,int y) {
- u32 physical_address = modeInfo->PhysBasePtr + y * modeInfo->LinBytesPerScanLine + x * bytesPerPixel;
- if (_sbuffers == NULL)
- _sbuffers = (u32 *) malloc(sizeof(u32) * 2 * SCREEN_SIZE);
+ u32 physical_address = modeInfo->PhysBasePtr;
+ physical_address += y * modeInfo->LinBytesPerScanLine;
+ physical_address += x * bytesPerPixel;
- SBUF(_sback,physical_address)=color;
+ _sbuffers[physical_address] = color;
}
static inline uint8_t inb(uint16_t port)
## -247,8 +239,7 ## static inline void *memcpy(void *dst, const void *src, size_t n)
}
void screen_swap() {
- memcpy(BUFFER, CURRENT, SCREEN_SIZE);
- SWAP();
+ memcpy(BUFFER, _sbuffers, SCREEN_SIZE);
}
unsigned read_pit(void) {
## -302,6 +293,8 ## static void render(int c0, int c1) {
void main(struct VBE_modeInfo *vbe) {
modeInfoPointer = vbe;
+ _sbuffers = malloc(sizeof(u32) * SCREEN_SIZE);
+
int clock = 0;
int incC1 = 0;
int incC0 = 0;
Not to worry ... Since we've had trouble with the patch before, here is the full kernel.c file:
/*
TODO:
-Filesystem
-Mouse Inputs
-Simple GUI
-3d Viewer
-Maybe Link Downloader and Viewer
*/
#define NULL ((void*)0)
#define true 1
#define false 0
typedef unsigned char uint8_t;
typedef unsigned char u8;
typedef unsigned short uint16_t;
typedef unsigned int u32;
typedef u32 size_t;
typedef unsigned long phys_bytes;
#define SCREEN_WIDTH (int)(modeInfo->XResolution)
#define SCREEN_HEIGHT (int)(modeInfo->YResolution)
#define BPP 32
#define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
#define FPS 30
#define PIT_HERTZ 1193131.666
#define CLOCK_HIT (int)(PIT_HERTZ/FPS)
#define KEY_LEFT 0x4B
#define KEY_UP 0x48
#define KEY_RIGHT 0x4D
#define KEY_DOWN 0x50
void * malloc(size_t len) {
static size_t curoff = 0;
static char space[1 * 1024 * 1024 * 1024];
void *ptr = NULL;
if ((curoff + len) < sizeof(space)) {
ptr = &space[curoff]; curoff += len;
} return ptr;
}
typedef struct VBE_modeInfo{
/* Mandatory information for all VBE revisions */
uint16_t ModeAttributes;
uint8_t WinAAttributes;
uint8_t WinBAttributes;
uint16_t WinGranularity;
uint16_t WinSize;
uint16_t WinASegment;
uint16_t WinBSegment;
phys_bytes WinFuncPtr;
uint16_t BytesPerScanLine;
/* Mandatory information for VBE 1.2 and above */
uint16_t XResolution;
uint16_t YResolution;
uint8_t XCharSize;
uint8_t YCharSize;
uint8_t NumberOfPlanes;
uint8_t BitsPerPixel;
uint8_t NumberOfBanks;
uint8_t MemoryModel;
uint8_t BankSize;
uint8_t NumberOfImagePages;
uint8_t Reserved1;
/* Direct Color fields (required for direct/6 and YUV/7 memory models) */
uint8_t RedMaskSize; /* size of direct color red mask in bits */
uint8_t RedFieldPosition; /* bit position of lsb of red mask */
uint8_t GreenMaskSize; /* size of direct color green mask in bits */
uint8_t GreenFieldPosition; /* bit position of lsb of green mask */
uint8_t BlueMaskSize; /* size of direct color blue mask in bits */
uint8_t BlueFieldPosition; /* bit position of lsb of blue mask */
uint8_t RsvdMaskSize; /* size of direct color reserved mask in bits */
uint8_t RsvdFieldPosition; /* bit position of lsb of reserved mask */
uint8_t DirectColorModeInfo; /* direct color mode attributes */
/* Mandatory information for VBE 2.0 and above */
phys_bytes PhysBasePtr;
uint8_t Reserved2[4];
uint8_t Reserved3[2];
/* Mandatory information for VBE 3.0 and above */
uint16_t LinBytesPerScanLine; /* bytes per scan line for linear modes */
uint8_t BnkNumberOfImagePages; /* number of images for banked modes */
uint8_t LinNumberOfImagePages; /* number of images for linear modes */
uint8_t LinRedMaskSize; /* size of direct color red mask (linear modes) */
uint8_t LinRedFieldPosition; /* bit position of lsb of red mask (linear modes) */
uint8_t LinGreenMaskSize; /* size of direct color green mask (linear modes) */
uint8_t LinGreenFieldPosition; /* bit position of lsb of green mask (linear modes) */
uint8_t LinBlueMaskSize; /* size of direct color blue mask (linear modes) */
uint8_t LinBlueFieldPosition; /* bit position of lsb of blue mask (linear modes ) */
uint8_t LinRsvdMaskSize; /* size of direct color reserved mask (linear modes) */
uint8_t LinRsvdFieldPosition; /* bit position of lsb of reserved mask (linear modes) */
u32 MaxPixelClock; /* maximum pixel clock (in Hz) for graphics mode */
uint8_t Reserved4[190]; /* remainder of ModeInfoBlock */
} VBE_modeInfo;
struct VBE_modeInfo *modeInfoPointer;
#define modeInfo modeInfoPointer
#define BUFFER ((u32 *) (modeInfo->PhysBasePtr))
// double buffers
u32 *_sbuffers;
u32 _sback = 0;
static inline void outb(uint16_t port, uint8_t val)
{
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
}
#define bytesPerPixel ((modeInfo->BitsPerPixel + 7) / 8)
void screen_set(u32 color,int x,int y) {
u32 physical_address = modeInfo->PhysBasePtr;
physical_address += y * modeInfo->LinBytesPerScanLine;
physical_address += x * bytesPerPixel;
_sbuffers[physical_address] = color;
}
static inline uint8_t inb(uint16_t port)
{
uint8_t ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "Nd"(port) );
return ret;
}
const unsigned char font[128-32][8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
{ 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
{ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
{ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
{ 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
{ 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
{ 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
{ 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
{ 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (()
{ 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
{ 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
{ 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
{ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
{ 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
{ 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
{ 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2)
{ 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
{ 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
{ 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
{ 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
{ 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
{ 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
{ 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;)
{ 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<)
{ 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
{ 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
{ 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
{ 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (#)
{ 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
{ 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
{ 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
{ 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F)
{ 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
{ 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
{ 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
{ 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
{ 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
{ 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
{ 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
{ 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
{ 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
{ 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P)
{ 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
{ 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
{ 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
{ 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
{ 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
{ 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
{ 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
{ 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z)
{ 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
{ 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
{ 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
{ 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
{ 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
{ 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
{ 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
{ 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
{ 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d)
{ 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
{ 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
{ 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
{ 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
{ 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
{ 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
{ 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
{ 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
{ 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n)
{ 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
{ 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
{ 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
{ 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
{ 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
{ 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
{ 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
{ 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
{ 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
{ 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
{ 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F
};
static inline void *memcpy(void *dst, const void *src, size_t n)
{
u8 *d = (u8*)dst;
const u8 *s = (const u8*)src;
while (n-- > 0) {
*d++ = *s++;
}
return d;
}
void screen_swap() {
memcpy(BUFFER, _sbuffers, SCREEN_SIZE);
}
unsigned read_pit(void) {
unsigned count = 0;
// al = channel in bits 6 and 7, remaining bits clear
outb(0x43,0b0000000);
count = inb(0x40); // Low byte
count |= inb(0x40)<<8; // High byte
return count;
}
void draw_char(char c, int x, int y, u32 color)
{
const unsigned char *glyph = font[(int)c-32];
for(int cy=0;cy<8;cy++){
for(int cx=0;cx<8;cx++){
if(((int)glyph[cy]&(1<<cx))==(1<<cx)){
screen_set(color,x+cx,y+cy);
}
}
}
}
void draw_string(const char * s, int x, int y, u32 color) {
int i = 0;
while(s[i] != false) {
draw_char(s[i],x+(i*8),y,color);
i++;
}
}
void draw_rect(int pos_x, int pos_y, int w, int h, u32 color) {
for(int y = 0; y<h; y++) {
for(int x = 0; x<w; x++) {
screen_set(color,x+pos_x,y+pos_y);
}
}
}
static void render(int c0, int c1) {
//draw_rect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,0);
//draw_string("Hello, reader. This is written text.", 100, 180, 16777215);
//draw_string("If this is displayed, my code works.", 100+c0, 100+c1, 16777215);
}
void main(struct VBE_modeInfo *vbe) {
modeInfoPointer = vbe;
_sbuffers = malloc(sizeof(u32) * SCREEN_SIZE);
int clock = 0;
int incC1 = 0;
int incC0 = 0;
while(true) {
uint16_t scancode = (uint16_t) inb(0x60);
clock++;
if(read_pit()!= 0 && clock == CLOCK_HIT) {
if(scancode == KEY_LEFT) {
incC0--;
}else if(scancode == KEY_RIGHT) {
incC0++;
}
if(scancode == KEY_DOWN) {
incC1++;
}else if(scancode == KEY_UP) {
incC1--;
}
clock = 0;
render(incC0,incC1);
screen_swap();
}
}
return;
}
Side note: In your commit log, you have a number of sparse messages of the form:
Add files via upload
That's not super descriptive. A one liner would be okay if you're just renaming [as you did].
But, after some time (e.g. six months from now), you'll want a better summary.
As an example, here's a partial commit log from the project I use for some of my SO answers. As with all commit messages, they're a bit cryptic without the context of having the source code:
commit db7cb6b97acef7554618cb71cbcd5459e2e7452b
Author: Craig Estey <censored#by_the.gov>
Date: Sat Jun 4 11:44:13 2022 -0400
- dlkdupdel
- fixed typo in code
commit 79f1919890b025a6bc1c7b1af4d48e5b629af2f7
Author: Craig Estey <censored#by_the.gov>
Date: Fri Jun 3 17:50:24 2022 -0400
- dlkdupdel
- added answer number to Makefile
commit 37fda9cb2c2d308499bf1c4d750e4057398b9846
Author: Craig Estey <censored#by_the.gov>
Date: Thu Jun 2 19:20:19 2022 -0400
- dlkdupdel
- added list_t struct (posted in UPDATE #2)
commit c66e04ec662fa95481590bb11001c4f91ba3db67
Author: Craig Estey <censored#by_the.gov>
Date: Thu Jun 2 19:18:57 2022 -0400
- dlkdupdel
- whole program with diagnostic (posted in UPDATE)
commit 4a7dd901e1128dd3f2bc69304e4c0d7ec5329d8c
Author: Craig Estey <censored#by_the.gov>
Date: Thu Jun 2 19:17:30 2022 -0400
- dlkdupdel
- posted version
commit 8ad6164a90b78bbde847919de3ce4eeea03c1a64
Author: Craig Estey <censored#by_the.gov>
Date: Thu Jun 2 19:16:09 2022 -0400
- dlkdupdel
- first fix (partial function only)
commit 240e5f4c53af062292884e3a31063a36276ac3cd
Author: Craig Estey <censored#by_the.gov>
Date: Thu Jun 2 19:14:53 2022 -0400
- dlkdupdel
- orignal (OP) code
commit 64fa06b1da5a44d06ff1e6c70807a6e00cdeeefa
Author: Craig Estey <censored#by_the.gov>
Date: Wed Jun 1 12:01:44 2022 -0400
- svrfixup
- added getaddrinfo
- added xmsg_status to allow server to show final status to client
- changed xsend/xrecv to retry on EINTR
- added vxcode to interpret return status
- moved child pipe to server_pipe function
- fixed bug in server stop command by clearing SA_RESTART when setting
up signal handler
commit 087d588be67337769a0013295ede96dbf6206b03
Author: Craig Estey <censored#by_the.gov>
Date: Wed May 25 22:23:14 2022 -0400
- svrfixup
- major refactoring to more usual program model
- 3rd posting in UPDATE section
commit c5dd474f35419390b7e1674e7f625837c0f82621
Author: Craig Estey <censored#by_the.gov>
Date: Wed May 25 18:08:41 2022 -0400
- svrfixup
- 2nd posted code
commit 5bfbc62b02c04ef716df21fd2a6bd9171a39c301
Author: Craig Estey <censored#by_the.gov>
Date: Wed May 25 18:05:24 2022 -0400
- added svrfixup
- first posted code
commit 53105b1027b515cb3195b0da620f472aa49ae7ce
Author: Craig Estey <censored#by_the.gov>
Date: Thu May 19 19:09:10 2022 -0400
- mtskbnc
- added automatic retries
commit 2c821006e3a834ec511a09ac6105e6cafbfa120f
Author: Craig Estey <censored#by_the.gov>
Date: Thu May 19 19:07:49 2022 -0400
- mtskbnc
- converted to use single array
commit eddb6bf744d50b0b79e253ec107b19bfa9e57efd
Author: Craig Estey <censored#by_the.gov>
Date: Thu May 19 19:06:51 2022 -0400
- added mtskbnc
commit f6e744f376c9d7be3a9131a5cece4b82782a24d1
Author: Craig Estey <censored#by_the.gov>
Date: Fri Apr 22 10:31:56 2022 -0400
- sparse
- improved ADD message to use UPD
commit 024cf83eec1f753a5c97eb53c3307f5ed0bdb361
Author: Craig Estey <censored#by_the.gov>
Date: Fri Apr 22 10:30:10 2022 -0400
- added sparse matrix code
commit e65496497d91a2d24281a7ac376ac5249a037ca7
Author: Craig Estey <censored#by_the.gov>
Date: Mon Apr 18 13:50:20 2022 -0400
- armstrong
- split up anumdiag script into anxbld, anxcmp, anxdiag, anxgo
- reworked anuixop.rdb to use set* x86 instructions instead of jxx
commit 020e16e527088f71c88e59feb1c253bcb3d232c8
Author: Craig Estey <censored#by_the.gov>
Date: Sat Apr 16 12:20:03 2022 -0400
- dbglib
- added dbgcas.c dbgmsg.c
- added dlk*.c et. al.
- added systty* routines
- renamed some DBGPRT* routines/macros to DBGFLG*
- added spy routines [intercept libc calls]
- dbglib.h
- added dbgpush*/dbgpop* routines
- added table of prefixes for debug environment variables
- added auxv ELF auxiliary vector support
- dbgtype.h
- added ARYFOR* macros
- added UCMP macro
- added SYSFREEME/SYSCLOSEME/SYSFCLOSEME macros
- added u128 typedef
- added tgb support
- evt.c
- converted to use qrng* routines
- added evtprtf support
- evt.h
- converted to qrng
- added additional triggers (e.g. stop on full)
- evtpm
- added support for evtmem* hooks and leak detection
- qrng.c
- reworked from ovrlib version
- added multitask/lock support
- added qrng_buf_* to allow external memcpy in/out of queue
- qrng.h
- added quepair_t
- reworked/renamed qrng_* routines to use quepair_p and rename to qpair_*
- tsk.c
- added tsksetup
- added master control (e.g. tsm)
- tsk.h
- added tskmst

Most efficent way to calculate CRC64 with reflected input

I need to calculate a CRC-64 using this setup into this wonderful website: http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
As you can see I require "input reflected" and that means that I need to reverse the bit order of any byte (a bit annoying).
For the moment, I implemented this with a lookup table (for example 0x55 -> 0xAA), but I was wondering if there is any property of CRC which can be used to be more efficient.
This is my code (in C):
static const unsigned long long CRC64_TABLE[256] = {
0x0000000000000000, 0x42F0E1EBA9EA3693, 0x85E1C3D753D46D26, 0xC711223CFA3E5BB5, 0x493366450E42ECDF, 0x0BC387AEA7A8DA4C, 0xCCD2A5925D9681F9, 0x8E224479F47CB76A,
0x9266CC8A1C85D9BE, 0xD0962D61B56FEF2D, 0x17870F5D4F51B498, 0x5577EEB6E6BB820B, 0xDB55AACF12C73561, 0x99A54B24BB2D03F2, 0x5EB4691841135847, 0x1C4488F3E8F96ED4,
0x663D78FF90E185EF, 0x24CD9914390BB37C, 0xE3DCBB28C335E8C9, 0xA12C5AC36ADFDE5A, 0x2F0E1EBA9EA36930, 0x6DFEFF5137495FA3, 0xAAEFDD6DCD770416, 0xE81F3C86649D3285,
0xF45BB4758C645C51, 0xB6AB559E258E6AC2, 0x71BA77A2DFB03177, 0x334A9649765A07E4, 0xBD68D2308226B08E, 0xFF9833DB2BCC861D, 0x388911E7D1F2DDA8, 0x7A79F00C7818EB3B,
0xCC7AF1FF21C30BDE, 0x8E8A101488293D4D, 0x499B3228721766F8, 0x0B6BD3C3DBFD506B, 0x854997BA2F81E701, 0xC7B97651866BD192, 0x00A8546D7C558A27, 0x4258B586D5BFBCB4,
0x5E1C3D753D46D260, 0x1CECDC9E94ACE4F3, 0xDBFDFEA26E92BF46, 0x990D1F49C77889D5, 0x172F5B3033043EBF, 0x55DFBADB9AEE082C, 0x92CE98E760D05399, 0xD03E790CC93A650A,
0xAA478900B1228E31, 0xE8B768EB18C8B8A2, 0x2FA64AD7E2F6E317, 0x6D56AB3C4B1CD584, 0xE374EF45BF6062EE, 0xA1840EAE168A547D, 0x66952C92ECB40FC8, 0x2465CD79455E395B,
0x3821458AADA7578F, 0x7AD1A461044D611C, 0xBDC0865DFE733AA9, 0xFF3067B657990C3A, 0x711223CFA3E5BB50, 0x33E2C2240A0F8DC3, 0xF4F3E018F031D676, 0xB60301F359DBE0E5,
0xDA050215EA6C212F, 0x98F5E3FE438617BC, 0x5FE4C1C2B9B84C09, 0x1D14202910527A9A, 0x93366450E42ECDF0, 0xD1C685BB4DC4FB63, 0x16D7A787B7FAA0D6, 0x5427466C1E109645,
0x4863CE9FF6E9F891, 0x0A932F745F03CE02, 0xCD820D48A53D95B7, 0x8F72ECA30CD7A324, 0x0150A8DAF8AB144E, 0x43A04931514122DD, 0x84B16B0DAB7F7968, 0xC6418AE602954FFB,
0xBC387AEA7A8DA4C0, 0xFEC89B01D3679253, 0x39D9B93D2959C9E6, 0x7B2958D680B3FF75, 0xF50B1CAF74CF481F, 0xB7FBFD44DD257E8C, 0x70EADF78271B2539, 0x321A3E938EF113AA,
0x2E5EB66066087D7E, 0x6CAE578BCFE24BED, 0xABBF75B735DC1058, 0xE94F945C9C3626CB, 0x676DD025684A91A1, 0x259D31CEC1A0A732, 0xE28C13F23B9EFC87, 0xA07CF2199274CA14,
0x167FF3EACBAF2AF1, 0x548F120162451C62, 0x939E303D987B47D7, 0xD16ED1D631917144, 0x5F4C95AFC5EDC62E, 0x1DBC74446C07F0BD, 0xDAAD56789639AB08, 0x985DB7933FD39D9B,
0x84193F60D72AF34F, 0xC6E9DE8B7EC0C5DC, 0x01F8FCB784FE9E69, 0x43081D5C2D14A8FA, 0xCD2A5925D9681F90, 0x8FDAB8CE70822903, 0x48CB9AF28ABC72B6, 0x0A3B7B1923564425,
0x70428B155B4EAF1E, 0x32B26AFEF2A4998D, 0xF5A348C2089AC238, 0xB753A929A170F4AB, 0x3971ED50550C43C1, 0x7B810CBBFCE67552, 0xBC902E8706D82EE7, 0xFE60CF6CAF321874,
0xE224479F47CB76A0, 0xA0D4A674EE214033, 0x67C58448141F1B86, 0x253565A3BDF52D15, 0xAB1721DA49899A7F, 0xE9E7C031E063ACEC, 0x2EF6E20D1A5DF759, 0x6C0603E6B3B7C1CA,
0xF6FAE5C07D3274CD, 0xB40A042BD4D8425E, 0x731B26172EE619EB, 0x31EBC7FC870C2F78, 0xBFC9838573709812, 0xFD39626EDA9AAE81, 0x3A28405220A4F534, 0x78D8A1B9894EC3A7,
0x649C294A61B7AD73, 0x266CC8A1C85D9BE0, 0xE17DEA9D3263C055, 0xA38D0B769B89F6C6, 0x2DAF4F0F6FF541AC, 0x6F5FAEE4C61F773F, 0xA84E8CD83C212C8A, 0xEABE6D3395CB1A19,
0x90C79D3FEDD3F122, 0xD2377CD44439C7B1, 0x15265EE8BE079C04, 0x57D6BF0317EDAA97, 0xD9F4FB7AE3911DFD, 0x9B041A914A7B2B6E, 0x5C1538ADB04570DB, 0x1EE5D94619AF4648,
0x02A151B5F156289C, 0x4051B05E58BC1E0F, 0x87409262A28245BA, 0xC5B073890B687329, 0x4B9237F0FF14C443, 0x0962D61B56FEF2D0, 0xCE73F427ACC0A965, 0x8C8315CC052A9FF6,
0x3A80143F5CF17F13, 0x7870F5D4F51B4980, 0xBF61D7E80F251235, 0xFD913603A6CF24A6, 0x73B3727A52B393CC, 0x31439391FB59A55F, 0xF652B1AD0167FEEA, 0xB4A25046A88DC879,
0xA8E6D8B54074A6AD, 0xEA16395EE99E903E, 0x2D071B6213A0CB8B, 0x6FF7FA89BA4AFD18, 0xE1D5BEF04E364A72, 0xA3255F1BE7DC7CE1, 0x64347D271DE22754, 0x26C49CCCB40811C7,
0x5CBD6CC0CC10FAFC, 0x1E4D8D2B65FACC6F, 0xD95CAF179FC497DA, 0x9BAC4EFC362EA149, 0x158E0A85C2521623, 0x577EEB6E6BB820B0, 0x906FC95291867B05, 0xD29F28B9386C4D96,
0xCEDBA04AD0952342, 0x8C2B41A1797F15D1, 0x4B3A639D83414E64, 0x09CA82762AAB78F7, 0x87E8C60FDED7CF9D, 0xC51827E4773DF90E, 0x020905D88D03A2BB, 0x40F9E43324E99428,
0x2CFFE7D5975E55E2, 0x6E0F063E3EB46371, 0xA91E2402C48A38C4, 0xEBEEC5E96D600E57, 0x65CC8190991CB93D, 0x273C607B30F68FAE, 0xE02D4247CAC8D41B, 0xA2DDA3AC6322E288,
0xBE992B5F8BDB8C5C, 0xFC69CAB42231BACF, 0x3B78E888D80FE17A, 0x7988096371E5D7E9, 0xF7AA4D1A85996083, 0xB55AACF12C735610, 0x724B8ECDD64D0DA5, 0x30BB6F267FA73B36,
0x4AC29F2A07BFD00D, 0x08327EC1AE55E69E, 0xCF235CFD546BBD2B, 0x8DD3BD16FD818BB8, 0x03F1F96F09FD3CD2, 0x41011884A0170A41, 0x86103AB85A2951F4, 0xC4E0DB53F3C36767,
0xD8A453A01B3A09B3, 0x9A54B24BB2D03F20, 0x5D45907748EE6495, 0x1FB5719CE1045206, 0x919735E51578E56C, 0xD367D40EBC92D3FF, 0x1476F63246AC884A, 0x568617D9EF46BED9,
0xE085162AB69D5E3C, 0xA275F7C11F7768AF, 0x6564D5FDE549331A, 0x279434164CA30589, 0xA9B6706FB8DFB2E3, 0xEB46918411358470, 0x2C57B3B8EB0BDFC5, 0x6EA7525342E1E956,
0x72E3DAA0AA188782, 0x30133B4B03F2B111, 0xF7021977F9CCEAA4, 0xB5F2F89C5026DC37, 0x3BD0BCE5A45A6B5D, 0x79205D0E0DB05DCE, 0xBE317F32F78E067B, 0xFCC19ED95E6430E8,
0x86B86ED5267CDBD3, 0xC4488F3E8F96ED40, 0x0359AD0275A8B6F5, 0x41A94CE9DC428066, 0xCF8B0890283E370C, 0x8D7BE97B81D4019F, 0x4A6ACB477BEA5A2A, 0x089A2AACD2006CB9,
0x14DEA25F3AF9026D, 0x562E43B4931334FE, 0x913F6188692D6F4B, 0xD3CF8063C0C759D8, 0x5DEDC41A34BBEEB2, 0x1F1D25F19D51D821, 0xD80C07CD676F8394, 0x9AFCE626CE85B507
};
static const unsigned char REVERSE_BITS_TABLE[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
unsigned long long calculateCRC64(unsigned char* data, unsigned long size)
{
unsigned long long myCRC64 = 0;
for(unsigned long i = 0; i < size; i++)
myCRC64 = CRC64_TABLE[((myCRC64 >> 56) ^ REVERSE_BITS_TABLE[data[i]]) & 0xFF] ^ (myCRC64 << 8);
return myCRC64;
}
Thanks in advance for any help!
Update: actually I'm wondering if some properties of CRC allow me to get the same result using reflected table, opposite shifting, reciprocal / reverse polynomial... etc. That would let skip the step of reversing bits.
Solution: using reflected table, changing shift direction and reversing bits just of the very last result:
static const unsigned long long CRC64_TABLE_REF[256] = {
0x0000000000000000, 0xB32E4CBE03A75F6F, 0xF4843657A840A05B, 0x47AA7AE9ABE7FF34, 0x7BD0C384FF8F5E33, 0xC8FE8F3AFC28015C, 0x8F54F5D357CFFE68, 0x3C7AB96D5468A107,
0xF7A18709FF1EBC66, 0x448FCBB7FCB9E309, 0x0325B15E575E1C3D, 0xB00BFDE054F94352, 0x8C71448D0091E255, 0x3F5F08330336BD3A, 0x78F572DAA8D1420E, 0xCBDB3E64AB761D61,
0x7D9BA13851336649, 0xCEB5ED8652943926, 0x891F976FF973C612, 0x3A31DBD1FAD4997D, 0x064B62BCAEBC387A, 0xB5652E02AD1B6715, 0xF2CF54EB06FC9821, 0x41E11855055BC74E,
0x8A3A2631AE2DDA2F, 0x39146A8FAD8A8540, 0x7EBE1066066D7A74, 0xCD905CD805CA251B, 0xF1EAE5B551A2841C, 0x42C4A90B5205DB73, 0x056ED3E2F9E22447, 0xB6409F5CFA457B28,
0xFB374270A266CC92, 0x48190ECEA1C193FD, 0x0FB374270A266CC9, 0xBC9D3899098133A6, 0x80E781F45DE992A1, 0x33C9CD4A5E4ECDCE, 0x7463B7A3F5A932FA, 0xC74DFB1DF60E6D95,
0x0C96C5795D7870F4, 0xBFB889C75EDF2F9B, 0xF812F32EF538D0AF, 0x4B3CBF90F69F8FC0, 0x774606FDA2F72EC7, 0xC4684A43A15071A8, 0x83C230AA0AB78E9C, 0x30EC7C140910D1F3,
0x86ACE348F355AADB, 0x3582AFF6F0F2F5B4, 0x7228D51F5B150A80, 0xC10699A158B255EF, 0xFD7C20CC0CDAF4E8, 0x4E526C720F7DAB87, 0x09F8169BA49A54B3, 0xBAD65A25A73D0BDC,
0x710D64410C4B16BD, 0xC22328FF0FEC49D2, 0x85895216A40BB6E6, 0x36A71EA8A7ACE989, 0x0ADDA7C5F3C4488E, 0xB9F3EB7BF06317E1, 0xFE5991925B84E8D5, 0x4D77DD2C5823B7BA,
0x64B62BCAEBC387A1, 0xD7986774E864D8CE, 0x90321D9D438327FA, 0x231C512340247895, 0x1F66E84E144CD992, 0xAC48A4F017EB86FD, 0xEBE2DE19BC0C79C9, 0x58CC92A7BFAB26A6,
0x9317ACC314DD3BC7, 0x2039E07D177A64A8, 0x67939A94BC9D9B9C, 0xD4BDD62ABF3AC4F3, 0xE8C76F47EB5265F4, 0x5BE923F9E8F53A9B, 0x1C4359104312C5AF, 0xAF6D15AE40B59AC0,
0x192D8AF2BAF0E1E8, 0xAA03C64CB957BE87, 0xEDA9BCA512B041B3, 0x5E87F01B11171EDC, 0x62FD4976457FBFDB, 0xD1D305C846D8E0B4, 0x96797F21ED3F1F80, 0x2557339FEE9840EF,
0xEE8C0DFB45EE5D8E, 0x5DA24145464902E1, 0x1A083BACEDAEFDD5, 0xA9267712EE09A2BA, 0x955CCE7FBA6103BD, 0x267282C1B9C65CD2, 0x61D8F8281221A3E6, 0xD2F6B4961186FC89,
0x9F8169BA49A54B33, 0x2CAF25044A02145C, 0x6B055FEDE1E5EB68, 0xD82B1353E242B407, 0xE451AA3EB62A1500, 0x577FE680B58D4A6F, 0x10D59C691E6AB55B, 0xA3FBD0D71DCDEA34,
0x6820EEB3B6BBF755, 0xDB0EA20DB51CA83A, 0x9CA4D8E41EFB570E, 0x2F8A945A1D5C0861, 0x13F02D374934A966, 0xA0DE61894A93F609, 0xE7741B60E174093D, 0x545A57DEE2D35652,
0xE21AC88218962D7A, 0x5134843C1B317215, 0x169EFED5B0D68D21, 0xA5B0B26BB371D24E, 0x99CA0B06E7197349, 0x2AE447B8E4BE2C26, 0x6D4E3D514F59D312, 0xDE6071EF4CFE8C7D,
0x15BB4F8BE788911C, 0xA6950335E42FCE73, 0xE13F79DC4FC83147, 0x521135624C6F6E28, 0x6E6B8C0F1807CF2F, 0xDD45C0B11BA09040, 0x9AEFBA58B0476F74, 0x29C1F6E6B3E0301B,
0xC96C5795D7870F42, 0x7A421B2BD420502D, 0x3DE861C27FC7AF19, 0x8EC62D7C7C60F076, 0xB2BC941128085171, 0x0192D8AF2BAF0E1E, 0x4638A2468048F12A, 0xF516EEF883EFAE45,
0x3ECDD09C2899B324, 0x8DE39C222B3EEC4B, 0xCA49E6CB80D9137F, 0x7967AA75837E4C10, 0x451D1318D716ED17, 0xF6335FA6D4B1B278, 0xB199254F7F564D4C, 0x02B769F17CF11223,
0xB4F7F6AD86B4690B, 0x07D9BA1385133664, 0x4073C0FA2EF4C950, 0xF35D8C442D53963F, 0xCF273529793B3738, 0x7C0979977A9C6857, 0x3BA3037ED17B9763, 0x888D4FC0D2DCC80C,
0x435671A479AAD56D, 0xF0783D1A7A0D8A02, 0xB7D247F3D1EA7536, 0x04FC0B4DD24D2A59, 0x3886B22086258B5E, 0x8BA8FE9E8582D431, 0xCC0284772E652B05, 0x7F2CC8C92DC2746A,
0x325B15E575E1C3D0, 0x8175595B76469CBF, 0xC6DF23B2DDA1638B, 0x75F16F0CDE063CE4, 0x498BD6618A6E9DE3, 0xFAA59ADF89C9C28C, 0xBD0FE036222E3DB8, 0x0E21AC88218962D7,
0xC5FA92EC8AFF7FB6, 0x76D4DE52895820D9, 0x317EA4BB22BFDFED, 0x8250E80521188082, 0xBE2A516875702185, 0x0D041DD676D77EEA, 0x4AAE673FDD3081DE, 0xF9802B81DE97DEB1,
0x4FC0B4DD24D2A599, 0xFCEEF8632775FAF6, 0xBB44828A8C9205C2, 0x086ACE348F355AAD, 0x34107759DB5DFBAA, 0x873E3BE7D8FAA4C5, 0xC094410E731D5BF1, 0x73BA0DB070BA049E,
0xB86133D4DBCC19FF, 0x0B4F7F6AD86B4690, 0x4CE50583738CB9A4, 0xFFCB493D702BE6CB, 0xC3B1F050244347CC, 0x709FBCEE27E418A3, 0x3735C6078C03E797, 0x841B8AB98FA4B8F8,
0xADDA7C5F3C4488E3, 0x1EF430E13FE3D78C, 0x595E4A08940428B8, 0xEA7006B697A377D7, 0xD60ABFDBC3CBD6D0, 0x6524F365C06C89BF, 0x228E898C6B8B768B, 0x91A0C532682C29E4,
0x5A7BFB56C35A3485, 0xE955B7E8C0FD6BEA, 0xAEFFCD016B1A94DE, 0x1DD181BF68BDCBB1, 0x21AB38D23CD56AB6, 0x9285746C3F7235D9, 0xD52F0E859495CAED, 0x6601423B97329582,
0xD041DD676D77EEAA, 0x636F91D96ED0B1C5, 0x24C5EB30C5374EF1, 0x97EBA78EC690119E, 0xAB911EE392F8B099, 0x18BF525D915FEFF6, 0x5F1528B43AB810C2, 0xEC3B640A391F4FAD,
0x27E05A6E926952CC, 0x94CE16D091CE0DA3, 0xD3646C393A29F297, 0x604A2087398EADF8, 0x5C3099EA6DE60CFF, 0xEF1ED5546E415390, 0xA8B4AFBDC5A6ACA4, 0x1B9AE303C601F3CB,
0x56ED3E2F9E224471, 0xE5C372919D851B1E, 0xA26908783662E42A, 0x114744C635C5BB45, 0x2D3DFDAB61AD1A42, 0x9E13B115620A452D, 0xD9B9CBFCC9EDBA19, 0x6A978742CA4AE576,
0xA14CB926613CF817, 0x1262F598629BA778, 0x55C88F71C97C584C, 0xE6E6C3CFCADB0723, 0xDA9C7AA29EB3A624, 0x69B2361C9D14F94B, 0x2E184CF536F3067F, 0x9D36004B35545910,
0x2B769F17CF112238, 0x9858D3A9CCB67D57, 0xDFF2A94067518263, 0x6CDCE5FE64F6DD0C, 0x50A65C93309E7C0B, 0xE388102D33392364, 0xA4226AC498DEDC50, 0x170C267A9B79833F,
0xDCD7181E300F9E5E, 0x6FF954A033A8C131, 0x28532E49984F3E05, 0x9B7D62F79BE8616A, 0xA707DB9ACF80C06D, 0x14299724CC279F02, 0x5383EDCD67C06036, 0xE0ADA17364673F59
};
unsigned long long calculateCRC64(unsigned char* data, unsigned long size)
{
unsigned long long myCRC64 = 0;
for(unsigned long i = 0; i < size; i++)
myCRC64 = CRC64_TABLE_REF[(myCRC64 ^ data[i]) & 0xFF] ^ (myCRC64 >> 8);
unsigned long long tmp = myCRC64;
myCRC64 = 0;
for (int i = 0; i < 64; i++) {
myCRC64 = (myCRC64 << 1) | (tmp & 1);
tmp >>= 1;
}
return myCRC64;
}
Thanks to everybody for the help!
actually I'm wondering if some properties of CRC allow me to get the same result using reflected table, opposite shifting, reciprocal / reverse polynomial... etc. That would let skip the step of reversing bits.
There is such a property, and you only need one reverse, in the end. The whole logic of the CRC can be bit-reversed*, so that the bits stream the opposite way and don't need to be reversed during the calculation itself:
unsigned long long CRC64(unsigned char* data, unsigned long size)
{
unsigned long long crc = 0;
for(unsigned long i = 0; i < size; i++)
crc = CRC64_TABLE_R[(crc & 0xff) ^ data[i]] ^ (crc >> 8);
return rbit(crc);
}
CRC64_TABLE_R is like CRC64_TABLE, but with the entries and indexes both bit-reversed. So they relate to each other like this: (naturally you would hard-code this table)
for (int i = 0; i < 256; i++) {
CRC64_TABLE_R[REVERSE_BITS_TABLE[i]] = rbit(CRC64_TABLE[i]);
}
rbit is just some function that reverses bits, I used this really dumb one, use a better one if you want but it's only used once:
unsigned long long rbit(unsigned long long n)
{
unsigned long long x = 0;
for (int i = 0; i < 64; i++) {
x = (x << 1) | (n & 1);
n >>= 1;
}
return x;
}
*: really what this means is that the integer holding the bits during the calculation is viewed in reverse, with what would normally be its least significant bit instead held in its most significant bit etc. So depending on how you look at it, the calculation is not even different. The same bits are created, but we hold them in a variable differently.
The code just needs to switch from a left shifting CRC to a right shifting CRC, with the polynomial bits reversed. The "#if 0" is used to select between two common polynomials, in this case, "#if 0" will use CRC64 ecma, which is what is shown in the question's CRC table. (0x42F0E1EBA9EA3693 bit reversed == 0xC96C5795D7870F42).
uint64_t crctbl[256];
void gentbl(void)
{
uint64_t crc;
uint64_t b;
uint64_t c;
uint64_t i;
for(c = 0; c < 0x100; c++){
crc = c;
for(i = 0; i < 8; i++){
b = crc&1;
crc >>= 1;
#if 0
crc ^= (0 - b) & 0xd800000000000000ull; // crc64 iso
#else
crc ^= (0 - b) & 0xc96c5795d7870f42ull; // crc64 ecma
#endif
}
crctbl[c] = crc;
}
}
uint64_t crc64c(uint64_t crc64, uint8_t * bfr, size_t size)
{
uint64_t crc = crc64;
while(size--)
crc = (crc >> 8) ^ crctbl[(crc & 0xff)^*bfr++];
return(crc);
}
"Most efficient way" - if running on X86 X64 with carryless multiply, a really fast CRC, over 20 times as fast as the table method shown above (For a CRC of 256 MB of data, Intel Core i7-10510U .475 seconds table, .015 seconds pclmulqdq, 31.5 times as fast) , can be performed using pclmulqdq instruction and xmm registers. Link to a zip of a 520+ line assembly file, for Visual Studio's MASM (ML64.EXE), for 64 bit reflected CRC, with the same "if 0" as the gentbl() function above to choose between the two CRC polynomials.
http://rcgldr.net/misc/crc64ra.zip
Intel document explaining the algorithm for a 32 bit CRC:
https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
A carryless multiply of two 64 bit non-reflected operands produces a 127 bit product in bits 126 (msb) to bit 0 (lsb). For reflected operands, a carryless multiply effectively multiplies the product by 2, which is taken into account with the constants. For 64 bit CRC, the poly is 65 bits, so some adjustments are also needed to handle that.

Manual HMACSHA1 calculation differs from openssl results

I am trying to implement HMACSHA1 by Hand, to check if our serviceprovider or we calculate a wrong HMAC for a Support-Ticket (a SOAP call, hence the xml content).
The problem is, I stick to NIST Specification for HMACs and get a different result by Hand and when using openssl HMAC functions.
The following code prints:
B92674DCBA96F2DA93F7043071B931F5F2583FBD
4303E965D88D288C9AC594CE6C5E6AFF27D40B2D
while the result by openssl is the same we get in our application - so I assume, on the basis that openssl is so commonly used, that my result is wrong - but where is my error?
This is the spec I refer to:
http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.198-1.pdf
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <string.h>
#define byte unsigned char
#define IPAD 0x36
#define OPAD 0x5c
#define DIGESTSIZE 20
int main () {
byte *derivedKey = (byte[DIGESTSIZE]) {0x42,0xA9,0x78,0x90,0xFC,0xE5,0x16,0x8E,0x58,0x12,0x2F,0xF1,0xBA,0x32,0x5F,0x09,0x88,0x94,0x02,0x91};
byte *content = "<ds:SignedInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\"><ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"><ec:InclusiveNamespaces xmlns:ec=\"http://www.w3.org/2001/10/xml-exc-c14n#\" PrefixList=\"soap\"></ec:InclusiveNamespaces></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#hmac-sha1\"></ds:SignatureMethod><ds:Reference URI=\"#TS-B183A13FEB0189143115136776276601\"><ds:Transforms><ds:Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"><ec:InclusiveNamespaces xmlns:ec=\"http://www.w3.org/2001/10/xml-exc-c14n#\" PrefixList=\"wsse soap\"></ec:InclusiveNamespaces></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></ds:DigestMethod><ds:DigestValue>rXJdGuDqoRrUJxuGiA1eyAozifk=</ds:DigestValue></ds:Reference></ds:SignedInfo>";
byte *oPadKey = malloc(DIGESTSIZE);
byte *iPadKey = malloc(DIGESTSIZE);
int i;
for(i=0;i<DIGESTSIZE;i++){
iPadKey[i]=derivedKey[i]^IPAD;
oPadKey[i]=derivedKey[i]^OPAD;
}
byte *rOpInput= malloc(strlen(content)+DIGESTSIZE);
//concat iPad and content
memcpy(rOpInput, iPadKey, DIGESTSIZE);
memcpy(rOpInput+DIGESTSIZE,content,strlen(content));
//SHA1 (iPad||content) gives the rightmost 20 bytes of the final SHA1 Input
byte *rOp=malloc(DIGESTSIZE); // H(iPad||content)
SHA1(rOpInput,strlen(content)+DIGESTSIZE,rOp);
free(rOpInput);
byte *finalInput = malloc(2*DIGESTSIZE); //oPad||H(iPad||content)
//concat oPad and H(ipad||content)
memcpy(finalInput, oPadKey,DIGESTSIZE);
memcpy(finalInput+DIGESTSIZE,rOp,DIGESTSIZE);
free(rOp);
free(oPadKey);
free(iPadKey);
//SHA1(oPad||H(iPad||content))
byte *hmac = malloc(DIGESTSIZE);
SHA1(finalInput,40,hmac);
free(finalInput);
//print calculated HMAC as HEX
for(i=0;i<DIGESTSIZE;i++){
printf("%02X", (hmac[i] & 0xFF ));
}
printf("\n");
//verify with openssl HMAC
byte *result = HMAC(EVP_sha1(), derivedKey, DIGESTSIZE, content, strlen(content), NULL, NULL);
for(i=0;i<DIGESTSIZE;i++){
printf("%02X", (result[i] & 0xFF ));
}
printf("\n");
return 0;
}
The bug is simple. The ipad and opad need to be (input) block size in length, not the length of the digest output. I.e. they must be 512 bits (64 bytes) for SHA-1, not 20.
I.e.
#define INPUT_BLOCK_SIZE 64
byte derivedKey[64] = {0x42,0xA9,0x78,0x90,0xFC,0xE5,0x16,0x8E,0x58,0x12,
0x2F,0xF1,0xBA,0x32,0x5F,0x09,0x88,0x94,0x02,0x91};
// null-padded on the right
and then change the DIGESTSIZE to INPUT_BLOCK_SIZE for wherever the length of ipad, opad is needed.
Result:
4303E965D88D288C9AC594CE6C5E6AFF27D40B2D
From Wikipedia
K' is another secret key, derived from the original key K (by padding K to the right with extra zeroes to the input block size of the hash function, or by hashing K if it is longer than that block size)
(emphasis mine).
P.S. It would be better to use the SHA1_Init/Update/Final, as then lots of copying would be skipped. You can also avoid allocating memory for the ipad and opad separately by first calculating ipad and after it has been used, then xorring in place by 0x6a to get the opad.
Please refer this. You can easily calculate the hash
https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA1.pdf
#define IPAD 0x36
#define OPAD 0x5c
#define DIGESTSIZE 20
#define INPUT_BLOCK_SIZE 64
#define byte unsigned char
static byte mykey[64];
int main () {
int i;
byte mykey[INPUT_BLOCK_SIZE] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F };
byte content[] = {0x53, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x6D, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6B, 0x65, 0x79, 0x6C, 0x65, 0x6E, 0x3D, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x6C, 0x65, 0x6E };
byte k0_ipad_text[sizeof(content) + INPUT_BLOCK_SIZE];
byte hmac[DIGESTSIZE];
byte k0_opad_hash[INPUT_BLOCK_SIZE + DIGESTSIZE];
/*
* K0 is mykey as size is 0x40 = 64 bytes
*/
byte *oPadKey = malloc(INPUT_BLOCK_SIZE);
byte *iPadKey = malloc(INPUT_BLOCK_SIZE);
memset(oPadKey, 0, INPUT_BLOCK_SIZE);
memset(iPadKey, 0, INPUT_BLOCK_SIZE);
for(i=0;i<INPUT_BLOCK_SIZE;i++){
iPadKey[i]=mykey[i]^IPAD;
oPadKey[i]=mykey[i]^OPAD;
}
printf("\n iPad key = ");
for(i=0;i<INPUT_BLOCK_SIZE;i++){
printf("%02x ", iPadKey[i]);
}
printf("\n oPad key = ");
for(i=0;i<INPUT_BLOCK_SIZE;i++){
printf("%02x ", oPadKey[i]);
}
//Key^ipad)||text)
memcpy(k0_ipad_text, iPadKey, INPUT_BLOCK_SIZE);
memcpy(k0_ipad_text + INPUT_BLOCK_SIZE, content, sizeof(content));
SHA1(k0_ipad_text, INPUT_BLOCK_SIZE + sizeof(content), hmac);
#if 0
printf("\n hmac = ");
for(i=0;i<DIGESTSIZE;i++){
printf("%02x ", hmac[i]);
}
#endif
memcpy(k0_opad_hash, oPadKey, INPUT_BLOCK_SIZE);
memcpy(k0_opad_hash + INPUT_BLOCK_SIZE, hmac, DIGESTSIZE);
SHA1(k0_opad_hash, INPUT_BLOCK_SIZE + DIGESTSIZE, hmac);
printf("\n hmac \n");
for(i=0;i<DIGESTSIZE;i++){
printf("%02x", hmac[i]);
}
printf("\n");
//verify with openssl HMAC
byte *result = HMAC(EVP_sha1(), mykey, INPUT_BLOCK_SIZE, content, sizeof(content), NULL, NULL);
for(i=0;i<DIGESTSIZE;i++){
printf("%02X", (result[i] & 0xFF ));
}
printf("\n");
return 0;
}

setting float pointer into character array read from header file

First, sorry for the long question, but it should be easy to follow. Say I use a struct image which contains channel, height, width number, and a pointer to the actual image data of c*h*w number of float values. I write the image structure array and the image data array (each image's data concatenated) into separate files using fwrite to load them in another system later. The loading system has no file system, so I want to pass the file as a header file and I used xxd -i bin_file to make the stored binary file data into character array(shown below) in the header file. In the load program, the image array and data array(concatenated for the images) are just static charater array as declared in the #include header files. I copy the image structures and overwrite the data pointer to point the data element corresponding to each image's data start location. But when I print the loaded data, only some starting data of the first image is correct and all following data are zero. I can't figure out what's wrong. Can somebody tell me what's wrong?
Below is shown the test code I made. (for channel = 2, height = 3, width = 4).
=== image.h ===
typedef struct {
int c;
int h;
int w;
float *data;
} image;
=== store.c ===
#include <stdio.h>
#include "image.h"
float data1_0[24] = \
{0.840188,0.394383,0.783099,0.798440,0.911647,0.197551,0.335223,0.768230,0.277775,0.553970,0.477397,0.628871,0.364784,0.513401,0.952230,0.916195,0.635712,0.717297,0.141603,0.606969,0.016301,0.242887,0.137232,0.804177};
float data1_1[24] = \
{0.156679,0.400944,0.129790,0.108809,0.998925,0.218257,0.512932,0.839112,0.612640,0.296032,0.637552,0.524287,0.493583,0.972775,0.292517,0.771358,0.526745,0.769914,0.400229,0.891529,0.283315,0.352458,0.807725,0.919026};
image alpha_images[2];
main()
{
int i;
image ab;
alpha_images[0].c = 2;
alpha_images[0].h = 3;
alpha_images[0].w = 4;
alpha_images[0].data = data1_0;
alpha_images[1].c = 2;
alpha_images[1].h = 3;
alpha_images[1].w = 4;
alpha_images[1].data = data1_1;
FILE *fpi = fopen("alpha_image.bin","wb");
FILE *fpd = fopen("alpha_data.bin","wb");
for(i=0;i<2;i++){
ab = alpha_images[i];
if (fwrite(&ab, sizeof(image), 1, fpi) != 1) printf ("error! 1234 \n");
if (fwrite(ab.data, ab.h*ab.w*ab.c, 1, fpd) != 1) printf ("error! 5678 \n");
}
printf("size of image = %d\n", sizeof(image));
}
I do xxd -i alpha_image.bin to make alpha_image_bin.h shown below in hex.
=== alpha_image_bin.h ===
unsigned char alpha_image_bin[] = {
0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x0b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x0b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int alpha_image_bin_len = 48;
.
and xxd -i alpha_data.bin to make alpha_data_bin.h shown below in hex.
=== alpha_data_bin.h ===
nsigned char alpha_data_bin[] = {
0x90, 0x16, 0x57, 0x3f, 0x92, 0xec, 0xc9, 0x3e, 0x2d, 0x79, 0x48, 0x3f,
0x90, 0x66, 0x4c, 0x3f, 0xb3, 0x61, 0x69, 0x3f, 0xcf, 0x4a, 0x4a, 0x3e,
0x76, 0x70, 0x20, 0x3e, 0x88, 0x48, 0xcd, 0x3e, 0xab, 0xe7, 0x04, 0x3e,
0x41, 0xd7, 0xde, 0x3d, 0x8c, 0xb9, 0x7f, 0x3f, 0xc3, 0x7e, 0x5f, 0x3e
};
unsigned int alpha_data_bin_len = 48;
I checked the generated values are correct when expressed in ieee754 single precision float (little endian).
The converted header files are as follows.
=== alpha_image_bin.h ===
unsigned char alpha_image_bin[] = {
0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int alpha_image_bin_len = 48;
=== alpha_data_bin.h ===
unsigned char alpha_data_bin[] = {
0x90, 0x16, 0x57, 0x3f, 0x92, 0xec, 0xc9, 0x3e, 0x2d, 0x79, 0x48, 0x3f,
0x90, 0x66, 0x4c, 0x3f, 0xb3, 0x61, 0x69, 0x3f, 0xcf, 0x4a, 0x4a, 0x3e,
0x76, 0x70, 0x20, 0x3e, 0x88, 0x48, 0xcd, 0x3e, 0xab, 0xe7, 0x04, 0x3e,
0x41, 0xd7, 0xde, 0x3d, 0x8c, 0xb9, 0x7f, 0x3f, 0xc3, 0x7e, 0x5f, 0x3e
};
unsigned int alpha_data_bin_len = 48;
Below is the loading program.
=== load.c ===
#include <stdio.h>
#include <string.h>
#include "image.h"
#include "alpha_image_bin.h"
#include "alpha_data_bin.h"
image alpha_image[2];
main()
{
int i, j;
image *iptr = (image *)&alpha_image_bin[0];
int dptr = 0;
for(i = 0; i < 2; i++){
alpha_image[i] = *iptr; // copy c,h,w
alpha_image[i].data = (float *)&alpha_data_bin[dptr]; // overwrite data pointer
iptr++; dptr+= 2*3*4*sizeof(float);
}
// check loading
for(i = 0; i < 2; i++){
printf("c = %d, h = %d, w = %d\n", alpha_image[i].c, alpha_image[i].h, alpha_image[i].w);
for(j=0; j<2*3*4; j++) {
printf("%f ", alpha_image[i].data[j]);
}
printf("\n");
}
}
When I run load, it gives me this result
=== load result ===
c = 2, h = 3, w = 4
0.840188 0.394383 0.783099 0.798440 0.911647 0.197551 0.156679 0.400944 0.129790 0.108809 0.998925 0.218257 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
c = 2, h = 3, w = 4
0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
The correct data should be as shown in store.c.
=== expected correct result ===
float data1_0[24] = \
{0.840188,0.394383,0.783099,0.798440,0.911647,0.197551,0.335223,0.768230,0.277775,0.553970,0.477397,0.628871,0.364784,0.513401,0.952230,0.916195,0.635712,0.717297,0.141603,0.606969,0.016301,0.242887,0.137232,0.804177};
float data1_1[24] = \
{0.156679,0.400944,0.129790,0.108809,0.998925,0.218257,0.512932,0.839112,0.612640,0.296032,0.637552,0.524287,0.493583,0.972775,0.292517,0.771358,0.526745,0.769914,0.400229,0.891529,0.283315,0.352458,0.807725,0.919026};
What is wrong with the load.c code? (note sizeof(image) is 24 because there are 4 bytes padding before the data pointer).
In float data1_0[24] = \ you can remove the backslash. I don't know if it hurts, but it certainly isn't necessary as the C compiler is line-independent (it just continues parsing on the next line).
In fwrite(&ab, sizeof(image), 1, fpi) you are also writing the pointer to the data. That is useless as you cannot read it back with meaning. Of couse you can read it back but you must then ignore any value of the pointer and replace it with the pointer to the actual data.
Finally, you forget to close the files, so add two calls to fclose().
In load.c I don't see you opening any files, so how do you expect to load anything??? Ah...you save it as .bin and then include it in a .h. Sounds a bit stupid: with every change you have to recompile it. If I were a teacher you got a fail for this setup. Just use malloc to allocate the memory then read the binary data into it.
The error you described is not in load.c. It is in store.c:
if (fwrite(ab.data, ab.h*ab.w*ab.c, 1, fpd) != 1) printf ("error! 5678 \n");
This only writes the first 24 bytes of ab.data instead of writing all 24 * sizeof (float) bytes (assuming float is 4 bytes, you only wrote the first 6 floats of each image).
Fix it by changing to:
if (fwrite(ab.data, sizeof(float)*ab.h*ab.w*ab.c, 1, fpd) != 1) printf ("error! 5678 \n");
And because of that error the char-array in alpha_data_bin.h, that you created from the file, is too short.

Resources