creating and using lookup table based on AD value - c++

I am having a little bit of trouble creating and using a look up table.
My code is for a microcontroller that polls an 11 bit AD converter, and based on the value updates a 7 segment display.
The way i want to write the code is to create a table with 2047 values, each value has a binary pattern attached to it representing which pins and on and off, and then having the table return that binary value as int.
I am however not sure on the syntax to create the table or calling to it.
So far i got:
int table[2048][2];
j=0;
for(i=0; i<2048; i++)
{
if(i%204==8)
{
j++;
}
if(j==0)
{
value=0x3F;
}
if(j==1)
{
value=0x06;
}
table[i][2]={i},{value};
}
the if statements keep going down to j==9, the value is the binary pattern I'm interested in returning.
Is this a smart way of approaching the problem? if the AD value returned is for example 300, how would I look it up in the table to be able to get 0x06 as the number i want?
The bits for each of the second segments are
111
6 2
6 2
777
5 3
5 3
444
So the digit 2 has bits 1, 2, 4, 5, and 7 set,and so is represented by 0x5B

That is a lot of duplicated bits, with a lot of runtime overhead, and I can't even think of an efficient way to use it. Why not a lookup table of each of the 10 decimal digits, and simply have a function assemble the result 1 decimal digit at a time?
static const unsigned char segment7digits = {
0x3F, //0 -> 00111111
0x3F, //1 -> 00000110
0x5B, //2 -> 01011011
0x4F, //3 -> 01001111
0x66, //4 -> 01100110
0x6D, //5 -> 01101101
0x7D, //6 -> 01111101
0x07, //7 -> 00000111
0x7F, //8 -> 01111111
0x6F, //9 -> 01101111
}; //these values are untested and probably have errors
int lookup_7segment_bits(int value) {
assert(value>=0 && value<=9999);
int result;
result = segment7digits[value/1%10]; //least significant decimal digit
result |= segment7digits[value/10%10]<<7;
result |= segment7digits[value/100%10]<<14;
result |= segment7digits[value/1000%10]<<21; //most significant decimal digit
return result;
};

Related

Impact of data padding on CRC calculation

I am calculating CRC on a large chunk of data every cycle in hardware (64B per cycle). In order to parallelize the CRC calculation, I want to calculate the CRC for small data chunks and then XOR them in parallel.
Approach:
We divide the data into small chunks (64B data divided into 8 chunks
of 8B each).
Then we calculate CRC's for all the chunks
individually (8 CRC's in parallel for 8B chunks).
Finally calculate
the CRC for padded data. This answer points out that the CRC
for padded data is obtained by multiplying the old CRC with x^n.
Hence, I am calculating the CRC for a small chunk of data, then multiply it with CRC of 0x1 shifted by 'i' times as shown below.
In short, I am trying to accomplish below:
For example: CRC-8 on this site:
Input Data=(0x05 0x07) CRC=0x54
Step-1: Data=0x5 CRC=0x1B
Step-2: Data=0x7 CRC=0x15
Step-3: Data=(0x1 0x0) CRC=0x15
Step-4: Multiply step-1 CRC and step-3 CRC with primitive polynomial 0x7. So, I calculate (0x1B).(0x15) = (0x1 0xC7) mod 0x7.
Step-5: Calculate CRC Data=(0x1 0xC7) CRC=0x4E (I assume this is same as (0x1 0xC7) mod 0x7)
Step-6: XOR the result to get the final CRC. 0x4E^0x15=0x5B
As we can see, the result in step-6 is not the correct result.
Can someone help me how to calculate the CRC for padded data? Or where am I going wrong in the above example?
Rather than calculate and then adjust multiple CRC's, bytes of data can be carryless multiplied to form a set of 16 bit "folded" products, which are then xor'ed and a single modulo operation performed on the xor'ed "folded" products. An optimized modulo operation uses two carryless multiples, so it's avoided until all folded products have been generated and xor'ed together. A carryless multiply uses XOR instead of ADD and a borrowless divide uses XOR instead of SUB. Intel has a pdf file about this using the XMM instruction PCLMULQDQ (carryless multiply), where 16 bytes are read at a time, split into two 8 byte groups, with each group folded into a 16 byte product, and the two 16 byte products are xor'ed to form a single 16 byte product. Using 8 XMM registers to hold folding products, 128 bytes at time are processed. (256 bytes at at time in the case of AVX512 and ZMM registers).
https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
Assume your hardware can implement a carryless multiply that takes two 8 bit operands and produces a 16 bit (technically 15 bit) product.
Let message = M = 31 32 33 34 35 36 37 38. In this case CRC(M) = C7
pre-calculated constants (all values shown in hex):
2^38%107 = DF cycles forwards 0x38 bits
2^30%107 = 29 cycles forwards 0x30 bits
2^28%107 = 62 cycles forwards 0x28 bits
2^20%107 = 16 cycles forwards 0x20 bits
2^18%107 = 6B cycles forwards 0x18 bits
2^10%107 = 15 cycles forwards 0x10 bits
2^08%107 = 07 cycles forwards 0x08 bits
2^00%107 = 01 cycles forwards 0x00 bits
16 bit folded (cycled forward) products (can be calculated in parallel):
31·DF = 16CF
32·29 = 07E2
33·62 = 0AC6
34·16 = 03F8
35·6B = 0A17
36·15 = 038E
37·07 = 0085
38·01 = 0038
----
V = 1137 the xor of the 8 folded products
CRC(V) = 113700 % 107 = C7
To avoid having to use borrowless divide for the modulo operation, CRC(V) can be computed using carryless multiply. For example
V = FFFE
CRC(V) = FFFE00 % 107 = 23.
Implementation, again all values in hex (hex 10 = decimal 16), ⊕ is XOR.
input:
V = FFFE
constants:
P = 107 polynomial
I = 2^10 / 107 = 107 "inverse" of polynomial
by coincidence, it's the same value
2^10 % 107 = 15 for folding right 16 bits
fold the upper 8 bits of FFFE00 16 bits to the right:
U = FF·15 ⊕ FE00 = 0CF3 ⊕ FE00 = F2F3 (check: F2F3%107 = 23 = CRC)
Q = ((U>>8)·I)>>8 = (F2·107)>>8 = ...
to avoid a 9 bit operand, split up 107 = 100 ⊕ 7
Q = ((F2·100) ⊕ (F2·07))>>8 = ((F2<<8) ⊕ (F2·07))>>8 = (F200 ⊕ 02DE)>>8 = F0DE>>8 = F0
X = Q·P = F0·107 = F0·100 ⊕ F0·07 = F0<<8 ⊕ F0·07 = F000 ⊕ 02D0 = F2D0
CRC = U ⊕ X = F2F3 ⊕ F2D0 = 23
Since the CRC is 8 bits, there's no need for the upper 8 bits in the last two steps, but it doesn't help that much for the overall calculation.
X = (Q·(P&FF))&FF = (F0·07)&FF = D0
CRC = (U&FF) ⊕ X = F3 ⊕ D0 = 23
Example program to generate 2^0x10 / 0x107 and powers of 2 % 0x107:
#include <stdio.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
#define poly 0x107
uint16_t geninv(void) /* generate 2^16 / 9 bit poly */
{
uint16_t q = 0x0000u; /* quotient */
uint16_t d = 0x0001u; /* initial dividend = 2^0 */
for(int i = 0; i < 16; i++){
d <<= 1;
q <<= 1;
if(d&0x0100){ /* if bit 8 set */
q |= 1; /* q |= 1 */
d ^= poly; /* d ^= poly */
}
}
return q; /* return inverse */
}
uint8_t powmodpoly(int n) /* generate 2^n % 9 bit poly */
{
uint16_t d = 0x0001u; /* initial dividend = 2^0 */
for(int i = 0; i < n; i++){
d <<= 1; /* shift dvnd left */
if(d&0x0100){ /* if bit 8 set */
d ^= poly; /* d ^= poly */
}
}
return (uint8_t)d; /* return remainder */
}
int main()
{
printf("%04x\n", geninv());
printf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
powmodpoly(0x00), powmodpoly(0x08), powmodpoly(0x10), powmodpoly(0x18),
powmodpoly(0x20), powmodpoly(0x28), powmodpoly(0x30), powmodpoly(0x38),
powmodpoly(0x40), powmodpoly(0x48));
printf("%02x\n", powmodpoly(0x77)); /* 0xd9, cycles crc backwards 8 bits */
return 0;
}
Long hand example for 2^0x10 / 0x107.
100000111 quotient
-------------------
divisor 100000111 | 10000000000000000 dividend
100000111
---------
111000000
100000111
---------
110001110
100000111
---------
100010010
100000111
---------
10101 remainder
I don't know how many registers you can have in your hardware design, but assume there are five 16 bit registers used to hold folded values, and either two or eight 8 bit registers (depending on how parallel the folding is done). Then following the Intel paper, you fold values for all 64 bytes, 8 bytes at a time, and only need one modulo operation. Register size, fold# = 16 bits, reg# = 8 bits. Note that powers of 2 modulo poly are pre-calculated constants.
foldv = prior buffer's folding value, equivalent to folded msg[-2 -1]
reg0 = foldv>>8
reg1 = foldv&0xFF
foldv = reg0·((2^0x18)%poly) advance by 3 bytes
foldv ^= reg1·((2^0x10)%poly) advance by 2 bytes
fold0 = msg[0 1] ^ foldv handling 2 bytes at a time
fold1 = msg[2 3]
fold2 = msg[4 5]
fold3 = msg[6 7]
for(i = 8; i < 56; i += 8){
reg0 = fold0>>8
reg1 = fold0&ff
fold0 = reg0·((2^0x48)%poly) advance by 9 bytes
fold0 ^= reg1·((2^0x40)%poly) advance by 8 bytes
fold0 ^= msg[i+0 i+1]
reg2 = fold1>>8 if not parallel, reg0
reg3 = fold1&ff and reg1
fold1 = reg2·((2^0x48)%poly) advance by 9 bytes
fold1 ^= reg3·((2^0x40)%poly) advance by 8 bytes
fold1 ^= msg[i+2 i+3]
...
fold3 ^= msg[i+6 i+7]
}
reg0 = fold0>>8
reg1 = fold0&ff
fold0 = reg0·((2^0x38)%poly) advance by 7 bytes
fold0 ^= reg1·((2^0x30)%poly) advance by 6 bytes
reg2 = fold1>>8 if not parallel, reg0
reg3 = fold1&ff and reg1
fold1 = reg2·((2^0x28)%poly) advance by 5 bytes
fold1 ^= reg3·((2^0x20)%poly) advance by 4 bytes
fold2 ... advance by 3 2 bytes
fold3 ... advance by 1 0 bytes
foldv = fold0^fold1^fold2^fold3
Say the final buffer has 5 bytes:
foldv = prior folding value, equivalent to folded msg[-2 -1]
reg0 = foldv>>8
reg1 = foldv&0xFF
foldv = reg0·((2^0x30)%poly) advance by 6 bytes
foldv ^= reg1·((2^0x28)%poly) advance by 5 bytes
fold0 = msg[0 1] ^ foldv
reg0 = fold0>>8
reg1 = fold0&ff
fold0 = reg0·((2^0x20)%poly) advance by 4 bytes
fold0 ^= reg1·((2^0x18)%poly) advance by 3 bytes
fold1 = msg[2 3]
reg2 = fold1>>8
reg3 = fold1&ff
fold1 = reg0·((2^0x10)%poly) advance by 2 bytes
fold1 ^= reg1·((2^0x08)%poly) advance by 1 bytes
fold2 = msg[4] just one byte loaded
fold3 = 0
foldv = fold0^fold1^fold2^fold3
now use the method above to calculate CRC(foldv)
As shown in your diagram, you need to calculate the CRC of 0x05 0x00, (A,0), and the CRC of 0x00 0x07, (0,B), and then exclusive-or those together. Calculating on the site you linked, you get 0x41 and 0x15 respectively. Exclusive-or those together, and, voila, you get 0x54, the CRC of 0x05 0x07.
There is a shortcut for (0,B), since for this CRC, the CRC of a string of zeros is zero. You can calculate the CRC of just 0x07 and get the same result as for 0x00 0x07, which is 0x15.
See crcany for how to combine CRCs in general. crcany will generate C code to compute any specified CRC, including code to combine CRCs. It employs a technique that applies n zeros to a CRC in O(log(n)) time instead of O(n) time.

C++ Byte, sprintf, hex. Convert byte to binary

I am working on this project which has this format/command. My problem is with b0,b1..b5. I am not very good at c++. I can do this in c#.
Configure Image Data (CID) Command
Esc*v6W b0 b1 b2 b3 b4 b5
Where:
• 6 = the number of bytes following the command
• b0 = byte 0 = the color space
• b1 = byte 1 = the Pixel Encoding mode
• b2 = byte 2 = the number of bits per index or palette size
• b3 = byte 3 = the number of bits in the color component
• b4 = byte 4 = the number of bits in the color component
• b5 = byte 5 = the number of bits in the color component
Bytes 0 through 5 must contain binary data, not ASCII.
How should I do this in c++. This is what I have so far.
int srcBitsPerPixel = 24;
BYTE bitsPerIndex = 0x00;
std::string str;
std::vector<unsigned char> seq(6);
char bufv6[6];
StringCchPrintfA(bufv6, 6, "%c%s", 27, "*v6W"); // 5 chars
MoveMemory(pOemPDEV->pBufStart + dwOffset, bufv6, 6);
dwOffset += 5;
seq[0] = (BYTE)0x02; // 0: ColourSpace
seq[1] = (BYTE)0x03; // 1: Pixel Encoding Mode
seq[2] = (BYTE)0x00; // 2: Bits Per Index
seq[3] = (BYTE)0x08; // 3: Bits Per Component
seq[4] = (BYTE)0x08; // 4: Bits Per Component
seq[5] = (BYTE)0x08; // 5: Bits Per Component
for (int i = 0; i < 6; i++)
{
char bufV6W[4];
StringCchPrintfA(bufV6W, 4, "%02X", seq[i]);
str.append(bufV6W);
}
char v6[50];
StringCchPrintfA(v6,50, "%c%s",27, str);
MoveMemory(pOemPDEV->pBufStart + dwOffset, v6, 50);
dwOffset += 1;
But I am not getting the correct results. Can anyone provide some suggestions. This is HP PCL in c++. This way of doing may be very old, not C++ standards, I agree.
Here is how it looks in a HxD editor
Judging by the functions used there, you probably need to build and output that sequence to a stream (but you should really try to explain better next time), so try this:
std::vector<unsigned char> v = { '*', 'v', '6', 'W',
0x02, // b0: ColourSpace
0x00, // b1
0x08, // b2
0x08, // b3
0x08, // b4
0x08 }; // b5
std::copy(v.begin(), v.end(), pOemPDEV->pBufStart + dwOffset);

How many decimal number possibilities are there for a 26-bit Wiegand number?

I have successfully emulated a 26 bit Wiegand signal using an ESP32. Basically, the program transforms a manually inputted decimal number into a proper 26 bit Wiegand binary number and then sends it on 2 wires following the protocol:
bool* wiegandArray = new bool[26];
void getWiegand(unsigned int dec) {
// transform dec number into binary number using single bit shift operation
// and store it in wiegandArray[]
for (int i = 24; i > 0; --i) {
wiegandArray[i] = dec & 1;
dec >>= 1;
}
// check for parity of the first 12 bits
bool even = 0;
for(int i = 1; i < 13; i++) {
even ^= wiegandArray[i];
}
// add 0 or 1 as first bit (leading parity bit - even) based on the number of 'ones' in the first 12 bits
wiegandArray[0] = even;
// check for parity of the last 12 bits
bool odd = 1;
for(int i = 13; i < 25; i++) {
odd ^= wiegandArray[i];
}
// add 0 or 1 as last bit (trailing parity bit - odd) based on the number of 'ones' in the last 12 bits
wiegandArray[25] = odd;
}
Using this online calculator I can generate appropriate decimal numbers for a 26 bit Wiegand number.
Now, the problem that I am facing is that the end-user will actually input a CARD ID. A Card ID is a decimal number that should always result in a 24 bit binary number: 8 bits of facility code and 16 bits of ID code. And upon this 24 bit number I apply the parity bits to get a 26 bit code.
For example:
CARD ID= 16336141 / 101000111000110100101101
Facility Code: 163 / 10100011
Card Number: 36141 / 1000110100101101
Resulting 26 Wiegand: 10718509 / 11010001110001101001011010
The issue is that I don't know how to tackle this issue.
How can I generate a 26 bit Wiegand from 0 ? That would be 0 00000000 0000000000000000 1.
The largest 24 bit number is 16777215. But 8 bits for site codes (0-255) and 16 bits for card numbers (0-65535) mean 255*65535 = 16711425.
What is the actual range ? Should I start generating 26 bit Wiegand binary numbers from 0 ?

Binary numbers and Bit flag 'x'

I'm learning C++ through a website - learncpp.com
and I encountered a line of code that confuses me and I'm not sure how to research it. I went back looking for an explanation on what it is and couldn't find it and I would simply like to know what to look up or what it's called so I could learn more about it.
Here's the code:
unsigned char option_viewed = 0x01;
It's referring to a bit flag. What i'm confused about is the 0x01; part. I'm assuming it's hexadecimal for one, but I'm not sure.
Thanks
When creating bit flags, people often write the literal values in hex because they are easier to read:
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
Instead of:
1, 2, 4, 8, 16, 32, 64, 128
In C++ you can represent an integer literal in 3 different bases: decimal (base 10), octal (base 8), or hexidecimal (base 16). Numbers written the "normal" way (1, 13, 405, ...) are interpreted by the compiler as base 10. Numbers starting with a 0 (01, 040, 0800, ...) are interpreted as base 8. Numbers starting with a 0x (0x1, 0x01, 0x800, ...) are interpreted as base 16.
Note that with base 16 numbers, you can have as many leading 0's after the 0x as you want. That is, 0x1, 0x01, and 0x00000001 are all just 1. The reason you might want to include more leading 0's is for alignment of the code to help with readability. As John Zwinck pointed out it's common for people to use hexidecimal to represent bit flags because every power of 2 can be written with either a 1, 2, 4, or 8 in one of the digits. So you might see something like
unsigned char red = 0x01; // 1 base 10, 00000001 base 2
unsigned char green = 0x02; // 2 base 10, 00000010 base 2
unsigned char blue = 0x04; // 4 base 10, 00000100 base 2
unsigned char yellow = 0x08; // 8 base 10, 00001000 base 2
unsigned char magenta = 0x10; // 16 base 10, 00010000 base 2
unsigned char cyan = 0x20; // 32 base 10, 00100000 base 2
unsigned char white = 0x40; // 64 base 10, 01000000 base 2
unsigned char black = 0x80; // 128 base 10, 10000000 base 2
Really each variable stores a numeric value, but because we're using powers of 2 then each value is represented by a different bit being set to 1. Since the type is an unsigned char which is only 8-bits, you'll never encounter a power larger than 255, or 0xFF hexidecimal, so two digits after the 0x is enough. If you were storing an unsigned short then you might want to write it as 0x0001 which is still just 1, but you're making it obvious that it's a 16-bit integer rather than 8-bit.
You can read more about the different numerical bases in C++ here.

Bitfields in C++

I have the following code for self learning:
#include <iostream>
using namespace std;
struct bitfields{
unsigned field1: 3;
unsigned field2: 4;
unsigned int k: 4;
};
int main(){
bitfields field;
field.field1=8;
field.field2=1e7;
field.k=18;
cout<<field.k<<endl;
cout<<field.field1<<endl;
cout<<field.field2<<endl;
return 0;
}
I know that unsigned int k:4 means that k is 4 bits wide, or a maximum value of 15, and the result is the following.
2
0
1
For example, filed1 can be from 0 to 7 (included), field2 and k from 0 to 15. Why such a result? Maybe it should be all zero?
You're overflowing your fields. Let's take k as an example, it's 4 bits wide. It can hold values, as you say, from 0 to 15, in binary representation this is
0 -> 0000
1 -> 0001
2 -> 0010
3 -> 0011
...
14 -> 1110
15 -> 1111
So when you assign 18, having binary representation
18 -> 1 0010 (space added between 4th and 5th bit for clarity)
k can only hold the lower four bits, so
k = 0010 = 2.
The equivalent holds true for the rest of your fields as well.
You have these results because the assignments overflowed each bitfield.
The variable filed1 is 3 bits, but 8 takes 4 bits to present (1000). The lower three bits are all zero, so filed1 is zero.
For filed2, 17 is represented by 10001, but filed2 is only four bits. The lower four bits represent the value 1.
Finally, for k, 18 is represented by 10010, but k is only four bits. The lower four bits represent the value 2.
I hope that helps clear things up.
In C++ any unsigned type wraps around when you hit its ceiling[1]. When you define a bitfield of 4 bits, then every value you store is wrapped around too. The possible values for a bitfield of size 4 are 0-15. If you store '17', then you wrap to '1', for '18' you go one more to '2'.
Mathematically, the wrapped value is the original value modulo the number of possible values for the destination type:
For the bitfield of size 4 (2**4 possible values):
18 % 16 == 2
17 % 16 == 1
For the bitfield of size 3 (2**3 possible values):
8 % 8 == 0.
[1] This is not true for signed types, where it is undefined what happens then.