C: Access consecutive series of 12 bits in a char array - c

I want to perform Golay encoding/decoding on a easurement, which is stored in a char array. Thus, I need to access consecutive 12 bits of the measurement, which are passed to the encoder/decoder.
The char array is 22 byte long and looks like this, for example:
unsigned char measurement1[22] =
{0xb5, 0x31, 0xc6, 0x51, 0x84, 0x26, 0x2c, 0x69, 0xfd, 0x9e,
0xef, 0xd4, 0xcf, 0xf1, 0x24, 0xd4, 0xf1, 0x97, 0xe5, 0x81,
0x02, 0xf8}
At the moment, I am converting the char array into an array of corresponding bits and pass this to the encoder. However, this approach is quite memory exhausting, since the bit array also is a array of chars - 0 or 1 - with 176 bytes (22 * 8) in total.
Is there a more memory-saving approach, which does not depend on converting the byte array into a series of bits, but rather accesses consecutive 12 bits and passes them to the decoder?
Best regards,
P.

Convert an index i not to a 1-byte based offset to 8 bits, but to a 12-bit based offset instead. Then it depends on whether you are indexing an even or odd 12-bit triple:
for (i=0; i<22*8/12; i++)
{
printf ("%03x ", (i & 1) ? measurement1[3*i/2+1]+((measurement1[3*i/2] & 0x0f)<<8) : (measurement1[3*i/2]<<4)+((measurement1[3*i/2+1]>>4) & 0x0f) );
}
This assumes your measurement array is read left-to-right, i.e.
0xb5, 0x31, 0xc6
translates to
0xb53 0x1c6
If your order is different, you need to adjust the bit shifts.
Does it matter that your measurement array does not contain a multiple of 12 bits?

Untested, off the top of my head, I'm sure you can simplify it further...
int i = 0, left = 8, v = 0;
do
{
v = 0;
switch (left)
{
case 8:
{
v = measurement1[i++];
v = (v << 4) | (measurement1[i] >> 4); // please handle end here correctly
left = 4;
break;
}
case 4:
{
v = measurement1[i++] & 0x0F; // lower nibble
v = (v << 8) | measurement1[i++]; // please handle end here correctly
left = 8;
break;
}
}
// Now encode v
} while (i < 22);

You could "parse" the mesurement as an 12 bit array:
typedef union { // you can use union or struct here
uint16_t i : 12;
} __attribute__((packed)) uint12_t;
printf("%u", ((uint12_t*) mesurement)[0]);
This will print the first 12 bits of your array.

Related

Defining array of bytes for use to call later in C program

Initializing a SI labs radio, the software develops a header file as well as a patch file. first part is, depending on the patch file it outputs different ways. here is a snippet of each patch:
Rev B patch:
#define SI446X_PATCH_CMDS \
{ 0x04,0x11,0xF7,0x76,0x00,0x00,0xA6,0x82 }, \
{ 0x05,0x61,0xE6,0x82,0x5E,0xB7,0xFB,0x93 }, \
{ 0x05,0x1E,0x12,0xBD,0x5A,0xC2,0x52,0x41 }, \
{ 0xE7,0xF4,0xDF,0x6A,0x24,0xD9,0xBA,0x31 }, \
OR
Rev C patch:
#define SI446X_PATCH_CMDS \
0x08,0x04,0x21,0x71,0x4B,0x00,0x00,0xDC,0x95, \
0x08,0x05,0xA6,0x22,0x21,0xF0,0x41,0x5B,0x26, \
0x08,0xE2,0x2F,0x1C,0xBB,0x0A,0xA8,0x94,0x28, \
0x08,0x05,0x87,0x67,0xE2,0x58,0x1A,0x07,0x5B, \
Now this will be hardcoded into the software and either one commented out. but it must have been done this way for a reason and i dont understand it. for initial testing i placed each line of 8 bytes (as it needs to be pushed over SPI this way) into an array and then created a pointer to the array since the length isnt necessary as they are all 8 bytes like i said. iss there a more intelligent way i should cade this based on the way it is presented?
uint8_t array_1[8] = { 0x04, 0x11, 0xF7, 0x76, 0x00, 0x00, 0xA6, 0x82 };
uint8_t array_2[8] = { 0x05, 0x61, 0xE6, 0x82, 0x5E, 0xB7, 0xFB, 0x93 };
uint8_t *theArrays[] = { array_1, array_2, array_3, array_4, array_5, array_6,
array_7, array_8, array_9, array_10, array_11, array_12, array_13,
I then program the SPI using this code and manually typed in the qty into a for loop as i cant get sizeof from the pointer array.
HAL_SPI_Transmit(&hspi1, theArrays[i], 8, 50);
These macros just make things a bit easier.
Assuming the number of (sub)arrays in both macros matches the number of arrays in your array of pointers, your code would look like this in full version:
uint8_t array_1[8] = { 0x04, 0x11, 0xF7, 0x76, 0x00, 0x00, 0xA6, 0x82 };
uint8_t array_2[8] = { 0x05, 0x61, 0xE6, 0x82, 0x5E, 0xB7, 0xFB, 0x93 };
uint8_t array_3[8] = ...
uint8_t array_4[8] = ...
uint8_t array_...
uint8_t array_12[8] = ...
uint8_t array_13[8] = ...
uint8_t *theArrays[] = { array_1, array_2, array_3, array_4, array_5, array_6,
array_7, array_8, array_9, array_10, array_11, array_12, array_13,
...
HAL_SPI_Transmit(&hspi1, theArrays[i], 8, 50);
With these macros (stored in some nice header) you can just do this:
Revision B:
#define SPI_MESSAGE_SIZE 8
const uint8_t theArray[][SPI_MESSAGE_SIZE] = {SI446X_PATCH_CMDS};
_Static_assert(sizeof theArray/sizeof *theArray == SOME_EXPECTED_SIZE, "SI446X_PATCH_CMDS corrupt");
...
HAL_SPI_Transmit(&hspi1, theArrays[i], SPI_MESSAGE_SIZE, 50);
or in case of Revision C
#define SPI_MESSAGE_SIZE 8
const uint8_t theArray[] = {SI446X_PATCH_CMDS};
_Static_assert(sizeof theArray/sizeof *theArray == SOME_EXPECTED_SIZE, "SI446X_PATCH_CMDS corrupt");
...
// For Rev C, the array contains a <length> byte before the SPI data.
// Adjust addressing accordingly
uint8_t len = theArrays[i*(SPI_MESSAGE_SIZE+1)];
HAL_SPI_Transmit(&hspi1, &theArrays[i*(SPI_MESSAGE_SIZE+1)+1], len, 50);
The static assert was suggested by Lundin. I am not aware of the correct value to compare but there should be some useful define somewhere in Silabs Radio's headers.

How to prepare data for use with MMX/SSE intrinsics for shifting 16bit values?

No matter what I do with {0,8,16,0}(16bit vector, representation for copying into a big endian 64bit value) I am unable to properly bit shift a test value of { 0x00, 0x01, (...) 0x07 };
The result I get in the debugger is always 0x0.
I tried to convert the value in a couple of different ways, but I am unable to get this right.
Executed on a little endian:
#include <mmintrin.h>
#include <stdint.h>
int main(int argc, char** argv) {
__m64 input;
__m64 vectors;
__m64 output;
_Alignas(8) uint16_t bit16Vectors[1*4] = {
0x0000,0x0008,0x0010,0x0000
// Intent: {0,8,16,0} 16 bit array
// Convert for copy: {0,16,8,0} 64bit one item
// 8bit data, Bytes need to rotate: {0,8,16,0}
};
_Alignas(8) uint8_t in[8] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};
input = _m_from_int64(*((long long*)in) );
vectors = _m_from_int64 (*((long long*)bit16Vectors));
output = _mm_sll_pi16(input, vectors);
__asm__("int3");
}
I wrote down a simple MMX-only RGB24 plane separation pseudoAssembly[which processes 8x1 values], but I am unable to convert all the 16+32bit bit shift vectors to "real world", or I do something wrong with the intrinsics.
I am unable to pin it down exactly, I just know it fails at the very first bit shift and returns the value of 0x0.

Very slow SPI writing STM32

I am currently writing a code to write on an LCD screen pixel by pixel. The code works fine, however the speed at which the code is processed is incredibly slow. The goal is simply to write number on the LCD screen so I am using the "switch" function with a "for loop" to read each of the bit I will activate. I am wondering if someone could tell me a way to speed up my code...
int* switch_library_number_1(int num, int octet)
{
switch(num)
{
case 0 : ;
int number_0 [] = {0x80, 0x08,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x88,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, ...};
int * pNumber_0 = &number_0[octet];
return pNumber_0;
break;
case 1 : ;
int number_1 [] = {0x80, 0x08,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x88, ...};
int * pNumber_1 = &number_1[octet];
return pNumber_1;
break;
}
Then it goes up to nine like that, I don't think you need to seem all the cases. Plus even if I deleted most of them, I have 522 bytes by number. The rest of the code goes as fallow :
int main(void)
{
ADC_Initialization();
SPI_Initialization();
int nombre_octet = 522;
int premier_nombre;
int deuxieme_nombre;
while(1)
{
GPIOA->BSRRL = CS;
for(int i = 0; i < nombre_octet; i++)
{
write_spi(*switch_library_number_1(0, i));
}
GPIOA -> BSRRH = CS;
for(int i = 0; i < 100; i++)
{
}
GPIOA->BSRRL = CS;
for(int i = 0; i < nombre_octet; i++)
{
write_spi(*switch_library_number_2(1, i));
}
GPIOA -> BSRRH = CS;
}
}
Finally, here is the write_SPI function, but due to it's simplicity, I don't think that it is the problem.
void write_spi(char data)
{
SPI1->DR = data;
while (!(SPI1->SR & SPI_I2S_FLAG_TXE));
while (!(SPI1->SR & SPI_I2S_FLAG_RXNE));
while (SPI1->SR & SPI_I2S_FLAG_BSY);
}
Thanks in advance!
I quite like the way you split your code into three snippets. I can suggest improvements for each of them:
switch_library_number_1():
This could be just a 2D array, number[][], or if number_0, number_1... are not of the same length, it could be an array of pointers to these. There would need to be checks for valid num and offset. This might be a minor speed improvement.
Your number_0... arrays are currently on stack, and read-write. Make them const, so they won't use RAM.
Currently you are returning a pointer to memory location on stack - this doesn't normally work, if it does it's by luck and accident. You should not access stack data when you're out of scope (function) where it's been defined. static const would make this safe, as it wouldn't be on stack anymore.
main loop:
It's a bit odd to call switch_library_number_1/2 on each loop iteration. You know your data will just be in array. This could probably be replaced by write_spi(number[0][i]); if number array is properly set up. This should get you some speed improvement, as it very much simplifies data fetching.
You appear to have a busy loop. That's a tricky practice (I bet 100 is a guess, and note that compiler could optimise this loop away). If possibly use some library provided delay function or a timer to get precise delays. Is this an actual requirement of SPI slave?
write_spi(char data):
char should be unsigned char here. chars might be signed or unsigned, so when you're using them as bytes (not actual string characters), you should specify signedness.
You seem to wait for every byte transmission to finish, which is safe, but a bit slow. Normally this can be rewritten into a faster alternative of wait_for_SPI_ready_for_TX; SPI_TX, where you only wait before sending next byte. Note that you will also need to wait for byte to be transmitted fully before pulling CS back high again. This could be a big speed improvement.
Some other things to consider:
What's the actual SPI clock? There may be huge speed improvements if clock is increased.
How did you measure this to be "slow"? Does it point to slow parts of code (what are those then? If not obvious from C, what are they assembled to?)
Have you got an oscilloscope/logic analyser to look at actual signals on wire? This may provide useful data.
I had a similar problem with STM32F207 Series Cortex-M3 controller, when I observed the TX line through Oscillator, I saw that CHIP_SELECT disable was taking too much time to set in, after all the data has sent.I figured out it is related to flag controls So ı play with the control flags a little bit, Here how it worked out just fine for me;
static void SPI_Send(uint16_t len,uint8_t* data)
{
uint16_t i;
for(i = 0;i<len;i++)
{
SPI_I2S_SendData(SPI1,*(data+i));
while(!(SPI1->SR & SPI_SR_TXE));
}
while(SPI1->SR & SPI_SR_BSY);
CHIP_SEL_DISABLE;
}
I believe it is slow because you are also checking the 'Receive Buffer Not Empty' where you don't need to.

How to XOR char array with an integer in C [duplicate]

This question already has answers here:
How to make bit wise XOR in C
(7 answers)
Closed 5 years ago.
I am trying to implement a cryptographic algorithm in C. I have an unsigned char array;
unsigned char ciphertext[] = { 0xA5, 0xB2, 0x3C, 0xAB, 0x03, 0xF1, 0xD3, 0x1C, 0x7F, 0xAD, 0x37, 0xA8, 0x8C, 0x8B, 0xCD, 0x90, 0xD4, 0xC2, 0x30, 0xAB, 0xD2, 0x3F, 0x3D, 0xAF, 0x58, 0x94, 0x1F, 0x50, 0xAF, 0xA2, 0xCE, 0x01 };
I need to XOR the char array with all values from 1 to 256. How can I do it in C? Thank you in advance.
EDİT:
I want to XOR my char array with;
unsigned char [] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
unsigned char two = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02};
unsigned char three[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03};
And so on... That is the reason why I can not xor through each elements. It would be something different.
Something like:
int i;
for (i = 0; i < length; i++) {
cryptotext[i] = ciphertext[i] ^ (i%256);
}
Note that you can use only one array if you don't want to keep you plain text:
ciphertext[i] ^= (i%256);
XOR performs the following operations. please see below.
x y XOR
------------
0 0 0
1 0 1
0 1 1
1 1 0
You can't xor the entire array in one piece. you need to loop through the array and transform it character by character.
perform loop through the array and perform the XOR Operation.

Best way to define 2 bytes for easy use with array initialization / comparing in C?

Again, I am fairly new to C so forgive the simplicity / stupidity of this question. Anyway, here it goes. What is the best way to #define a 2 byte macro (i.e. #define MSGID 0xABCD) in C that is easy to put inside a byte array but also compare the contents of with if statements?
To clarify this, take the 0xABCD example again. Say I want to do an:
unsigned char test_msg[] = { 0x00, 0x01, 0x02, MSGID, 0x03, 0x04, 0x05 };
With how I defined it above, it won't work because it's defined as a large int and gcc truncates it to an unsigned type. When I define it as #define MSGID 0xAB,0xCD it seems to work fine, but I don't understand what the comma does there and that doesn't look very clean. Another option I found that works, but also not clean, is splitting it like #define MSGIDCLASS 0xAB then #define MSGID 0xCD.
I would also like to compare these MSGID bytes and at the moment I'm having to constantly do an if(data[n] == MSGIDCLASS && data[n+1] == MSGID) ... for every message I need to parse and respond to. I was wondering if there was an easier way of doing this, that's all. If not, I'll leave it as is. Thanks again for the help. Sorry for not using the code sample tags, didn't think they were necessary with one liners.
#define's simply get replaced with their contents. So when you use commas the final code becomes:
unsigned char test_msg[] = { 0x00, 0x01, 0x02, 0xAB, 0xCD, 0x03, 0x04, 0x05 };
That's why it seems to work.
Instead, defining MSGIDHI and MSGIDLO components separately allows you to both use and compare easily. And you can define MSGID as:
#define MSGIDLO 0xCD
#define MSGIDHI 0xAB
#define MSGID (MSGIDLO | (MSGIDHI << 8))
This way you can use them in any form you want.
Sometimes you may prefer a solution without a preprocessor instead, like this:
enum {MSGID = 0xABCD};
// in C++ you can use const int MSGID = 0xABCD instead, not sure about C
unsigned char test_msg[] = { 0x00, 0x01, 0x02, MSGID>>8, MSGID&0xff, 0x03, 0x04, 0x05 };
If your message-ID's are really composed of a Class and an ID, and that separation is not just made to split them into two bytes, then you could do the following:
Keep the separate class and ID values
Use those separate val;ues to fill in in the messages
Use the following macros to compare them:
#define MSGID(msgClass, ID) (((msgClass) << 8) | (ID))
#define GET_MSGID(data, n) (((data)[n] << 8) | (data)[(n)+1])
You use them like this:
#define MSGCLASS_A 0xAB
#define MSGID_B 0xCD
unsigned char test_msg[] = { 0x00, 0x01, 0x02, MSGCLASS_A, MSGID_B, 0x03, 0x04, 0x05 };
if (GET_MSGID(test_msg, 0) == MSG_ID(MSGCLASS_A, MSGID_B))
{
// matched message
}
If your message-ID's are really just a 16-bit number, you could do the following:
Use a single define for your message-ID's
Use the following macros to insert/extract them from a message:
#define MSGID(ID) (((ID) >> 8) & 0xFF), ((ID) & 0xFF) /* For static message definitions */
#define ADD_MSGID(data, n, ID) do { (data)[n] = (((ID) >> 8) & 0xFF; (data)[(n)+1] = ((ID) & 0xFF; } while (0)
#define GET_MSGID(data, n) (((data)[n] << 8) | (data)[(n)+1])
You use them like this:
#define MSGID_A 0xABCD
unsigned char test_msg[] = { 0x00, 0x01, 0x02, MSGID(MSGID_A), 0x03, 0x04, 0x05 };
// or: ADD_MSGID(test_msg, 0, MSGID_A)
if (GET_MSGID(test_msg, 0) == MSGID_A)
{
// matched message
}
The comma in the MSGID macro is handled just like any comma separating initialisers for an array, because macros just perform a textual replacement before the compiler parses the code.

Resources