How to guarantee that write() will transfer entire int over socket? - c

First of all I found similar question here. But I didn't understand how this should work:
int data = rand();
char* tosend = (char*)&data;
int remaining = sizeof(data);
I want to send size of file which I store into int variable. And I use next code for this:
Server side:
struct stat st;
stat("file", &st);
int file_size = st.st_size;
write(client_fd, &file_size, sizeof(file_size));
Client side:
int file_size;
read(server_fd, &file_size, sizeof(int));
And it works fine. But in documentation of write says that:
Note that a successful write() may transfer fewer than count
bytes
And same for read:
It is not an error if this number is smaller than the number of
bytes requested
If I'd send buffer of chars, which are 1 byte long each. I would just add offset to the buffer and store each next of bytes in buffer. Like this:
int write_all(int fd, void* buffer, int count) {
int offset = 0, b = 0, status;
while ((status = write(fd, buffer + offset, count)) != count) {
if (status == -1) {
/error check/
return -1;
}
count -= status;
offset += status;
b += status;
}
b += status;
return b;
}
But how to make the same thing for variable?

The example you refer to is not great because it gives no consideration of the integer byte order - and you have no guarantee that the byte order on the receiving host will be the same as on the host you are sending from.
My suggestion would be to
choose a byte order - LSB first (little endian) or MSB first (big endian), and then
allocate a char or uint8_t buffer of the relevant size (e.g. 2 bytes for a 16-bit integer, 4 bytes for a 32-bit integer) and store the integer there byte by byte
use your existing write_all() function to send it.
Big-endian is maybe more typical for network data, so it might be better to use that. Then, if you want to send a 32-bit integer ...
void send_u32(int client_fd, int32_t n) {
uint8_t buf[4];
// Big-endian byte order ...
for (int i=0; i<4; i++) {
buf[i] = n >> ((3-i)*8);
}
int res = write_all(client_fd, buf, 4);
}
For 16-bit integer just use a 2-byte buffer.
You will need to #include <stdint.h> for above.
P.S. st_size in struct stat is of type off_t - which I think might be OS-dependent. Maybe someone who knows more about POSIX can shed some light on that. (You can probably forget about using a 16-bit integer anyway - as I expect it will always be at least a 32-bit integer, except maybe on some embedded systems?.)

Your write_all() implementation is faulty. It will fail on short writes.
Consider these:
size_t write_some(const int desc, const void *buffer, const size_t min_length, const size_t max_length)
{
const char *ptr = (const char *)buffer;
const char *const need = (const char *)buffer + min_length;
const char *const end = (const char *)buffer + max_length;
while (ptr < need) {
ssize_t len = write(desc, ptr, (size_t)(end - ptr));
if (len > 0) {
ptr += len;
} else
if (len != -1) {
errno = EIO;
return (size_t)(ptr - (const char *)buffer);
} else {
/* errno set by write() */
return (size_t)(ptr - (const char *)buffer);
}
}
errno = 0;
return (size_t)(ptr - (const char *)buffer);
}
size_t read_some(const int desc, void *buffer, const size_t min_length, const size_t max_length)
{
char *const end = (char *)buffer + max_length;
char *const need = (char *)buffer + min_length;
char *ptr = (char *)buffer;
while (ptr < need) {
ssize_t len = read(desc, ptr, (size_t)(end - ptr));
if (len > 0) {
ptr += len;
} else
if (len == 0) {
errno = 0;
return (size_t)(ptr - (char *)buffer);
} else
if (len != -1) {
errno = EIO;
return (size_t)(ptr - (char *)buffer);
} else {
/* errno set by read() */
return (size_t)(ptr - (char *)buffer);
}
}
errno = 0;
return (size_t)(ptr - (char *)buffer);
}
They both always set errno, to zero if successful, errno otherwise, and return the actual number of bytes sent/received.
If you receive a stream (using descriptor desc) of packets starting with four-byte big-endian (network-endian) length fields, the length including the four-byte length field itself (so that its minimum valid value is 4), you can use the following:
static inline size_t packet_size4(const void *const from)
{
const unsigned char *src = (const unsigned char *)from;
return ((size_t)(src[0]) << 24)
| ((size_t)(src[1]) << 16)
| ((size_t)(src[2]) << 8)
| src[3];
}
int handle_all_packets(int desc, unsigned char *buffer, size_t maxlen)
{
size_t have = 0;
size_t len = 0;
while (1) {
if (have < 4) {
have += read_some(desc, buffer + have, 4 - have, maxlen - have);
if (have < 4)
return errno;
len = packet_size4(buffer);
if (len < 4)
return errno = EBADMSG;
if (len > maxlen)
return errno = EOVERFLOW;
}
if (have < len) {
have += read_some(desc, buffer + have, len - have, maxlen - have);
if (errno)
return errno;
if (have < len)
return errno = EIO;
}
/* Process len-byte packet in buffer. */
if (have > len) {
memmove(buffer, buffer + len, have - len);
have -= len;
len = 0;
} else {
have = 0;
len = 0;
}
}
}
If there were no errors, it will return 0, otherwise it returns a nonzero errno error code.
To send such a packet, you can use the following:
static inline void set_packet_size4(unsigned char *dst, size_t size)
{
dst[0] = (size >> 24) & 255;
dst[1] = (size >> 16) & 255;
dst[2] = (size >> 8) & 255;
dst[3] = size & 255;
}
int send_packet(const int desc, const void *data, const size_t len)
{
size_t n;
{
unsigned char buf[4];
set_packet_size4(buf, len + 4);
n = write_some(desc, buf, 4, 4);
if (errno)
return errno;
if (n != 4)
return errno = EIO;
}
n = write_some(desc, data, len, len);
if (errno)
return errno;
if (n != len)
return errno = EIO;
return 0;
}
If the packet is written correctly, the function returns 0, otherwise it returns a nonzero errno error code.

There is actually a standardized network byte order (which happens to be big endian), and standard functions to convert from host to network and vice versa:
htons() Host to Network Short
htonl() Host to Network Long
ntohl() Network to Host Long
ntohs() Network to Host Short
Use these for a portable way to transfer binary integers over the network. You might also look at writen() for really, really trying to write n bytes, although that function comes with its own set of pitfalls.

Both write and read return the number of bytes sent or received respectively. Don't start processing your data before you have received enough bytes to do so.
In more detail: TCP/IP will try to pass on the data it has as quickly as possible. Therefore if data is split between packets, your read may return before the expected number of bytes has been received, this may allow you to get a head start on data processing instead of waiting.

Related

How to sprintf with uint8_t array?

The main problem is that actually I have a uint8_t* data buffer. It an array and I only know Its size and Its pointer.
I want to sprintf the data from this pointer in a buffer like this :
void send_bin(uint8_t* binarypayload, uint8_t size, uint32_t mode)
{
char buffer[256];
sprintf(buffer, "AT+ZF=%s,%lu\r\n", binarypayload, mode);
HAL_UART_Transmit(&husart1, (uint8_t*)buffer, strlen((char*) buffer), 1000);
}
But on my uart I can only see the binary value on my uart:
þTÞ­˜.
Where am I going wrong ?
Sorry I have forgotten to say that my datas is like :
uint8_t buffer[4] = {0x45, 0xAD, 0xEF, 0x5B};
And I want it to look like this on my uart :
AT+ZF=45ADEF5B,45
but I only have access to its pointer
You need to convert the binary data into a hexadecimal format. The easiest way, is to convert each byte individually:
void send_bin(uint8_t* binarypayload, uint8_t size, uint32_t mode)
{
char buffer[256];
strcpy(buffer, "AT+ZF=");
for (int i = 0; i < size; i++) {
sprintf(buffer + strlen(buffer), "%02x", binarypayload[i]);
}
sprintf(buffer + strlen(buffer), ",%lud\r\n", mode);
HAL_UART_Transmit(&husart1, (uint8_t*)buffer, strlen(buffer), 1000);
}
snprintf can convert the bytes into their hexadecimal format in a string, but it doesn't have the automatic ability to do that to an array of them. We can call it multiple times in a for loop to enable that ability though.
void send_bin(uint8_t* binarypayload, uint8_t size, uint32_t mode) {
char buffer[256] = {};
int offset = 0;
int ret = snprintf(buffer + offset, sizeof(buffer) - offset,
"AT+ZF=");
assert(ret == 6);
offset += ret;
for (int i = 0; i < size; i++) {
ret = snprintf(buffer + offset, sizeof(buffer) - offset;
"%02X", binarypayload[i]);
assert(ret == 2);
offset += ret;
}
ret = snprintf(buffer + offset, sizeof(buffer) - offset,
"\r\n");
assert(ret == 2);
HAL_UART_Transmit(&husart1, (uint8_t*)buffer, strlen((char*) buffer), 1000);
}
sprintf on uC for this simple task is overkill. And it will not work if you decide to use RTOS in your project.
I would:
const char digits[] = "0123456789ABCDEF";
char *dumphex(char *buff, const void *data, size_t size)
{
char *wrk = buff;
const uint8_t *u8data = data;
if(buff && data)
{
while(size--)
{
*wrk++ = digits[*u8data >> 4];
*wrk++ = digits[*u8data & 0x0f];
}
*wrk = 0;
}
return buff;
}
or if you do not want to use lookup string
#define GETDIGIT(x) ((x) > 9 ? ((x) - 10) + 'A' : (x) + '0')
char *dumphex1(char *buff, const void *data, size_t size)
{
char *wrk = buff;
const uint8_t *u8data = data;
if(buff && data)
{
while(size--)
{
*wrk++ = GETDIGIT(*u8data >> 4);
*wrk++ = GETDIGIT(*u8data & 0x0f);
}
*wrk = 0;
}
return buff;
}

A potential memory overflow but not sure what's causing it

I am seeing a potential overflow: streamBuffer is a struct object (part of the FreeRTOS lib) and upon executing the following line in OutputToSerial(), I see streamBuffer.xHead's value is set to an extremely large value even though it's not being modified at the time.
LONG_TO_STR(strData, txStr);
Note that I didn't have any issues when I called nRF24_ReadReg() multiple times before.
Also, often times I see that printf doesn't print the entire text that's being printed (prior to calling the time when I see a potential overflow) - instead misses on some chars.
Any way to get a better understanding of the cause? I don't see any hardfaults or anything to look in the registers...
For a reference, the following is the struct's definition:
typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */
{
volatile size_t xTail; /* Index to the next item to read within the buffer. */
volatile size_t xHead; /* Index to the next item to write within the buffer. */
size_t xLength; /* The length of the buffer pointed to by pucBuffer. */
size_t xTriggerLevelBytes; /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */
volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */
volatile TaskHandle_t xTaskWaitingToSend; /* Holds the handle of a task waiting to send data to a message buffer that is full. */
uint8_t *pucBuffer; /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */
uint8_t ucFlags;
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */
#endif
} StreamBuffer_t;
// file.c
#define PRI_UINT64_C_Val(value) ((unsigned long) (value>>32)), ((unsigned long)value)
#define LONG_TO_STR(STR, LONG_VAL) (sprintf(STR, "%lx%lx", PRI_UINT64_C_Val(LONG_VAL)))
unsigned long long concatData(uint8_t *arr, uint8_t size)
{
long long unsigned value = 0;
for (uint8_t i = 0; i < size; i++)
{
value <<= 8;
value |= arr[i];
}
return value;
}
void nRF24_ReadReg(nrfl2401 *nrf, uint8_t reg, const uint8_t rxSize, uint8_t *rxBuffer, char *text)
{
uint8_t txBuffer[1] = {0};
uint8_t spiRxSize = rxSize;
if (reg <= nRF24_CMD_W_REG)
{
txBuffer[0] = nRF24_CMD_R_REG | (reg & nRF24_R_W_MASK);
spiRxSize++;
}
else
{
txBuffer[0] = reg;
}
nRF24_SendCommand(nrf, txBuffer, rxBuffer, spiRxSize);
OutputToSerial(txBuffer, rxBuffer, spiRxSize, text);
}
void OutputToSerial(uint8_t *writeBuffer, uint8_t *readBuffer, uint8_t size, char *text)
{
char strData[100] = {0}, rxStrData[100] = {0};
long long unsigned txStr = concatData(writeBuffer, size);
long long unsigned rxStr = concatData(readBuffer, size);
LONG_TO_STR(strData, txStr); // POTENTIAL ERROR.....!
LONG_TO_STR(rxStrData, rxStr);
char outputMsg[60] = {0};
strcpy(outputMsg, text);
strcat(outputMsg, ": 0x%s ----------- 0x%s\n");
printf (outputMsg, strData, rxStrData);
}
// main.c
StreamBufferHandle_t streamBuffer;
Perhaps other issues, yet the LONG_TO_STR(x) is simply a mess.
Consider the value 0x123400005678 would print as "12345678". That ref code is broken.
Yes its too bad code has long long yet no "%llx". Easy enough to re-write it all into a clean function.
//#define PRI_UINT64_C_Val(value) ((unsigned long) (value>>32)), ((unsigned long)value)
//#define LONG_TO_STR(STR, LONG_VAL) (sprintf(STR, "%lx%lx", PRI_UINT64_C_Val(LONG_VAL)))
#include <stdio.h>
#include <string.h>
#include <limits.h>
// Good for base [2...16]
void ullong_to_string(char *dest, unsigned long long x, int base) {
char buf[sizeof x * CHAR_BIT + 1]; // Worst case size
char *p = &buf[sizeof buf - 1]; // set to last element
*p = '\0';
do {
p--;
*p = "0123456789ABCDEF"[x % (unsigned) base];
x /= (unsigned) base;
} while (x);
strcpy(dest, p);
}
int main(void) {
char buf[100];
ullong_to_string(buf, 0x123400005678, 16); puts(buf);
ullong_to_string(buf, 0, 16); puts(buf);
ullong_to_string(buf, ULLONG_MAX, 16); puts(buf);
ullong_to_string(buf, ULLONG_MAX, 10); puts(buf);
return 0;
}
Output
123400005678
0
FFFFFFFFFFFFFFFF
18446744073709551615

How to use USART interrupt char variable in main code?

I am using PIC18F4550, and following the example given in https://www.electronicwings.com/pic/pic18f4550-usart, the program works because when i send a character via bluetooth (HC05) it received it and then transmit the same character, the problem is, that is done in the interrupt USART function and if i try to compare the character received in the main code for example
if(data == 'a')
The condition never met, but if i do that in the same interrupt fnction, it does recognize the character.
I am using MPLAB X v5.2 with XC8 compiler. The problem is not the bluetooth or the app used because i have used it before with arduino.
MAIN CODE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pic18f4550.h>
#include "Configuration_Header_File.h"
#include "LCD_16x2_8-bit_Header_File.h"
void USART_Init(int);
#define F_CPU 8000000/64
char data;
void __interrupt(low_priority) ISR(void)
{
while(RCIF==0);
data=RCREG;
LCD_Char(data);
while(TXIF==0);
if(data=='b')
TXREG='b';
if(data=='a')
TXREG='a';
}
void main()
{
OSCCON=0x72;
MSdelay(10);
LCD_Init();
USART_Init(9600);
LCD_String_xy(1,0,"Receive");
LCD_Command(0xC0);
while(1){
if(data=='c') /* THIS IS WHAT IS WRONG */
TXREG='c';
}
}
void USART_Init(int baud_rate)
{
float temp;
TRISC6=0; /*Make Tx pin as output*/
TRISC7=1; /*Make Rx pin as input*/
temp=(((float)(F_CPU)/(float)baud_rate)-1);
SPBRG=(int)temp; /*baud rate=9600 SPBRG=(F_CPU /(64*9600))-1*/
TXSTA=0x20; /*TX enable; */
RCSTA=0x90; /*RX enanle and serial port enable*/
INTCONbits.GIE=1; /*Enable Global Interrupt */
INTCONbits.PEIE=1; /*Enable Peripheral Interrupt */
PIE1bits.RCIE=1; /*Enable Receive Interrupt*/
PIE1bits.TXIE=1; /*Enable Transmit Interrupt*/
}
As you can see in the code, the conditions inside the interrupt function works, because if i send an 'a' via bluettoth (APP), an 'a' is what i received in the same APP, and same with a 'b', but, when i received a 'c', nothing happens. So i guess that the problem is how is declare the variable "data" or something related to that variable, i have not tried to make it global but i am pretty sure there have to be a better solution. Maybe the content in "data" is erased when the interrupt is done.
I expect the "data" content to be available in the main code but i do not know why it is only recognize in the USART interrupt function.
I would appreciate all your help.
You need to capture the received data in a FIFO, or other buffering solution for use in the main 'thread'.
The idea is to keep buffering input bytes continously from your ISR and while grabbing the input at your leisure from the main loop.
Here's an example of a simple COM port solution... I have not tested it, but it shows the minimal steps needed for an echo application.
char rx_buffer[16];
char tx_buffer[16];
_fifo_t rx_fifo; // need 2 buffers, one for sending, and one for receiving.
_fifo_t tx_fifo;
void __interrupt(low_priority) ISR(void)
{
// never wait for a flag to becom set or reset within an ISR. the ISR will be
// called automatically when the
while (RCIF)
{
data=RCREG;
LCD_Char(data); // you should considfer moving this out o the ISR.
FifoPutByte(&rx_fifo, data); // check for overruns is handled by the fifo module.
}
while (TXIE && TXIF && !FifoEmpty(&tx_fifo))
TXREG = FifoGetByte(&tx_fifo);
if (FifoEmpty(&tx_fifo)) // if no more data to send, disable TX interrupt.
TXIE = 0;
}
int COM_Transmit(char c)
{
if (!FifoPutByte(&tx_fifo, c))
return 0; // buffer is full!
TXIE = 1; // enable UART TX interrupts
// now comes the tricky part, you need to 'prime' the transmission of bytes
// in the transmit fifo. This operation MUST be done
// with interrupts disabled.
if (TXIF) // can only be true if TX interrupts are not kicking in.
{
PEIE = 0; // disable peripheral interrupts
TXREG = FifoGetByte(&tx_fifo); // clears TXIF
PEIE = 1; // enable peripheral inrerrupts
// ISR will be called when UART is done sending the byte in TXREG.
}
}
void main()
{
/* initialization code... */
FifoInit(&rx_fifo, rx_buffer, sizeof(rx_buffer));
FifoInit(&tx_fifo, tx_buffer, sizeof(tx_buffer));
while(1)
{
// simple UART echo code
while (!FifoEmpty(&rx_fifo) && !FifoFull(&tx_fifo))
COM_Transmit(FifoGetByte(&rx_fifo));
/* doing the other stuff that your controller must do may take some time */
/* You must make sure that rx_buffer is large enough to capture any bytes */
/* that could be received during this delay, at 9600 bauds, count 1ms per char */
MSdelay(15); // for example... A larger processing time will warrant larger buffer size for rx_fifo.
}
}
include file:
#ifndef _fifo_h
#define _fifo_h
/* *****************************************************************************
*
* file: fifo.h
*
* Simple byte fifo definitions.
*
******************************************************************************/
#define FIFO_DEBUG 0
typedef struct _fifo_t
{
volatile unsigned char* pHead; // head of data to extract.
volatile unsigned char* pTail; // tail of data for insertion.
unsigned char* pStart; // start of buffer.
unsigned char* pEnd; // end of buffer.
volatile unsigned int nOverruns; // overrun counter, in bytes.
volatile unsigned int nUnderruns; // underrun counter, in bytes.
#ifdef FIFO_DEBUG
volatile unsigned int nWaterMark; // Water mark indicating the maximum number of bytes ever held.
#endif
} fifo_t;
void FifoInit(fifo_t* fifo, unsigned char* buffer, unsigned int len);
void FifoReset(fifo_t* fifo);
int FifoEmpty(fifo_t* fifo);
unsigned int FifoGetFreeSpace(fifo_t* fifo);
// returns nuèmber of bytes available for GET op
unsigned int FifoGetCount(fifo_t* fifo);
// returns total buffer length
unsigned int FifoGetSize(fifo_t* fifo);
// returns the number of bytes in overrun
unsigned int FifoPut(fifo_t* fifo, const void* data, unsigned int len);
// return the number of bytes copied to data buffer.
unsigned int FifoGet(fifo_t* fifo, void* data, unsigned int len);
// returns negative value if fifo was empty
int FifoGetByte(fifo_t* fifo);
// returns non zetro value on success.
int FifoPutByte(fifo_t* fifo, unsigned char c);
// returns a contiguous buffer inside fifo, the length of contiguous part is returned in availLen.
// caller is responsible for advancing get/put pointer when the data is consumed.
unsigned char* FifoGetContiguousPutBuffer(fifo_t* fifo, unsigned int reqLen, unsigned int* availLen);
unsigned char* FifoGetContiguousGetBuffer(fifo_t* fifo, unsigned int reqLen, unsigned int* availLen);
// - peeks at data inside fifo, with optional offset from GET pointer,
// the length of contiguous part is returned in availLen.
// - buffer must be large enough to hold reqLen bytes.
// - the value returned is either a direct pointer to fifo buffer, if the data is contuguous, or buffer.
// if the data was copied to it, or NULL if the data is not avialable in buffer.
// - caller is responsible for advancing get/put pointer when the data is consumed.
void* FifoPeekBuffer(fifo_t* fifo, unsigned int offset, unsigned int reqLen, void* buffer);
// - Modifies a single byte at offset from GET pointer.
// - returns non-zero if successful.
char FifoPoke(fifo_t* fifo, unsigned int offset, unsigned char c);
// NOTE: interrupts should be disabled around calls to this function.
void FifoSetCount(fifo_t* fifo, unsigned int count);
unsigned int FifoAdvancePutPtr(fifo_t* fifo, unsigned int len);
unsigned int FifoAdvanceGetPtr(fifo_t* fifo, unsigned int len);
#endif
.c module:
/* *****************************************************************************
*
* file: fifo.c
*
* Simple byte fifo definitions.
*
******************************************************************************/
#include <string.h> // memcpy()
#include "fifo.h"
void FifoInit(fifo_t* fifo, unsigned char* buffer, unsigned int len)
{
fifo->pStart = (unsigned char*)(buffer);
fifo->pEnd = (unsigned char*)((buffer) + (len));
fifo->pHead = (unsigned char*)(buffer);
fifo->pTail = (unsigned char*)(buffer);
fifo->nOverruns = 0;
#ifdef FIFO_DEBUG
fifo->nWaterMark = 0;
#endif
}
void FifoReset(fifo_t* fifo)
{
fifo->pHead = fifo->pStart;
fifo->pTail = fifo->pStart;
fifo->nOverruns = 0;
}
int FifoEmpty(fifo_t* fifo)
{
return (fifo->pHead == fifo->pTail);
}
unsigned int FifoGetFreeSpace(fifo_t* fifo)
{
return ((fifo->pEnd - fifo->pStart) - FifoGetCount(fifo)) - 1;
}
unsigned int FifoGetCount(fifo_t* fifo)
{
unsigned char* pHead, * pTail;
unsigned int nResult;
pHead = (unsigned char*)fifo->pHead;
pTail = (unsigned char*)fifo->pTail;
if (pTail >= pHead)
{
nResult = pTail - pHead;
}
else
{
nResult = (pTail - fifo->pStart) + (fifo->pEnd - pHead);
}
return nResult;
}
unsigned int FifoGetSize(fifo_t* fifo)
{
return fifo->pEnd - fifo->pStart;
}
unsigned int FifoPut(fifo_t* fifo, const void* data, unsigned int len)
{
unsigned int nMax, nLeft;
unsigned char* pTail, * pHead;
const unsigned char* p;
nLeft = (len);
p = (const unsigned char*)data;
while(nLeft)
{
pHead = (unsigned char*)fifo->pHead;
if (pHead > fifo->pTail)
{
nMax = (pHead - fifo->pTail) - 1;
}
else
{
nMax = fifo->pEnd - fifo->pTail;
}
if (nMax > nLeft)
{
nMax = nLeft;
}
if (!nMax)
{
fifo->nOverruns += nLeft;
break;
}
memcpy((void*)fifo->pTail, p, nMax);
pTail = (unsigned char*)fifo->pTail + nMax;
if (pTail >= fifo->pEnd)
{
pTail = fifo->pStart;
}
fifo->pTail = pTail;
p += nMax;
nLeft -= nMax;
}
#ifdef FIFO_DEBUG
nMax = FifoGetCount(fifo);
if (nMax > fifo->nWaterMark)
{
fifo->nWaterMark = nMax;
}
#endif
return nLeft;
}
unsigned int FifoGet(fifo_t* fifo, void* data, unsigned int len)
{
unsigned int nMax, nLeft;
unsigned char* p, * pTail, * pHead;
nLeft = (len);
p = (unsigned char*)(data);
while(nLeft)
{
pTail = (unsigned char*)fifo->pTail;
if (pTail >= fifo->pHead)
{
nMax = pTail - fifo->pHead;
}
else
{
nMax = fifo->pEnd - fifo->pHead;
}
if (!nMax)
{
break;
}
if (nMax > nLeft)
{
nMax = nLeft;
}
memcpy(p, (void*)fifo->pHead, nMax);
pHead = (unsigned char*)fifo->pHead + nMax;
if (pHead >= fifo->pEnd)
{
pHead = fifo->pStart;
}
fifo->pHead = pHead;
p += nMax;
nLeft -= nMax;
}
return len - nLeft;
}
int FifoPutByte(fifo_t* fifo, unsigned char c)
{
int result = 0;
if (FifoGetFreeSpace(fifo))
{
unsigned char* pTail = (unsigned char*)fifo->pTail;
*pTail++ = c;
if (pTail >= fifo->pEnd)
{
pTail = fifo->pStart;
}
fifo->pTail = pTail;
result = 1;
}
return result;
}
int FifoGetByte(fifo_t* fifo)
{
int result = -1;
if (fifo->pHead != fifo->pTail)
{
unsigned char* pHead = (unsigned char*)fifo->pHead;
result = *(fifo->pHead);
if (++pHead >= fifo->pEnd)
{
pHead = fifo->pStart;
}
fifo->pHead = pHead;
}
return result;
}
unsigned char* FifoGetContiguousPutBuffer(fifo_t* fifo, unsigned int reqLen, unsigned int* availLen)
{
unsigned int nMax;
unsigned char* pHead;
pHead = (unsigned char*)fifo->pHead;
if (pHead > fifo->pTail)
{
nMax = (pHead - fifo->pTail) - 1;
}
else
{
nMax = fifo->pEnd - fifo->pTail;
if (pHead == fifo->pStart)
{
--nMax;
}
}
if (nMax > reqLen)
{
nMax = reqLen;
}
*availLen = nMax;
return (unsigned char*)fifo->pTail;
}
unsigned char* FifoGetContiguousGetBuffer(fifo_t* fifo, unsigned int reqLen, unsigned int* availLen)
{
unsigned int nMax;
unsigned char* pTail;
pTail = (unsigned char*)fifo->pTail;
if (pTail >= fifo->pHead)
{
nMax = pTail - fifo->pHead;
}
else
{
nMax = fifo->pEnd - fifo->pHead;
}
if (nMax > reqLen)
{
nMax = reqLen;
}
*availLen = nMax;
return (unsigned char*)fifo->pHead;
}
void* FifoPeekBuffer(fifo_t* fifo, unsigned int offset, unsigned int reqLen, void* buffer)
{
void* result;
result = NULL;
if ((reqLen + offset) <= FifoGetCount(fifo))
{
unsigned char* pHead, * pTail;
pHead = (unsigned char*)fifo->pHead + offset;
if (pHead >= fifo->pEnd)
{
pHead -= (fifo->pEnd - fifo->pStart);
}
pTail = pHead + reqLen;
if (pTail <= fifo->pEnd)
{
result = pHead;
}
else
{
// need to copy, as requested data wraps around
unsigned char* p;
unsigned int n;
p = (unsigned char*)buffer;
n = fifo->pEnd - pHead;
memcpy(p, pHead, n);
memcpy(p + n, fifo->pStart, reqLen - n);
result = buffer;
}
}
return result;
}
char FifoPoke(fifo_t* fifo, unsigned int offset, unsigned char c)
{
unsigned char* p;
char result = 0;
if (offset < FifoGetCount(fifo))
{
p = (unsigned char*)fifo->pHead + offset;
if (p >= fifo->pEnd)
{
p -= (fifo->pEnd - fifo->pStart);
}
*p = c;
result = 1;
}
return result;
}
unsigned int FifoAdvancePutPtr(fifo_t* fifo, unsigned int len)
{
unsigned int n;
unsigned char* pTail;
n = FifoGetFreeSpace(fifo);
if (len > n)
{
fifo->nOverruns += (len - n);
len = n;
}
pTail = (unsigned char*)fifo->pTail + len;
while (pTail >= fifo->pEnd)
{
pTail -= (fifo->pEnd - fifo->pStart);
}
fifo->pTail = pTail;
#ifdef FIFO_DEBUG
n = FifoGetCount(fifo);
if (n > fifo->nWaterMark)
{
fifo->nWaterMark = n;
}
#endif
return len;
}
unsigned int FifoAdvanceGetPtr(fifo_t* fifo, unsigned int len)
{
unsigned int n;
unsigned char* pHead;
n = FifoGetCount(fifo);
if (len > n)
{
fifo->nUnderruns += (len - n);
len = n;
}
pHead = (unsigned char*)fifo->pHead + len;
while (pHead >= fifo->pEnd)
{
pHead -= (fifo->pEnd - fifo->pStart);
}
fifo->pHead = pHead;
return len;
}
void FifoSetCount(fifo_t* fifo, unsigned int count)
{
unsigned int n;
unsigned char* pTail;
n = FifoGetSize(fifo);
if (count > n)
{
fifo->nOverruns += (count - n);
count = n;
}
pTail = (unsigned char*)fifo->pHead + count;
while (pTail >= fifo->pEnd)
{
pTail -= (fifo->pEnd - fifo->pStart);
}
fifo->pTail = pTail;
#ifdef FIFO_DEBUG
n = FifoGetCount(fifo);
if (n > fifo->nWaterMark)
{
fifo->nWaterMark = n;
}
#endif
}
Note that this fifo struct is not the most efficient for a small PIC, but it should work fine nonetheless. Writing your own FIFO is a very good exercise. The one above is taken from production code, I think I last used it on an STM32. It's also been used in production on dsPIC and on Arduino.

BIO_get_mem_ptr is returnig 0 as length and output

Here I am trying to get the size of bio file as ,
long res = BIO_get_mem_ptr(certBio, &bptr);
length = bptr->length; // is the length
I got this sample code from some stackoverflow question. I have tried many time but the BIO_get_mem_ptr is giving a null pointer in bptr with return value 0. I can't find any solutions related to this problem in any reference sites.
Here is the source code,
int pass_cb(char *buf, int size, int rwflag, void *u)
{
int len;
char *tmp;
tmp = "123456";
len = strlen(tmp);
if (len <= 0)
return 0;
if (len > size)
len = size;
memcpy(buf, tmp, len);
return len;
}
int main(void)
{
X509 *x509;
int length = 0;
unsigned char data[1000];
unsigned char *buffer = NULL;
buffer = data;
BIO *certBio = BIO_new(BIO_s_file());
// BIO *certBio = BIO_new(BIO_s_mem()); -> have tried this one too gives the same result
BUF_MEM *bptr = 0;
BIO_read_filename(certBio, "E:\\share\\Folder\\TempCert.pem");
x509 = PEM_read_bio_X509_AUX(certBio, NULL, pass_cb, NULL);
long res = BIO_get_mem_ptr(certBio, &bptr);
length = bptr->length;
memset(&buffer, 0, 1000);
int ret = BIO_read(certBio, &buffer, length);
BIO_free_all(certBio);
CertFreeCertificateContext(pContext);
CertCloseStore(hStore, 0);
return 0;
}
What is the problem causing here,
As you can see on The Man bio_get_mem_ptr wants a memory BIO
A memory BIO is a source/sink BIO which uses memory for its I/O. Data written to a memory BIO is stored in a BUF_MEM structure which is extended as appropriate to accommodate the stored data.
You are trying to use a file, so you should use the example code on The Man of bio_s_file

msgpack packing char array in C

How do I work with msgpack_pack_raw and msgpack_pack_raw_body to send an unsigned char array to more importantly, how to retrieve (unpack) it?
What I have done is as follows:
msgpack_sbuffer* buffer = msgpack_sbuffer_new();
msgpack_packer* pk = msgpack_packer_new(buffer, msgpack_sbuffer_write);
msgpack_sbuffer_clear(buffer);
msgpack_pack_array(pk, 10);
unsigned char a[10] = "0123456789";
msgpack_pack_raw(pk, 10);
msgpack_pack_raw_body(pk,a,10);
and in the receiver part I have:
msgpack_unpacked msg;
msgpack_unpacked_init(&msg);
msgpack_unpack_next(&msg, buffer->data, buffer->size, NULL);
msgpack_object obj = msg.data;
msgpack_object* p = obj.via.array.ptr;
int length = (*p).via.raw.size;
IDPRINT(length);
unsigned char* b = (unsigned char*) malloc(length);
memcpy(b,(*p).via.raw.ptr,length);
But it throws seg fault when executing "int length = (*p).via.raw.size;".
Any idea why?
Any idea why?
This is because msgpack_pack_array(pk, 10); is not required here, since you pack your data as a raw buffer of a given size. In other words msgpack_pack_raw and msgpack_pack_raw_body are sufficient.
At unpack time, you must access its fields as follow:
length: obj.via.raw.size
data: obj.via.raw.ptr
see: msgpack_object_raw in object.h.
Here's a recap of how to proceed:
#include <stdio.h>
#include <assert.h>
#include <msgpack.h>
int main(void) {
unsigned char a[10] = "0123456789";
char *buf = NULL;
int size;
/* -- PACK -- */
msgpack_sbuffer sbuf;
msgpack_sbuffer_init(&sbuf);
msgpack_packer pck;
msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write);
msgpack_pack_raw(&pck, 10);
msgpack_pack_raw_body(&pck, a, 10);
size = sbuf.size;
buf = malloc(sbuf.size);
memcpy(buf, sbuf.data, sbuf.size);
msgpack_sbuffer_destroy(&sbuf);
/* -- UNPACK -- */
unsigned char *b = NULL;
int bsize = -1;
msgpack_unpacked msg;
msgpack_unpacked_init(&msg);
if (msgpack_unpack_next(&msg, buf, size, NULL)) {
msgpack_object root = msg.data;
if (root.type == MSGPACK_OBJECT_RAW) {
bsize = root.via.raw.size;
b = malloc(bsize);
memcpy(b, root.via.raw.ptr, bsize);
}
}
/* -- CHECK -- */
assert(bsize == 10);
assert(b != NULL);
for (int i = 0; i < bsize; i++)
assert(b[i] == a[i]);
printf("ok\n");
free(buf);
free(b);
return 0;
}

Resources