How to pass hexadecimal data inside the following function - c

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

Related

How is tmc2209 stepper driver IC calculating CRC?

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
}

c: interpreting bytes of a given sequence as int16_t values and summing them

I am trying to figure out how to add sequential bytes in a block of data starting at a given place(sequenceOffset) to a certain length(sequenceLength), by typcasting them to signed 16 bit integers(int16_t). The numbers can be negative and positive.I also cannot use any arrays, only pointer syntax.
*blockAddress points to the first byte of the memory region
*blockLength is number of bytes in the memory region
* sequenceOffset is the offset of the first byte of the sequence that
* is to be summed
* sequenceLength is the number of bytes in the sequence, and
* sequenceLength > 0
*
* Returns: the sum of the int16_t values obtained from the given sequence;
* if the sequence contains an odd number of bytes, the final byte
* is ignored; return zero if there are no bytes to sum
int16_t sumSequence16(const uint8_t* const blockAddress, uint32_t blockLength,
uint32_t sequenceOffset, uint8_t sequenceLength){
uint16_t sum = 0;
const uint8_t* curr = blockAddress; // deref
uint16_t pointer = *(uint16_t*)curr; // typecast to int16
for (uint16_t i = 0; i< sequenceLength; i++){
sum = sequenceOffset + (pointer +i +1);
}// for
an example of a test case:
--Summing sequence of 8 bytes at offset 113:
5D 5C 4E 6E FA B3 5D 4C
23645 28238 -19462 19549
You said the sum is: -7412
Should be: -13566
i'm not sure how to handle the case where I ignore the final byte if the sequence contains an odd number of bytes.
#include <stdint.h>
#include <stdio.h>
int16_t sumSequence16sane(const uint8_t* block, uint32_t length)
{
int16_t ret = 0;
while (length >= 2)
{
ret += block[1] << 8 | block[0];
block += 2;
length -= 2;
}
return ret;
}
int16_t sumSequence16(const uint8_t* const blockAddress, uint32_t blockLength,
uint32_t sequenceOffset, uint8_t sequenceLength)
{
return sumSequence16sane (blockAddress + sequenceOffset, sequenceLength);
}
int main()
{
uint8_t b[8] = { 0x5d, 0x5c, 0x4e, 0x6e, 0xfa, 0xb3, 0x5d, 0x4c };
printf("%d\n", sumSequence16sane(b, 8));
}
Some might prefer this inner loop. It's a bit more compact but potentially a bit more confusing:
for (; length >= 2; block += 2, length -= 2)
ret += block[1] << 8 | block[0];

Extract data from the frame using C

I have a function as follows:
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;
for(i=0;i<16;i++)
{
if(length == i)
mask|=(1<<i);
}
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;
}
The start bit is 46 and length is 7 and the data in 8 bytes is 0x00 0x09 0x03 0x84 0x03 0x70 0x02 0xA8 has to be passed. I have to extract the data with start bit 46 and upto a length of 7 bits and find out its value. I have a doubt with numbershift and is my function working correctly? It would be great if someone confirms this.Thanks in advance.
Your problem here, is the way in which you set your mask:
for(i=0;i<16;i++)
{
if(length == i)
mask|=(1<<i); /* BTW, mask is not initialized */
}
is simply equivalent to:
mask |= (1 << length);
which will set only one bit in you mask. So either you substruct one from mask after the for, or you set it directly:
#define UINT16_WIDTH 16
mask = (1u << (length & (UINT16_WIDTH - 1))) - 1u;

Slice up an uint8_t array

Let's say that I have an array of 16 uint8_t as follows:
uint8_t array[] = {0x13, 0x01, 0x4E, 0x52, 0x31, 0x4A, 0x35, 0x36, 0x4C, 0x11, 0x21, 0xC6, 0x3C, 0x73, 0xC2, 0x41};
This array stores the data contained in a 128 bits register of an external peripheral. Some of the information it represents are stored on 2, 3, 8, 12 bits ... and so on.
What is the best and elegant way to slice it up and bit mask the information I need? (The problem is that some things that I need overlaps the length of one cell of the array)
If that can help, this snippet I wrote converts the whole array into a char* string. But casting this into an int is not option because.. well 16 bytes.
int i;
char str[33];
for(i = 0; i < sizeof(array) / sizeof(*array) ; i++) {
sprintf(str+2*i,"%02hX",array[i]);
}
puts(str);
13014E52314A35364C1121C63C73C241
Actually such problem also occures when trying to parse all kind of bitstreams, like video or image files or compressed data by algorithms like LZ*. So the approach used there is to implement a bitstream reader.
But in your case the bit sequence is fixed length and quite short, so one way is to manually check the field values using bitwise operations.
Or you can use this function that I just wrote, which can extract arbitrary number of bits from a uint8 array, starting from desired bit position:
uint32_t extract_bits(uint8_t *arr, unsigned int bit_index, unsigned int bit_count)
{
/* Assert that we are not requested to extract more than 32 bits */
uint32_t result = 0;
assert(bit_count <= sizeof(result)*8 && arr != NULL);
/* You can additionally check if you are trying to extract bits exceeding the 16 byte range */
assert(bit_index + bit_count <= 16 * 8);
unsigned int arr_id = bit_index / 8;
unsigned int bit_offset = bit_index % 8;
if (bit_offset > 0) {
/* Extract first 'unaligned_bit_count' bits, which happen to be non-byte-aligned.
* When we do extract those bits, the remaining will be byte-aligned so
* we will thread them in different manner.
*/
unsigned int unaligned_bit_count = 8 - bit_offset;
/* Check if we need less than the remaining unaligned bits */
if (bit_count < unaligned_bit_count) {
result = (arr[arr_id] >> bit_offset) & ((1 << bit_count) - 1);
return result;
}
/* We need them all */
result = arr[arr_id] >> bit_offset;
bit_count -= unaligned_bit_count;
/* Move to next byte element */
arr_id++;
}
while (bit_count > 0) {
/* Try to extract up to 8 bits per iteration */
int bits_to_extract = bit_count > 8 ? 8 : bit_count;
if (bits_to_extract < 8) {
result = (result << bits_to_extract) | (arr[arr_id] & ((1 << bits_to_extract)-1));
}else {
result = (result << bits_to_extract) | arr[arr_id];
}
bit_count -= bits_to_extract;
arr_id++;
}
return result;
}
Here is example of how it is used.
uint32_t r;
/* Extracts bits [7..8] and places them as most significant bits of 'r' */
r = extract_bits(arr, 7, 2)
/* Extracts bits [4..35] and places them as most significant bits of 'r' */
r = extract_bits(arr, 4, 32);
/* Visualize */
printf("slice=%x\n", r);
And then the visualisation of r is up to you. They can either be represented as hex dwords, characters, or however you decide.

Flow Cytometry FCS file data segment, linear data seems skewed

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.

Resources