final and last update (I promise)
The core of the problem is traversing the data, as Jonathan Leffler kind of alluded. The binary data is "arranged" in a matrix. For example, if I have 3 events and 4 parameters of bitwidth 8, the binary data
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
would look like
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
I have two for loops i & j, and I need to calculate the offset using that.
I initially had
(i * PAR * 2) + (j * PnB/8)
Where PAR is the number of Parameters, PnB is the bitwidth, and i is from 0 to total events and j is from 0 to PAR. This is incorrect, and not sure how I got this formula.
==
I am working on an in-house flow analysis software and am running into some issues. The FCS sample data file I am using to test the software was generated with FACSCaliber on MacOS 9 CellQuest. When I extract the data points for FSC-H and SSC-H I don't get the same results as I would on other flow software (namely FlowJo). I understand that data generated on MacOS 9 CellQuest is stored in big endian order and believe that I am correctly transforming the data as such:
for (int i = 0; i < params[j-1].PnB/8; ++i)
{
lebyte[i] = (bytes[(params[j-1].PnB/8)-1-i] & 0xff) << i*8u;
cx |= lebyte[i];
}
The code may not be elegant but it seems to do what I intend it to do with known data samples.
PnB is the bitwidth
PnR is the channel value range
The result I get when using real flow data looks correct in that the values are within the range specified by PnR, i.e. if PnR = 1024 the data stored in the 16bit space is between 0 - 1023.
However, when I plot the data I get a skewed dot plot where the scatters bend towards the FSC-H x axis.
Here is an excerpt from the FCS 3.1 Standard (Data File Standard for Flow Cytometry, International Society for Advancement of Cytometry; P. 13):
$BYTEORD/n1,n2,n3,n4/ $BYTEORD/4,3,2,1/ [REQUIRED]
This keyword specifies the endianness of the data, i.e., the byte order used to binary store numeric data values in the data set. This value of the keyword corresponds to the order from numerically least significant {1} to numerically most significant {4} in which four binary data bytes are written to compose a 32-bit word in the data acquisition computer. The numbers are separated by commas (ASCII 44). Only two distinct values are allowed:
$BYTEORD/1,2,3,4/ (little endian, i.e., least significant byte written first, e.g., x86 based personal computers)
$BYTEORD/4,3,2,1/ (big endian, i.e., least significant byte is written last, e.g., PowerPC including older Apple Macintosh computers prior to switch to Intel-based architecture)
One of these values shall be used to specify the endianness even if the size of data values exceeds 32 bits ($DATATYPE/D/)
I apologize in advance if I did not do a good job explaining and would be happy to further clarify any points as necessary. Any help will be very much appreciated.
Update
Attached image to illustrate point.
Figure 1
Update 2
I made a simplified version of the endian converter and tested it.
#include <stdio.h>
#include <stdlib.h>
int main() {
int PnB = 16; // bitwidth of data stored for a specific channel value
// for example the data value for sample A is stored in 16 bits.
char bytes[PnB/8];
unsigned int lebyte[PnB/8];
unsigned int cx = 0;
unsigned int b0, b1;
/* | [0] | [1] |
* | 0xff | 0x03 |
*/
bytes[1] = 0x03;
bytes[0] = 0xff;
// in big endian print out
b0 = (bytes[0] & 0xff) << 8u;
b1 = bytes[1] & 0xff;
cx = b0 | b1;
printf("%d\n", cx);
cx = 0;
// convert to little endian
for (int i = 0; i < PnB/8; ++i)
{
lebyte[i] = (bytes[i] & 0xff) << i*8u;
cx |= lebyte[i];
}
printf("%d\n", cx);
}
The results were correct:
65283
1023
So I made the corrections to the original source code (changes made in original post to conserve space).
Additionally I am doing memcpy to copy data over from a buffer.
memset(bytes, '\0', sizeof(char)*params[j-1].PnB/8);
memcpy(bytes, databuf+((i*data->PAR*2)+(j*params[j-1].PnB/8)), params[j-1].PnB/8);
But I still get a skewed data. It may be something to do with how the data is transformed. I just can't find any information online and I'm sure the makers of FlowJo would be unwilling to share the secret ;). I'll keep looking and see what I find.
Update 3
sorry to make it longer but additional information:
typedef struct _fcs_parameter {
double f1; // logarithmic decade
double f2; // minimum value on log scale
unsigned int PnB; // bitwidth
unsigned int PnR; // range
fcs_events *events; // event data
char *sname; // short name
char *lname; // filter name
} fcs_parameter;
Take a good hard look at the memset() and memcpy() lines you show. Since you've not shown how i is set, nor what's in your params array of structures, it's a bit hard to interpret. However, if you have any varying sizes in the PnB member, then I think your memcpy() offset calculation is bogus.
Here's some code and the output from it; you'll have to adapt it a bit to your scenario. The last section tries to emulate your memset/memcpy code, given that there's no explanation of a number of the variables you show. It includes an alternative interpretation that seems to make more sense.
You could make some of the functions into static inline, assuming you have C99. There are other bits of code that also assume C99. It's not hard to fix it to C89, but I'm not going to do that for you.
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static uint16_t convert_uint16be(uint8_t const *bytes)
{
uint16_t r = (bytes[0] << 8) | bytes[1];
return r;
}
static uint32_t convert_uint32be(uint8_t const *bytes)
{
uint32_t r = (((((bytes[0] << 8) | bytes[1]) << 8) | bytes[2]) << 8) | bytes[3];
return r;
}
static void print16(uint8_t const *bytes)
{
uint16_t r1 = convert_uint16be(bytes);
int16_t r2 = convert_uint16be(bytes);
printf("0x%.2X 0x%.2X = 0x%.4" PRIX16 " = %6" PRId16 "\n", bytes[0], bytes[1], r1, r2);
}
static void print32(uint8_t const *bytes)
{
uint32_t r1 = convert_uint32be(bytes);
int32_t r2 = convert_uint32be(bytes);
printf("0x%.2X 0x%.2X 0x%.2X 0x%.2X = 0x%.8" PRIX32 " = %11" PRId32 "\n", bytes[0], bytes[1], bytes[2], bytes[3], r1, r2);
}
int main(void)
{
int PnB = 16; // bitwidth of data stored for a specific channel value
// for example the data value for sample A is stored in 16 bits.
char bytes[PnB/8];
unsigned int lebyte[PnB/8];
unsigned int cx = 0;
unsigned int b0, b1;
/* | [0] | [1] |
* | 0xff | 0x03 |
*/
bytes[0] = 0xff;
bytes[1] = 0x03;
// in big endian print out
b0 = (bytes[0] & 0xff) << 8u;
b1 = bytes[1] & 0xff;
cx = b0 | b1;
printf("%5d = 0x%.4X\n", cx, cx);
// convert to little endian
cx = 0;
for (int i = 0; i < PnB/8; ++i)
{
lebyte[i] = (bytes[i] & 0xff) << i*8u;
cx |= lebyte[i];
}
printf("%5d = 0x%.4X\n", cx, cx);
print16((uint8_t *)bytes);
uint8_t data[] =
{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xFF,
0x00, 0x00, 0xFF, 0xFF,
0x08, 0x08, 0x09, 0xC0,
0x80, 0x80, 0x90, 0x0C,
0xFF, 0xFF, 0xED, 0xBC,
};
int data_size = sizeof(data) / sizeof(data[0]);
for (int i = 0; i < data_size; i += 2)
print16(&data[i]);
for (int i = 0; i < data_size; i += 4)
print32(&data[i]);
{
struct { int PnB; } params[] = { { 16 }, { 16 }, { 32 }, { 16 }, { 16 }, };
int num_params = sizeof(params) / sizeof(params[0]);
uint8_t value[4];
int i = 0;
int num = num_params;
int offset = 0;
for (int j = 1; j <= num; j++)
{
memset(value, '\0', sizeof(char)*params[j-1].PnB/8);
printf("i = %2d; j = %2d; offset = %2d; calc = %2d; size = %2d\n",
i, j, offset, ((i*7*2)+(j*params[j-1].PnB/8)), params[j-1].PnB/8);
/* The calculation works plausibly when all params[n].PnB are the same
* size, but not otherwise
*/
memcpy(value, data+((i*7*2)+(j*params[j-1].PnB/8)), params[j-1].PnB/8);
if (params[j].PnB == 16)
print16(value);
else
print32(value);
memcpy(value, data+offset, params[j-1].PnB/8);
if (params[j].PnB == 16)
print16(value);
else
print32(value);
offset += params[j-1].PnB/8;
}
}
return 0;
}
Sample output:
65283 = 0xFF03
1023 = 0x03FF
0xFF 0x03 = 0xFF03 = -253
0x00 0x00 = 0x0000 = 0
0x00 0x00 = 0x0000 = 0
0x00 0x00 = 0x0000 = 0
0x03 0xFF = 0x03FF = 1023
0x00 0x00 = 0x0000 = 0
0xFF 0xFF = 0xFFFF = -1
0x08 0x08 = 0x0808 = 2056
0x09 0xC0 = 0x09C0 = 2496
0x80 0x80 = 0x8080 = -32640
0x90 0x0C = 0x900C = -28660
0xFF 0xFF = 0xFFFF = -1
0xED 0xBC = 0xEDBC = -4676
0x00 0x00 0x00 0x00 = 0x00000000 = 0
0x00 0x00 0x03 0xFF = 0x000003FF = 1023
0x00 0x00 0xFF 0xFF = 0x0000FFFF = 65535
0x08 0x08 0x09 0xC0 = 0x080809C0 = 134744512
0x80 0x80 0x90 0x0C = 0x8080900C = -2139058164
0xFF 0xFF 0xED 0xBC = 0xFFFFEDBC = -4676
i = 0; j = 1; offset = 0; calc = 2; size = 2
0x00 0x00 = 0x0000 = 0
0x00 0x00 = 0x0000 = 0
i = 0; j = 2; offset = 2; calc = 4; size = 2
0x00 0x00 0x00 0x00 = 0x00000000 = 0
0x00 0x00 0x00 0x00 = 0x00000000 = 0
i = 0; j = 3; offset = 4; calc = 12; size = 4
0x08 0x08 = 0x0808 = 2056
0x00 0x00 = 0x0000 = 0
i = 0; j = 4; offset = 8; calc = 8; size = 2
0x00 0x00 = 0x0000 = 0
0x00 0x00 = 0x0000 = 0
i = 0; j = 5; offset = 10; calc = 10; size = 2
0xFF 0xFF 0x03 0xFF = 0xFFFF03FF = -64513
0xFF 0xFF 0x03 0xFF = 0xFFFF03FF = -64513
The problem was the formula I was using to calculate the offset.
I should have used the following:
for (int i = 0; i < data->TOT; ++i)
{
for (int j = 0; j < data->PAR; ++j)
{
// code removed for brevity
memset(bytes, '\0', sizeof(char)*params[j].PnB/8);
memcpy(bytes, databuf+((i*data->PAR*params[j].PnB/8)+(j*params[j].PnB/8)), params[j].PnB/8);
// more code here
}
}
Thanks for all your help! I wouldn't not have realized that the problem was the way I was calculating the offset if you had not mentioned the PnB problem.
Related
I have tmc2209 stepper driver. I am planning to use UART for communication. The communication protocol looks pretty simple, but I can't figure out how to calculate this damn CRC. The polynomial is CRC-8 0x07. For the message 0x05 0x00 0x00 the correct CRC is 0x48 and for message 0x05 0x00 0x06 is correct CRC 0x6F. I know this because I have brute forced all possible combinations for these messages and with correct CRC tmc2209 responses. When I calculate CRC manually for these messages it doesn't match. They have some CRC example calculation in datasheet but this code looks broken for me. Here is the datasheet:
https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2209_Datasheet_V103.pdf
UART starts at page 15 and CRC calculation is on page 17.
CRC located in last byte of message, add return datagram[datagramLength - 1]; on last method, you will get that crc value. Look at this:
#include <stdio.h>
#include <stdint.h>
uint8_t swuart_calcCRC (uint8_t * datagram, uint8_t datagramLength) {
int i, j;
uint8_t *crc = datagram + (datagramLength - 1); // CRC located in last byte of message
uint8_t currentByte;
*crc = 0;
for (i = 0; i < (datagramLength - 1); i++) { // Execute for all bytes of a message
currentByte = datagram[i]; // Retrieve a byte to be sent from Array
for (j = 0; j < 8; j++) {
if ((*crc >> 7) ^ (currentByte & 0x01)) { // update CRC based result of XOR operation
*crc = (*crc << 1) ^ 0x07;
}
else {
*crc = (*crc << 1);
}
currentByte = currentByte >> 1;
} // for CRC bit
} // for message byte
return datagram[datagramLength - 1];
}
int main () {
uint8_t datagram1[] = { 0x05, 0x00, 0x00, 0x00 };
uint8_t datagram2[] = { 0x05, 0x00, 0x06, 0x00 };
uint8_t length = 4;
uint8_t crc1 = swuart_calcCRC (datagram1, length);
printf ("crc1: %02X\n", crc1);
uint8_t crc2 = swuart_calcCRC (datagram2, length);
printf ("crc2: %02X\n", crc2);
return 0;
}
Result:
crc1: 48
crc2: 6F
Documentation from your link says:
An 8 bit CRC polynomial is used for checking both read and write access. It allows detection of up to
eight single bit errors. The CRC8-ATM polynomial with an initial value of zero is applied LSB to MSB,
including the sync- and addressing byte. The sync nibble is assumed to always be correct. The
TMC2209 responds only to correctly transmitted datagrams containing its own slave address. It
increases its datagram counter for each correctly received write access datagram.
X^8 + X^2 + X^1 + X^0
And start value is 0
And even code is provided
void swuart_calcCRC(UCHAR* datagram, UCHAR datagramLength)
{
int i,j;
UCHAR* crc = datagram + (datagramLength-1); // CRC located in last byte of message
UCHAR currentByte;
*crc = 0;
for (i=0; i<(datagramLength-1); i++) { // Execute for all bytes of a message
currentByte = datagram[i]; // Retrieve a byte to be sent from Array
for (j=0; j<8; j++) {
if ((*crc >> 7) ^ (currentByte&0x01)) // update CRC based result of XOR operation
{
*crc = (*crc << 1) ^ 0x07;
}
else
{
*crc = (*crc << 1);
}
currentByte = currentByte >> 1;
} // for CRC bit
} // for message byte
}
I did test a crc-16/ibm implementation i found on the net. when I test it with hex byte array it works fine but if I include some 0x00 values, then it doesn't give the proper result.
here is its code
unsigned short ComputeCRC16(const unsigned char* buf, unsigned int len) {
unsigned short crc = 0;
for (unsigned int j = 0; j < len; j++)
{
unsigned char b = buf[j];
for (unsigned char i = 0; i < 8; i++)
{
crc = ((b ^ (unsigned char)crc) & 1) ? ((crc >> 1) ^ 0xA001) : (crc >> 1);
b >>= 1;
}
}
return crc;
}
I tested it with this code:
int main() {
//fe b5 5f f7
unsigned char buf1[4096] = { 0xfe, 0xb5, 0x5f, 0xf7 };
//fe b5 00 5f f7 00
unsigned char buf2[4096] = { 0xfe, 0xb5, 0x00, 0x5f, 0xf7, 0x00 };
int a = strlen(buf1);
unsigned short res = ComputeCRC16(buf1, a);
printf("res = %04x\n", res); //res : 7858, the result is correct
int b = strlen(buf2);
unsigned short res = ComputeCRC16(buf2, b);
printf("res = %04x\n", res); //res : d781, the result is not correct
return 0; //the correct result : 26EE
}
to verify the result I use this website:
https://www.lammertbies.nl/comm/info/crc-calculation
Your CRC routine gives correct results. It is your test that's wrong. strlen(p) returns how many bytes there are before the first zero byte at p. For buf2, that's four, not five as you intended. For buf1 it's not even defined, since there can be anything in memory after that array. You might be getting four, if the compiler happened to put zeros after the array.
For testing, you should simply provide len manually. (buf1, 4), (buf2, 5).
By the way, that code could be more efficient. It doesn't have to test with b every time. Just exclusive-oring with b to start has the same effect:
crc ^= buf[j];
for (unsigned char i = 0; i < 8; i++)
crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1;
let's say I have an array:
uint16 my_uint16_Array[6] = {0x1A20, 0x1A35, 0X1AEC, 0x1AB8, 0x1A5D, 0x1AF3}
I want to convert this array to an byte array in order to have:
uint8 my_uint8_Array[12] = {0x1A, 0x20, 0x1A, 0x35, 0X1A, 0xEC, 0x1A, 0xB8, 0x1A, 0x5D, 0x1A, 0xF3}
What is the fastest way to do it in c?
Well memcpy will not sufficient for this task on little endian machine. In that case I would do this. Although I not guarantee this is the fastest way.
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t my_uint16_Array[6] = {0x1A20, 0x1A35, 0X1AEC, 0x1AB8, 0x1A5D, 0x1AF3};
uint8_t my_uint8_Array[12];
for (int i = 0; i < 6; i++)
{
my_uint8_Array[i << 1] = my_uint16_Array[i] >> 8;
my_uint8_Array[(i << 1) + 1] = my_uint16_Array[i] & 0xFF;
}
for (int i = 0; i < 12; i++)
printf("0x%x ", my_uint8_Array[i]);
return 0;
}
Output
0x1a 0x20 0x1a 0x35 0x1a 0xec 0x1a 0xb8 0x1a 0x5d 0x1a 0xf3
Another version which seem to produce less assembly instruction with MSP430 architecture with gcc 6.2.1 and -O3 flag. Also this is somewhat closer what x86 will actually do after optimization with the above code.
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t my_uint16_Array[6] = {0x1A20, 0x1A35, 0X1AEC, 0x1AB8, 0x1A5D, 0x1AF3};
uint8_t my_uint8_Array[12];
uint8_t *highBytePtr = (uint8_t*) my_uint16_Array;
uint8_t *lowBytePtr = (uint8_t*) my_uint16_Array;
highBytePtr++;
for (int i = 0; i < 12; i += 2, highBytePtr += 2, lowBytePtr += 2)
{
my_uint8_Array[i] = *highBytePtr;
my_uint8_Array[i + 1] = *lowBytePtr;
}
for (int i = 0; i < 12; i++)
printf("0x%x ", my_uint8_Array[i]);
return 0;
}
you can declare a uint8_t pointer and just "reinterpret" the data as a uint8_t array. But beware of endianness! the ordering may not in the way you expect it to be:
uint8_t *bytePointer = (uint8_t*) my_uint16_Array;
for(uint8_t i=0; i< sizeof(my_uint16_Array); i++) {
printf("%02X, ", bytePointer[i]);
}
On a little endian machine you get this output:
20, 1A, 35, 1A, EC, 1A, B8, 1A, 5D, 1A, F3, 1A
On a big endian machine, all value pairs are flipped:
1A, 20, 1A 35, 1A, EC, 1AB8, 1A, 5D, 1A, F3
I have my following program that has a function that will extract the particular Bytes from a frame of 8 Bytes data and will give a corresponding value needed based on the start bit and bit length (length counted from the start bit).
How can i pass the data of 8 bytes which is in hexa decimal to my pointer *data in the main function.
For example this is my frame data in hexadecimal '05 00 00 00 00 03 E8 00'. Here is my program. Would be grat if someone help me to solve this. Should i take an array and pass the data as 0x05 0x00 0x00 0x00 0x00 0x03 0xE8 0x00 into the array and then give assign address of the array to the pointer variable? or just take a variable that holds 0x050000000003E800 and assign this address to the pointer.Are the both same? Thanks in advance.
union u_t
{
uint16_t u16;
uint8_t u8[2];
};
uint16_t Frame2Data(uint8_t *data,uint8_t startBit,uint16_t length)
{
uint16_t mask;
uint8_t start;
uint8_t firstByte,offset;
uint8_t numShift;
union u_t ut;
/*if(length == 8) //preliminary, has to be fixed by correct function.
mask = 0xff;*/
if(length == 7)
mask = 0x7F;
if(length == 10)
mask = 0x3ff;
if(length == 12)
mask = 0xfff;
firstByte = startBit / 8;
offset = (firstByte+2) * 8;
start = startBit + length;
numShift = offset - start;
ut.u8[1] = data[firstByte];
ut.u8[0] = data[firstByte+1];
return (ut.u16 >> numShift) & mask;
}
int main()
{
??????????
uint8_t sB = 46;
uint16_t l = 7;
uint16_t extractValue = Frame2Data(?,sB,l);
return 0;
}
To pass data written in hexadecimal to data, you can simply write:
uint8_t data [] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE8, 0x00};
Note that variable mask is uninitialized, because l is equal to 7 and all instructions to initialize variable mask are dead code, as show in red, with a source code analyzer:
https://taas.trust-in-soft.com/tsnippet/t/6d486c5b
Say we have 8 bytes saved in an array like:
char array[8];
All of them are set to zero:
for (i = 0; i < 7; i++){
array[i] = 0x00;
}
How can shift a 1 from the first LSBit until the last MSBit like
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x04
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x08
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x10
.....................................
to
0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Here is what I've tried but the result isn't what I'm looking for:
uint8_t buffer[8];
int index = 0 ;
for ( index = 0; index < 8; index++){
buffer[index] = 0x00;
}
*buffer= 0x01;
for( index = 0 ; index < 64; index++){
*buffer = *buffer<< 1 ;
}
UPDATE
Here is an example of what I get:
#include <stdio.h>
int main (){
char buffer[2]={0x01, 0x00};
int i ;
for( i = 0 ; i < 12 ; i++){
printf("0x %2X %x \n",buffer[0], buffer[1]);
*buffer <<= 1;
}
}
And the output is:
0x 1 0
0x 2 0
0x 4 0
0x 8 0
0x 10 0
0x 20 0
0x 40 0
0x FFFFFF80 0
0x 0 0
0x 0 0
0x 0 0
0x 0 0
I really don't understand the 0xFFFFFF80!
What byte that is "LS byte" and which one that is "MS byte" is perhaps not obvious. An array of 8 characters is always allocated in memory like this:
LS address MS address
Byte 0, ... Byte 7
This is true for all CPUs. So the 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 in your question doesn't make any sense: you have misunderstood how arrays are allocated in memory. What you have shown in your examples is how to take bit 0 in the ms byte and left shift it to bit 7 in the ls byte. Which probably doesn't make any sense.
However, if you would attempt to print this array as a 64 bit integer, the value array[0]=1 would give you 0000000000000001 on a little endian machine, but 0100000000000000 on a big endian machine. But nothing in your question states that you want to print the array as a 64 bit value, so it is not clear what you are actually asking.
Try this:
#include <stdio.h>
#include <stdint.h>
typedef union
{
uint8_t array[8];
uint64_t u64;
} my_type;
int main()
{
my_type t = {0};
t.array[0] = 0x01;
// how the array is actually allocated:
for(int i=0; i<8; i++) // 0100000000000000 on all machines
{
printf("%.2X", t.array[i]);
}
printf("\n");
// how the array turns out when printed as a 64 bit int:
printf("%.16llX\n", t.u64); // 0000000000000001 little endian
// perhaps what you intended to do, on a little endian machine
t.u64 <<= 63;
printf("%.16llX\n", t.u64); // 8000000000000000 little endian
return 0;
}
As per harold's comment, just carry the 1. So, to shift one place:
uint8_t carry = 0;
for( index = 7 ; index >= 0; index--){
uint8_t nextCarry = buffer[index] >> 7;
buffer[index] = (buffer[index] << 1) | carry;
carry = nextCarry;
}
EDIT: also, it strikes me that your CPU almost certainly has a native 64-bit type. In which case just use a uint64_t directly rather than an array of bytes and perform variable <<= 1;.
I'm not sure if this is what you want, but the following code does at least what was posed in the question:
uint8_t temp = buffer[0];
printf("Initial Buffer :\n");
for(int i = 0 ; i < 8 ; i++)
printf("0x%X ", buffer[7-i]);
// Left Shift until highest bit that is 1 is found
while(!(temp & 0x80))
temp = temp<<1;
// Re-assignments
buffer[7] = temp;
buffer[0] = 0;
printf("\nFinal Buffer :\n");
for(int i = 0 ; i < 8 ; i++)
printf("0x%X ", buffer[7-i]);
In true sense, this is not "shifting entirely through the buffer", but if you could provide more details on what you wish to accomplish, this code could be modified accordingly.
Since you are trying to treat your char array as a single 64 bit object, why not use an actual 64 bit object?
union
{
char array[8];
uint64_t all;
} data;
int index = 0;
data.all = 0;
data.array[0] = 0x01;
for(index = 0; index < 64; index++)
{
data.all = data.all << 1;
}
Note that this assumes that you are working on a little endian machine.
So I've done it , maybe it's not the best way but it works, and if someone needs I'll be glade to share it :
#include <stdio.h>
#include <stdint.h>
int main (){
uint8_t buffer[8];
char* pChar = buffer;
uint8_t carry =0x01;
int i = 0;
short lock [8];
// Array initialization
for ( i =0 ; i <8; i++){
buffer[i] =0x00;
lock[i] = 0x00;
}
pChar =buffer;
for( i = 0 ; i < 64 ; i++){
*pChar = carry;
printf(" 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x \n",buffer[0], buffer[1],buffer[2],buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]);
carry<<=1;
if( i>=7 && lock[0]==0){
*pChar = 0;
pChar++;
carry=0x01;
lock[0]=1;
}else if ( i>=15 && lock[1]==0) {
*pChar = 0;
pChar++;
carry=0x01;
lock[1]=1;
}else if( i>= 23 && lock[2]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[2] =1;
}
else if( i>= 31 && lock[3]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[3] =1;
}
else if( i>=39 && lock[4]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[4] =1;
}
else if( i>= 47 && lock[5]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[5] =1;
}
else if( i>= 55 && lock[6]==0){
*pChar =0;
pChar++;
carry=0x01;
lock[6] =1;
}
}
thanks for your help !