[SOLVED]atmega 328p with w5500 TCP client - converting long to char array[4]

Go To Last Post
40 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm trying to convert uint32_t to char array[4] - the following code work verrywell on my Qt using QByteArray and qint32 but on atmega 328p using uint32_t and char array[4] is not doing anything

 

void intTo4Char(unsigned char intChar[4], const uint32_t num ){
	intChar[0] = (char)((num>>24) & 0xFF);
	intChar[1] = (char)((num>>16) & 0xFF);
	intChar[2] = (char)((num>>8) & 0xFF);
	intChar[3] = (char)(num & 0xFF);
}

then I try to concatenate the 2 char arrays

 

void concatChars(unsigned char* ch1, uint16_t len1, unsigned char* ch2, uint16_t len2, unsigned char* conChar){

	for(int i=0; i<len1; i++)
		conChar[i] = ch1[i];
	for(int n = 0; n<len2; n++)
		conChar[len1+n] = ch2[n];
}

it seams that atmega328p have a different aproch to char then an intel proccessor - does enyone know how I could make a long to 4 bytes char? - I need this in order to send info over the network - wish to send first the length of the message - has to be 4 bytes and then the message itself

 

Thanking you all

P.S. this is first time posting here

This topic has a solution.
Last Edited: Fri. Oct 4, 2019 - 02:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

You need to show more code, in particular the code that is calling these functions.

And what do you mean by "is not doing anything".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok... here you have it

 
#include "atp_tcpClient.h"
#include "Ethernet/wizchip_conf.h"
#include "Ethernet/socket.h"

#include "../atmega328p/atp_uart.h"
#include <util/delay.h>
#include <stdint.h>
#include <string.h>

/*
 * @brief read function
 * @param  n : pointer to a Network structure
 *         that contains the configuration information for the Network.
 *         buffer : pointer to a read buffer.
 *         len : buffer length.
 * @retval received data length or SOCKERR code
 */

uint16_t charLength(unsigned char* buffer){
	uint16_t len = 0;
	while(buffer[len] != 0x00){
		len++;
	}
	return len;
}

void intTo4Char(unsigned char intChar[4], const uint32_t num ){
	//TODO nu merge mai departe???
	#if APPTYPE == 1
	atpUartSendAll("num: %d A: %c B: %c C: %c D: %c \r\n", num, ((num >> 24) & 0xFF), (char)((num >> 16) & 0xFF), ((num >> 8) & 0xFF), (num & 0xFF));
	#endif
	
	intChar[0] = (char)((num>>24) & 0xFF);
	intChar[1] = (char)((num>>16) & 0xFF);
	intChar[2] = (char)((num>>8) & 0xFF);
	intChar[3] = (char)(num & 0xFF);
}

void concatChars(unsigned char* ch1, uint16_t len1, unsigned char* ch2, uint16_t len2, unsigned char* conChar){

	for(int i=0; i<len1; i++)
		conChar[i] = ch1[i];
	for(int n = 0; n<len2; n++)
		conChar[len1+n] = ch2[n];
}

int atpTcpClientRead(uint8_t sn, unsigned char* buffer, int len) {

	if((getSn_SR(sn) == SOCK_ESTABLISHED) && (getSn_RX_RSR(sn)>0))
		return recv(sn, buffer, len);

	return SOCK_ERROR;
}

int atpTcpClientWriteOnly(uint8_t sn, unsigned char* buffer, int len) {
	if(getSn_SR(sn) == SOCK_ESTABLISHED)
		return send(sn, buffer, len);
	return SOCK_ERROR;
}

int atpTcpClientWrite(uint8_t sn, unsigned char* buffer) {
	uint16_t len = charLength(buffer);
	unsigned char lenChar[4];
	intTo4Char(lenChar, len);
	unsigned char toSend[len+4];
	concatChars(lenChar, 4, buffer, len, toSend);
	uint16_t lenToSend = charLength(toSend);
	#if APPTYPE == 1
	atpUartSendAll("len: %d buffer: %s lenChar: %s toSend: %s lenToSend: %d\r\n", len, buffer, lenChar, toSend, lenToSend);
	atpUartSendText(lenChar);
	atpUartSendText(toSend);
	
	atpUartSendStrings(lenChar);
	atpUartSendStrings(toSend);
	#endif
	
	return atpTcpClientWriteOnly(sn, toSend, lenToSend);
}

/*
 * @brief disconnect function
 * @param  n : pointer to a Network structure
 *         that contains the configuration information for the Network.
 */
void atpTcpClientDisconnect(uint8_t sn) {
	disconnect(sn);
}

/*
 * @brief connect network function
 * @param  n : pointer to a Network structure
 *         that contains the configuration information for the Network.
 *         ip : server iP.
 *         port : server port.
 */
int32_t atpTcpClientConnect(uint8_t sn, uint8_t* destip, uint16_t destport) {

    int32_t ret; // return value for SOCK_ERRORs

    static uint16_t any_port = 	50000; // Port number for TCP client (will be increased)
    
    socket(sn, Sn_MR_TCP, any_port, SF_TCP_NODELAY);
	connect(sn, destip, destport);

    // Socket Status Transitions
    // Check the W5500 Socket n status register (Sn_SR, The 'Sn_SR' controlled by Sn_CR command or Packet send/recv status)
  
        switch(getSn_SR(sn)) {
            case SOCK_ESTABLISHED :
                if(getSn_IR(sn) & Sn_IR_CON) {// Socket n interrupt register mask; TCP CON interrupt = connection with peer is successful
                    #if APPTYPE == 1
                        atpUartSendAll("%d:Connected to - %d.%d.%d.%d : %u\r\n",sn, destip[0], destip[1], destip[2], destip[3], destport);
                    #endif
                    setSn_IR(sn, Sn_IR_CON);  // this interrupt should be write the bit cleared to '1'
                }

                break;

            case SOCK_CLOSE_WAIT :
                #if APPTYPE == 1
                    atpUartSendAll("%d:CloseWait\r\n",sn);
                #endif
                if((ret=disconnect(sn)) != SOCK_OK)
                    return ret;
                #if APPTYPE == 1
                    atpUartSendAll("%d:Socket Closed\r\n", sn);
                #endif
                break;

            case SOCK_INIT :
                #if APPTYPE == 1
                    atpUartSendAll("%d:Try to connect to the %d.%d.%d.%d : %u\r\n", sn, destip[0], destip[1], destip[2], destip[3], destport);
                #endif
                if( (ret = connect(sn, destip, destport)) != SOCK_OK)
                    return ret;	//	Try to TCP connect to the TCP server (destination)
                break;

            case SOCK_CLOSED:
                #if APPTYPE == 1
                    atpUartSendAll("%d:Soxcket closed - e inchis\r\n", sn);
                #endif
                close(sn);
                if((ret=socket(sn, Sn_MR_TCP, any_port++, SF_TCP_NODELAY)) != sn) {
                    if(any_port == 0xffff) any_port = 50000;
                        return ret; // TCP socket open with 'any_port' port number
                } 
                #if APPTYPE == 1
                    atpUartSendAll("%d:TCP client loopback start\r\n",sn);
                    atpUartSendAll("%d:Socket opened\r\n",sn);
                #endif
                break;
            default:
                break;
        }

    return 1;
}

by not doing anything... it means that when I try to print out the chars that supose to be

source 512 temp "\x00\x00\x02\x00"

 is printing nothing -

here you have a short version in Qt that is working

#include <QCoreApplication>
#include <QByteArray>
#include <QDataStream>
#include <QDebug>


QByteArray IntToArray(qint32 source) { //Use qint32 to ensure that the number have 4 bytes

    //Avoid use of cast, this is the Qt way to serialize objects
    qDebug() << "array to int";
    QByteArray temp;
    QDataStream data(&temp, QIODevice::ReadWrite);
    data.setVersion(QDataStream::Qt_5_12);
    data << source;
    qDebug() << "data: " << data << "source" << source << "temp" << temp;
    return temp;
}

qint32 ArrayToInt(QByteArray source) {
    qDebug() << "array to int";
    qint32 temp;
    QDataStream data(&source, QIODevice::ReadWrite);
    data.setVersion(QDataStream::Qt_5_12);
    data >> temp;
    return temp;
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    qDebug() << IntToArray(512);
    QByteArray test;
    int i = 512;
    test[0] = (i>>24) & 0xFF;
    test[1] = (i>>16) & 0xFF;
    test[2] = (i>>8) & 0xFF;
    test[3] = i & 0xFF;

    qDebug() << "test" << test;
    qDebug() << ArrayToInt(test);




    return a.exec();
}

so.. why is this diference??

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

arsinte_andrei@yahoo.com wrote:

        unsigned char toSend[len+4];
	concatChars(lenChar, 4, buffer, len, toSend);
	uint16_t lenToSend = charLength(toSend);

I don't think the toSend array will be null terminated, so charLength won't work.

(There are standard library C functions to do some of what you're doing eg. strlen()).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

arsinte_andrei@yahoo.com wrote:
 is printing nothing -
What does that mean? You haven't shown the implementation  but we see various calls to:

atpUartSendAll("num: %d A: %c B: %c C: %c D: %c \r\n", num, ((num >> 24) & 0xFF), (char)((num >> 16) & 0xFF), ((num >> 8) & 0xFF), (num & 0xFF));
atpUartSendAll("len: %d buffer: %s lenChar: %s toSend: %s lenToSend: %d\r\n", len, buffer, lenChar, toSend, lenToSend);
atpUartSendAll("%d:Connected to - %d.%d.%d.%d : %u\r\n",sn, destip[0], destip[1], destip[2], destip[3], destport);
atpUartSendAll("%d:Try to connect to the %d.%d.%d.%d : %u\r\n", sn, destip[0], destip[1], destip[2], destip[3], destport);
atpUartSendAll("%d:TCP client loopback start\r\n",sn);
atpUartSendAll("%d:Socket opened\r\n",sn);

I am guessing that atpUartSendAll() is a variadic function a bit like printf() (kind of makes me wonder why you don't actually use printf() ??) so are you saying that none of these calls produces ANY output when you say:

arsinte_andrei@yahoo.com wrote:
 is printing nothing -

Surely that just means your UART routines need work?

 

Or by "nothing" did you really mean "something". That these output the text bits but the variadic number parts are not the values you expect?

 

In engineering you need to be very specific when describing things: "printing nothing" (unless you really do mean "nothing at all"?) is a very vague fault report.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
what do you mean by "is not doing anything".

Indeed!

 

You should be able to see exactly what is happening by stepping this in the debugger ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

arsinte_andrei@yahoo.com wrote:

	unsigned char toSend[len+4];

Also, since len + 4 is not a constant expression, this is presumably a variable length array (introduced in C99?)

Something I've never used and don't have time to look it up now. It might have some other implications.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok..here you have what I mean by not doin nothing...

10:50:52.027 ->  0000000000:Soxcket closed - e inchis
10:50:52.094 -> 0000000000:TCP client loopback start
10:50:52.094 -> 0000000000:Socket opened
10:50:52.127 -> Val connSts : 1 , writeSts :  0000000000
10:50:52.193 ->  num: 5 A:  

that is the serial monitor.

I do not use printf- I do not know how to redirect my uart chars there...

this is my uart file

 

#include <stdarg.h>

#include "atp_uart.h"

void atpUartSetup(void){
	
	/* Set Baudrate  */
	UBRR0H = (unsigned char)(BAUDRATE>>8); // Shift the 16bit value ubrr 8 times to the right and transfer the upper 8 bits to UBBR0H register.
	UBRR0L = (unsigned char)BAUDRATE;    // Copy the 16 bit value ubrr to the 8 bit UBBR0L register,Upper 8 bits are truncated while lower 8 bits are copied
    
    UCSR0B = (1<<RXEN0)|(1<<TXEN0); /*Enable receiver and transmitter*/
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);/*Set frame format: 8data, 2stop bit*/
}

void atpUartSendChar(unsigned char data){

 		while (!( UCSR0A & (1<<UDRE0)));  /* Wait for empty transmit buffer       */
 		UDR0 = data;				      /* Put data into buffer, sends the data */

}

void atpUartSendText(unsigned char data[]) {
    int i = 0;
    while(data[i] != 0) {
        atpUartSendChar(data[i]);
        i++;
    }

    /* Sending '\n'  '\r' Character pair helps to format the output properly on console putty Screen */
	/*************************************************************************************************/
	/* Send "\n" Character */
	 while (!( UCSR0A & (1<<UDRE0)));   /* Wait for empty transmit buffer       */
	 UDR0 = '\n';					    /* Put data into buffer, sends the data */
	
	/* Send "\r" Character */
	 while (!( UCSR0A & (1<<UDRE0)));   /* Wait for empty transmit buffer       */
	 UDR0 = '\r';					    /* Put data into buffer, sends the data */
	/*------------------------------------------------------------------------------------------------*/
        
}

void atpUartSendStrings(char *myText){
    while(*myText)
        atpUartSendChar(*myText++);
}

void atpUartSendNumber(uint8_t numBase, uint32_t number, uint8_t noOfDigit){
    
    uint8_t i = 0, a[10];
    
    if(numBase == ATP_BINARY){
        while(noOfDigit != 0){
            i = util_GetBitStatus(number, (noOfDigit-1));
            atpUartSendChar(util_Dec2Ascii(i));
            noOfDigit--;
        }
    } else if(number == 0) {
        /* If the number is zero then update the array with the same for transmitting */
        for(i=0;((i<noOfDigit) && (i<MaxDigitsToTransmit)) ;i++)
            atpUartSendChar('0');
    } else {
        for(i = 0; i < noOfDigit; i++) {
            if(number != 0) {
                a[i] = util_GetMod32(number,numBase);
                number = number/numBase;
            } else if( (noOfDigit == DefaultDigitsToTransmit) || (noOfDigit > MaxDigitsToTransmit)) {
                /* Stop the iteration if the Max number of digits are reached or
                 the user expects exact(Default) digits in the number to be transmitted */ 
                break;
            } else {
                /*In case user expects more digits to be transmitted than the actual digits in number,
                  then update the remaining digits with zero.
                Ex: v_number_u32 is 123 and user wants five digits then 00123 has to be transmitted */
                a[i]=0;
            }
        }
        while(i) {
            atpUartSendChar(util_Hex2Ascii(a[i-1]));
            i--;
        }
    }
}

void atpUartSendFloat(float floatNumber){
    uint32_t tempNumber;
	/* Dirty hack to support the floating point by extracting the integer and fractional part.
      1.Type cast the number to int to get the integer part.
	  2.transmit the extracted integer part followed by a decimal point(.).
	  3.Later the integer part is made zero by subtracting with the extracted integer value.
	  4.Finally the fractional part is multiplied by 100000 to support 6-digit precision */

	tempNumber = (uint32_t) floatNumber;
	atpUartSendNumber(ATP_DECIMAL,tempNumber,DefaultDigitsToTransmit);

	atpUartSendChar('.');

	floatNumber = floatNumber - tempNumber;
	tempNumber = floatNumber * 1000000;
	atpUartSendNumber(ATP_DECIMAL, tempNumber,DefaultDigitsToTransmit);
}

void atpUartSendAll(const char *argList, ...) {
	const char *ptr;
	va_list argp;
	sint16_t v_num_s16;
	sint32_t v_num_s32;
	uint16_t v_num_u16;
	uint32_t v_num_u32;
	char *str;
	char  ch;
	uint8_t v_numOfDigitsToTransmit_u8;
	double v_floatNum_f32;

	va_start(argp, argList);

	/* Loop through the list to extract all the input arguments */
	for(ptr = argList; *ptr != '\0'; ptr++) {

		ch= *ptr;
		if(ch == '%') {         /*Check for '%' as there will be format specifier after it */
		    ptr++;
		    ch = *ptr;
		   if((ch>=0x30) && (ch<=0x39)) {
			   v_numOfDigitsToTransmit_u8 = 0;
			   while((ch>=0x30) && (ch<=0x39)) {
				   v_numOfDigitsToTransmit_u8 = (v_numOfDigitsToTransmit_u8 * 10) + (ch-0x30);
				   ptr++;
				   ch = *ptr;
				}
			} else {
			  v_numOfDigitsToTransmit_u8 = MaxDigitsToTransmitUsingPrintf;
			}

			switch(ch) {       /* Decode the type of the argument */
                case 'C':
                case 'c':     /* Argument type is of char, hence read char data from the argp */
                    ch = va_arg(argp, int);
                    atpUartSendChar(ch);
                    break;

                case 'd':    /* Argument type is of signed integer, hence read 16bit data from the argp */
                    v_num_s16 = va_arg(argp, sint16_t);
                    if(v_num_s16<0) { /* If the number is -ve then display the 2's complement along with '-' sign */ 
                        v_num_s16 = -v_num_s16;
                        atpUartSendChar('-');
                    }
                    atpUartSendNumber(ATP_DECIMAL, v_num_s16, v_numOfDigitsToTransmit_u8);
                    break;

                case 'D':    /* Argument type is of integer, hence read 16bit data from the argp */
                    v_num_s32 = va_arg(argp, sint32_t);				
                    if(v_num_s32<0) { /* If the number is -ve then display the 2's complement along with '-' sign */
                        v_num_s32 = -v_num_s32;
                        atpUartSendChar('-');
                    }
                    atpUartSendNumber(ATP_DECIMAL, v_num_s32, v_numOfDigitsToTransmit_u8);
                    break;	

                case 'u':    /* Argument type is of unsigned integer, hence read 16bit unsigned data */
                    v_num_u16 = va_arg(argp, uint16_t);
                    atpUartSendNumber(ATP_DECIMAL, v_num_u16, v_numOfDigitsToTransmit_u8);
                    break;

                case 'U':    /* Argument type is of integer, hence read 32bit unsigend data */
                    v_num_u32 = va_arg(argp, uint32_t);			
                    atpUartSendNumber(ATP_DECIMAL, v_num_u32, v_numOfDigitsToTransmit_u8);				
                    break;

                case 'x':  /* Argument type is of hex, hence hexadecimal data from the argp */
                    v_num_u16 = va_arg(argp, uint16_t);				
                    atpUartSendNumber(ATP_HEX, v_num_u16, v_numOfDigitsToTransmit_u8);			
                    break;

                case 'X':  /* Argument type is of hex, hence hexadecimal data from the argp */
                    v_num_u32 = va_arg(argp, uint32_t);
                    atpUartSendNumber(ATP_HEX, v_num_u32, v_numOfDigitsToTransmit_u8);
                    break;

                case 'b':  /* Argument type is of binary,Read int and convert to binary */
                    v_num_u16 = va_arg(argp, uint16_t);

                    if(v_numOfDigitsToTransmit_u8 == MaxDigitsToTransmitUsingPrintf)
                        v_numOfDigitsToTransmit_u8 = 16;
               
                    atpUartSendNumber(ATP_BINARY, v_num_u16, v_numOfDigitsToTransmit_u8);			
                    break;

                case 'B':  /* Argument type is of binary,Read int and convert to binary */
                    v_num_u32 = va_arg(argp, uint32_t);			
                
                    if(v_numOfDigitsToTransmit_u8 == MaxDigitsToTransmitUsingPrintf)
                        v_numOfDigitsToTransmit_u8 = 32;		
               
                    atpUartSendNumber(ATP_BINARY, v_num_u32, v_numOfDigitsToTransmit_u8);				
                    break;

                case 'F':
                case 'f': /* Argument type is of float, hence read double data from the argp */
                    v_floatNum_f32 = va_arg(argp, double);
                    atpUartSendFloat(v_floatNum_f32);
                    break;                

                case 'S':
                case 's': /* Argument type is of string, hence get the pointer to sting passed */
                    str = va_arg(argp, char *);
                    atpUartSendStrings(str);
                    break;

                case '%':
                    atpUartSendChar('%');
                    break;
			}
		} else { /* As '%' is not detected transmit the char passed */
            atpUartSendChar(ch);
		}
	}

	va_end(argp);
    
}

unsigned char atpUartReceive(void){
    while (!(UCSR0A & (1<<RXC0))); /* Wait for data to be received */
    return UDR0;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

from serial monitor

10:50:54.711 ->  num: 5 A:  B:  C:  D:

10:50:55.772 -> len: 5 buffer: Salut lenChar:  toSend:  lenToSend: 9

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, again, step through your code in the debugger to see what's going on!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok..let me get back where i do think the problem originate...

Io can not see that this function is working or is doing anything

void intTo4Char(unsigned char intChar[4], const uint32_t num ){
	//TODO nu merge mai departe???
	#if APPTYPE == 1
	atpUartSendAll("num: %d A: %X B: %X C: %X D: %X \r\n", num, ((num >> 24) & 0xFF), (char)((num >> 16) & 0xFF), ((num >> 8) & 0xFF), (num & 0xFF));
	#endif
	
	intChar[0] = (char)((num>>24) & 0xFF);
	intChar[1] = (char)((num>>16) & 0xFF);
	intChar[2] = (char)((num>>8) & 0xFF);
	intChar[3] = (char)(num & 0xFF);
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Change this:

atpUartSendAll("num: %d A: %c B: %c C: %c D: %c \r\n", num, ((num >> 24) & 0xFF), (char)((num >> 16) & 0xFF), ((num >> 8) & 0xFF), (num & 0xFF));

to this:

atpUartSendAll("num: %d A: %02X B: %02X C: %02X D: %02X \r\n", num, ((num >> 24) & 0xFF), (char)((num >> 16) & 0xFF), ((num >> 8) & 0xFF), (num & 0xFF));

and what do you see? Presumably "A: 00 B: 00 C: 00 D: 00" ??

 

So it's not printing nothing, it's printing non-visible 0's (NULs)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ps the implication seems to be that at the invocation of 

void intTo4Char(unsigned char intChar[4], const uint32_t num )

that "num" is just 0. So I don't think the error is in this routine (your >>'s look right) I think it's what delivers into this routine. To test this (as you should test every function in your program using unit tests) by actually using:

intTo4Char(somechars, 0xBABEFACE);

and see what is then output.

 

PS as the thing I think may be wrong is your value passed into intTo4Char I looked at what that was. I see it comes from:

uint16_t charLength(unsigned char* buffer){
	uint16_t len = 0;
	while(buffer[len] != 0x00){
		len++;
	}
	return len;
}

You do know that C has a library function called strlen() don't you? Why would you reinvent it??

Last Edited: Fri. Oct 4, 2019 - 10:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

arsinte_andrei@yahoo.com wrote:
I do not use printf- I do not know how to redirect my uart chars there...

 

https://www.avrfreaks.net/forum/...

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Let me explain to you what I want to achieve... I have a TCP server made in Qt that is leasening to a port. the message has to be in the format 4bytes - length of the message then the messaage of the exact that length. I do this in order to know t5hat I've received the mesasagecomplete and is not something lost down the line... so without this functyion I do receive things there.. but I want to know for shure that what I'm receiving is complete... anything helpfull about it??

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't see that in the code you showed?? In that the thing that prints "num: ...." is:

void intTo4Char(unsigned char intChar[4], const uint32_t num ){
	//TODO nu merge mai departe???
	#if APPTYPE == 1
	atpUartSendAll("num: %d A: %c B: %c C: %c D: %c \r\n", num, ((num >> 24) & 0xFF), (char)((num >> 16) & 0xFF), ((num >> 8) & 0xFF), (num & 0xFF));
	#endif

and the place where that is called is:

int atpTcpClientWrite(uint8_t sn, unsigned char* buffer) {
	uint16_t len = charLength(buffer);
	unsigned char lenChar[4];
	intTo4Char(lenChar, len);

so this is not attempting to print  any received bytes. It is attempting to print the "len" of the byte string ?? If, as I suspect len=0 here then it suggests buffer[0] = 0x00.

 

Why don't you either use a debugWire debugger or just more atpUartSerial() calls to print more details of this. Get atpUartSerial() to print the actual value of "len", Also get it to print the first few bytes of buffer[] with

 

"%02X %02X %0x2X %02X", buffer[0], buffer[1], buffer[2], buffer[3]

 

Life is much easier if you have a debugWire debugger as you can simply breakpoint then inspect all of "len" and "buffer[]" without having to sprinkle printf()s all over the code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The function signature needs to use *intChar not intChar[4].

 

Oops, wrong.   I compiled to assembly and it first showed no code at first.  My bad.

Here the assembly your code generates when I compile it correctly:

.global intTo4Char
        .type   intTo4Char, @function
intTo4Char:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
        movw r30,r24
        st Z,r23
        std Z+1,r22
        std Z+2,r21
        std Z+3,r20
        ret
        .size   intTo4Char, .-intTo4Char
        .ident  "GCC: (GNU) 5.4.0"

 

Last Edited: Fri. Oct 4, 2019 - 01:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use intChar[4] just because I wish to make sure is only 4 bytes an no more that is why...any way after few days spent on this I can confirm that this is working now

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From the K&R bible:

union u_tag {
    uint32_t val;
    char  sval[4];
}u;

Now you can just access the byte you need via u.sval[n]  with out all the shifting!

 

arsinte_andrei@yahoo.com wrote:
it seams that atmega328p have a different aproch to char then an intel proccessor

No just a different processor size (8 bit vs 64 bit mpu)!

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MattRW wrote:
The function signature needs to use *intChar not intChar[4].

No.

 

As you've already discovered, the 2 are equivalent.

 

It could also be just intChar[]

 

arsinte_andrei@yahoo.com wrote:
I use intChar[4] just because I wish to make sure is only 4 bytes an no more

No, it will not do that!

 

'C' will just pass in a pointer - there is no length information, and no bounds checking!

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Fri. Oct 4, 2019 - 01:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

arsinte_andrei@yahoo.com wrote:
I can confirm that this is working now

So, for the benefit of future readers, what was the actual problem, and how did you fix it?

 

Then see Tip #5.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the problem was here

uint16_t len = charLength(buffer);
	unsigned char lenChar[4];
	intTo4Char(lenChar, len);
	uint16_t lenToSend = len+4;
	unsigned char toSend[lenToSend];
	concatChars(lenChar, 4, buffer, len, toSend);
	#if APPTYPE == 1
	atpUartSendAll("len: %d buffer: %s lenChar: %s toSend: %s lenToSend: %d\r\n", len, buffer, lenChar, toSend, lenToSend);
	atpUartSendText(lenChar);
	atpUartSendText(toSend);
	
	atpUartSendStrings(lenChar);
	atpUartSendStrings(toSend);
	#endif
	
	return atpTcpClientWriteOnly(sn, toSend, lenToSend);

if you compare this with the above one you will see the diference - the problem was with my counting for the length - that was always 0 (zero) witch was wrong... lotof thanks for people that advise me to use strlengt insead of re-inventing the wheel...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

arsinte_andrei@yahoo.com wrote:
 lotof thanks for people that advise me to use strlengt insead of re-inventing the wheel...

Please also note this advice:

 

clawson wrote:
Life is much easier if you have a debugWire debugger as you can simply breakpoint then inspect all of "len" and "buffer[]" 

 

awneil wrote:
 step through your code in the debugger to see what's going on! 

 

This would have found the problem in minutes - instead of a day and two dozen posts on the forum!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

ki0bk wrote:
Now you can just access the byte you need via u.sval[n]  with out all the shifting!
This is one occasion where I would disagree with K&R. the shifting solution is the "safe" solution as it does not care about endianism. The union solution does.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
the shifting solution is the "safe" solution

Agreed.

 

It is safe, general, and portable.

 

It also means you won't get bitten by any packing issues if/when you move to a target where that matters.

 

Although very common, the union approach is strictly an abuse.

 

Speaking of wheel reinvention, this is what htonl() et al were invented for ...

 

https://linux.die.net/man/3/htonl

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Seems you figured out the problem.

Basically, you are mixing things that aren't null terminated strings with things that are.

The initial 32 bit number is broken down into 4 bytes, stored in the array in big endian order. This isn't a null terminated string. However, unless your 32 bit number is 0x1000000 or more, the first byte will be 0. So if you do use the array as a string it will appear as empty string with len=0.

You then concat that with some other array, the size of which is determined by a str like function, suggesting this other array is a null terminated string.

Your cat function doesn't null terminate the result.

You then use a str like function to get the length of the result, even though you didn't null terminate the result, however by good/bad fortune the first byte is 0  (that came from the original 32 bit number) so it is seen as empty string with len=0.

In short, don't use str functions for things that aren't null terminated strings.

 

The VLA (variable length array)

unsigned char toSend[len+4]

which puzzled me a bit (having never used this feature) I think is OK, however I would question why a VLA is needed.

Typically for this kind of thing you would expect the function to work up to some maximum message length, in which case you may as well use a fixed size array big enough for the maximum, and then check that what is passed in will actually fit.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you look at the assembler generated by the compiler for 8, 16 and 24 bit shifts you will be horrified. It's done by an unrolled loop one shift st s time. Basically you have the 4 bytes in memory already as a 32 bit type, it's just that C won't let you get at them! I have a similar problem. I have to send 16 bit integers over the SPI port. The sending end is no problem because it's in assembler. At the receiving end though the problem is how, in C do you put two consecutive bytes into a UINT16_t?
I haven't found a good way in C yet. BTW a multiply by 256 compiles to much faster code than an 8bit shift

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PWD999 wrote:
in C do you put two consecutive bytes into a UINT16_t?
I haven't found a good way in C yet. BTW a multiply by 256 compiles to much faster code than an 8bit shift
Well there's several ways:

 

1) make a union between bytes and uint16_t:

typedef union {
    uint16_t word;
    uint8_t bytes[2];
} joined_t;

joined_t join;

join.bytes[0] = 0xAD;
join.bytes[1] = 0xDE;

now join.word contains 0xDEAD. However this relied on me knowing the endianism. I knew to put the 0xAD in byte 0 and 0xDE in byte 1, not the other way around (which would have been big-endian instead of little endian).

 

2) A bit naughty I know but I can do (get away with?) this:

uint16_t result;
uint8_t * p = (uint8_t *)&result;

*p++ = 0xAD;
*p = 0xDE;

once again result = 0xDEAD. Once again it relied on me knowing the endianism.

 

3) the "official" way to do this, that does not need a knowledge of endianism is:

uint16_t result;

result = (0xDE << 8) | 0xAD;

that puts 0xDEAD into result whatever the endianism the compiler uses to hold it.

 

If you do use the <<24, <<16, <<8 mechanism to build a compound value from bytes then one would hope an intelligent compiler is smart enough to know that <<'s using 8 bit multiples just mean "the next byte" or the "byte after that" or whatever.

BTW a multiply by 256 compiles to much faster code than an 8bit shift

Good grief - which compiler is this then?? Again, any decent compiler knows a *256 or*65536 just means next byte or the byte after etc.

 

PS: I hope it's obvious in the above but 0xDE and 0xAD are just placeholders for "byte 0 and byte 1 from 'some source'". Obviously if you really started doing things like "(0xDE << 8) | 0xAD" then all that would be washed away at compile time.

Last Edited: Thu. Oct 10, 2019 - 12:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for that . I am indeed looking at UNIONS to do it. These are equivslent to but way more cumbersome than the FORTRAN Equivalence statement which allows you to declare two variable or array names having different type to share the same RAM . Yes you would hope an intelligent compiler would interpret an 8 bit shift as a one byte shift. I guess GCC C is not intelligent! BTW your example used constants DE and AD, not vatiables. In this case the compiler does the operation and just puts the 16 bit result into the code. But with variables that has to be done in real time by really asinine code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am not a C fan so try to avoid it but maybe you could tell me if this would work. Could I write a procedure that took two arguments - a 16 bit integer and a 2-byte array. But inside the procedure I declare them to be both 16 bit integers. Then I just copy one to the other and return.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

PWD999 wrote:
but way more cumbersome
I don't gt it? How is:

union {
    uint16_t word;
    uint8_t bytes[2];
} joined;

"cumbersome". You are bout to have the two bits in the middle in any syntax as they are the two things you are asking to co-locate so is the "cumbersome" bit the word "union" or the two braces to group it or the assigned name for the join?

 

I must go and google "FORTRAN equivalence" - it's about 38 years since I last did any FORTRAN and I don't remember it!

PWD999 wrote:
In this case the compiler does the operation and just puts the 16 bit result into the code.
That's exactly why I added that PS: above. Presumably the inputs are volatile or at least "extern" sources?

 

EDIT: Holy mother of God, I found "equivalence":

 

How is that less cumbersome than

union {
    something;
    something_else;
}

??

 

The general syntax seems to be roughly:

DEFINE something, something_else
EQUIVALENCE (something, something_else)

 

Last Edited: Thu. Oct 10, 2019 - 12:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In FORTRAN you would just write

INTEGER*16 WORD
BYTE BYTES(2)
EQUIVALENCE ( BYTES, WORD)

Thereafter you can just address the same RAM 16 bits st a time using WORD or byte at a time using BYTES(1) or BYTES(2)

No need to execute a function to get at them. They are already in RAM , both together if you want them pair at a time or separate if you want them byte at a time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, so I tried this:

#include <avr/io.h>

union {
	uint16_t word;
	uint8_t bytes[2];	
} u;

volatile uint16_t result;

int main(void)
{	
	uint8_t * p;
	
	p = &result;
	*p++ = PINB;
	*p = PIND;

	u.bytes[0] = PINB;
	u.bytes[1] = PIND;

	result = (PINB << 8) | PIND;
	while(1);
}

That is building a 16 bit value 3 times from volatile PINB and PIND inputs. The results were:

	*p++ = PINB;
  8a:	83 b1       	in	r24, 0x03	; 3
  8c:	80 93 00 01 	sts	0x0100, r24	; 0x800100 <_edata>
	*p = PIND;
  90:	89 b1       	in	r24, 0x09	; 9
  92:	80 93 01 01 	sts	0x0101, r24	; 0x800101 <_edata+0x1>
	u.bytes[0] = PINB;
  96:	83 b1       	in	r24, 0x03	; 3
  98:	80 93 02 01 	sts	0x0102, r24	; 0x800102 <u>
	u.bytes[1] = PIND;
  9c:	89 b1       	in	r24, 0x09	; 9
  9e:	80 93 03 01 	sts	0x0103, r24	; 0x800103 <u+0x1>
	result = (PINB << 8) | PIND;
  a2:	23 b1       	in	r18, 0x03	; 3
  a4:	89 b1       	in	r24, 0x09	; 9
  a6:	90 e0       	ldi	r25, 0x00	; 0
  a8:	92 2b       	or	r25, r18
  aa:	90 93 01 01 	sts	0x0101, r25	; 0x800101 <_edata+0x1>
  ae:	80 93 00 01 	sts	0x0100, r24	; 0x800100 <_edata>

I agree that register shuffling with the OR R25 is a bit disappointing but otherwise I'm scratching my head to see how the compiler could have been any more efficient with this? Certainly the first two are as good as it could possibly get.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK you have helped me understand UNION. It likely is the same as FORTRAN equivalence. I was concerned with what 'join' and 'joined' would compile to but I see now that they are just declarations and shouldn't result in any code - they just condition how the compiler treats future references to those variables.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In my most recent example I simply called it u. It's just a variable name. It just means "the name for the common location where I am putting 'word' and 'bytes' is 'u'" (or whatever you want it to be)

 

The one thing that Fortran seems to have as an advantage is this way you can automatically offset the bases. In C if you wanted the middle 16 bit from a 32 bit word you'd end up with something cumbersome like:

union {
    uint32_t dword;
    struct {
        uint8_t reserved01;
        uint16_t the_16_bits;
        uint8_t reserved 02;
    };
} foo;

If you used foo.dword = 0xBABEFACE then foo.the_16_bits would be 0xBEFA.

 

Actually the syntax I just used uses a GCC extension called anonymous members. Standard C would insist on:

union {
    uint32_t dword;
    struct {
        uint8_t reserved01;
        uint16_t the_16_bits;
        uint8_t reserved 02;
    } this_needs_a_name;
} foo;

You would still write to foo.dword but you would read back from foo.this_needs_a_name.the_16_bits

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

result = (PINB << 8) | PIND;

That compiled way more efficiently for you than me. I was using GCC C to compile to an ATMEGA1284. It compiled to doing the 8 shifts one at a time and each shift was about 4 instructions.. Maybe I need a compiler update!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PWD999 wrote:
Maybe I need a compiler update!
More likely you were building with the wrong optimisation setting. Make sure it's -O3 or -Os.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually FORTRAN would not be guaranteed to let you offset the base as it generally forces 4byte quantities to be located on 4 byte boundaries and 16 bit quantities to be located on 2byte boundaries. So you can't usually get away with

BYTE BYTES(5)
INTEGER*16 WORD
EQUIVALENCE (WORD, BYTES(2))

You would likely get "Alignment error"

Now a FORTRAN written for 8 bit processors could potentially allow that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks I will try optimization settings. I like your UNION formulation best though.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PWD999 wrote:
I like your UNION formulation best though.
Not mine. Technically it belongs to Denis Ritchie ;-)