UDP & General programing question

Hi,
I’m looking for some guidance and maybe some examples.

I’m building a light controller for the LIFX blubs using their LAN protocol that use UDP to communicate.

Also let me start by saying I’m leaning to program as I go so I could have things very wrong.

I would like to listen for UDP packets and also send some packets from a lifx class when a button is pressed.

I currently have the following (cut down) main.ino:[code]#include “lifx.h”

// IO
int INTRPT = D2;
// UDP
uint16_t localPort = 56800;
// Objects
lifx LIFX = lifx();
UDP Udp;

void setup() {
Udp.begin(localPort);
// Setup IO
pinMode(INTRPT, INPUT_PULLUP);

//Setup Test Lamp
uint8_t mac[6];

mac[0] = 0xD0;
mac[1] = 0x73;
mac[2] = 0xD5;
mac[3] = 0x00;
mac[4] = 0x07;
mac[5] = 0x43;

LIFX.addLight(mac, 56700);

}

void loop() {

// Check if data has been received
udpPacketSize = Udp.parsePacket();
if (udpPacketSize > 0) {
    byte packetBuffer[128]; //buffer to hold incoming packet

    // Read first 128 of data received
    Udp.read(packetBuffer, 128);

    // Ignore other chars
    Udp.flush();

    // Interpret buffer
    LIFX.msgIn(packetBuffer);

}

}[/code]lifx.h[code]/*

  • lifx.h - library for talking to the light blubs.
    */
    #ifndef _lifx_h
    #define _lifx_h

    /* includes */
    #include “common.h”
    #include “device.h”
    #include “light.h”

    class lifx{
    public:
    /* Members Functions */
    lifx();
    void discover(); // Find active lights
    void addLight(uint8_t mac[6], uint32_t port); // Add light to Lights vector by mac address
    void removeLight(uint8_t mac[6]); // Remove light from Lights vector by mac address
    void togglePower(); // Toggle power (on/off) of currently selected light/s
    void toggleColor(); // Change currently selected light/s from color to white
    void cycleColor(); // Change color/temperature of currently selected light/s
    void dimLights(); // Change the brightness of currently selected light/s
    void msgIn(uint8_t packetBuffer[128]); // UDP message in

     	/* Members */
     	device Device;
         light Lights[16];
         int numberOfLights = 0;                             // The current number of lights under control
     
     private:
     	/* Members Functions */
     	boolean _byteArrayCompare(byte a[], byte b[], int arraySize);
     
     	/* Members */
     	bool _powerState;                                  // 1 := Lights On, 0 := Lights Off
    

    };

#endif[/code]lifx.cpp[code]/*

  • lifx.cpp - library for talking to the LIFX blubs.
    */

#include “lifx.h”

lifx::lifx()
{
device Device = device();
}

void lifx::discover()
{
Serial.printlnf(“lifx discover…”);
Device.getService();
}

void lifx::addLight(uint8_t mac[6], uint32_t port)
{
Serial.printlnf(“lifx addLight…”);
light Light = light();
Light.setMAC(mac);
Light.setPort(port);

Lights[numberOfLights] = Light;

numberOfLights++;

}
/*

  • remove and resort array
    */
    void lifx::removeLight(uint8_t mac[6])
    {
    int index;
    int i;

    for (i = 0; i < numberOfLights - 1; i++)
    {
    if (_byteArrayCompare(Lights[i].lamp.mac, mac, 6))
    {
    index = i;
    }
    }

    for (i = index - 1; i < numberOfLights - 1; i++)
    {
    Lights[i] = Lights[i + 1];
    }
    numberOfLights–;
    }

void lifx::togglePower()
{
Serial.printlnf(“lifx togglePower…Number of Lights: %d”, numberOfLights);
_powerState = !_powerState;

for(int i = 0; i < numberOfLights; i++)
{
    Lights[i].setPower(_powerState);
}

}

void lifx::toggleColor()
{

}

void lifx::cycleColor()
{

}

void lifx::dimLights()
{

}

void lifx::msgIn(byte packetBuffer[128])
{
/*
is it a lifx msg
is it for me (senders mac)
Check for return type Status
send to light status function
*/
// LIFX Header Decode
// Frame
uint16_t lifxSize = packetBuffer[0] + (packetBuffer1 << 8); //little endian
uint8_t lifxOrigin = (packetBuffer2 + (packetBuffer[3] << 8) & 0xC000) >> 14;
bool lifxTagged = (packetBuffer2 + (packetBuffer[3] << 8) & 0x2000) >> 13;
bool lifxAddressable = (packetBuffer2 + (packetBuffer[3] << 8) & 0x1000) >> 12;
uint16_t lifxProtocol = (packetBuffer2 + (packetBuffer[3] << 8) & 0x0FFF);
uint32_t lifxSource = packetBuffer[4] + (packetBuffer[5] << 8) + (packetBuffer[6] << 16) + (packetBuffer[7] << 24);
// Frame Address
uint8_t lifxTarget[8] = {packetBuffer[8], packetBuffer[9], packetBuffer[10], packetBuffer[11], packetBuffer[12], packetBuffer[13], packetBuffer[14], packetBuffer[15]};
uint8_t lifxReservedA[6]= {packetBuffer[16], packetBuffer[17], packetBuffer[18], packetBuffer[19], packetBuffer[20], packetBuffer[21]};
uint8_t lifxReservedB = (packetBuffer[22] & 0xFC) >> 2;
bool lifxAckRequired = (packetBuffer[22] & 0x02) >> 1;
bool lifxResRequired = packetBuffer[22] & 0x01;
uint8_t lifxSequence = packetBuffer[23];
// Protocol Header
uint64_t lifxReservedC = (packetBuffer[24] + (packetBuffer[25] << 4) + (packetBuffer[26] << 8) + (packetBuffer[27] << 12)) + ((packetBuffer[28] + (packetBuffer[29] << 4) + (packetBuffer[30] << 8) + (packetBuffer[31] << 12)) << 16);
uint16_t lifxPacketType = packetBuffer[32] + (packetBuffer[33] << 8);
uint16_t lifxReservedD = packetBuffer[34] + (packetBuffer[35] << 8);

Serial.println("Header:");
Serial.println("Frame:");
Serial.printlnf("   Size: %d", lifxSize);
Serial.printlnf("   Origin: %d", lifxOrigin);
Serial.printlnf("   Tagged: %s", lifxTagged ? "true" : "false");
Serial.printlnf("   Addressable: %s", lifxAddressable ? "true" : "false");
Serial.printlnf("   Protocol: %d", lifxProtocol);
Serial.printlnf("   Source: %d", lifxSource);
Serial.println("Frame Address:");
Serial.printlnf("   Target: 0x %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", lifxTarget[0], lifxTarget[1], lifxTarget[2], lifxTarget[3], lifxTarget[4], lifxTarget[5], lifxTarget[6], lifxTarget[7]);
Serial.printlnf("   ReservedA: 0x %02X:%02X:%02X:%02X:%02X:%02X", lifxReservedA[0], lifxReservedA[1], lifxReservedA[2], lifxReservedA[3], lifxReservedA[4], lifxReservedA[5]);
Serial.printlnf("   ReservedB: %d", lifxReservedB);
Serial.printlnf("   AckRequired: %s", lifxAckRequired ? "true" : "false");
Serial.printlnf("   ResRequired: %s", lifxResRequired ? "true" : "false");
Serial.printlnf("   Sequence: %d", lifxSequence);
Serial.println("Protocol Header:");
Serial.printlnf("   ReservedA: %d", lifxReservedC);
Serial.printlnf("   PacketType: %d", lifxPacketType);
Serial.printlnf("   ReservedD: %d", lifxReservedD);
Serial.println("Payload:");
Serial.print("  0x ");
for(int i = 36; i < lifxSize; i++ ){
    Serial.printf("%02X ", packetBuffer[i]);
}
Serial.println("");

Serial.println("Raw:");
Serial.print("  0x ");
for(int j = 0; j < lifxSize; j++ ){
    Serial.printf("%02X ", packetBuffer[j]);
}
Serial.println("");

Serial.println("---");

}

boolean lifx::_byteArrayCompare(byte a[], byte b[], int arraySize)
{
for (int i = 0; i < arraySize; i++)
{
if (a[i] != b[i])
{
return(false);
}
}
return(true);
}

[/code]light.h[code]/*

  • light.h - Light half of library for talking to the light blubs.
    */
    #ifndef _light_h
    #define _light_h

    /* includes */
    #include “common.h”

    class light{
    public:
    /* Members /
    struct Header
    {
    /
    frame /
    uint16_t size;
    uint16_t protocol:12;
    uint8_t addressable:1;
    uint8_t tagged:1;
    uint8_t origin:2;
    uint32_t source;
    /
    frame address /
    uint8_t target[8];
    uint8_t reservedA[6];
    uint8_t res_required:1;
    uint8_t ack_required:1;
    uint8_t reservedB:6;
    uint8_t sequence;
    /
    protocol header */
    uint64_t reservedC;
    uint16_t type;
    uint16_t reservedD;
    }attribute ((packed));

      struct Lamp {
          uint8_t ip[4];
          uint8_t mac[6];
          uint32_t port;
          uint16_t level;
          uint64_t time;
          uint8_t service;
          uint32_t tx;
          uint32_t rx;
          uint64_t build;
          uint32_t version;
          uint32_t vendor;
          uint32_t product;
          uint64_t uptime;
          uint64_t downtime;
          HSBK hsbk;
          float signal;
          char lable[32];
      }__attribute__ ((__packed__));
      
      /* Member Functions */
      light();
      Lamp lamp = Lamp();
      void setIP(uint8_t ip[4]);
      void setMAC(uint8_t mac[6]);
      void setPort(uint32_t port);
      void get();
      void setColor(HSBK hsbk);
      void setColor(HSBK hsbk, uint32_t duration);
      void setColor(uint16_t hue, uint16_t saturation, uint16_t brightness, uint16_t kelvin);
      void setColor(uint16_t hue, uint16_t saturation, uint16_t brightness, uint16_t kelvin, uint32_t duration);
      void setPower(bool onOff);
      void setPower(bool onOff, uint32_t duration);
      void state(uint8_t msg[]);
      void statePower(byte msg[]);
      
      private:
          //lamp _lamp;
          UDP _udp;
          
          enum msg{
              _get = 101,
              _setColor = 102,
              _state = 107,
              _getPower = 116,
              _setPower = 117,
              _statePower = 118
          };
    

    };

#endif
[/code]light.cpp[code]/*

  • light.cpp - Light half of library for talking to the LIFX blubs.
    */

#include “light.h”

light::light()
{

};

void light::setIP(uint8_t ip[4])
{
Serial.println(“Setting IP…”);
memcpy(&lamp.ip, &ip, sizeof(ip));
}

void light::setMAC(uint8_t mac[6])
{
Serial.printlnf(“light setMAC…”);
//memcpy(&_lamp.mac, &mac, sizeof(mac));
lamp.mac[0] = mac[0];
lamp.mac1 = mac1;
lamp.mac2 = mac2;
lamp.mac[3] = mac[3];
lamp.mac[4] = mac[4];
lamp.mac[5] = mac[5];
}

void light::setPort(uint32_t port)
{
lamp.port = port;
}

void light::get()
{
Serial.println(“Light get…”);
}

void light::setColor(HSBK hsbk)
{
setColor(hsbk, 0);
}

void light::setColor(HSBK hsbk, uint32_t duration)
{
setColor(hsbk.hue, hsbk.saturation, hsbk.brightness, hsbk.kelvin, duration);
}

void light::setColor(uint16_t hue, uint16_t saturation, uint16_t brightness, uint16_t kelvin)
{
setColor(hue, saturation, brightness, kelvin, 0);
}

void light::setColor(uint16_t hue, uint16_t saturation, uint16_t brightness, uint16_t kelvin, uint32_t duration)
{
Serial.println(“Light setColor…”);
}

void light::setPower(bool onOff)
{
Serial.println(“Light setPower…”);

setPower(onOff, 0);

}

void light::setPower(bool onOff, uint32_t duration)
{
/* header */
Header header = Header();
int16_t headerSize = sizeof(header);

/* payload */
uint8_t payload[6];
int16_t payloadSize = sizeof(payload);
if (onOff)
{
    lamp.level = 65535;
} else {
    lamp.level = 0;
}

/* UDP Packet */
uint8_t udpPacket[headerSize + payloadSize];

/* build header */
header.size = headerSize + payloadSize; 
//header.origin = 0;            
header.tagged = 0;            
header.addressable = 1;       
header.protocol = 1024;       
//header.source = 0;
header.target[0] = lamp.mac[0];
header.target[1] = lamp.mac[1];
header.target[2] = lamp.mac[2];
header.target[3] = lamp.mac[3]; 
header.target[4] = lamp.mac[4]; 
header.target[5] = lamp.mac[5]; 
//header.target[6] = 0; 
//header.target[7] = 0;
//header.reservedA[0] = 0;
//header.reservedA[1] = 0;
//header.reservedA[2] = 0;
//header.reservedA[3] = 0;
//header.reservedA[4] = 0;
//header.reservedA[5] = 0;
//header.reservedB = 0;
//header.ack_required = 0;
header.res_required = 1;
//header.sequence = 0;
//header.reservedC = 0;
header.type = _setPower;
//header.reservedD = 0;

/* build payload */
/* Level, 0 or 65535 uint16_t */
payload[0] = (lamp.level) & 0xff;
payload[1] = (lamp.level >> 8) & 0xff;
/* Duration, transition time in milliseconds uint32_t */
payload[2] = (duration) & 0xff;
payload[3] = (duration >> 8) & 0xff;
payload[4] = (duration >> 16) & 0xff;
payload[5] = (duration >> 24) & 0xff;

/* build udp packet */
/* header */
memcpy(&udpPacket, &header, headerSize);
/* payload */
for (int i = 0; i < payloadSize; i++)
{
    udpPacket[headerSize + i] = payload[i];
}

/* Send UDP Packet */
// TODO
if (WiFi.ready()) {
    Serial.printlnf("Light setPower - Sending UDP to 192.168.1.255:%d", lamp.port);
    _udp.begin(lamp.port);
    _udp.beginPacket(IPAddress(192,168,1,255), lamp.port);
    _udp.write(udpPacket, sizeof(udpPacket));
    _udp.endPacket();
    _udp.stop();
}

#if _DEBUG
    Serial.printf("Light setPower - UDP: 0x ");
    for(int i = 0; i < sizeof(udpPacket); i++)
    {
        Serial.printf("%02X ", udpPacket[i]);
    }
    Serial.println("");
#endif

};[/code]device.h[code]/*

  • device.h - Device half of library for talking to the LIFX blubs.
    */
    #ifndef device_h
    #define device_h

    /* includes */
    #include “common.h”

    class device{
    public:
    /* Member Functions */
    device();
    void getService();

         /* Members */
         struct Header
         {
             /* frame */
             uint16_t size;
             uint16_t protocol:12;
             uint8_t  addressable:1;
             uint8_t  tagged:1;
             uint8_t  origin:2;
             uint32_t source;
             /* frame address */
             uint8_t  target[8];
             uint8_t  reservedA[6];
             uint8_t  res_required:1;
             uint8_t  ack_required:1;
             uint8_t  reservedB:6;
             uint8_t  sequence;
             /* protocol header */
             uint64_t reservedC;
             uint16_t type;
             uint16_t reservedD;
         }__attribute__ ((__packed__));
     
     private:
     /* Members */
     // _Udp;
     // Stream *_serial;
     
     enum _msg{
         _getService = 2,
         _stateService = 3,
         _getHostInfo = 12,
         _stateHostInfo = 13,
         _getHostFirmware = 14,
         _stateHostFirmware = 15,
         _getWifiInfo = 16,
         _stateWifiInfo = 17,
         _getWifiFirmware = 18,
         _stateWifiFirmware = 19,
         _getPower = 20,
         _setPower = 21,
         _statePower = 22,
         _getLabel = 23,
         _setLabel = 24,
         _stateLabel = 25,
         _getVersion = 32,
         _stateVersion = 33,
         _getInfo = 34,
         _stateInfo = 35,
         _acknowledgement = 45,
         _echoRequest = 58,
         _echoResponse = 59
     };
    

    };

#endif
[/code]device.cpp[code]/*

  • device.cpp - Device half of library for talking to the LIFX blubs.
    */
    #include “device.h”

device::device()
{
/* debug serial interface */
};

void device::getService()
{
Serial.printlnf(“device getService…”);
/* header */
Header header = Header();
int headerSize = sizeof(header);

/* payload */
// N/A

/* UDP Packet */
uint8_t udpPacket[headerSize];

/* build header */
header.size = headerSize; 
//header.origin = 0;            
header.tagged = 1;            
header.addressable = 1;       
header.protocol = 1024;       
//header.source = 0;
//header.target[0] = 0;
//header.target[1] = 0;
//header.target[2] = 0;
//header.target[3] = 0; 
//header.target[4] = 0; 
//header.target[5] = 0; 
//header.target[6] = 0; 
//header.target[7] = 0;
//header.reservedA[0] = 0;
//header.reservedA[1] = 0;
//header.reservedA[2] = 0;
//header.reservedA[3] = 0;
//header.reservedA[4] = 0;
//header.reservedA[5] = 0;
//header.reservedB = 0;
//header.ack_required = 0;
//header.res_required = 0;
//header.sequence = 0;
//header.reservedC = 0;
header.type = _getService;
//header.reservedD = 0;

/* build payload */
// N/A

/* build udp packet */
memcpy(&udpPacket, &header, headerSize);

/* Send UDP Packet */
// TODO
#if _DEBUG
    Serial.printf("Deivce getService - UDP: ");
    for(int i = 0; i < sizeof(udpPacket); i++ )
    {
        Serial.printf("0x%02x ", udpPacket[i]);
    }
    Serial.println("");
#endif

};

[/code]
This code can send packets OK but stops listening, I think it’s something to do with trying to have 2 UDP ports/sockets open. I’m thinking I need to move the UDP to a class and then use that to listen, send and limit the sending of packets to 20 time/second to each blub. but this is where I’m getting stuck.

I’ve been reading up on inheritance for classes and am thinking this maybe the way to go but still haven’t got my head around it yet or even know if this work.

Any help would be much appreciated, Thanks for reading.

And I’m trying this on a Photon…

OK so I kind of got something working, I’m passing the UDP by reference down to the light class
change main.ino to [code]UDP _udp;
lifx LIFX;

void setup() {
LIFX = lifx(_udp);[/code] lifx.h [code]class lifx{
public:
/* Members Functions /
lifx();
lifx(UDP &udpRef);
private:
/
Members Functions */
boolean _byteArrayCompare(byte a[], byte b[], int arraySize);

    	/* Members */
    	bool _powerState;					// 1 := Lights On, 0 := Lights Off
    	UDP _udp;[/code] lifx.cpp [code]lifx::lifx()

{
//Serial.printlnf(“lifx constructor…”);
}

lifx::lifx(UDP &udpRef)
{
//Serial.printlnf(“lifx constructor overload…”);
_udp = udpRef;
Device = device(_udp);
}

void lifx::addLight(uint8_t mac[6], uint32_t port)
{
Serial.printlnf(“lifx addLight…”);
light Light = light(_udp);
Light.setMAC(mac);
Light.setPort(port);

Lights[numberOfLights] = Light;

numberOfLights++;
Serial.printlnf("lifx addLight...Number of Lights: %d", numberOfLights);

}[/code] light.h class light{ public: // Member Functions light(); light(UDP &udpRef); private: UDP _udp; light.cpp [code]light::light()
{

}

light::light(UDP &udp)
{
lamp = Lamp();
_udp = udp;
};[/code] don’t know if its the right way to do it but it seam to work for now.

so change in question I’ve been advised that it would be best to listen on the ephemeral port for the reply is this possible to do on a Photon? and how would you do this?