Passing a subset of an array to linux spi driver - c

I have a problem that I'm having difficulty solving.
I have a union that contains a buffer with a struct mapping the bits of the buffer. Something along the lines of (it is pragma packed of course):
union
uint32 buf[512]
struct
uint8_t pad[256];
uint32_t data[256];
the buf[] part is intended to be passed to the Linux spi driver as a Receive buffer. The issue I'm having is, depending on my transmits, the size of the padding I receive back is variable, and because of this it isn't straight forward to access using the union.
What i need to do is to be able to pass buf[] at a specific index to the spi driver, I.E the Rx buffer begins at buf[128] instead of buf[0]. This isn't always equal, so i have an equation that tells me where i need the start point to be which is &(buf[0]+padmax-padsize]) which should result in a value between buf[0] and buf[256]. However, the issue is the spi driver expects the argument of the transfer buffer to contain a pointer to a buffer, and passing it the straight address isn't giving me what i want.
I have also tried assigning a pointer to the address of the above equation and passing that to the rxbuffer part of the spi struct and it again doesn't give me what i want.
Is it possible to create an array that is a subset of another array, starting at a specified address of the outer array? I think this may solve my problem but I'm also afraid of the memory implications of that

The reason is most likely that you're calculating the address in 32-bit units (in units of buf elements), not bytes as you expect, based on the arithmetic.
Let's simplify the situation, and say the structure is just
#define MAX_PAD 256
#define MAX_DATA 256
struct spi_data {
uint8_t pad[MAX_PAD];
uint32_t data[MAX_DATA];
};
and that you want to implement a function similar to
size_t spi_recv(int fd, struct spi_data *ref, size_t pad, size_t data)
where
fd is the file descriptor to read() from
ref is a pointer to the struct spi_data to be used
pad is the number of padding entries filled at the end of the ref->pad[] array
data is the number of entries filled at the beginning of the ref->data[] array
the return value is the number of data entries received (completely filled)
Consider the following (argument checks for fd == -1, ref == NULL, pad > MAX_PAD, data > MAX_DATA omitted for simplicity):
size_t spi_recv(int fd, struct spi_data *ref, size_t pad, size_t data)
{
ssize_t n;
n = read(fd, &ref->pad[sizeof ref->pad / sizeof ref->pad[0] - pad],
pad * sizeof ref->pad[0] + data * sizeof ref->data[0]);
if (n == -1) {
/* Error; errno already set */
return 0;
} else
if (n < 0) {
/* Should never occur, but let's be paranoid */
errno = EIO;
return 0;
} else
if (n < pad * sizeof ref->pad[0]) {
/* Only partial padding received */
errno = 0;
return 0;
} else {
/* Zero or more data words received */
errno = 0;
return (n - pad * sizeof ref->pad[0]) / sizeof ref->data[0];
}
}
The pointer to the last pad elements of padding is
&ref->pad[sizeof ref->pad / sizeof ref->pad[0] - pad])
which is essentially equivalent to &(ref->pad[MAX_PAD - pad]), except that instead of the MAX_PAD macro, we use (sizeof ref->pad)/(sizeof ref->pad[0]) to evaluate the number of members declared for the ref->pad[] array. (This only works if ref->pad is an array; it does not work if it is a pointer.)
As usual, read() takes the number of bytes -- not elements of ref->pad or ref->data -- as a parameter, so we need to multiply the element counts by their respective element sizes in bytes; thus, the number of bytes in pad elements of padding and data elements of data is pad * sizeof ref->pad[0] + data * sizeof ref->data[0].
Since the function returns the number of complete data words received, the number of padding bytes must be subtracted from the return value, then divided by the data element type (integer division rounding down), to get the number of complete data words.
I don't think the above interface is optimal, however. I particularly dislike the possibility of the SPI transfer ending with a partial word; the above interface does not let the caller detect such a situation reliably.
If you use spidev, the ioctl() interface would be much better to use. For one, you could use SPI_IOC_MESSAGE(2) to read the padding and the data into separate buffers, or even SPI_IOC_MESSAGE(3) to write a command, followed by a read to the padding buffer and another to the data buffer. The Linux-Sunxi Wiki page has a pretty simple example of this kind of usage here, except that it uses single reads instead of reading padding into a separate buffer. However, it should be quite simple to extend the examples to do that.

Related

Initialize C array to custom character

I have built a Winsock2 server. Part of that program has a function that receives data from clients. Originally the receive function I built would peek at the incoming data and determine if there was any additional data to be read before allowing recv() to pull the data from the buffer. This worked fine in the beginning of the project but I am now working on improving performance.
Here is a portion of the code I've written to eliminate the use of peek:
unsigned char recv_buffer[4096];
unsigned char *pComplete_buffer = malloc(sizeof(recv_buffer) * sizeof(unsigned char*));
int offset = 0;
int i = 0;
...
for (i; i <= sizeof(recv_buffer); i++) {
if (recv_buffer[i] == NULL) {
break;
}
pComplete_buffer[offset] = recv_buffer[i];
offset++;
}
...
This code would work great but the problem is that NULL == 0. If the client happens to send a 0 this loop will break prematurely. I thought I would be clever and leave the data uninitialized to 0xcc and use that to determine the end of recv_buffer but it seems that clients sometimes send that as part of their data as well.
Question:
Is there a character I can initialize recv_buffer to and reliably break on?
If not, is there another way I can eliminate the use of peek?
The correct solution is to keep track of how many bytes you store in recv_buffer to begin with. sizeof() gives you the TOTAL POSSIBLE size of the buffer, but it does not tell you HOW MANY bytes actually contain valid data.
recv() tells you how many bytes it returns to you. When you recv() data into recv_buffer, use that return value to increment a variable you define to indicate the number of valid bytes in recv_buffer.
For example:
unsigned char recv_buffer[4096];
int num_read, recv_buffer_size = 0;
const int max_cbuffer_size = sizeof(recv_buffer) * sizeof(unsigned char*);
unsigned char *pComplete_buffer = malloc(max_cbuffer_size);
...
num_read = recv(..., recv_buffer, sizeof(recv_buffer), ...);
if (num_read <= 0) {
// error handling...
return;
}
recv_buffer_size = num_read;
...
int available = max_cbuffer_size - offset;
int num_to_copy = min(recv_buffer_size, available);
memcpy(pComplete_buffer + offset, recv_buffer, num_to_copy);
offset += num_to_copy;
memmove(recv_buffer, recv_buffer + num_to_copy, recv_buffer_size - num_to_copy);
recv_buffer_size -= num_to_copy;
...
Is there a character I can initialize recv_buffer to and reliably break on?
Nope. If the other side can send any character at any time, you'll have to examine them.
If you know the sender will never send two NULs in a row (\0\0), you could check for that. But then some day the sender will decide to do that.
If you can change the message structure, I'd send the message length first (as a byte, network-ordered short or int depending on your protocol). Then, after parsing that length, the receiver will know exactly how long to keep reading.
Also if you're using select, that will block until there's something to read or the socket closes (mostly -- read the docs).

C: Find occurrences of bytes in region of memory

I am trying to write a function which uses only pointer-based logic to search through a region of memory (baseAddr) for a certain byte (Byte), counts the occurrences, and stores the offsets in an array (Offsets). Here is what I have so far:
uint8_t findBytes( uint16_t* const Offsets, const uint8_t* const baseAddr,
uint32_t length, uint8_t Byte) {
uint8_t bytesRead = 0;
int count = 0;
while (bytesRead < length) {
if ((baseAddr + bytesRead) == Byte) {
*(Offsets + count) = bytesRead;
count++;
}
bytesRead++;
}
return count;
}
For whatever reason, I always get stuck in an infinite loop if I use (bytesRead < length). Length is always 1024. What exactly is wrong with this code? I am still learning the proper uses of pointers, so I'm 99% sure it's to do with that.
bytesRead is a uint8_t, which has a maximum value of 255. If you have a uint32_t length, your offset should be the same data type. And since potentially every byte could be a match, your count (return value) also needs to be the same type, as does the offsets array.
More problems:
if ((baseAddr + bytesRead) == Byte)
You're not dereferencing the pointer here, you're only checking its value. Your compiler should be issuing a warning here for the type mismatch.
Try:
if (*(baseAddr + bytesRead) == Byte)
Finally, you need to make sure offsets points at enough memory. Again, potentially *every byte could match, which means offsets should be the same length (in elements) as the input data.

c reinterpret pointer to datatype with bigger size

I'm trying to interpret WebSocket Frames that I get over a TCP connection. I want to do this in pure C (so no reinterpret_cast). The Format is specified in IEEE RFC 6455. I want to fill the following struct:
typedef struct {
uint8_t flags;
uint8_t opcode;
uint8_t isMasked;
uint64_t payloadLength;
uint32_t maskingKey;
char* payloadData;
} WSFrame;
with the following Function:
static void parseWsFrame(char *data, WSFrame *frame) {
frame->flags = (*data) & FLAGS_MASK;
frame->opcode = (*data) & OPCODE_MASK;
//next byte
data += 1;
frame->isMasked = (*data) & IS_MASKED;
frame->payloadLength = (*data) & PAYLOAD_MASK;
//next byte
data += 1;
if (frame->payloadLength == 126) {
frame->payloadLength = *((uint16_t *)data);
data += 2;
} else if (frame->payloadLength == 127) {
frame->payloadLength = *((uint64_t *)data);
data += 8;
}
if (frame->isMasked) {
frame->maskingKey = *((uint32_t *)data);
data += 4;
}else{
//still need to initialize it to shut up the compiler
frame->maskingKey = 0;
}
frame->payloadData = data;
}
The code is for the ESP8266, so debugging is only possible with printfs to the serial console. Using this method, I discovered that the code crashes right after the frame->maskingKey = *((uint32_t *)data); and the first two ifs get skipped, so this is the first time I cast a pointer to another pointer.
The data is not \0 terminated, but i get the size in the data received callback. In my test, I'm trying to send the message 'test' over the already established WebSocket, and the received data length is 10, so:
1 byte flags and opcode
1 byte masked and payload length
4 bytes masking key
4 bytes payload length
At the point the code crashes, I expect data to be offsetted by 2 bytes from the initial position, so it has enough data to read the following 4 bytes.
I did not code any C for a long time, so I expect only a small error in my code.
PS.: I've seen a lot code where they interpret the values byte-by-byte and shift the values, but I see no reason why this method should not work either.
The problem with casting a char* to a pointer to a larger type is that some architectures do not allow unaligned reads.
That is, for example, if you try to read a uint32_t through a pointer, then the value of the pointer itself has to be a multiple of 4. Otherwise, on some architectures, you will get a bus fault (e.g. - signal, trap, exception, etc.) of some sort.
Because this data is coming in over TCP and the format of the stream / protocol is laid out without any padding, then you will likely need to read it out from the buffer into local variables byte by byte (e.g. - using memcpy) as appropriate. For example:
if (frame->isMasked) {
mempcy(&frame->maskingKey, data, 4);
data += 4;
// TODO: handle endianness: e.g.: frame->maskingKey = ntohl(frame->maskingKey);
}else{
//still need to initialize it to shut up the compiler
frame->maskingKey = 0;
}
There's two problems:
data might not be correctly aligned for uint32_t
The bytes in data might not be in the same order as your hardware uses for value representation of integer. (sometimes called "endianness issue").
To write reliable code, look at the message specification to see which order the bytes are coming in. If they are most-significant-byte first then the portable version of your code would be:
unsigned char *udata = (unsigned char *)data;
frame->maskingKey = udata[0] * 0x1000000ul
+ udata[1] * 0x10000ul
+ udata[2] * 0x100ul
+ udata[3];
This might look like a handful at first, but you could make an inline function that takes a pointer as argument, and returns the uint32_t, which will keep your code readable.
Similar problem applies to your reads of uint16_t.

How to receive an integer arrray in C/C++ socket?

While receiving the integer array, checking the bytes of data received is needed.
For example, when receiving an integer array with length 100:
int count = 0;
int msg[100];
while(count < 100 * sizeof(int)){
count += read(fd, msg + count / sizeof(int), 100 * sizeof(int) - count);
}
Is this a right way? Will read() return a value which is not a multiple of sizeof(int)?
If this is not correct, what the right way to receive an integer array?
On Linux you can use the MSG_WAITALL option for recv(), which makes the function wait for the full given length of incoming data.
In alternative (working on all platforms) you can also write a generic receive function that receives a given amount of bytes, like this one (which assumes the socket is not set as non-blocking; requires including <stdint.h>):
/// \brief Receives a block of data of the specified size
/// \param sk Socket for incoming data
/// \param data Pointer to input buffer
/// \param len Number of bytes to read
/// \return Number of bytes received (same as len) on success, -1 on failure
int block_recv(const int sk, uint8_t* data, unsigned int len)
{
int i, j = 0;
while (len > 0) {
i = recv(sk, (char*) data, len, 0);
if (i <= 0) {
return -1;
}
data += i;
len -= i;
j += i;
}
return j;
}
Then you can just call it to receive your integer buffer:
if (block_recv(fd, (uint8_t*) msg, sizeof(msg)) != sizeof(msg)) {
fprintf(stderr, "Error receiving integer buffer...\n");
// whatever error handling you need...
}
You are correct that read may not return all the data you requested, esp. if it is connected to a network socket. read will not necessarily return a value with multiple of sizeof(int). If you want to use this (manual) method of receiving data, I would probably recommend you count bytes instead of sizeof(int)s (which can be 4 or 8 depending on your system). Even easier than doing this is to use something like Protocol Buffers, which lets you define a data format for your packets and serialize/deserialize them quickly and easily. (Define a message that simply includes your integer array and let protobuf take care of everything else.)
You're right - there's no guarantee that read will return data whose size is a multiple of sizeof(int).
The minimum size you may receive is a char.
There are other issues such as endianness when receiving integers from across a network (which obviously also apply to sending integers across a network) that you should be aware of.
For these reasons, an easier solution is to use a char[] instead of int[] to store the message, and then copy it to an int[]. If you are concerned about efficiency, prove to yourself that this is a bottleneck (profile your code) before you worry about optimizing code.
Also, if you are sending and recving across a network, be aware that protocols like TCP are stream-based, i.e. they simply send streams of characters and you need to implement some way of detecting the end of a message and formatting it to your needs. Two common ways are to either send the length of the message as a header or to use a special character like '\n' to signal the end of the message. Also, since you are sending an array, you could use something like '|' to separate elements.
So a sample message can be: "1|100|239|23|\n"

Reallocing a char*

I am trying to do a function that will store in a char array some information to print on it:
int offset = 0;
size_t size = 1;
char *data = NULL;
data = malloc(sizeof(char));
void create(t_var *var){
size_t sizeLine = sizeof(char)*(strlen(var->nombre)+2)+sizeof(int);
size = size + sizeLine;
realloc(data, size);
sprintf(data+offset,"%s=%d\n",var->name,var->value);
offset=strlen(data);
}
list_iterate(aList, (void *)create);
t_var is a struct that has two fields: name (char*) and value (int).
What's wrong with this code? When running it on Valgrind it complains about the realloc and sprintf.
Without knowing the specific valgrind errors, the standout one is:
realloc(data, size); should be data = realloc(data, size);
I'm sorry to say that, but almost EVERYTHING is wrong with your code.
First, incomplete code.
You say your t_var type has two members, name and value.
But your code refers to a nombre member. Did you forget to mention it or did you forget to rename it when publishing the code?
Second, misused sizeof.
You use a sizeof(int) expression. Are you aware what you actually do here?!
Apparently you try to calculate the length of printed int value. Alas, operator sizeof retrieves the information about a number of bytes the argument occupies in memory. So, for example, for 32-bits integer the result of sizeof(int) is 4 (32 bits fit in 4 bytes), but the maximum signed 32-bit integer value is power(2,31)-1, that is 2147483647 in decimal. TEN digits, not four.
You can use (int)(2.41 * sizeof(any_unsigned_int_type)+1) to determine a number of characters you may need to print the value of any_unsigned_int_type. Add one for a preceding minus in a case of signed integer types.
The magic constant 2.41 is a decimal logarithm of 256 (rounded up at the 3-rd decimal digi), thus it scales the length in bytes to a length in decimal digits.
If you prefer to avoid floating-point operations you may use another approximation 29/12=2.41666..., and compute (sizeof(any_unsigned_int_type)*29/12+1).
Third, sizeof(char).
You multiply the result of strlen by sizeof(char).
Not an error, actually, but completely useless, as sizeof(char) equals 1 by definition.
Fourth, realloc.
As others already explained, you must store the return value:
data = realloc(data, size);
Otherwise you risk you loose your re-allocated data AND you continue writing at the previous location, which may result in overwriting (so destroying) some other data on the heap.
Fifth, offset.
You use that value to determine the position to sprintf() at. However, after the print you substitute offset with a length of last printout instead of incrementing it. As a result consecutive sprintfs will overwrite previous output!
Do:
offset += strlen(data);
Sixth: strlen of sprintf.
You needn't call strlen here at all, as all functions of printf family return the number of characters printed. You can just use that:
int outputlen = sprintf(data+offset, "%s=%d\n", var->name, var->value);
offset += outputlen;
Seventh: realloc. Seriously.
This is quite costly function. It may need to do internal malloc for a new size of data, copy your data into a new place and free the old block. Why do you force it? What impact will it have on your program if it needs to print five thousand strings some day...?
It is also quite dangerous. Really. Suppose you need to print 5,000 strings but there is room for 2,000 only. You will get a NULL pointer from realloc(). All the data printed to the point are still at the current data pointer, but what will you do next?
How can you tell list_iterate to stop iterating...?
How can you inform the routine above the list_iterate that the string is incomplete...?
There is no good answer. Luckily you needn't solve the problem — you can just avoid making it!
Solution.
Traverse your list first and calculate the size of buffer you need. Then allocate the buffer — just once! — and go on with filling it. There is just one place where the allocation may fail and you can simply not go into the problem if that ever happens:
int totaloutputlength = 0;
char *outputbuffer = NULL;
char *currentposition = NULL;
void add_var_length(t_var *var){
const int numberlength = sizeof(var->value)*29/12 + 1;
totaloutputlength += strlen(var->name) + 2 + numberlength;
}
void calculate_all_vars_length(t_list *aList){
totaloutputlength = 0;
list_iterate(aList, (void *)add_var_length);
}
void sprint_var_value(t_var *var){
int outputlen = sprintf(currentposition, "%s=%d\n", var->name, var->value);
currentposition += outputlen; // advance the printing position
}
int sprint_all_vars(t_list *aList){
calculate_all_vars_length(aList);
outputbuffer = malloc(totaloutputlength + 1); // +1 for terminating NUL char
// did allocation succeed?
if(outputbuffer == NULL) { // NO
// possibly print some error message...
// possibly terminate the program...
// or just return -1 to inform a caller something went wrong
return -1;
}
else { // YES
// set the initial printing position
currentposition = outputbuffer;
// go print all variables into the buffer
list_iterate(aList, (void *)sprint_var_value);
// return a 'success' status
return 0;
}
}

Resources