How to sprintf with uint8_t array? - c

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;
}

Related

Copy structure to buffer

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define RAND(lower,upper) (rand()%(upper-lower+1))+lower
int power(int base, int exp)
{
int result=1;
while (exp != 0)
{
result *= base;
--exp;
}
return result;
}
int isKthBitSet(int n, int k)//from right, 1<=k<=n
{
int new_num = n >> (k - 1);
// if it results to '1' then bit is set,
// else it results to '0' bit is unset
return (new_num & 1);
}
struct Astructure{
uint16_t bitmap;
uint32_t a;
uint32_t b;
char str[10];
uint16_t d;
}__attribute__((packed));
int main()
{
struct Astructure abitmap;
abitmap.bitmap = 0;
char buffer[(sizeof(struct Astructure))];
abitmap.a = 52;
abitmap.b = 16;
char c[10]={"ramya"};
strcpy(abitmap.str, c);
abitmap.d = 59;
char ch;
srand(time(0));
for(uint8_t position =1;position<5;position++)
{
int random10 = RAND(0,1);
if(random10==1)
{
int value = power(2,position-1);
abitmap.bitmap = abitmap.bitmap | value;
}
}
memcpy(buffer, (char *)&abitmap.bitmap, sizeof(abitmap.bitmap)+1);
uint8_t temp4 = isKthBitSet(abitmap.bitmap,4);
uint8_t temp3 = isKthBitSet(abitmap.bitmap,3);
uint8_t temp2 = isKthBitSet(abitmap.bitmap,2);
uint8_t temp1 = isKthBitSet(abitmap.bitmap,1);
uint8_t previousLength = sizeof(abitmap.bitmap);
if(temp4){
//add a to buffer
memcpy(buffer + previousLength, (void *)&abitmap.a, sizeof(abitmap.a)+1);
previousLength += sizeof(abitmap.a);
}
if(temp3){
//add b to buffer
memcpy(buffer + previousLength, (void *)&abitmap.b, sizeof(abitmap.b)+1);
previousLength += sizeof(abitmap.b);
}
if(temp2){
//add c to buffer
memcpy(buffer + previousLength, (void *)&abitmap.str, sizeof(abitmap.str)+1);
previousLength += sizeof(abitmap.str);
}
if(temp1){
//add d to buffer
memcpy(buffer + previousLength, (char *)&abitmap.d, sizeof(abitmap.d)+1);
previousLength += sizeof(abitmap.d);
}
//SHOW BUFFER
previousLength = sizeof(abitmap.bitmap);
uint32_t a;
uint32_t b;
char str[10];
uint16_t d;
if(temp4){
memcpy(&a , (void *) buffer+previousLength , sizeof(abitmap.a)+1);//
printf("a = %d\t",a);
previousLength += sizeof(a);
}
if(temp3){
memcpy(&b , (void *) buffer+previousLength , sizeof(abitmap.b)+1);
printf("b = %d\t",b);
previousLength += sizeof(b);
}
if(temp2){
memcpy(str , (void *) buffer+previousLength , sizeof(abitmap.str)+1);//memccpy
printf("string = %s\t",str);
previousLength += sizeof(str);
}
if(temp1){
memcpy(&d , (void *) buffer+previousLength , sizeof(abitmap.d)+1);
printf("d = %d\t",d);
previousLength += sizeof(d);
}
printf("\n");
}
I trying to copy some variables to my buffer. The variables I want to add in the buffer is picked at random. Here I gave the size of my buffer before hand to the size of my structure. But as per my program I may not be adding all my variables in the buffer. So its a waste.
So How am I supposed to declare my buffer here.
if my replace this
char buffer[(sizeof(struct Astructure))];
to
char *buffer;
this
I get below error.
a = 52 string = ramya
*** stack smashing detected ***: terminated
Aborted (core dumped)
I dont want to waste the size of my buffer in here, giving the whole size of structure. so what do i do.
If you want to allocate only the required memory:
typedef struct
{
size_t length;
unsigned char data[];
}buff_t;
buff_t *addtobuffer(buff_t *buff, const void *data, size_t size)
{
size_t pos = buff ? buff -> length : 0;
buff = realloc(buff, pos + size + sizeof(*buff));
if(buff)
{
memcpy(buff -> data + pos, data, size);
buff -> length = pos + size;
}
return buff;
}
and example usage:
buff_t *buffer = NULL;
/* ... */
if(temp4)
{
buff_t *tmp = addtobuffer(buffer, &abitmap.a, sizeof(abitmap.a)+1);
if(!tmp) { /* error handling */}
buffer = tmp;
/*...*/
}

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

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.

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.

Convert char * to unsigned char array in C

I would like to optimize my code and avoid errors, I have this function that does the "work" but I think I can improve and avoid memory problems.
void function(char* message)
{
char * pointer;
unsigned char buffer[2048] = {0};
int buffer_len = 0;
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, message);
buffer_len = strlen(buffer);
memset(buffer, 0, sizeof(&buffer));
for(int i = 0, pointer = message; i < (buffer_len / 2); i++, pointer += 2)
{
sscanf(pointer, "%02hhX", &buffer[i]);
}
}
The idea of ​​the function is to receive a string of this style "0123456789" and pass it to 0x01, 0x23, 0x45, ... in an unsigned char array. Any tip, good practice or improvement would be very useful.
The ussage is something like this:
function("0123456789");
In the function buffer ends like:
buffer[0] = 0x01
buffer[1] = 0x23
...
There are a few optimizations possible.
The biggest optimization comes from avoiding doing
2x memset and strcpy,
No need to:
// memset(buffer, 0, sizeof(buffer));
// strcpy(buffer, message);
// memset(buffer, 0, sizeof(&buffer));
which drastically simplifies the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(char* message)
{
unsigned char * pointer;
unsigned char buffer[2048]; // not needed = {0};
int buffer_half_len; // not needed = 0;
buffer_half_len = strlen(message)/2; // avoiding division in the for loop;
pointer = message;
for(int i = 0; i < buffer_half_len; i++, pointer += 2)
{
sscanf(pointer, "%02hhX", &buffer[i]);
printf("%02hhX\n", buffer[i] );
}
}
OUTPUT:
01
23
45
67
89
char * a= -80; // let supposed you get returned value( i represented in int) from whatever source.
unsigned char b = * a; // now b equal the complemntry of -80 which will be 176
std::cout << b ;

How to construct and return a String in C? [duplicate]

This question already has answers here:
Function returning address of local variable error in C
(3 answers)
Closed 5 years ago.
I'm trying to construct and return a string in C, but running into a function returns address of local variable [-Wreturn-local-addr] compiler warning. I get that returning packet like I'm trying to do won't work, because packet is a pointer to the beginning of my chars of size packet_size, and that memory address isn't valid outside my function. I'm running on an AVR chip and don't want to use malloc. How should I go about solving this problem?
#include <stdio.h>
#include <string.h>
#include <stdint.h>
const char* construct_packet(const char* data);
void append(char* str, char c);
int main()
{
const char* my_packet = construct_packet("QERT");
printf("%s", my_packet);
return 0;
}
const char* construct_packet(const char* data)
{
const char training_chars[] = "___";
const char start_char = '>';
uint8_t checksum = 0;
for(uint16_t i = 0; i < strlen(data); i++) {
checksum += data[i];
}
const char checksum_char = checksum;
uint8_t packet_size = strlen(training_chars) + strlen(data) + 2; // Plus 2 for start byte and checksum byte
char packet[packet_size];
strcat(packet, training_chars);
append(packet, start_char);
strcat(packet, data);
append(packet, checksum_char);
return packet;
}
void append(char* str, char c)
{
str[strlen(str) + 1] = c;
}
If you don't want to use dynamic memory allocation, and don't want to use a static buffer, then you might try calculating and providing the memory buffer on the stack:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
const char* construct_packet(const char* data, const char* training_chars, const char start_char, char* packet);
void append(char* str, char c);
int main()
{
const char data[] = "QERT";
const char training_chars[] = "___";
const char start_char = '>';
const uint8_t packet_size = strlen(training_chars) + strlen(data) + 2; // Plus 2 for start byte and checksum byte
char packet[packet_size];
const char* my_packet = construct_packet(data, training_chars, start_char, packet);
printf("%s", my_packet); // same as printf("%s", packet);
return 0;
}
const char* construct_packet(const char* data, const char* training_chars, const char start_char, char* packet)
{
uint8_t checksum = 0;
for(uint16_t i = 0; i < strlen(data); i++) {
checksum += data[i];
}
const char checksum_char = checksum;
strcat(packet, training_chars);
append(packet, start_char);
strcat(packet, data);
append(packet, checksum_char);
return packet;
}
void append(char* str, char c)
{
str[strlen(str) + 1] = c;
}
Phil Brubaker: If you don't want to use dynamic memory allocation, and don't want to use a static buffer, then you might try calculating and providing the memory buffer on the stack:
I will not say better, my implementation:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
// in some header file
const char *construct_packet(char *packet, const char* data);
size_t size_packet(const char* data);
int main(void)
{
const char *data = "QERT";
size_t packet_size = size_packet(data);
char packet[packet_size];
construct_packet(packet, data);
printf("%s", packet);
}
// can be on a other file of course `training_chars` and `start_char` could be give in parameter
// of course cause there are static `size_packet()` and `contruct_packet()` must be in the same file
static const char * const training_chars = "___";
static const char start_char = '>';
size_t size_packet(const char* data)
{
// you forgot nul terminate byte
return sizeof training_chars - 1 + 1 + strlen(data) + 1 + 1;
}
const char *construct_packet(char *packet, const char* data)
{
size_t i = 0;
// I replace strcat because I supose you want speed note they are better method that this one
for (size_t j = 0; training_chars[j] != '\0'; j++) {
packet[i++] = training_chars[j];
}
packet[i++] = start_char;
// maybe this should be a char but you don't give information about checksum so I can't be sure
uint8_t checksum = 0;
for (size_t j = 0; data[j] != '\0'; j++) {
packet[i++] = data[j];
checksum += data[j];
}
packet[i++] = (char)checksum;
// you forgot nul terminate byte
packet[i] = '\0';
return packet;
}
Of course, you could just not calculate the size and give a maximum:
char packet[256];
construct_packet(packet, data, 256);

Resources