I need to implement my own packets to send over UDP. I decided that I would do this by sending a char buffer which has the sequence number, checksum, size, and the data of the packet which is bytes from a file. The string i'm sending separates each field by a semicolon. Then, when I receive the string (which is my packet) I want to extract each felid, use them accordingly (the sequence number, size, and checksum) and write the bytes to a file. So far I have wrote a method to create 100 packets, and I'm trying to extract and write the bytes to a file (I'm not doing it in the receiver yet, first I'm testing the parsing in the sender). For some reason, the bytes written to my file are incorrect and I'm getting "JPEG DATATSTREAM CONTAINS NO IMAGE" error when I try to open it.
struct packetNode{
char packet[1052]; // this is the entire packet data including the header
struct packetNode *next;
};
This is how I'm creating my packets:
//populate initial window of size 100
for(i = 0; i < 100; i++){
memset(&data[0], 0, sizeof(data));
struct packetNode *p; // create packet node
p = (struct packetNode *)malloc(sizeof(struct packetNode));
bytes = fread(data, 1, sizeof(data), fp); // read 1024 bytes from file into data buffer
int b = fwrite(data, 1, bytes, fpNew);
printf("read: %d\n", bytes);
memset(&p->packet[0], 0, sizeof(p->packet));
sprintf(p->packet, "%d;%d;%d;%s", s, 0, numPackets, data); // create packet
//calculate checksum
int check = checksum8(p->packet, sizeof(p->packet));
sprintf(p->packet, "%d;%d;%d;%s", s, check, numPackets, data); //put checksum in packet
s++; //incremenet sequence number
if(i == 0){
head = p;
tail = p;
tail->next = NULL;
}
else{
tail->next = p;
tail = p;
tail->next = NULL;
}
}
fclose(fp);
and this is where I parse and write the bytes to a file:
void test(){
FILE *fpNew = fopen("test.jpg", "w");
struct packetNode *ptr = head;
char *tokens;
int s, c, size;
int i = 0;
char data[1024];
while(ptr != NULL){
memset(&data[0], 0, sizeof(data));
tokens = strtok(ptr->packet,";");
s = atoi(tokens);
tokens = strtok(NULL, ";");
c = atoi(tokens);
tokens = strtok(NULL, ";");
size = atoi(tokens);
tokens = strtok(NULL, ";");
if(tokens != NULL)
strcpy(data, tokens);
printf("sequence: %d, checksum: %d, size: %d\n", s,c,size);
int b = fwrite(data, 1, sizeof(data), fpNew);
ptr = ptr->next;
i++;
}
fclose(fpNew);
}
Since there is transfer of binary data, a JPEG stream, this data cannot be treated as a string. It's better to go all binary. For instance, instead of
sprintf(p->packet, "%d;%d;%d;%s", s, 0, numPackets, data); // create packet
you would do
sprintf(p->packet, "%d;%d;%d;", s, 0, numPackets);
memcpy(&p->packet[strlen(p->packet)], data, bytes);
but this leads to parsing problems: we would need to change this:
tokens = strtok(NULL, ";");
if(tokens != NULL)
strcpy(data, tokens);
to something like this:
tokens += 1 + ( size < 10 ? 1 : size < 100 ? 2 : size < 1000 ? 3 : size < 10000 ? 4 : 5 );
memcpy(data, tokens, sizeof(data));
#Binary Protocol
It's easier to use a binary packet:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma push(pack,1)
typedef struct Packet {
int seq, maxseq, size;
unsigned short cksum;
unsigned char payload[];
} Packet;
#pragma pop(pack)
typedef struct PacketNode{
struct PacketNode * next;
Packet packet;
} PacketNode;
PacketNode * allocPacketNode(int maxPayloadSize) {
void * ptr = malloc(sizeof(PacketNode) + maxPayloadSize); // FIXME: error checking
memset(ptr, 0, sizeof(PacketNode) + maxPayloadSize); // mallocz wouldn't cooperate
return (PacketNode*) ptr;
}
PacketNode * prepare(FILE * fp, int fsize, int chunksize)
{
PacketNode * head = allocPacketNode(chunksize);
PacketNode * pn = head;
int rd, seq = 0;
int maxseq = fsize / chunksize + ( fsize % chunksize ? 1 : 0 );
while ( ( rd = fread(pn->packet.payload, 1, chunksize, fp ) ) > 0 )
{
printf("read %d bytes\n", rd);
pn->packet.seq = seq++;
pn->packet.maxseq = maxseq;
pn->packet.size = rd + sizeof(Packet);
pn->packet.cksum = 0;
pn->packet.cksum = ~checksum(&pn->packet, pn->packet.size);
if ( rd == chunksize )
pn = pn->next = allocPacketNode(chunksize);
}
return head;
}
int checksum(unsigned char * data, int len)
{
int sum = 0, i;
for ( i = 0; i < len; i ++ )
sum += data[i];
if ( sum > 0xffff )
sum = (sum & 0xffff) + (sum>>16);
return sum;
}
void test( PacketNode * ptr ) {
FILE *fpNew = fopen("test.jpg", "w");
while (ptr != NULL)
{
printf("sequence: %d/%d, checksum: %04x, size: %d\n",
ptr->packet.seq,
ptr->packet.maxseq,
ptr->packet.cksum,
ptr->packet.size - sizeof(Packet)
);
int b = fwrite(ptr->packet.payload, ptr->packet.size - sizeof(Packet), 1, fpNew);
ptr = ptr->next;
}
fclose(fpNew);
}
void fatal( const char * msg ) { printf("FATAL: %s\n", msg); exit(1); }
int main(int argc, char** argv)
{
if ( ! argv[1] ) fatal( "missing filename argument" );
FILE * fp = fopen( argv[1], "r" );
if ( ! fp ) fatal( "cannot open file" );
fseek( fp, 0, SEEK_END );
long fsize = ftell(fp);
fseek( fp, 0, SEEK_SET );
printf("Filesize: %d\n", fsize );
test( prepare(fp, fsize, 1024) );
}
The #pragma push(pack,1) changes how the compiler aligns fields of the struct. We want them to be compact, for network transport. Using 1 is byte-aligned. The #pragma pop(pack) restores the previous setting of the pack pragma.
A note on the checksum method
First we calculate the sum of all the bytes in the packet:
int sum = 0, i;
for ( i = 0; i < len; i ++ )
sum += data[i];
Since the packet uses an unsigned short (16 bits, max value 65535 or 0xffff) to store the checksum, we make sure that the result will fit:
if ( sum > 0xffff ) // takes up more than 16 bits.
Getting the low 16 bits of this int is done using sum & 0xffff, masking out everything but the low 16 bits. We could simply return this value, but we would loose the information from higher checksum bits. So, we will add the upper 16 bits to the lower 16 bits. Accessing the higher 16 bits is done by shifting the int to the right 16 bits, like so: sum >> 16. This is the same as sum / 65536, since 65536 = 216 = 1 << 16.
sum = (sum & 0xffff) + (sum>>16); // add low 16 bits and high 16 bits
I should note that network packet checksums are usually computed 2 bytes (or 'octets' as they like to call them there) at a time. For that, the data should be cast to an unsigned short *, and len should be divided by 2. However! len may be odd, so in that case we'll need to take special care of the last byte. For instance, assuming that the maximum packet size is even, and that the len argument is always <= max_packet_size:
unsigned short * in = (unsigned short *) data;
if ( len & 1 ) data[len] = 0; // make sure last byte is 0
len = (len + 1) / 2;
The rest of the checksum method can remain the same, except that it should operate on in instead of data.
Hello I am writing my program in C, using PSoC tools to program my Cypress development kit. I am facing an issue regarding type conversion of a string of characters collected in my circular buffer (buffer) to a local variable "input_R", ultimately to a global variable st_input_R. The event in my FSM calling this action function is given below:
void st_state_5_event_0(void) //S6 OR S4
{
char buffer[ST_NODE_LIMIT] = {0};
st_copy_buffer(buffer);
uint32 input_R = {0};
mi_utoa(input_R, buffer);
if ((input_R >= 19000) && (input_R <= 26000))
{
st_input_R = input_R;
_st_data.state = ST_STATE_6;
}
else
{
_st_data.status = ST_STATE_4;
}
UART_1_Stop();
st_stop();
st_empty_buffer();
}
ST_NODE_LIMIT = 64
st_copy_buffer copies the the numbers I type in using hyper terminal to the circular buffer named "buffer".
input_R is the 32 bit integer I want the buffer content to be converted to.
mi_utoa is the function I am using for converting the contents in the buffer to input_R and is detailed below:
uint8 mi_utoa(uint32 number, char *string)
{
uint8 result = MI_BAD_ARGUMENT;
if (string != NULL)
{
uint8 c = 0;
uint8 i = 0;
uint8 j = 0;
do
{
string[i++] = number % 10 + '0';
} while ((number /=10) > 0);
string[i] = '\0';
for (i = 0, j = strlen(string) - 1 ; i < j ; i++, j--)
{
c = string[i];
string[i] = string[j];
string[j] = c;
}
result = MI_SUCCESS;
}
return result;
}
The problem is, suppose if I enter 21500(+\r), the mi_utoa function converts the first digit to 0 the second digit to \000 while the other digits including the carriage return "\r" remains unaltered. As a result the input_R is NOT = 21500. Its happening for any string of digits I input. So the condition "if ((input_R >= 19000) && (input_R <= 26000))" is never satisfied. Hence the FSM returns to state 4 all the time and I am going in circles.
Can you please advice where the bug is in the mi_utoa function? Let me know if you want to know any other details.
Your function st_state_5_event_0() sets the value input_R to zero. Then you call mi_utoa(), which converts the value input_R to an ascii string, "0".
void st_state_5_event_0(void) //S6 OR S4
{
char buffer[ST_NODE_LIMIT] = {0};
//what is the value of buffer after this statement?
st_copy_buffer(buffer);
//the value of input_R after the next statement is =0
uint32 input_R = {0};
//conversion of input_R to string will give ="0"
mi_utoa(input_R, buffer);
if ((input_R >= 19000) && (input_R <= 26000))
{
st_input_R = input_R;
_st_data.state = ST_STATE_6;
}
//...
}
You probably want a function which converts your ascii buffer to a number.
uint8
mi_atou(uint32* number, char *string)
{
uint8 result = MI_BAD_ARGUMENT;
if (!string) return result;
if (!number) return result;
uint8 ndx = 0;
uint32 accum=0;
for( ndx=0; string[ndx]; ++ndx )
{
if( (string[ndx] >= '0') && (string[ndx] <= '9') )
{
accum = accum*10 + (string[ndx]-'0');
//printf("[%d] %s -> %d\n",ndx,string,accum);
}
else break;
}
//printf("[%d] %s -> %d\n",ndx,string,accum);
*number = accum;
result = MI_SUCCESS;
return result;
}
Which you would call by providing the address of the number to store the result,
mi_atou(&input_R, buffer);
I have two CVImageBufferRef buffers that correspond to two images grabbed in sequence by AVCaptureSession. I would like to compare both to see if all the pixels are the same. In order to loop thru all pixels of the frame buffer and compare them, I have this:
unsigned char *pixelA = (unsigned char *)CVPixelBufferGetBaseAddress(pixelBufferA);
unsigned char *pixelB = (unsigned char *)CVPixelBufferGetBaseAddress(pixelBufferB);
- (BOOL) isBuffer:(unsigned char *)pixelA equalToBuffer:(unsigned char *)pixelB {
for( int row = 0; row < bufferHeight; row++ ) {
for( int column = 0; column < bufferWidth; column++ ) {
if ((pixelA[0] != pixelB[0]) ||
(pixelA[1] != pixelB[1]) ||
(pixelA[2] != pixelB[2]) ){
return NO;
// means at some point pixelA is not equal to pixelB, so
// pixelBufferA is not equal to pixelBufferB
}
pixelA += BYTES_PER_PIXEL;
pixelB += BYTES_PER_PIXEL;
}
}
// if the method reached here, pixelBufferA is equal to pixelBufferB, so
return YES; // are equal
}
Obviously it is crashing in the comparison. How do I compare all values in pixelA with pixelB ? thanks
I've never actually done what you're doing, but is there a reason you can't just compare the buffers in one go, say, with memcmp?
- (BOOL) isBuffer:(unsigned char*)pixelA equalToBuffer:(unsigned char*)pixelB
{
size_t bufferSize = bufferWidth * bufferHeight * BYTES_PER_PIXEL;
return memcmp( pixelA, pixelB, bufferSize ) == 0;
}
The following is extremely slow for what I need.
CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), i);
Currently this takes 20,000ns in my tests to execute on my 3gs. Perhaps that sounds fast, but I can create and release two NSMutableDictionaries in the time this executes. My C is weak, but there must be something equivalent to itoa that I can use on IOS.
This is the faster I can get:
CFStringRef TECFStringCreateWithInteger(NSInteger integer)
{
size_t size = 21; // long enough for 64 bits integer
char buffer[size];
char *characters = buffer + size;
*(--characters) = 0; // NULL-terminated string
int sign = integer < 0 ? -1 : 1;
do {
*(--characters) = '0' + (integer % 10) * sign;
integer /= 10;
}
while ( integer );
if ( sign == -1 )
*(--characters) = '-';
return CFStringCreateWithCString(NULL, characters, kCFStringEncodingASCII);
}
I have used the following code for converting the bigint in decimal to bytearray (raw data), but I'm getting wrong result.
What is the mistake here?
I'm trying this in Apple Mac ( for Iphone app)
COMP_BYTE_SIZE is 4
Is there any bigendian/ little endian issue, please Help.
void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
{
int i, j, k = size-1;
check(x);
memset(data, 0, size); /* ensure all leading 0's are cleared */
for (i = 0; i < x->size; i++)
{
for (j = 0; j < COMP_BYTE_SIZE; j++)
{
comp mask = 0xff << (j*8);
int num = (x->comps[i] & mask) >> (j*8);
data[k--] = num;
if (k < 0)
{
break;
}
}
}
Thanks.
The argument size is at least x->size*4, ie. the target array is big enough? Also use
comp mask = (comp)0xff << (j*8);
num should be cast to uint8_t before copy
data[k--] = (uint8_t)num;