Local build error after HAL edit

Hey everyone,

I’m porting an Arduino library for the W550 SPI Ethernet adapter for the Photon. One of the things I ran into is IPAddress needs a raw_address function which returns a 4 byte array. The arduino IPAddress class has a member called bytes which is just a 4 byte array that the IP address is stored in. Particle’s IPAddress class does not have this member so I added it to inet_hall like this:

typedef struct __attribute__((__packed__)) _HAL_IPAddress_t  {
    union {
        uint32_t ipv4;
        uint32_t ipv6[4];
    };
    uint8_t v;              // 4 for Ipv4, 6 for Ipv6
} HAL_IPAddress;

However I still get a build error of 'HAL_IPAddress' has no member named 'bytes'

Any idea why I get that build error? I am compiling from the modules director with make command:
make clean all PLATFORM=photon

address.bytes shows up in my auto complete in Eclipse(IDE of choice for stuff like this) but when I compile it’s like it has no idea what I’m talking about. It’s as if inet_hal is not compiling, is that the case and if so how do I make it compile?

When porting a library I’d rather make the lib fit the system than bending the system to fit the lib.

BTW, uint32_t can easily be cast to a byte array.

2 Likes

So the IPAddress class has these overloads that you peak into the address:

    operator const HAL_IPAddress& () const {
        return address;
    }

    operator const HAL_IPAddress* () const {
        return &address;
    }


    const HAL_IPAddress& raw() const {
        return address;
    }

    HAL_IPAddress& raw() {
        return address;
}

This lets you memcpy() the address or use any other construct where it will be const reading. The only trick is making sure you use const access.

1 Like

Thanks @bko and @ScruffR

So I added a function to the spark_wiring_ipaddress class(raw_address) like this:

uint8_t *raw_address(){
	uint8_t * b;
	b = (uint8_t*)malloc(4);
	b[0] = (address.ipv4 >> 24) & 0xFF;
	b[0] = (address.ipv4 >> 16) & 0xFF;
	b[0] = (address.ipv4 >> 8) & 0xFF;
	b[0] = (address.ipv4 >> 0) & 0xFF;
	return b;
}  

Seemed like the most uninvasive way to accomplish what I needed. Does it look correct? From what I gathered it seemed the IP address was stored in a uint32_t with all 4 bytes of the IP squeezed into that one variable. Are my assumptions correct?

On to the next compile error, yee haw. Don’t you just love porting code. Compile, fix compile error, rise and repeat.

With a mere typecast you’ll get the same thing

  uint32_t myIP = 0x12345678;
  byte *byteIP = (byte*)&myIP;

  Serial.print(byteIP[0]);
  Serial.print(byteIP[1]);
  Serial.print(byteIP[2]);
  Serial.print(byteIP[3]);

And this does not involve manipulation to system files.
And don’t malloc() when you can’t ensure the allocated memory will be freed again. This is a good recipe for memory leaks.
After all you already have the raw() methods that return pointers or references, what do you need more?

BTW, your code should use other indexes than 0 too.

1 Like

Hey @ScruffR and @bko

Any ideas why I would be seeing a hard fault with this code:

void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet)
{
  w5500.init(w5500_cspin);
  w5500.setMACAddress(mac);

  byte* lA = (byte*)local_ip.raw().ipv4;	//hard fault on this line.
  byte* gA = (byte*)gateway.raw().ipv4;
  byte* sA = (byte*)subnet.raw().ipv4;

  w5500.setIPAddress(lA);
  w5500.setGatewayIp(gA);
  w5500.setSubnetMask(sA);
  _dnsServerAddress = dns_server;
}

Compiles fine but I get a hard fault when trying to cast the IP to a byte*

The way you do it there you are using the IP address as pointer to a byte storage, but you actually want to use the location where the IPv4 number is stored as that value, so you’ll need to use the address of operator & as I have done above.

 byte* lA = (byte*)&local_ip.raw().ipv4;	//hard fault on this line.
 byte* gA = (byte*)&gateway.raw().ipv4;
 byte* sA = (byte*)&subnet.raw().ipv4;
3 Likes