Related
Summarize the Problem:
I wrote a userspace SPI driver in linux for the NRF24L01+ transceiver. My goal is to send files to a server. A jetson nano is the sender, and a raspberry pi 3b+ the receiver. Both the spi and nano are running Linux.
I can consistently send packets and receive acknowledgements.
However, the issue is whenever I send a packet such as 0x ff ee dd 00 cc bb aa the receiver only receives the packet 0x ff ee dd 00 00 00 00. So what is happening is that whenever the first byte encountered is zero, the rest of the packet becomes zero. This causes the files I send to become corrupted.
I was able to reproduce this bug with a char array having a similar pattern. I noticed this trend when I printed out the file contents I was sending on the transmitter and receiver.
What I've tried:
I've tried altering my SPI read function. What I thought was happening was the chip select line was being flipped high early. This did not work, I got the same results.
I've printed the packets before calling the ioctl() function from the transmitter and the packet remains intact.
I've printed the return value of the ioctl() function to see how many bytes I was receiving and sending. I was sending 31 bytes from the transmitter, and receiving 32 bytes from the receiver. So it doesn't look like my reads and sends are failing.
If I had a logic analyzer my next step would be to check the SPI pins on the transmitter, but unfortunately I don't have one.
I've added a 10uF decoupling capacitor on the transceivers and that sped up communication.
Show Some Code:
Receiver side:
/**
* Reads the payload when data pipe
* is available.
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_rx_read(int spi_dev_fd, char * payload, int * pipe, int * bytes)
{
int pipe_temp, rtn;
// TODO: Add timeout.
do
{
rtn = nrf_rx_pipe_available(spi_dev_fd, &pipe_temp);
}while(rtn != 0);
if(rtn == 0)
{
char status;
if(bytes != NULL)
{
char size;
spi_read_msg(spi_dev_fd, R_RX_PL_WID, &status, &size, 1);
*bytes = (int) size;
}
spi_read_msg(spi_dev_fd, R_RX_PAYLOAD , &status, payload, (int) NUM_PAYLOAD_BYTES);
*pipe = pipe_temp;
char msg;
msg = RX_DR;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &msg, 1);
return 0;
}
return 1;
}
bool nrf_rx_pipe_available(int spi_dev_fd, int * pipe)
{
char addr = NOP;
char status;
spi_read_msg(spi_dev_fd, addr, &status, NULL, 0);
if((status & RX_DR) > 0)
{
*pipe = (status >> RX_P_NO) & 0x07;
if(*pipe > 5)
{
return 1;
}
return 0;
}
return 1;
}
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
string temp = string(recv_buffer);
temp = temp.substr(1);
strncpy(copy_to, temp.c_str(), len);
}
// debug code
for(int i = 0; i < len; ++i)
{
printf("copy_to: %x \n ", copy_to[i]);
}
// end debug code.
}
return res;
}
Transmitter side:
/**
* Function to load a payload and send a packet.
*
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_tx_send_packet(int spi_dev_fd, char * payload, int len)
{
int rtn;
// Put low so we can add the payload.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW);
// Set a new payload.
nrf_tx_new_payload(spi_dev_fd, payload, len);
// Start tx transmission.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_HIGH);
do
{
rtn = nrf_tx_pending_send(spi_dev_fd);
if(rtn == 2)
{
char clr = MAX_RT;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &clr, 1);
}
}while(rtn != 1);
// Go back to standby mode
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW); // Setting chip enable to 0.
char reg = W_REGISTER | STATUS;
char val = RX_DR | TX_DS | MAX_RT;
spi_send_msg(spi_dev_fd, reg, &val, 1);
return 0;
}
int spi_send_msg(int spi_dev_fd, char addr, char * data, int len)
{
char data_buffer[len + 1];
char recv_buffer;
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer[0] = addr;
for(int i = 1; i < len + 1; ++i)
{
data_buffer[i] = data[i-1];
printf("databuffer[i]: %x \n", data_buffer[i]);
}
xfer.tx_buf = (unsigned long) data_buffer;
xfer.rx_buf = (unsigned long) NULL;
xfer.len = len + 1;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
//xfer.rx_nbits = 8;
xfer.rx_nbits = 0;
xfer.tx_nbits = (8 * len) + 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
printf("res: %i \n", res);
return res;
}
I tried to add all the relevant code, sorry if it is a bit much. Main thing to look at is the send and receive functions. They all work as expected until I encounter the zeroed out byte.
If I am missing any information that can help someone out please let me know and I can add it. I think the send and receive functions are the most important however. I'm able to set and read the registers of the transceiver.
I can send files now!
The fix was done in spi_read_msg() function.
The problem was I was converting the buffer received to a string, which caused the data to be trimmed when the byte 0x00 was encountered. This is also equivalent to the null terminating character.
Receiver code:
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
for(int i = 0; i < len; ++i)
{
copy_to[i] = recv_buffer[i + 1];
}
}
}
return res;
}
I'm making a BMP to PNG Converter.
The BMP Images are uncompressed.
So my question is when the BMP File is converted to a PNG File, then is the PNG File compressed i.e is the image data compressed. If so how is the image data aligned in the PNG File Format?
If the PNG Image Data is uncompressed then how is the BMP Image Data Aligned in PNG File.
#include<stdio.h>
#include<stdlib.h>
#pragma pack(1)
typedef struct
{
unsigned short int st_m40_FileType;
unsigned int st_m40_ImgFileSize;
unsigned short int st_m40_RsvdBytes1;
unsigned short int st_m40_RsvdBytes2;
unsigned int st_m40_ImgDataOffset;
unsigned int st_m40_Info40HeaderSze;
int st_m40_PxWdth;
int st_m40_PxHeight;
unsigned short int st_m40_NumOfColrPlnes;
unsigned short int st_m40_BitsPerPixel;
unsigned int st_m40_CmprsnType;
unsigned int st_m40_AftrCmprsnImgDataSze;
int st_m40_xResolutn_ppm;
int st_m40_yResolutn_ppm;
unsigned int st_m40_NumOfColrTbleColrs;
unsigned int st_m40_NumOfImprtntColrs;
}ST_BMP40HEADER_t;
typedef struct
{
ST_BMP40HEADER_t st_mBMP40MainHdrVar;
unsigned char * pst_mImgeData;
}ST_IMAGE_40_HEADER_t;
typedef enum
{
BI_RGB = 0x00,
BI_RLE8,
BI_RLE4,
BI_BITFIELDS,
BI_JPEG,
BI_PNG,
BI_ALPHABITFIELDS,
BI_CMYK,
BI_CMYKRLE8,
BI_CMYKRLE4,
}EN_BMP_COMPRESN_TYPE_t;
#pragma pack(1)
typedef struct
{
int st_mImgWdth;
int st_ImgHeight;
unsigned char st_mBitDepth;
unsigned char st_mColorType;
unsigned char st_mCmprsnMthd;
unsigned char st_mFltrMthd;
unsigned char st_mInterlaceMthd;
}ST_IHDR_DATA_FIELDS_t;
#pragma pack(1)
typedef struct
{
unsigned int st_mChunkDataLngth;
unsigned char st_mChunkType[4];
ST_IHDR_DATA_FIELDS_t st_IHDR_DataFieldsVar;
unsigned int st_mCRC32CheckSum;
}ST_IHDR_t;
#pragma pack(1)
typedef struct
{
unsigned int st_mPLTE_ChunkDataLngth;
unsigned char st_mPLTE_ChunkType[4];
unsigned char* st_mPLTE_ChunkDataPtr;
unsigned int st_mPLTE_CRC32CheckSum;
}ST_PLTE_t;
#pragma pack(1)
typedef struct
{
unsigned int st_mIDAT_ChunkDataLngth;
unsigned char st_mIDAT_ChunkType[4];
unsigned char* st_mIDAT_ChunkDataPtr;
unsigned int st_mIDAT_CRC32CheckSum;
}ST_IDAT_t;
#pragma pack(1)
typedef struct
{
unsigned int st_mIEND_ChunkDataLength;
unsigned char st_mIEND_ChunkType[4];
unsigned char * st_mIEND_ChunkDataPtr;
unsigned int st_mIEND_CRC32CheckSum;
}ST_IEND_t;
/* Little Endian to Big-Endian API. */
unsigned int BMP2PNG_LitToBigEndian(unsigned int f_BigEndianVal)
{
return (((f_BigEndianVal>>24) & 0x000000ff) | ((f_BigEndianVal>>8) & 0x0000ff00) |\
((f_BigEndianVal<<8) & 0x00ff0000) | ((f_BigEndianVal<<24) & 0xff000000));
}
/* CRC32 API.*/
unsigned int BMP2PNG_CmputeCRC32(unsigned char *p_fIpVal, unsigned int f_IpSize)
{
int l_LoopVar;
unsigned int l_ByteVal, l_CRCVal, l_MaskVal;
unsigned int l_TmpIncVar = 0;
l_CRCVal = 0xFFFFFFFF;
while (l_TmpIncVar <= f_IpSize)
{
// Get next byte.
l_ByteVal = p_fIpVal[l_TmpIncVar];
l_CRCVal = l_CRCVal ^ l_ByteVal;
for (l_LoopVar = 7; l_LoopVar >= 0; l_LoopVar--)
{
// Do eight times.
l_MaskVal = -(l_CRCVal & 1);
l_CRCVal = (l_CRCVal >> 1) ^ (0xEDB88320 & l_MaskVal);
}
l_TmpIncVar = l_TmpIncVar + 1;
}
return ~l_CRCVal;
}
/* API converts BMP-to-PNG format. */
char * Convert__40_BMP2PNG(ST_IMAGE_40_HEADER_t * pst_fBMP40ImgHdrVar, FILE * p_ImgFilePtr,\
unsigned char * p_fBMP_ColrTble)
{
FILE * l_BMP2PNGFilePtr;
ST_IHDR_t * pst_lIHDRChunkVar;
unsigned char l_PNGSignature[8]={137, 80, 78, 71, 13, 10, 26, 10};
unsigned int l_BigEndianVal;
unsigned int l_CRC32Val;
unsigned char * l_TempCRCBuff;
unsigned char * l_CRCBuffer;
unsigned int l_BuffLength = 0;
unsigned int l_TempIHDRChunkDataLngth;
pst_lIHDRChunkVar = (ST_IHDR_t *) malloc(sizeof(*pst_lIHDRChunkVar));
l_BMP2PNGFilePtr = fopen("BMP2PNG2.png","w");
/* Writing the 1st 8-bytes to the PNG File.*/
fwrite(l_PNGSignature,1,8,l_BMP2PNGFilePtr);
fseek(l_BMP2PNGFilePtr,8,SEEK_SET);
pst_lIHDRChunkVar->st_mChunkDataLngth = 13;
l_TempIHDRChunkDataLngth = BMP2PNG_LitToBigEndian(13);
/*Writing the IHDR Chunk Data-Length-Size value to the file.*/
fwrite(&l_TempIHDRChunkDataLngth,sizeof(unsigned int),1,l_BMP2PNGFilePtr);
pst_lIHDRChunkVar->st_mChunkType[0] = 'I';
pst_lIHDRChunkVar->st_mChunkType[1] = 'H';
pst_lIHDRChunkVar->st_mChunkType[2] = 'D';
pst_lIHDRChunkVar->st_mChunkType[3] = 'R';
/* Writing the IHDR-Chunk-Type value to the file.*/
fwrite( pst_lIHDRChunkVar->st_mChunkType ,sizeof(unsigned char),4,l_BMP2PNGFilePtr);
// pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mImgWdth = BMP2PNG_LitToBigEndian(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxWdth);
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mImgWdth = BMP2PNG_LitToBigEndian(3);
// pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_ImgHeight = BMP2PNG_LitToBigEndian(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxHeight);
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_ImgHeight = BMP2PNG_LitToBigEndian(3);
if(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel <= 8)
{
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mBitDepth = pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel;
}
else if( (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel == 24) || \
(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel == 32) )
{
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mBitDepth = 8;
}
else
{
/*No Action.*/
}
if( pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel <=8 )
{
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mColorType = 3;
}
else if (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel == 24)
{
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mColorType = 2;
}
else if (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel == 32)
{
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mColorType = 6;
}
else
{
/*No Action.*/
}
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mCmprsnMthd = 0;
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mFltrMthd = 0;
pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mInterlaceMthd = 0;
fseek(l_BMP2PNGFilePtr,16,SEEK_SET);
fwrite(&pst_lIHDRChunkVar->st_IHDR_DataFieldsVar,sizeof(ST_IHDR_DATA_FIELDS_t),1,l_BMP2PNGFilePtr);
{
/* Framing the data for calculating the 32-bit CRC Checksum.*/
l_BuffLength = 4+(pst_lIHDRChunkVar->st_mChunkDataLngth);
l_CRCBuffer = (unsigned char*)malloc(l_BuffLength);
l_TempCRCBuff = l_CRCBuffer;
*l_TempCRCBuff++ = pst_lIHDRChunkVar->st_mChunkType[0];
*l_TempCRCBuff++ = pst_lIHDRChunkVar->st_mChunkType[1];
*l_TempCRCBuff++ = pst_lIHDRChunkVar->st_mChunkType[2];
*l_TempCRCBuff++ = pst_lIHDRChunkVar->st_mChunkType[3];
*l_TempCRCBuff++ = (unsigned char)pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mImgWdth;
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mImgWdth << 8);
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mImgWdth << 16);
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mImgWdth << 24);
*l_TempCRCBuff++ = (unsigned char)pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_ImgHeight;
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_ImgHeight << 8);
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_ImgHeight << 16);
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_ImgHeight << 24);
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mBitDepth);
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mColorType);
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mCmprsnMthd);
*l_TempCRCBuff++ = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mFltrMthd);
*l_TempCRCBuff = (unsigned char)(pst_lIHDRChunkVar->st_IHDR_DataFieldsVar.st_mInterlaceMthd);
// Compute and output CRC
l_CRC32Val = BMP2PNG_CmputeCRC32(l_CRCBuffer, l_BuffLength);
l_CRC32Val = BMP2PNG_LitToBigEndian( l_CRC32Val);
fseek(l_BMP2PNGFilePtr,29,SEEK_SET);
unsigned int returnVal = fwrite(&l_CRC32Val,sizeof(unsigned int),1,l_BMP2PNGFilePtr);
}
unsigned char * p_lBMPImgData = pst_fBMP40ImgHdrVar->pst_mImgeData;
// unsigned int l_BMPImgeDataSze = ( (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxWdth) * \
(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxHeight) );
unsigned int l_BMPImgeDataSze = (3*3)*3;
ST_IDAT_t * pst_lIDAT_ChunkVar;
pst_lIDAT_ChunkVar = (ST_IDAT_t *) malloc(sizeof(*pst_lIDAT_ChunkVar));
unsigned int l_ImgDataSzeIncVar = 0;
unsigned char * p_IDATBuf;
unsigned char * p_TempIDATBuf;
unsigned int l_IDATBufSze;
if(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel == 24)
{
fseek(l_BMP2PNGFilePtr,33,SEEK_SET);
l_BMPImgeDataSze *= 3;
l_IDATBufSze = 4 + l_BMPImgeDataSze;
p_IDATBuf = (unsigned char*)malloc(l_IDATBufSze);
p_TempIDATBuf = p_IDATBuf;
pst_lIDAT_ChunkVar->st_mIDAT_ChunkDataLngth = BMP2PNG_LitToBigEndian(l_BMPImgeDataSze);
fwrite(&pst_lIDAT_ChunkVar->st_mIDAT_ChunkDataLngth,sizeof(unsigned int),1,l_BMP2PNGFilePtr);
pst_lIDAT_ChunkVar->st_mIDAT_ChunkType[0] = 'I';
pst_lIDAT_ChunkVar->st_mIDAT_ChunkType[1] = 'D';
pst_lIDAT_ChunkVar->st_mIDAT_ChunkType[2] = 'A';
pst_lIDAT_ChunkVar->st_mIDAT_ChunkType[3] = 'T';
fwrite( pst_lIDAT_ChunkVar->st_mIDAT_ChunkType ,sizeof(unsigned char),4,l_BMP2PNGFilePtr);
fseek(l_BMP2PNGFilePtr,41,SEEK_SET);
unsigned char ImgeData[27] = { 0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,};
while(l_ImgDataSzeIncVar <= l_BMPImgeDataSze )
{
fwrite(ImgeData,sizeof(unsigned char),1,l_BMP2PNGFilePtr);
/*
fwrite( (p_lBMPImgData+2),sizeof(unsigned char),1,l_BMP2PNGFilePtr);
*p_TempIDATBuf++ = *(p_lBMPImgData+2);
fwrite( (p_lBMPImgData+1),sizeof(unsigned char),1,l_BMP2PNGFilePtr);
*p_TempIDATBuf++ = *(p_lBMPImgData+1);
fwrite( (p_lBMPImgData),sizeof(unsigned char),1,l_BMP2PNGFilePtr);
*p_TempIDATBuf++ = *(p_lBMPImgData);
p_lBMPImgData += 3;
l_ImgDataSzeIncVar += 3;
*/
}
// Compute and output CRC
unsigned int crc32 = BMP2PNG_CmputeCRC32(p_IDATBuf, l_IDATBufSze);
fwrite(&crc32,sizeof(unsigned int),1,l_BMP2PNGFilePtr);
}
}
ST_IMAGE_40_HEADER_t * ReadBMP40HdrImage(ST_IMAGE_40_HEADER_t * pst_fBMP40ImgHdrVar, \
FILE * p_ImgFilePtr)
{
unsigned short int l_ColorTbleSze;
unsigned char * l_ColorTbleVal;
unsigned int l_ImageDataOffset;
unsigned int l_ImageDataSize;
unsigned int l_ImageDataSzeIncVar = 1;
unsigned char * l_ImageDataPtr;
unsigned int l_PixelCount = 1;
int l_NumOfReadBlks = fread(pst_fBMP40ImgHdrVar,sizeof(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar),1,p_ImgFilePtr);
printf("\n********************************************************************\n");
printf("\nPrinting the BMP Image Parameters:\n");
printf("\nBMP File Header Parameters.\n");
printf("File Type:\t'BM'\n");
printf("Total Size of the image:\t%u\n",pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_ImgFileSize);
printf("Image Data Offset:\t%u\n",pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_ImgDataOffset);
printf("\nBMP Info Header Parameters.\n");
printf("Size of the Info-Header:\t'%u-Bytes'.\n",pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_Info40HeaderSze);
printf("Width of the BMP Image:\t'%d-Pixels'.\n",pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxWdth);
printf("Height of the BMP Image:\t'%d-Pixels'.\n",pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxHeight);
printf("Number of Color Planes:\t'%d'.\n",pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_NumOfColrPlnes);
printf("Number of Bits-Per-Pixel:\t'%d'.\n",pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel);
printf("Compression Type used for compressing the BMP Raw Image:\t'%d'.\n",\
pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_CmprsnType);
printf("Horizontal Resolution:\t'%d-Pixels Per Meter'.\n,",\
pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_xResolutn_ppm);
printf("Vertical Resolution:\t'%d-Pixels Per Meter'.\n,",\
pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_yResolutn_ppm);
if(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_NumOfColrTbleColrs !=0 )
{
printf("Number of Colors in the color table:\t'%u'.\n",\
pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_NumOfColrTbleColrs);
}
if( (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel <= 8) && \
(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_NumOfColrTbleColrs !=0) )
{
rewind(p_ImgFilePtr);
fseek(p_ImgFilePtr,55,SEEK_SET);
l_ColorTbleSze = (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_NumOfColrTbleColrs) * 4 ;
l_ColorTbleVal = (unsigned char*) malloc( l_ColorTbleSze );
l_NumOfReadBlks = fread(l_ColorTbleVal, l_ColorTbleSze, 1, p_ImgFilePtr);
if(l_NumOfReadBlks <1)
{
printf("Couldn't read the Color-Table values from the BMP File.\n");
return NULL;
}
else if(l_NumOfReadBlks == 1)
{
unsigned short int l_ClrTbleIncVar = 0;
unsigned char * l_TempColorTbleVal = l_ColorTbleVal;
unsigned short int l_IndexVal = 0;
printf("\n*****************************************************************************\n");
printf("Printing the color Table.\n");
while (l_ClrTbleIncVar <= (l_ColorTbleSze-4) )
{
printf("Index '%d' : ", l_IndexVal);
printf("Blue -> '%d'\t",*l_TempColorTbleVal);
l_TempColorTbleVal++;
printf("Green -> '%d'\t",*l_TempColorTbleVal);
l_TempColorTbleVal++;
printf("Red -> '%d'\t\n",*l_TempColorTbleVal);
l_TempColorTbleVal+=2;
l_ClrTbleIncVar += 4;
l_IndexVal++;
}
}
}
rewind(p_ImgFilePtr);
l_ImageDataOffset = pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_ImgDataOffset;
fseek(p_ImgFilePtr,l_ImageDataOffset,SEEK_SET);
if(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel == 4)
{
l_ImageDataSize = ( (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxWdth) * \
(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxHeight) )/2;
pst_fBMP40ImgHdrVar->pst_mImgeData = (unsigned char*)malloc(l_ImageDataSize);
l_ImageDataPtr = pst_fBMP40ImgHdrVar->pst_mImgeData;
l_NumOfReadBlks = fread(l_ImageDataPtr,1,l_ImageDataSize,p_ImgFilePtr);
if(l_NumOfReadBlks < 1)
{
printf("Couldn't read the image data from the file.\n");
return NULL;
}
}
else if(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel == 8)
{
l_ImageDataSize = ( (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxWdth) * \
(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxHeight) );
pst_fBMP40ImgHdrVar->pst_mImgeData = (unsigned char*)malloc(l_ImageDataSize);
l_ImageDataPtr = pst_fBMP40ImgHdrVar->pst_mImgeData;
l_NumOfReadBlks = fread(l_ImageDataPtr,l_ImageDataSize,1,p_ImgFilePtr);
if(l_NumOfReadBlks < 1)
{
printf("Couldn't read the image data from the file.\n");
return NULL;
}
}
else if(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel == 24)
{
l_ImageDataSize = ( (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxWdth) * \
(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxHeight) * 3 );
pst_fBMP40ImgHdrVar->pst_mImgeData = (unsigned char*)malloc(l_ImageDataSize);
l_ImageDataPtr = pst_fBMP40ImgHdrVar->pst_mImgeData;
l_NumOfReadBlks = fread(l_ImageDataPtr,l_ImageDataSize,1,p_ImgFilePtr);
if(l_NumOfReadBlks < 1)
{
printf("Couldn't read the image data from the file.\n");
return NULL;
}
}
else if(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_BitsPerPixel == 32)
{
l_ImageDataSize = ( (pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxWdth) * \
(pst_fBMP40ImgHdrVar->st_mBMP40MainHdrVar.st_m40_PxHeight) * 4 );
pst_fBMP40ImgHdrVar->pst_mImgeData = (unsigned char*)malloc(l_ImageDataSize);
l_ImageDataPtr = pst_fBMP40ImgHdrVar->pst_mImgeData;
l_NumOfReadBlks = fread(l_ImageDataPtr,l_ImageDataSize,1,p_ImgFilePtr);
if(l_NumOfReadBlks < 1)
{
printf("Couldn't read the image data from the file.\n");
return NULL;
}
}
rewind(p_ImgFilePtr);
Convert__40_BMP2PNG(pst_fBMP40ImgHdrVar,p_ImgFilePtr,l_ColorTbleVal);
}
int main()
{
FILE * l_ImgeFilePtr;
l_ImgeFilePtr = fopen("FLAG_B24.BMP","r");
unsigned short int l_ImgeFileType;
unsigned int l_InfoHdrSze;
int l_NumofReadBlocks;
l_NumofReadBlocks = fread(&l_ImgeFileType,2,1,l_ImgeFilePtr);
if(l_NumofReadBlocks <1)
{
printf("Couldn't read the bytes from the file.\n");
return 0;
}
if(l_ImgeFileType != 19778)
{
printf("Image Passed is not a BMP file.\n");
return 0;
}
fseek(l_ImgeFilePtr,14,SEEK_SET);
l_NumofReadBlocks = fread(&l_InfoHdrSze, 4, 1, l_ImgeFilePtr);
if(l_NumofReadBlocks <1)
{
printf("Couldn't read the bytes from the file.\n");
return 0;
}
rewind(l_ImgeFilePtr);
if( l_InfoHdrSze == 40 )
{
ST_IMAGE_40_HEADER_t * pst_Img40HdrVar;
pst_Img40HdrVar = malloc(sizeof(*pst_Img40HdrVar));
if(pst_Img40HdrVar == NULL)
{
printf("There isn't enough memory to allocate for the Image header variable.\n");
return 0;
}
ST_IMAGE_40_HEADER_t * pst_l40_ReadAPIReturnVal = ReadBMP40HdrImage(pst_Img40HdrVar, l_ImgeFilePtr);
}
}
is the PNG File compressed
Yes.
how is the image data aligned in the PNG File Format?
It's not aligned. From the spec, "The chunk data length may be any number of bytes up to the maximum; therefore, implementors cannot assume that chunks are aligned on any boundaries larger than bytes."
Multitudinous image handling libraries exist to save you from worrying about these details, though. I'd recommend against rolling your own converter unless your goal is specifically to learn about image file formats.
I've writen this code but it doesn't work correctly.
This is menu interface:
*************ENCODE_DECODE_BASE64**************
******* 1. Encode ********
******* 2. Decode ********
******* 3. Exit ********
***********************************************
When i choose 1, "Encode". The function runs but the process exits.
I want when I choose 1, the function to run and then after that, the menu to display again.
Can you help me?
Here is Clientcode:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#define MAX 1024
// read filename
char *inputString(int size){
int test=0;
char *s=(char*)malloc(size);
do{
if(test!=0){
printf("File not found !!!!!!");
}
fgets(s,size,stdin);
test++;
}while(strlen(s)<=1);
return strtok(s,"\n");
}
int main(int argc, char *argv[]){
int sockfd;
struct sockaddr serverAddr; //server address
char buff[1024];
struct sockaddr_in inAddr;
long int sentBytes,revedBytes;
sockfd=socket(AF_INET,SOCK_STREAM,0); // create socket
if (sockfd == -1)
{
printf("ERROR opening socket\n");
return 1;
}
printf("Socket done\n");
inAddr.sin_family=AF_INET; //default
inAddr.sin_port=htons(5500); // service port
inet_aton("127.0.0.1",&inAddr.sin_addr);
//connectting
if(connect(sockfd,(struct sockaddr *)&inAddr,sizeof(struct sockaddr))<0){
printf("Connect failed.\n");
return 1;
}
printf("Connection accepted\n");
char *FileName; // file input
char *Result; // file return
int choice;
do{
printf("\n*************ENCODE_DECODE_BASE64**************");
printf("\n******* 1. Encode ********");
printf("\n******* 2. Decode ********");
printf("\n******* 3. Exit ********");
printf("\n***********************************************\n");
printf("Choice: ");
choice = getchar();
while(getchar() !='\n');
switch(choice)
{
case '1':
//demo encode////////////////////////////////////////
send(sockfd,"encode",5,0); // send to server when choose 1
printf("File Encode : ");
FileName = inputString(20);
FILE *fpt = fopen(FileName,"r");
if(fpt==NULL){
printf("File not found");
return -1;
}
printf("File Result: ");
Result = inputString(20);
FILE *ft = fopen(Result,"w");
while(!feof(fpt)){
if (fgets(buff,MAX,fpt) != NULL ){
sentBytes=send(sockfd,buff,1024,0);
revedBytes=recv(sockfd,buff,1024,0);
fprintf(ft,"%s\n",buff);
}
}
printf("Encode done!thanks you !\n");
//close(sockfd);
fclose(fpt);fclose(ft);
return 0;
break;
//decode ///////////////////////////////////////////////
case '2':
send(sockfd,"decode",6,0);
printf("File Decode : ");
FileName = inputString(20);
FILE *fpt1 = fopen(FileName,"r");
if(fpt1==NULL){
printf("File not found");
return -1;
}
printf("File Result : ");
Result = inputString(20);
FILE *ft1 = fopen(Result,"w");
while(!feof(fpt1)){
if (fgets(buff,MAX,fpt1) != NULL ){
sentBytes=send(sockfd,buff,1024,0);
revedBytes=recv(sockfd,buff,1024,0);
fprintf(ft1,"%s",buff);
}
}
printf("Decode done ! thanks you !\n");
//close(sockfd);
fclose(fpt1);fclose(ft1);
return 0;
break;
///////////////////////////////////////////////////////
case '3':
printf("Thanks!\n");
break;
default: printf("wrong number, please try again!\n"); break;
//end choice///////////////////////////////////////
}
}while(choice!='3');
//end menu
//close(sockfd);
//return 0;
}
and here is ServerCode:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* decodeblock - decode 4 '6-bit' characters into 3 8-bit binary bytes */
void decodeblock(unsigned char in[], char *clrstr) {
unsigned char out[4];
out[0] = in[0] << 2 | in[1] >> 4;
out[1] = in[1] << 4 | in[2] >> 2;
out[2] = in[2] << 6 | in[3] >> 0;
out[3] = '\0';
strncat(clrstr, out, sizeof(out));
}
void b64_decode(char *b64src, char *clrdst) {
int c, phase, i;
unsigned char in[4];
char *p;
clrdst[0] = '\0';
phase = 0; i=0;
while(b64src[i]) {
c = (int) b64src[i];
if(c == '=') {
decodeblock(in, clrdst);
break;
}
p = strchr(b64, c);
if(p) {
in[phase] = p - b64;
phase = (phase + 1) % 4;
if(phase == 0) {
decodeblock(in, clrdst);
in[0]=in[1]=in[2]=in[3]=0;
}
}
i++;
}
}
/* encodeblock - encode 3 8-bit binary bytes as 4 '6-bit' characters */
void encodeblock( unsigned char in[], char b64str[], int len ) {
unsigned char out[5];
out[0] = b64[ in[0] >> 2 ];
out[1] = b64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
out[2] = (unsigned char) (len > 1 ? b64[ ((in[1] & 0x0f) << 2) |
((in[2] & 0xc0) >> 6) ] : '=');
out[3] = (unsigned char) (len > 2 ? b64[ in[2] & 0x3f ] : '=');
out[4] = '\0';
strncat(b64str, out, sizeof(out));
}
/* encode - base64 encode a stream, adding padding if needed */
void b64_encode(char *clrstr, char *b64dst) {
unsigned char in[3];
int i, len = 0;
int j = 0;
b64dst[0] = '\0';
while(clrstr[j]) {
len = 0;
for(i=0; i<3; i++) {
in[i] = (unsigned char) clrstr[j];
if(clrstr[j]) {
len++; j++;
}
else in[i] = 0;
}
if( len ) {
encodeblock( in, b64dst, len );
}
}
}
void sig_chld(int signo) //child
{
pid_t pid;
int stat;
while((pid = waitpid(-1, &stat, WNOHANG))>0)
printf("child %d terminated\n", pid);
return;
}
int main()
{
int listen_sock, conn_sock;
int server_len, client_len,choice;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
char myb64[1024] = ""; //encode
char mydst[1024] = ""; //decode
int sentBytes,revedBytes,bytes_readi;
char buff[1024]; //buffer to send data
listen_sock = socket(AF_INET, SOCK_STREAM, 0); //create socket
if (listen_sock == -1)
{
printf("ERROR opening socket\n");
return 0;
}
printf("Socket done\n");
//Thiet lap dia chi server
server_address.sin_family = AF_INET; //default
inet_aton("127.0.0.1",&server_address.sin_addr); //ip server
server_address.sin_port = htons(5500); // port server
server_len = sizeof(server_address);
if(bind(listen_sock, (struct sockaddr *)&server_address,server_len)<0)
{
printf("ERROR on binding\n");
return 0;
}
printf("Bind done\n");
int check = listen(listen_sock,10);
if (check == -1)
{
printf("Error connect");
return 0;
}
printf("Waiting connect..\n");
while(1) {
client_len = sizeof(client_address);
conn_sock = accept(listen_sock,(struct sockaddr *)&client_address, &client_len);
if(conn_sock==-1){
printf("Error connect\n");
return 1;
}else{
printf("Accept new connection\n");
}
if(fork() == 0){
close(listen_sock);
do{
revedBytes = recv(conn_sock,buff,1024,0);
buff[revedBytes]='\0';
if(strcmp(buff,"mahoa")==0) choice=1;
else if(strcmp(buff,"giaima")==0) choice=2; else choice = 3;
switch(choice)
{
case 1:
while((revedBytes = recv(conn_sock,buff,1024,0)) > 0){
buff[revedBytes]='\0';
//printf("string send by client encode : %s\n",buff);
b64_encode(buff, myb64); //ma hoa
sentBytes=send(conn_sock,myb64,1024,0); //gui lai string da ma hoa cho client
}
close(conn_sock);//Dong ket noi cua client
exit(0);
break;
case 2:
while((revedBytes = recv(conn_sock,buff,1024,0)) > 0){
buff[revedBytes]='\0';
//printf("string send by client decode: %s\n",buff);
b64_decode(buff,mydst); // giaima
sentBytes=send(conn_sock,mydst,1024,0);
}
close(conn_sock);
exit(0);
break;
case 3:break;
}
}while(choice!=3);
break;
}
signal(SIGCHLD,sig_chld);
close(conn_sock);
}
return 1;
}
I know there is an Objective-C wrapper around YAJL, but this is a really fat thing which blows up the whole JASON parser to a ridiculous huge amount of 21 files, many of them with tiny scroll bars.
So to keep my app binary small I'd like to stick with the C-version of that parser. But I'm having a hard time finding any useful documentation for this rather than the wrapper.
Maybe someone who used the C-base can point out such a tutorial or documentation?
The documentation with C examples can be found here: http://lloyd.github.com/yajl/
The github repository with examples can be found here : https://github.com/lloyd/yajl
Here is a C example that reformats JSON from stdin:
#include <yajl/yajl_parse.h>
#include <yajl/yajl_gen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int reformat_null(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_null(g);
}
static int reformat_boolean(void * ctx, int boolean)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_bool(g, boolean);
}
static int reformat_number(void * ctx, const char * s, size_t l)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_number(g, s, l);
}
static int reformat_string(void * ctx, const unsigned char * stringVal,
size_t stringLen)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_string(g, stringVal, stringLen);
}
static int reformat_map_key(void * ctx, const unsigned char * stringVal,
size_t stringLen)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_string(g, stringVal, stringLen);
}
static int reformat_start_map(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_map_open(g);
}
static int reformat_end_map(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_map_close(g);
}
static int reformat_start_array(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_array_open(g);
}
static int reformat_end_array(void * ctx)
{
yajl_gen g = (yajl_gen) ctx;
return yajl_gen_status_ok == yajl_gen_array_close(g);
}
static yajl_callbacks callbacks = {
reformat_null,
reformat_boolean,
NULL,
NULL,
reformat_number,
reformat_string,
reformat_start_map,
reformat_map_key,
reformat_end_map,
reformat_start_array,
reformat_end_array
};
static void
usage(const char * progname)
{
fprintf(stderr, "%s: reformat json from stdin\n"
"usage: json_reformat [options]\n"
" -m minimize json rather than beautify (default)\n"
" -u allow invalid UTF8 inside strings during parsing\n",
progname);
exit(1);
}
int
main(int argc, char ** argv)
{
yajl_handle hand;
static unsigned char fileData[65536];
/* generator config */
yajl_gen g;
yajl_status stat;
size_t rd;
int retval = 0;
int a = 1;
g = yajl_gen_alloc(NULL);
yajl_gen_config(g, yajl_gen_beautify, 1);
yajl_gen_config(g, yajl_gen_validate_utf8, 1);
/* ok. open file. let's read and parse */
hand = yajl_alloc(&callbacks, NULL, (void *) g);
/* and let's allow comments by default */
yajl_config(hand, yajl_allow_comments, 1);
/* check arguments.*/
while ((a < argc) && (argv[a][0] == '-') && (strlen(argv[a]) > 1)) {
unsigned int i;
for ( i=1; i < strlen(argv[a]); i++) {
switch (argv[a][i]) {
case 'm':
yajl_gen_config(g, yajl_gen_beautify, 0);
break;
case 'u':
yajl_config(hand, yajl_dont_validate_strings, 1);
break;
default:
fprintf(stderr, "unrecognized option: '%c'\n\n",
argv[a][i]);
usage(argv[0]);
}
}
++a;
}
if (a < argc) {
usage(argv[0]);
}
for (;;) {
rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin);
if (rd == 0) {
if (!feof(stdin)) {
fprintf(stderr, "error on file read.\n");
retval = 1;
}
break;
}
fileData[rd] = 0;
stat = yajl_parse(hand, fileData, rd);
if (stat != yajl_status_ok) break;
{
const unsigned char * buf;
size_t len;
yajl_gen_get_buf(g, &buf, &len);
fwrite(buf, 1, len, stdout);
yajl_gen_clear(g);
}
}
stat = yajl_complete_parse(hand);
if (stat != yajl_status_ok) {
unsigned char * str = yajl_get_error(hand, 1, fileData, rd);
fprintf(stderr, "%s", (const char *) str);
yajl_free_error(hand, str);
retval = 1;
}
yajl_gen_free(g);
yajl_free(hand);
return retval;
}
How to get a substring of a string in Mips?
Just get a cross compiler, code it in C and get the output assembly. You can use the -S option if using gcc.
For example:
root#:~/stackoverflow# cat strstr.c
#include <string.h>
/*
* Find the first occurrence of find in s.
*/
char *
strstr(const char *s, const char *find)
{
char c, sc;
size_t len;
if ((c = *find++) != 0) {
len = strlen(find);
do {
do {
if ((sc = *s++) == 0)
return (NULL);
} while (sc != c);
} while (strncmp(s, find, len) != 0);
s--;
}
return (s);
}
root#:~/stackoverflow# gcc -S -mrnames
strstr.c -o strstr.s
strstr.c: In function `strstr':
strstr.c:23: warning: return discards qualifiers from pointer target type
root#:~/stackoverflow#