Top
w600 - 2024年4月16日更新

Arduino(w600/arduino)を使って開発しています。
ここでは作成したコードを公開しています。
※最新情報や一部のソースはX(twitter) @inunyannで公開しています。ソースは画像になっていますが…

※arduinoでのw600開発は、私の環境では、ボード提供の一部ソースやバッチファイルを書き換えないとうまく動きませんでした。書き換えたファイル情報もそのうち公開していきたいです…
Amazonのほしいものリスト🎁お願いします!!

試作例:フルカラーLEDキューブ
試作例:neopixel(ws2812)での文字スクロール
NeoPixel::show()関数
mDNS(MDNS.cpp/MDNS.h) ※esp8266あたりからportingしたものです
NetBIOS(NetBIOS.cpp/NetBIOS.h) ※どこか(覚えていない)からportingしたものです
Ticker(Ticker.cpp/Ticker.h) ※どこか(覚えていない)からportingしたものです
localtime.h


●試作例:フルカラーLEDキューブ

#include "Adafruit_NeoPixel.h"
#include "W600InnerFlash.h"
// tls_os_task_create
extern "C" {
  #include "wm_osal.h"
}

// neopixel
#define PIN_NP    PA_1
#define NP_NUM_X  3
#define NP_NUM_Y  (NP_NUM_X)
#define NP_NUM_Z  (NP_NUM_X)
#define NP_LED   (NP_NUM_X * NP_NUM_Y * NP_NUM_Z)
Adafruit_NeoPixel np(NP_LED, PIN_NP, NEO_GRB + NEO_KHZ800);
const uint8_t brightness[] = { 0x07, 0x0f, 0x2f, 0x4f, 0x7f, 0xff };
#define NUM_BRIGHT (sizeof(brightness) / sizeof(brightness[0]))

// wdt
extern "C" {
  #include "wm_watchdog.h"
}
#define WDT_SEC 5

#define PIN_PWM PA_0

// button
#define PIN_BTN_1   PB_18
#define PIN_BTN_2   PB_9 // PB_10
#define PIN_BTN_GND PB_7
#define BTN_TASK_STK_SIZE 512
#define BTN_TASK_PRIO     (32 + 1)
static uint32_t btn_task_stack[BTN_TASK_STK_SIZE];
#define INPUT_PULLUP   0x02
#define INPUT_PULLDOWN 0x03

// flash
typedef enum { BRIGHT, MODE, _CONF_MAX } confDate_t;
uint8_t confData[_CONF_MAX];
#define FLASH_SECTOR 240 // 240-251

extern "C" {
  #include "random.h"
}
class ledCube {
  public:
    ledCube(uint32_t nums_X, uint32_t nums_Y, uint32_t nums_Z) : numsX(nums_X), numsY(nums_Y), numsZ(nums_Z), numsXY(nums_X * nums_Y) {
      cubeValue = (uint32_t *)malloc(sizeof(uint32_t) * nums_X * nums_Y * nums_Z);
      randomize();
    }
    ~ledCube() {
      free(cubeValue);
    }

    uint32_t speedTimer = 5000;
    uint32_t minInterval = 3;
    uint32_t maxInterval = minInterval << 5;
    uint32_t cubeMaxValue = 100;
    int32_t  minMag =  4 << 7;
    int32_t  maxMag = 11 << 7;
    int32_t  minDir =  2;
    int32_t  maxDir = 16;

    const uint32_t numsX = 3;
    const uint32_t numsY = 3;
    const uint32_t numsZ = 3;
    const uint32_t numsXY = numsX * numsY;

    uint32_t *cubeValue = nullptr;
    int32_t  pos[3] = { 0, 0, 0 };
    int32_t  dir[3] = { 6, 6, 6 };
    int32_t  mag = maxMag;
    int32_t  dirMag = (maxMag - minMag) / 20;
    uint32_t interval = maxInterval;
    int32_t  dirInterval = -1;
    uint32_t lastChgPos = millis();
    uint32_t lastChgSpd = millis();
    uint32_t mode = 0;
    uint16_t hue = 0;

    void changePos() {
      switch (mode) {
        case 1:
        case 2:
        case 3:
        case 4:
          if (millis() - lastChgPos < interval) return; else lastChgPos = millis();
          for (uint32_t z = 0; z < numsZ; z++) {
            for (uint32_t y = 0; y < numsY; y++) {
              for (uint32_t x = 0; x < numsX; x++) {
                uint32_t dx = (x << 7) - pos[0];
                uint32_t dy = (y << 7) - pos[1];
                uint32_t dz = (z << 7) - pos[2];
                uint32_t dist = ((dx * dx + dy * dy + dz * dz) * mag >> 14) * mag >> 14;
                cubeValue[numsXY * z + numsX * y + x] = cubeMaxValue / (dist ? dist : 1);
              }
            }
          }
          for (uint32_t i = 0; i < 3; i++) {
            if ((pos[i] += dir[i]) > (int32_t)((i ? i == 1 ? numsY : numsZ : numsX) - 1 << 7)) {
              pos[i] = (i ? i == 1 ? numsY : numsZ : numsX) - 1 << 7;
              dir[i] = -random(minDir, maxDir);
            } else if (pos[i] < 0) {
              pos[i] = 0;
              dir[i] = random(minDir, maxDir);
            }
          }
          if ((mag += dirMag) > maxMag) {
            mag = maxMag;
            dirMag = -random(minDir, maxDir);
          } else if (mag < minMag) {
            mag = minMag;
            dirMag = random(minDir, maxDir);
          }
          break;
        case 5: // rainbow
          break;
        case 6:
          if (millis() - lastChgPos < interval << 4) return; else lastChgPos = millis();
          clearCube();
          for (uint32_t i = 0; i < numsXY * numsZ; i++) {
            if (random() % 6) continue;
            cubeValue[i] = 1 + random() % 100;
          }
          break;
        default: // 0
          clearCube();
          cubeValue[0] = 10;
      }
    }

    void changeSpd() {
      if (mode != 1 && mode != 5 && mode != 6) return;
      if (millis() - lastChgSpd < speedTimer) return; else lastChgSpd = millis();
      if (dirInterval > 0 && (interval <<= 1) >= maxInterval) {
        interval = maxInterval;
        dirInterval = -1;
      } else if (dirInterval < 0 && (interval >>= 1) <= minInterval) {
        interval = minInterval;
        dirInterval = 1;
      }
    }

    void changeHue() {
      hue += mode != 5 ? 0x0020 : interval << 2;
    }

    void clearCube() {
      memset(cubeValue, 0, sizeof(uint32_t) * numsXY * numsZ);
    }

    void randomize() {
      uint32_t buf = analogRead(0);
      random_add_randomness((void *)&buf, sizeof(buf));
    }
    uint32_t random(uint32_t min = 0, uint32_t max = 0xffffffff) {
      uint32_t buf;
      random_get_bytes((void *)&buf, sizeof(buf));
      return buf % (max - min) + min;
    }
};
#define NUM_MODE 7
ledCube *cube;


void setup() {
  tls_watchdog_init(WDT_SEC * 1000 * 1000);
  pinMode(PIN_PWM, OUTPUT);
  pinMode(PIN_BTN_1, INPUT_PULLUP);
  pinMode(PIN_BTN_2, INPUT_PULLUP);
  pinMode(PIN_BTN_GND, OUTPUT);
  digitalWrite(PIN_BTN_GND, LOW);

  InnerFlash.begin();
  InnerFlash.flashRead(FLASH_SECTOR * 4096, &confData[0], sizeof(confData) / sizeof(confData[0])); // sector-size: 4096
  np.begin();
  setBrightness();

  cube = new ledCube(NP_NUM_X, NP_NUM_Y, NP_NUM_Z);
  cube->mode = confData[MODE];
  setInterval();

  tls_os_task_create(NULL, "btn", btn_task, (void *)0, (uint8_t *)&btn_task_stack, BTN_TASK_STK_SIZE * sizeof(uint32_t), BTN_TASK_PRIO, 0);
}

void loop() {
  analogWrite(PIN_PWM, millis() & 0x0200 ? 255 : 252);
  if (cube->mode == 5) np.rainbow(cube->hue, 1, 0x9f);
  else {
    for (uint32_t i = 0; i < cube->numsXY * cube->numsZ; i++) {
      np.setPixelColor(i % cube->numsXY / cube->numsX % 2 ? cube->numsX * (i / cube->numsX + 1) - i % cube->numsX - 1 : i,
        np.ColorHSV(cube->hue, 255, cube->cubeValue[i] * 0xff / cube->cubeMaxValue));
    }
  }
  np.show();
  cube->changePos();
  cube->changeSpd();
  cube->changeHue();
  tls_watchdog_clr();
  delay(1);
}

void setBrightness() { np.setBrightness(brightness[confData[BRIGHT] < NUM_BRIGHT ? confData[BRIGHT] : 0]); }
void setInterval() {
  uint32_t blen = 0;
  switch (confData[MODE]) {
    case 2:
      cube->interval = cube->maxInterval;
      break;
    case 3:
      for (uint32_t i = cube->maxInterval; i > cube->minInterval; i >>= 1) blen++;
      cube->interval = cube->minInterval << (blen >> 1);
      break;
    case 4:
      cube->interval = cube->minInterval;
      break;
  }
}
void saveToFlash() { InnerFlash.flashEraseSector(FLASH_SECTOR); InnerFlash.flashWrite(FLASH_SECTOR * 4096, &confData[0], sizeof(confData) / sizeof(confData[0])); }

void btn_task(void *data) {
  uint16_t btn1Count = 0;
  uint16_t btn2Count = 0;
  while (true) {
    if (!digitalRead(PIN_BTN_1)) btn1Count++;
    if (!digitalRead(PIN_BTN_2)) btn2Count++;
    if (btn1Count && digitalRead(PIN_BTN_1)) {
      if (++confData[BRIGHT] >= NUM_BRIGHT) confData[BRIGHT] = confData[MODE] < 5 ? 3 : 0;
      saveToFlash();
      setBrightness();
      btn1Count = 0;
    }
    if (btn2Count && digitalRead(PIN_BTN_2)) {
      if (++confData[MODE] >= NUM_MODE) confData[MODE] = 0;
      if (confData[MODE] < 5 && confData[BRIGHT] < 3) {
        confData[BRIGHT] = 3;
        setBrightness();
      }
      saveToFlash();
      cube->mode = confData[MODE];
      setInterval();
      btn2Count = 0;
    }
    tls_os_time_delay(HZ / 100);
  }
}

●試作例:neopixel(ws2812)での文字スクロール

#include 
#include "Adafruit_NeoPixel.h"
#include "img2.h"

// neopixel
#define PIN_NP PB_12
#define NP_LED 64
Adafruit_NeoPixel np(NP_LED, PIN_NP, NEO_RGB + NEO_KHZ800);
#define PIN_NP2 PB_11
#define PIN_NP3 PB_10
Adafruit_NeoPixel np2(NP_LED, PIN_NP2, NEO_RGB + NEO_KHZ800);
Adafruit_NeoPixel np3(NP_LED, PIN_NP3, NEO_RGB + NEO_KHZ800);
uint16_t hue = 1 << 4;
uint8_t  spd = 4;
uint16_t rainbowInterval = 8 * 1000;
uint32_t rainbowStart = 0;
uint16_t col = 0;

void setup() {
  np.begin();
  np.setBrightness(0x0f);
  np2.begin();
  np3.begin();
  np2.setBrightness(0x0f);
  np3.setBrightness(0x0f);
}

void loop() {
  showLed();
}

void showLed() {
  analogWrite(PIN_PWM, brightness);
  if ((brightness += fadeAmount) < 5) fadeAmount = 0xff - fadeAmount - (fadeAmount < 0x80 ? (brightness -= fadeAmount) && 0 : 1);
  if (!fadeAmount) fadeAmount = 5;
  if (col == 0xffff) {
    //np.rainbow(hue += spd << 5, 1, 0x9f);
    rainbow2(&np,  1, 3, hue += spd << 5, 0x9f);
    rainbow2(&np2, 2, 3, hue,             0x9f);
    rainbow2(&np3, 3, 3, hue,             0x9f);
    if (millis() - rainbowStart > rainbowInterval) col = 0;
  } else {
    for (uint8_t i = 0; i < 8 * 8; i++) {
      np.setPixelColor(i,  (img[ col       * 8 + i] & 0x00ffffff));
      np2.setPixelColor(i, (img[(col + 8)  * 8 + i] & 0x00ffffff));
      np3.setPixelColor(i, (img[(col + 16) * 8 + i] & 0x00ffffff));
    }
    if (++col > img_width - (8 * 3 + 1)) {
      col = 0xffff;
      rainbowStart = millis();
    }
  }
  //np.rainbow(hue += spd << 5, 1, 0x9f);
  np.show();
  np2.show();
  np3.show();
  delay(col == 0xffff ? 10 : col == 0 ? 500 : 50);
  //delay(10);
}

void rainbow2(Adafruit_NeoPixel *np, uint8_t n, uint8_t nMax, uint16_t first_hue, uint8_t saturation) {
  for (uint16_t i = 0; i < np->numPixels(); i++) np->setPixelColor(i, np->gamma32(np->ColorHSV(first_hue + (((uint32_t)i + np->numPixels() * (n - 1)) * 65536 / nMax) / (np->numPixels() * nMax), saturation, 255)));
}

●NeoPixel::show()関数

void Adafruit_NeoPixel::show(void) {
  if (!pixels) return;
  while (!canShow());

  uint8_t *ptr, *end, p, bitMask;
  uint32_t pinMask;
  ptr = pixels;
  end = ptr + numBytes;
  p = *ptr++;
  bitMask = 0x80;

  //volatile uint32_t *GPIOA_DATA = (volatile uint32_t *) 0x40010C00; // HR_GPIOA_DATA
  //volatile uint32_t *GPIOB_DATA = (volatile uint32_t *) 0x40011200; // HR_GPIOB_DATA
  volatile uint32_t *GPIO_DATA = (volatile uint32_t *) (pin < 16 ? HR_GPIOA_DATA : HR_GPIOB_DATA);
  pinMask = 1 << (pin < 16 ? pin : pin - 16);
  uint32_t cpu_sr = tls_os_set_critical();

#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled
  if (is800KHz) {
#endif
    for (;;) {
      if (p & bitMask) { // ONE
        // High 800ns
        *GPIO_DATA |= pinMask;  // 300ns?
        asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;"
            "nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;"); // 1nop = 12.5ns?
        // Low 450ns
        *GPIO_DATA &= ~pinMask;
        asm("nop; nop; nop;");
      } else { // ZERO
        // High 400ns
        *GPIO_DATA |= pinMask;
        asm("nop; nop; nop; nop; nop; nop;");
        // Low 850ns
        *GPIO_DATA &= ~pinMask;
        asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;"
            "nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");
      }
      if (bitMask >>= 1) {
        //asm("nop;");
        asm("nop; nop; nop; nop; nop;");
      } else {
        if (ptr >= end) break;
        p = *ptr++;
        bitMask = 0x80;
      }
    }
#if defined(NEO_KHZ400)
  } else { // 400 KHz bitstream
    // ToDo!
  }
#endif
  tls_os_release_critical(cpu_sr);

  endTime = micros(); // Save EOD time for latch on next call
}

●mDNS(MDNS.cpp/MDNS.h) ※esp8266あたりからportingしたものです

#define  HAS_SERVICE_REGISTRATION      1  // disabling saves about 1.25 kilobytes
#define  HAS_NAME_BROWSING             1  // disable together with above, additionally saves about 4.3 kilobytes

#include 
#include 
#include 
#include 

extern "C" {
   #include "EthernetUtil.h"
}

#include "MDNS.h"

#include 

#define  MDNS_DEFAULT_NAME       "arduino"
#define  MDNS_TLD                ".local"
#define  DNS_SD_SERVICE          "_services._dns-sd._udp.local"
#define  MDNS_SERVER_PORT        (5353)
#define  MDNS_NQUERY_RESEND_TIME (1000)   // 1 second, name query resend timeout
#define  MDNS_SQUERY_RESEND_TIME (10000)  // 10 seconds, service query resend timeout
#define  MDNS_RESPONSE_TTL       (120)    // two minutes (in seconds)

#define  MDNS_MAX_SERVICES_PER_PACKET  (6)

//#define  _BROKEN_MALLOC_   1
#undef _USE_MALLOC_

static uint8_t mdnsMulticastIPAddr[] = { 224, 0, 0, 251 };
//static uint8_t mdnsHWAddr[] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb };

typedef enum _MDNSPacketType_t {
   MDNSPacketTypeMyIPAnswer,
   MDNSPacketTypeNoIPv6AddrAvailable,
   MDNSPacketTypeServiceRecord,
   MDNSPacketTypeServiceRecordRelease,
   MDNSPacketTypeNameQuery,
   MDNSPacketTypeServiceQuery,
} MDNSPacketType_t;

typedef struct _DNSHeader_t {
   uint16_t    xid;
   uint8_t     recursionDesired:1;
   uint8_t     truncated:1;
   uint8_t     authoritiveAnswer:1;
   uint8_t     opCode:4;
   uint8_t     queryResponse:1;
   uint8_t     responseCode:4;
   uint8_t     checkingDisabled:1;
   uint8_t     authenticatedData:1;
   uint8_t     zReserved:1;
   uint8_t     recursionAvailable:1;
   uint16_t    queryCount;
   uint16_t    answerCount;
   uint16_t    authorityCount;
   uint16_t    additionalCount;
} __attribute__((__packed__)) DNSHeader_t;

typedef enum _DNSOpCode_t {
   DNSOpQuery     = 0,
   DNSOpIQuery    = 1,
   DNSOpStatus    = 2,
   DNSOpNotify    = 4,
   DNSOpUpdate    = 5
} DNSOpCode_t;

// for some reason, I get data corruption issues with normal malloc() on arduino 0017
void* my_malloc(unsigned s)
{
#if defined(_BROKEN_MALLOC_)
   char* b = (char*)malloc(s+2);
   if (b)
      b++;

   return (void*)b;
#else
   return malloc(s);
#endif
}

void my_free(void* ptr)
{
#if defined(_BROKEN_MALLOC_)
   char* b = (char*)ptr;
   if (b)
      b--;

   free(b);
#else
   free(ptr);
#endif
}

MDNS::MDNS(UDP& udp)
{
   memset(&this->_mdnsData, 0, sizeof(MDNSDataInternal_t));
   memset(&this->_serviceRecords, 0, sizeof(this->_serviceRecords));

   this->_udp = &udp;
   this->_state = MDNSStateIdle;
//   this->_sock = -1;

   this->_name = NULL;
   this->_resolveNames[0] = NULL;
   this->_resolveNames[1] = NULL;

   this->_lastAnnounceMillis = 0;
}

MDNS::~MDNS()
{
	this->_udp->stop();
}

// return values:
// 1 on success
// 0 otherwise
int MDNS::begin(const IPAddress& ip, const char* name)
{
	// if we were called very soon after the board was booted, we need to give the
	// EthernetShield (WIZnet) some time to come up. Hence, we delay until millis() is at
	// least 3000. This is necessary, so that if we need to add a service record directly
	// after begin, the announce packet does not get lost in the bowels of the WIZnet chip.
	while (millis() < 3000) delay(100);

	_ipAddress = ip;

	int statusCode = 0;
	statusCode = this->setName(name);
	//if (statusCode)
	//statusCode = this->_udp->beginMulticast(mdnsMulticastIPAddr, MDNS_SERVER_PORT);
  if (statusCode) {
    ip4_addr_t mdns;
    IP4_ADDR(&mdns, mdnsMulticastIPAddr[0], mdnsMulticastIPAddr[1], mdnsMulticastIPAddr[2], mdnsMulticastIPAddr[3]);
    statusCode = igmp_joingroup(IP4_ADDR_ANY4, &mdns) == ERR_OK;
    if (statusCode) this->_udp->begin(MDNS_SERVER_PORT);
  }

	return statusCode;
}

// return values:
// 1 on success
// 0 otherwise
int MDNS::begin(const IPAddress& ip)
{
   return this->begin(ip, MDNS_DEFAULT_NAME);
}

// return values:
// 1 on success
// 0 otherwise
int MDNS::_initQuery(uint8_t idx, const char* name, unsigned long timeout)
{
   int statusCode = 0;

   if (NULL == this->_resolveNames[idx] && NULL != ((0==idx) ? (void*)this->_nameFoundCallback :
                                                               (void*)this->_serviceFoundCallback)) {
      this->_resolveNames[idx] = (uint8_t*)name;

      if (timeout)
         this->_resolveTimeouts[idx] = millis() + timeout;
      else
         this->_resolveTimeouts[idx] = 0;

      statusCode = (MDNSSuccess == this->_sendMDNSMessage(0,
                                             0,
                                             (idx == 0) ? MDNSPacketTypeNameQuery :
                                                          MDNSPacketTypeServiceQuery,
                                             0));
   } else
      my_free((void*)name);

   return statusCode;
}

void MDNS::_cancelQuery(uint8_t idx)
{
   if (NULL != this->_resolveNames[idx]) {
      my_free(this->_resolveNames[idx]);
      this->_resolveNames[idx] = NULL;
   }
}

// return values:
// 1 on success
// 0 otherwise
int MDNS::resolveName(const char* name, unsigned long timeout)
{
   this->cancelResolveName();

   char* n = (char*)my_malloc(strlen(name) + 7);
   if (NULL == n)
      return 0;

   strcpy(n, name);
   strcat(n, MDNS_TLD);

   return this->_initQuery(0, n, timeout);
}

void MDNS::setNameResolvedCallback(MDNSNameFoundCallback newCallback)
{
   this->_nameFoundCallback = newCallback;
}

void MDNS::cancelResolveName()
{
   this->_cancelQuery(0);
}

int MDNS::isResolvingName()
{
   return (NULL != this->_resolveNames[0]);
}

void MDNS::setServiceFoundCallback(MDNSServiceFoundCallback newCallback)
{
   this->_serviceFoundCallback = newCallback;
}

// return values:
// 1 on success
// 0 otherwise
int MDNS::startDiscoveringService(const char* serviceName,
                                                  MDNSServiceProtocol_t proto,
                                                  unsigned long timeout)
{
   this->stopDiscoveringService();

   char* n = (char*)my_malloc(strlen(serviceName) + 13);
   if (NULL == n)
      return 0;

   strcpy(n, serviceName);

   const uint8_t* srv_type = this->_postfixForProtocol(proto);
   if (srv_type)
      strcat(n, (const char*)srv_type);

   this->_resolveServiceProto = proto;

   return this->_initQuery(1, n, timeout);
}

void MDNS::stopDiscoveringService()
{
   this->_cancelQuery(1);
}

int MDNS::isDiscoveringService()
{
   return (NULL != this->_resolveNames[1]);
}

// return value:
// A DNSError_t (DNSSuccess on success, something else otherwise)
// in "int" mode: positive on success, negative on error
MDNSError_t MDNS::_sendMDNSMessage(uint32_t /*peerAddress*/, uint32_t xid, int type,
                                                   int serviceRecord)
{
   MDNSError_t statusCode = MDNSSuccess;
   uint16_t ptr = 0;
#if defined(_USE_MALLOC_)
   DNSHeader_t* dnsHeader = NULL;
#else
   DNSHeader_t dnsHeaderBuf;
   DNSHeader_t* dnsHeader = &dnsHeaderBuf;
#endif
   uint8_t* buf;



#if defined(_USE_MALLOC_)
   dnsHeader = (DNSHeader_t*)my_malloc(sizeof(DNSHeader_t));
   if (NULL == dnsHeader) {
      statusCode = MDNSOutOfMemory;
      goto errorReturn;
   }
#endif

   memset(dnsHeader, 0, sizeof(DNSHeader_t));

   dnsHeader->xid = ethutil_htons(xid);
   dnsHeader->opCode = DNSOpQuery;

   switch (type) {
      case MDNSPacketTypeServiceRecordRelease:
      case MDNSPacketTypeMyIPAnswer:
         dnsHeader->answerCount = ethutil_htons(1);
         dnsHeader->queryResponse = 1;
         dnsHeader->authoritiveAnswer = 1;
         break;
      case MDNSPacketTypeServiceRecord:
         dnsHeader->answerCount = ethutil_htons(4);
         dnsHeader->additionalCount = ethutil_htons(1);
         dnsHeader->queryResponse = 1;
         dnsHeader->authoritiveAnswer = 1;
         break;
      case MDNSPacketTypeNameQuery:
      case MDNSPacketTypeServiceQuery:
         dnsHeader->queryCount = ethutil_htons(1);
         break;
      case MDNSPacketTypeNoIPv6AddrAvailable:
         dnsHeader->queryCount = ethutil_htons(1);
         dnsHeader->additionalCount = ethutil_htons(1);
         dnsHeader->responseCode = 0x03;
         dnsHeader->authoritiveAnswer = 1;
         dnsHeader->queryResponse = 1;
         break;
   }




   this->_udp->beginPacket(mdnsMulticastIPAddr,MDNS_SERVER_PORT);
   this->_udp->write((uint8_t*)dnsHeader,sizeof(DNSHeader_t));

   ptr += sizeof(DNSHeader_t);
   buf = (uint8_t*)dnsHeader;

   // construct the answer section
   switch (type) {
      case MDNSPacketTypeMyIPAnswer: {
         this->_writeMyIPAnswerRecord(&ptr, buf, sizeof(DNSHeader_t));
         break;
      }

#if defined(HAS_SERVICE_REGISTRATION) && HAS_SERVICE_REGISTRATION

      case MDNSPacketTypeServiceRecord: {

         // SRV location record
         this->_writeServiceRecordName(serviceRecord, &ptr, buf, sizeof(DNSHeader_t), 0);

         buf[0] = 0x00;
         buf[1] = 0x21;    // SRV record
         buf[2] = 0x80;    // cache flush
         buf[3] = 0x01;    // class IN

         // ttl
         *((uint32_t*)&buf[4]) = ethutil_htonl(MDNS_RESPONSE_TTL);

         // data length
         *((uint16_t*)&buf[8]) = ethutil_htons(8 + strlen((char*)this->_name));

         this->_udp->write((uint8_t*)buf,10);
         ptr += 10;
         // priority and weight
         buf[0] = buf[1] = buf[2] = buf[3] = 0;

         // port
         *((uint16_t*)&buf[4]) = ethutil_htons(this->_serviceRecords[serviceRecord]->port);

         this->_udp->write((uint8_t*)buf,6);
         ptr += 6;
         // target
         this->_writeDNSName(this->_name, &ptr, buf, sizeof(DNSHeader_t), 1);

         // TXT record
         this->_writeServiceRecordName(serviceRecord, &ptr, buf, sizeof(DNSHeader_t), 0);

         buf[0] = 0x00;
         buf[1] = 0x10;    // TXT record
         buf[2] = 0x80;    // cache flush
         buf[3] = 0x01;    // class IN

         // ttl
         *((uint32_t*)&buf[4]) = ethutil_htonl(MDNS_RESPONSE_TTL);

         this->_udp->write((uint8_t*)buf,8);
         ptr += 8;

         // data length && text
         if (NULL == this->_serviceRecords[serviceRecord]->textContent) {
            buf[0] = 0x00;
            buf[1] = 0x01;
            buf[2] = 0x00;

            this->_udp->write((uint8_t*)buf,3);
            ptr += 3;
         } else {
            int slen = strlen((char*)this->_serviceRecords[serviceRecord]->textContent);
            *((uint16_t*)buf) = ethutil_htons(slen);
            this->_udp->write((uint8_t*)buf,2);
            ptr += 2;

            this->_udp->write((uint8_t*)this->_serviceRecords[serviceRecord]->textContent,slen);
            ptr += slen;
         }

         // PTR record (for the DNS-SD service in general)
         this->_writeDNSName((const uint8_t*)DNS_SD_SERVICE, &ptr, buf,
                                          sizeof(DNSHeader_t), 1);

         buf[0] = 0x00;
         buf[1] = 0x0c;    // PTR record
         buf[2] = 0x00;    // no cache flush
         buf[3] = 0x01;    // class IN

         // ttl
         *((uint32_t*)&buf[4]) = ethutil_htonl(MDNS_RESPONSE_TTL);

         // data length.
         uint16_t dlen = strlen((char*)this->_serviceRecords[serviceRecord]->servName) + 2;
         *((uint16_t*)&buf[8]) = ethutil_htons(dlen);

         this->_udp->write((uint8_t*)buf, 10);
         ptr += 10;

         this->_writeServiceRecordName(serviceRecord, &ptr, buf, sizeof(DNSHeader_t), 1);

         // PTR record (our service)
         this->_writeServiceRecordPTR(serviceRecord, &ptr, buf, sizeof(DNSHeader_t),
                                      MDNS_RESPONSE_TTL);

         // finally, our IP address as additional record
         this->_writeMyIPAnswerRecord(&ptr, buf, sizeof(DNSHeader_t));

         break;
      }

      case MDNSPacketTypeServiceRecordRelease: {
         // just send our service PTR with a TTL of zero
         this->_writeServiceRecordPTR(serviceRecord, &ptr, buf, sizeof(DNSHeader_t), 0);
         break;
      }

#endif // defined(HAS_SERVICE_REGISTRATION) && HAS_SERVICE_REGISTRATION

#if defined(HAS_NAME_BROWSING) && HAS_NAME_BROWSING

      case MDNSPacketTypeNameQuery:
      case MDNSPacketTypeServiceQuery:
      {
         // construct a query for the currently set _resolveNames[0]
         this->_writeDNSName(
               (type == MDNSPacketTypeServiceQuery) ? this->_resolveNames[1] :
                                                      this->_resolveNames[0],
               &ptr, buf, sizeof(DNSHeader_t), 1);

         buf[0] = buf[2] = 0x0;
         buf[1] = (type == MDNSPacketTypeServiceQuery) ? 0x0c : 0x01;
         buf[3] = 0x1;

         this->_udp->write((uint8_t*)buf, sizeof(DNSHeader_t));
         ptr += sizeof(DNSHeader_t);

         this->_resolveLastSendMillis[(type == MDNSPacketTypeServiceQuery) ? 1 : 0] = millis();

         break;
      }

#endif // defined(HAS_NAME_BROWSING) && HAS_NAME_BROWSING

      case MDNSPacketTypeNoIPv6AddrAvailable: {
         // since the WIZnet doesn't have IPv6, we will respond with a Not Found message
         this->_writeDNSName(this->_name, &ptr, buf, sizeof(DNSHeader_t), 1);

         buf[0] = buf[2] = 0x0;
         buf[1] = 0x1c; // AAAA record
         buf[3] = 0x01;

         this->_udp->write((uint8_t*)buf, 4);
         ptr += 4;

         // send our IPv4 address record as additional record, in case the peer wants it.
         this->_writeMyIPAnswerRecord(&ptr, buf, sizeof(DNSHeader_t));

         break;
      }
   }


   this->_udp->endPacket();

#if defined(_USE_MALLOC_)
errorReturn:

   if (NULL != dnsHeader)
      my_free(dnsHeader);
#endif

   return statusCode;
}

// return value:
// A DNSError_t (DNSSuccess on success, something else otherwise)
// in "int" mode: positive on success, negative on error
MDNSError_t MDNS::_processMDNSQuery()
{
   MDNSError_t statusCode = MDNSSuccess;
#if defined(_USE_MALLOC_)
   DNSHeader_t* dnsHeader = NULL;
#else
   DNSHeader_t dnsHeaderBuf;
   DNSHeader_t* dnsHeader = &dnsHeaderBuf;
#endif
   unsigned int i, j;
   uint8_t* buf;
   uint32_t xid = 0;
   uint16_t udp_len, qCnt, aCnt, aaCnt, addCnt;
   uint8_t recordsAskedFor[NumMDNSServiceRecords+2];
   uint8_t recordsFound[2];
   uint8_t wantsIPv6Addr = 0;
   uint8_t * udpBuffer = NULL;
   uintptr_t ptr;

   memset(recordsAskedFor, 0, sizeof(uint8_t)*(NumMDNSServiceRecords+2));
   memset(recordsFound, 0, sizeof(uint8_t)*2);


   udp_len = this->_udp->parsePacket();
   if (0 == udp_len) {
      statusCode = MDNSTryLater;
      goto errorReturn;
   }
   //Serial.println("mdns len ok");

   udpBuffer = (uint8_t*) my_malloc(udp_len);  //allocate memory to hold _remaining UDP packet
   if (NULL == udpBuffer) {
      this->_udp->flush();
      statusCode = MDNSOutOfMemory;
      goto errorReturn;
   }
   this->_udp->read((uint8_t*)udpBuffer, udp_len);//read _remaining UDP packet from W5100/W5200 into memory
   ptr = (uintptr_t)udpBuffer;

#if defined(_USE_MALLOC_)
   dnsHeader = (DNSHeader_t*)my_malloc(sizeof(DNSHeader_t));
   if (NULL == dnsHeader) {
      statusCode = MDNSOutOfMemory;
      goto errorReturn;
   }
#endif

   buf = (uint8_t*)dnsHeader;
   memcpy((uint8_t*)buf, (uint16_t*)ptr ,sizeof(DNSHeader_t));

   xid = ethutil_ntohs(dnsHeader->xid);
   qCnt = ethutil_ntohs(dnsHeader->queryCount);
   aCnt = ethutil_ntohs(dnsHeader->answerCount);
   aaCnt = ethutil_ntohs(dnsHeader->authorityCount);
   addCnt = ethutil_ntohs(dnsHeader->additionalCount);

   if (0 == dnsHeader->queryResponse &&
       DNSOpQuery == dnsHeader->opCode &&
       MDNS_SERVER_PORT == this->_udp->remotePort())
	  {
      // process an MDNS query
      int offset = sizeof(DNSHeader_t);
      uint8_t* buf = (uint8_t*)dnsHeader;
      int rLen = 0, tLen = 0;

      // read over the query section
      for (i=0; i_name;
         servNamePos[0] = 0;
         servLens[0] = strlen((char*)this->_name);
         servMatches[0] = 1;

         // second entry is our own the general DNS-SD service
         servNames[1] = (const uint8_t*)DNS_SD_SERVICE;
         servNamePos[1] = 0;
         servLens[1] = strlen((char*)DNS_SD_SERVICE);
         servMatches[1] = 1;

         for (j=2; j_serviceRecords[j-2] && NULL != this->_serviceRecords[j-2]->servName) {
               servNames[j] = this->_serviceRecords[j-2]->servName;
               servLens[j] = strlen((char*)servNames[j]);
               servMatches[j] = 1;
               servNamePos[j] = 0;
            } else {
               servNames[j] = NULL;
               servLens[j] = 0;
               servMatches[j] = 0;
               servNamePos[j] = 0;
            }

         tLen = 0;
         do {

        	memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,1);
            offset += 1;

            rLen = buf[0];
            tLen += 1;

            if (rLen > 128) {// handle DNS name compression, kinda, sorta


            	memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,1);
            	offset += 1;

               for (j=0; j 0) {
               int tr = rLen, ir;

               while (tr > 0) {
                  ir = (tr > (int)sizeof(DNSHeader_t)) ? sizeof(DNSHeader_t) : tr;

                  memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,ir);
                  offset += ir;
                  tr -= ir;

                  for (j=0; j_matchStringPart(&servNames[j], &servLens[j], buf,
                                                                 ir);
                  }
               }

               tLen += rLen;
            }
         } while (rLen > 0 && rLen <= 128);

         // if this matched a name of ours (and there are no characters left), then
         // check whether this is an A record query (for our own name) or a PTR record query
         // (for one of our services).
         // if so, we'll note to send a record

         memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,4);
         offset += 4;

         for (j=0; jqueryResponse &&
              DNSOpQuery == dnsHeader->opCode &&
              MDNS_SERVER_PORT == this->_udp->remotePort() &&
              (NULL != this->_resolveNames[0] || NULL != this->_resolveNames[1]))
	     {
         int offset = sizeof(DNSHeader_t);
         uint8_t* buf = (uint8_t*)dnsHeader;
         int rLen = 0, tLen = 0;

         uint8_t* ptrNames[MDNS_MAX_SERVICES_PER_PACKET];
         uint16_t ptrOffsets[MDNS_MAX_SERVICES_PER_PACKET];
         uint16_t ptrPorts[MDNS_MAX_SERVICES_PER_PACKET];
         uint8_t ptrIPs[MDNS_MAX_SERVICES_PER_PACKET];
         uint8_t servIPs[MDNS_MAX_SERVICES_PER_PACKET][5];
         uint8_t* servTxt[MDNS_MAX_SERVICES_PER_PACKET];
         memset(servIPs, 0, sizeof(uint8_t)*MDNS_MAX_SERVICES_PER_PACKET*5);
         memset(servTxt, 0, sizeof(uint8_t*)*MDNS_MAX_SERVICES_PER_PACKET);

         const uint8_t* ptrNamesCmp[MDNS_MAX_SERVICES_PER_PACKET];
         int ptrLensCmp[MDNS_MAX_SERVICES_PER_PACKET];
         uint8_t ptrNamesMatches[MDNS_MAX_SERVICES_PER_PACKET];

         uint8_t checkAARecords = 0;
         memset(ptrNames, 0, sizeof(uint8_t*)*MDNS_MAX_SERVICES_PER_PACKET);

         const uint8_t* servNames[2];
         uint8_t servNamePos[2];
         int servLens[2];
         uint8_t servMatches[2];
         uint8_t firstNamePtrByte = 0;
         uint8_t partMatched[2];
         uint8_t lastWasCompressed[2];
         uint8_t servWasCompressed[2];

         servNamePos[0] = servNamePos[1] = 0;

         for (i=0; i<(unsigned int)(qCnt+aCnt+aaCnt+addCnt); i++) {

            for (j=0; j<2; j++) {
               if (NULL != this->_resolveNames[j]) {
                  servNames[j] = this->_resolveNames[j];
                  servLens[j] = strlen((const char*)this->_resolveNames[j]);
                  servMatches[j] = 1;
               } else {
                  servNames[j] = NULL;
                  servLens[j] = servMatches[j] = 0;
               }
            }

            for (j=0; j 128) { // handle DNS name compression, kinda, sorta...

            	   memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,1);
                  offset += 1;

                  for (j=0; j<2; j++) {
                     if (servNamePos[j] && servNamePos[j] != buf[0])
                        servMatches[j] = 0;
                     else
                        servWasCompressed[j] = 1;

                     lastWasCompressed[j] = 1;
                  }

                  tLen += 1;

                  if (0 == firstNamePtrByte)
                     firstNamePtrByte = buf[0];
               } else if (rLen > 0) {
                  if (i < qCnt)
                     offset += rLen;
                  else {
                     int tr = rLen, ir;

                     if (0 == firstNamePtrByte)
                        firstNamePtrByte = offset-1; // -1, since we already read length (1 byte)

                     while (tr > 0) {
                        ir = (tr > (int)sizeof(DNSHeader_t)) ? sizeof(DNSHeader_t) : tr;
                        memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,ir);
                        offset += ir;
                        tr -= ir;

                        for (j=0; j<2; j++) {
                           if (!recordsFound[j] && servMatches[j] && servNames[j])
                              servMatches[j] &= this->_matchStringPart(&servNames[j], &servLens[j],
                                                                       buf, ir);
                           if (!partMatched[j])
                              partMatched[j] = servMatches[j];

                           lastWasCompressed[j] = 0;
                        }

                        for (j=0; j= ir)
                                 ptrNamesMatches[j] &= this->_matchStringPart(&ptrNamesCmp[j],
                                                            &ptrLensCmp[j], buf, ir);
                           }
                        }
                     }

                     tLen += rLen;
                  }
               }
            } while (rLen > 0 && rLen <= 128);

            // if this matched a name of ours (and there are no characters left), then
            // check whether this is an A record query (for our own name) or a PTR record query
            // (for one of our services).
            // if so, we'll note to send a record
            if (i < qCnt)
               offset += 4;
            else if (i >= qCnt) {
               if (i >= qCnt + aCnt && !checkAARecords)
                  break;

               uint8_t packetHandled = 0;

               memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,4);
               offset += 4;
               if (i < qCnt+aCnt) {
                  for (j=0; j<2; j++) {
                     if (0 == servNamePos[j])
                        servNamePos[j] = offset - 4 - tLen;

                     if (servNames[j] &&
                         ((servMatches[j] && 0 == servLens[j]) ||
                         (partMatched[j] && lastWasCompressed[j]) ||
                         (servWasCompressed[j] && servMatches[j]))) { // somewhat handle compression by guessing

                        if (buf[0] == 0 && buf[1] == ((0 == j) ? 0x01 : 0x0c) &&
                           (buf[2] == 0x00 || buf[2] == 0x80) && buf[3] == 0x01) {
                           recordsFound[j] = 1;

                           // this is an A or PTR type response. Parse it as such.

                           memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,6);
                           offset += 6;
                           //uint32_t ttl = ethutil_ntohl(*(uint32_t*)buf);
                           uint16_t dataLen = ethutil_ntohs(*(uint16_t*)&buf[4]);

                           if (0 == j && 4 == dataLen) {
                              // ok, this is the IP address. report it via callback.

                        	   memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,4);

                              this->_finishedResolvingName((char*)this->_resolveNames[0],
                                                           (const byte*)buf);
                           } else if (1 == j) {
                              uint8_t k;
                              for (k=0; k= (unsigned int)(qCnt+aCnt+aaCnt)) {
                  //  check whether we find a service description
                  if (buf[1] == 0x21) {
                     for (j=0; j= 8) {

                        	   memcpy((uint8_t*)buf, (uint16_t*)(ptr+offset) ,8);
                              ptrPorts[j] = ethutil_ntohs(*(uint16_t*)&buf[4]);

                              if (buf[6] > 128) { // target is a compressed name
                                 ptrIPs[j] = buf[7];
                              } else { // target is uncompressed
                                 ptrIPs[j] = offset+6;
                              }
                           }
                           offset += dataLen;
                           packetHandled = 1;

                           break;
                        }
                     }
                 } else if (buf[1] == 0x10) { // txt record
                     for (j=0; j 1 && NULL == servTxt[j]) {
                              servTxt[j] = (uint8_t*)my_malloc(dataLen+1);
                              if (NULL != servTxt[j]) {

                            	  memcpy((uint8_t*)servTxt[j], (uint16_t*)(ptr+offset) ,dataLen);

                                 // zero-terminate
                                 servTxt[j][dataLen] = '\0';
                              }
                           }
                           offset += dataLen;
                           packetHandled = 1;

                           break;
                        }
                     }
                  } else if (buf[1] == 0x01) { // A record (IPv4 address)
                     for (j=0; j_resolveNames[1]) {
            char* typeName = (char*)this->_resolveNames[1];
            char* p = (char*)this->_resolveNames[1];
            while(*p && *p != '.')
               p++;
            *p = '\0';

            for (i=0; i_serviceFoundCallback) {
                     this->_serviceFoundCallback(typeName,
                                                this->_resolveServiceProto,
                                                (const char*)ptrNames[i],
                                                IPAddress((const byte*)ipAddr),
                                                (unsigned short)ptrPorts[i],
                                                (const char*)servTxt[i]);
                  }
               }
            *p = '.';
         }

         uint8_t k;
         for (k=0; k_sendMDNSMessage(this->_udp->remoteIP(), xid, (int)MDNSPacketTypeMyIPAnswer, 0);
         else if (1 == j) {
            uint8_t k = 2;
            for (k=0; k_serviceRecords[j-2])
            (void)this->_sendMDNSMessage(this->_udp->remoteIP(), xid, (int)MDNSPacketTypeServiceRecord, j-2);
      }
   }

   // if we were asked for our IPv6 address, say that we don't have any
   if (wantsIPv6Addr)
      (void)this->_sendMDNSMessage(this->_udp->remoteIP(), xid, (int)MDNSPacketTypeNoIPv6AddrAvailable, 0);

   return statusCode;
}

void MDNS::run()
{
   uint8_t i;
   unsigned long now = millis();

   // first, look for mDNS queries to handle
   (void)_processMDNSQuery();

   // are we querying a name or service? if so, should we resend the packet or time out?
   for (i=0; i<2; i++) {
      if (NULL != this->_resolveNames[i]) {
         // Hint: _resolveLastSendMillis is updated in _sendMDNSMessage
         if (now - this->_resolveLastSendMillis[i] > ((i == 0) ? (uint32_t)MDNS_NQUERY_RESEND_TIME :
                                                                 (uint32_t)MDNS_SQUERY_RESEND_TIME))
            (void)this->_sendMDNSMessage(0,
                                         0,
                                         (0 == i) ? MDNSPacketTypeNameQuery :
                                                    MDNSPacketTypeServiceQuery,
                                         0);

         if (this->_resolveTimeouts[i] > 0 && now > this->_resolveTimeouts[i]) {
            if (i == 0)
               this->_finishedResolvingName((char*)this->_resolveNames[0], NULL);
            else if (i == 1) {
               if (this->_serviceFoundCallback) {
                  char* typeName = (char*)this->_resolveNames[1];
                  char* p = (char*)this->_resolveNames[1];
                  while(*p && *p != '.')
                     p++;
                  *p = '\0';

                  this->_serviceFoundCallback(typeName,
                                              this->_resolveServiceProto,
                                              NULL,
                                              IPAddress(),
                                              0,
                                              NULL);
               }
            }

            if (NULL != this->_resolveNames[i]) {
               my_free(this->_resolveNames[i]);
               this->_resolveNames[i] = NULL;
            }
         }
      }
   }

   // now, should we re-announce our services again?
   unsigned long announceTimeOut = (((uint32_t)MDNS_RESPONSE_TTL/2)+((uint32_t)MDNS_RESPONSE_TTL/4));
   if ((now - this->_lastAnnounceMillis) > 1000*announceTimeOut) {
      for (i=0; i_serviceRecords[i])
            (void)this->_sendMDNSMessage(0, 0, (int)MDNSPacketTypeServiceRecord, i);
      }

      this->_lastAnnounceMillis = now;
   }
}

// return values:
// 1 on success
// 0 otherwise
int MDNS::setName(const char* name)
{
   if (NULL == name)
      return 0;

   if (this->_name != NULL)
      my_free(this->_name);

   this->_name = (uint8_t*)my_malloc(strlen(name) + 7);
   if (NULL == this->_name)
      return 0;

   strcpy((char*)this->_name, name);
   strcpy((char*)this->_name+strlen(name), MDNS_TLD);

   return 1;
}

// return values:
// 1 on success
// 0 otherwise
int MDNS::addServiceRecord(const char* name, uint16_t port,
                                           MDNSServiceProtocol_t proto)
{
#if defined(__MK20DX128__) || defined(__MK20DX256__)
	 return this->addServiceRecord(name, port, proto, NULL); //works for Teensy 3 (32-bit Arm Cortex)
#else
   return this->addServiceRecord(name, port, proto, ""); //works for Teensy 2 (8-bit Atmel)
#endif
}

// return values:
// 1 on success
// 0 otherwise
int MDNS::addServiceRecord(const char* name, uint16_t port,
                                           MDNSServiceProtocol_t proto, const char* textContent)
{
   int i, status = 0;
   MDNSServiceRecord_t* record = NULL;

   if (NULL != name && 0 != port) {
      for (i=0; i < NumMDNSServiceRecords; i++) {
         if (NULL == this->_serviceRecords[i]) {
            record = (MDNSServiceRecord_t*)my_malloc(sizeof(MDNSServiceRecord_t));
            if (NULL != record) {
               record->name = record->textContent = NULL;

               record->name = (uint8_t*)my_malloc(strlen((char*)name));
               if (NULL == record->name)
                  goto errorReturn;

               if (NULL != textContent) {
                  record->textContent = (uint8_t*)my_malloc(strlen((char*)textContent));
                  if (NULL == record->textContent)
                     goto errorReturn;

                  strcpy((char*)record->textContent, textContent);
               }

               record->port = port;
               record->proto = proto;
               strcpy((char*)record->name, name);

               uint8_t* s = this->_findFirstDotFromRight(record->name);
               record->servName = (uint8_t*)my_malloc(strlen((char*)s) + 12);
               if (record->servName) {
                  strcpy((char*)record->servName, (const char*)s);

                  const uint8_t* srv_type = this->_postfixForProtocol(proto);
                  if (srv_type)
                     strcat((char*)record->servName, (const char*)srv_type);
               }

               this->_serviceRecords[i] = record;

               status = (MDNSSuccess ==
                           this->_sendMDNSMessage(0, 0, (int)MDNSPacketTypeServiceRecord, i));

               break;
            }
         }
      }
   }

   return status;

errorReturn:
   if (NULL != record) {
      if (NULL != record->name)
         my_free(record->name);
      if (NULL != record->servName)
         my_free(record->servName);
      if (NULL != record->textContent)
         my_free(record->textContent);

      my_free(record);
   }

   return 0;
}

void MDNS::_removeServiceRecord(int idx)
{
   if (NULL != this->_serviceRecords[idx]) {
      (void)this->_sendMDNSMessage(0, 0, (int)MDNSPacketTypeServiceRecordRelease, idx);

      if (NULL != this->_serviceRecords[idx]->textContent)
         my_free(this->_serviceRecords[idx]->textContent);

      if (NULL != this->_serviceRecords[idx]->servName)
         my_free(this->_serviceRecords[idx]->servName);

      my_free(this->_serviceRecords[idx]->name);
      my_free(this->_serviceRecords[idx]);

      this->_serviceRecords[idx] = NULL;
   }
}

void MDNS::removeServiceRecord(uint16_t port, MDNSServiceProtocol_t proto)
{
   this->removeServiceRecord(NULL, port, proto);
}

void MDNS::removeServiceRecord(const char* name, uint16_t port,
                                               MDNSServiceProtocol_t proto)
{
   int i;
   for (i=0; i_serviceRecords[i]->port &&
          proto == this->_serviceRecords[i]->proto &&
          (NULL == name || 0 == strcmp((char*)this->_serviceRecords[i]->name, name))) {
             this->_removeServiceRecord(i);
             break;
          }
}

void MDNS::removeAllServiceRecords()
{
   int i;
   for (i=0; i_removeServiceRecord(i);
}

void MDNS::_writeDNSName(const uint8_t* name, uint16_t* pPtr,
                                         uint8_t* buf, int bufSize, int zeroTerminate)
{
   uint16_t ptr = *pPtr;
   uint8_t* p1 = (uint8_t*)name, *p2, *p3;
   int i, c, len;

   while(*p1) {
      c = 1;
      p2 = p1;
      while (0 != *p2 && '.' != *p2) { p2++; c++; };

      p3 = buf;
      i = c;
      len = bufSize-1;
      *p3++ = (uint8_t)--i;
      while (i-- > 0) {
         *p3++ = *p1++;

         if (--len <= 0) {
            this->_udp->write((uint8_t*)buf, bufSize);
            ptr += bufSize;
            len = bufSize;
            p3 = buf;
         }
      }

      while ('.' == *p1)
         ++p1;

      if (len != bufSize) {
    	  this->_udp->write((uint8_t*)buf, bufSize-len);
         ptr += bufSize-len;
      }
   }

   if (zeroTerminate) {
      buf[0] = 0;
      this->_udp->write((uint8_t*)buf, 1);
      ptr += 1;
   }

   *pPtr = ptr;
}

void MDNS::_writeMyIPAnswerRecord(uint16_t* pPtr, uint8_t* buf, int bufSize)
{
   uint16_t ptr = *pPtr;

   this->_writeDNSName(this->_name, &ptr, buf, bufSize, 1);

   buf[0] = 0x00;
   buf[1] = 0x01;
   buf[2] = 0x80; // cache flush: true
   buf[3] = 0x01;
   this->_udp->write((uint8_t*)buf, 4);
   ptr += 4;

   *((uint32_t*)buf) = ethutil_htonl(MDNS_RESPONSE_TTL);
   *((uint16_t*)&buf[4]) = ethutil_htons(4);      // data length

   uint8_t myIp[4];
   myIp[0] = _ipAddress [0];
   myIp[1] = _ipAddress [1];
   myIp[2] = _ipAddress [2];
   myIp[3] = _ipAddress [3];

   memcpy(&buf[6], &myIp, 4);              // our IP address

   this->_udp->write((uint8_t*)buf, 10);
   ptr += 10;

   *pPtr = ptr;
}

void MDNS::_writeServiceRecordName(int recordIndex, uint16_t* pPtr, uint8_t* buf,
                                                   int bufSize, int tld)
{
   uint16_t ptr = *pPtr;

   uint8_t* name = tld ? this->_serviceRecords[recordIndex]->servName :
                         this->_serviceRecords[recordIndex]->name;

   this->_writeDNSName(name, &ptr, buf, bufSize, tld);

   if (0 == tld) {
      const uint8_t* srv_type =
         this->_postfixForProtocol(this->_serviceRecords[recordIndex]->proto);

      if (NULL != srv_type) {
         srv_type++; // eat the dot at the beginning
         this->_writeDNSName(srv_type, &ptr, buf, bufSize, 1);
      }
   }

   *pPtr = ptr;
}

void MDNS::_writeServiceRecordPTR(int recordIndex, uint16_t* pPtr, uint8_t* buf,
                                                  int bufSize, uint32_t ttl)
{
   uint16_t ptr = *pPtr;

   this->_writeServiceRecordName(recordIndex, &ptr, buf, bufSize, 1);

   buf[0] = 0x00;
   buf[1] = 0x0c;    // PTR record
   buf[2] = 0x00;    // no cache flush
   buf[3] = 0x01;    // class IN

   // ttl
   *((uint32_t*)&buf[4]) = ethutil_htonl(ttl);

   // data length (+13 = "._tcp.local" or "._udp.local" + 1  byte zero termination)
   *((uint16_t*)&buf[8]) =
         ethutil_htons(strlen((char*)this->_serviceRecords[recordIndex]->name) + 13);

   this->_udp->write((uint8_t*)buf, 10);
   ptr += 10;

   this->_writeServiceRecordName(recordIndex, &ptr, buf, bufSize, 0);

   *pPtr = ptr;
}

uint8_t* MDNS::_findFirstDotFromRight(const uint8_t* str)
{
   const uint8_t* p = str + strlen((char*)str);
   while (p > str && '.' != *p--);
   return (uint8_t*)&p[2];
}

int MDNS::_matchStringPart(const uint8_t** pCmpStr, int* pCmpLen, const uint8_t* buf,
                                           int dataLen)
{
   int matches = 1;

   if (*pCmpLen >= dataLen)
      matches &= (0 == memcmp(*pCmpStr, buf, dataLen));
   else
      matches = 0;

   *pCmpStr += dataLen;
   *pCmpLen -= dataLen;
   if ('.' == **pCmpStr)
      (*pCmpStr)++, (*pCmpLen)--;

   return matches;
}

const uint8_t* MDNS::_postfixForProtocol(MDNSServiceProtocol_t proto)
{
   const uint8_t* srv_type = NULL;
   switch(proto) {
      case MDNSServiceTCP:
         srv_type = (uint8_t*)"._tcp" MDNS_TLD;
         break;
      case MDNSServiceUDP:
         srv_type = (uint8_t*)"._udp" MDNS_TLD;
         break;
   }

   return srv_type;
}

void MDNS::_finishedResolvingName(char* name, const byte ipAddr[4])
{
   if (NULL != this->_nameFoundCallback) {
      if (NULL != name) {
         uint8_t* n = this->_findFirstDotFromRight((const uint8_t*)name);
         *(n-1) = '\0';
      }

      this->_nameFoundCallback((const char*)name, IPAddress(ipAddr));
   }

   my_free(this->_resolveNames[0]);
   this->_resolveNames[0] = NULL;
}

#if !defined(__MDNS_H__)
#define __MDNS_H__ 1

extern "C" {
  #include 
}

#include 

typedef uint8_t byte;

typedef enum _MDNSState_t {
  MDNSStateIdle,
  MDNSStateQuerySent
} MDNSState_t;

typedef enum _MDNSError_t {
  MDNSTryLater = 3,
  MDNSNothingToDo = 2,
  MDNSSuccess  = 1,
  MDNSInvalidArgument = -1,
  MDNSOutOfMemory = -2,
  MDNSSocketError = -3,
  MDNSAlreadyProcessingQuery = -4,
  MDNSNotFound = -5,
  MDNSServerError = -6,
  MDNSTimedOut = -7
} MDNSError_t;

typedef struct _MDNSDataInternal_t {
  uint32_t xid;
  uint32_t lastQueryFirstXid;
} MDNSDataInternal_t;

typedef enum _MDNSServiceProtocol_t {
  MDNSServiceTCP,
  MDNSServiceUDP
} MDNSServiceProtocol_t;

typedef MDNSServiceProtocol_t MDNSServiceProtocol;

typedef struct _MDNSServiceRecord_t {
  uint16_t              port;
  MDNSServiceProtocol_t proto;
  uint8_t*              name;
  uint8_t*              servName;
  uint8_t*              textContent;
} MDNSServiceRecord_t;

typedef void (*MDNSNameFoundCallback)(const char*, IPAddress);
typedef void (*MDNSServiceFoundCallback)(const char*, MDNSServiceProtocol_t, const char*, IPAddress, unsigned short, const char*);

#define  NumMDNSServiceRecords   (8)

//class MDNS
class MDNS {
private:
  UDP*                 _udp;
  IPAddress            _ipAddress;
  MDNSDataInternal_t   _mdnsData;
  MDNSState_t          _state;
  uint8_t*             _name;
  MDNSServiceRecord_t* _serviceRecords[NumMDNSServiceRecords];
  unsigned long        _lastAnnounceMillis;

  uint8_t*             _resolveNames[2];
  unsigned long        _resolveLastSendMillis[2];
  unsigned long        _resolveTimeouts[2];

  MDNSServiceProtocol_t _resolveServiceProto;

  MDNSNameFoundCallback    _nameFoundCallback;
  MDNSServiceFoundCallback _serviceFoundCallback;

  MDNSError_t _processMDNSQuery();
  MDNSError_t _sendMDNSMessage(uint32_t peerAddress, uint32_t xid, int type, int serviceRecord);


  void _writeDNSName(const uint8_t* name, uint16_t* pPtr, uint8_t* buf, int bufSize, int zeroTerminate);
  void _writeMyIPAnswerRecord(uint16_t* pPtr, uint8_t* buf, int bufSize);
  void _writeServiceRecordName(int recordIndex, uint16_t* pPtr, uint8_t* buf, int bufSize, int tld);
  void _writeServiceRecordPTR(int recordIndex, uint16_t* pPtr, uint8_t* buf, int bufSize, uint32_t ttl);

  int _initQuery(uint8_t idx, const char* name, unsigned long timeout);
  void _cancelQuery(uint8_t idx);

  uint8_t* _findFirstDotFromRight(const uint8_t* str);

  void _removeServiceRecord(int idx);

  int _matchStringPart(const uint8_t** pCmpStr, int* pCmpLen, const uint8_t* buf, int dataLen);

  const uint8_t* _postfixForProtocol(MDNSServiceProtocol_t proto);

  void _finishedResolvingName(char* name, const byte ipAddr[4]);
public:
  MDNS(UDP& udp);
  ~MDNS();

  int begin(const IPAddress& ip);
  int begin(const IPAddress& ip, const char* name);
  void run();

  int setName(const char* name);

  int addServiceRecord(const char* name, uint16_t port, MDNSServiceProtocol_t proto);
  int addServiceRecord(const char* name, uint16_t port, MDNSServiceProtocol_t proto, const char* textContent);

  void removeServiceRecord(uint16_t port, MDNSServiceProtocol_t proto);
  void removeServiceRecord(const char* name, uint16_t port, MDNSServiceProtocol_t proto);

  void removeAllServiceRecords();

  void setNameResolvedCallback(MDNSNameFoundCallback newCallback);
  int resolveName(const char* name, unsigned long timeout);
  void cancelResolveName();
  int isResolvingName();

  void setServiceFoundCallback(MDNSServiceFoundCallback newCallback);
  int startDiscoveringService(const char* serviceName, MDNSServiceProtocol_t proto, unsigned long timeout);
  void stopDiscoveringService();
  int isDiscoveringService();
};

#endif // __MDNS_H__

●NetBIOS(NetBIOS.cpp/NetBIOS.h) ※どこか(覚えていない)からportingしたものです

#include "NetBIOS.h"

#include 

#define NBNS_PORT 137
#define NBNS_MAX_HOSTNAME_LEN 32

typedef struct {
  uint16_t id;
  uint8_t flags1;
  uint8_t flags2;
  uint16_t qcount;
  uint16_t acount;
  uint16_t nscount;
  uint16_t adcount;
  uint8_t name_len;
  char name[NBNS_MAX_HOSTNAME_LEN + 1];
  uint16_t type;
  uint16_t clas;
} __attribute__((packed)) nbns_question_t;

typedef struct {
  uint16_t id;
  uint8_t flags1;
  uint8_t flags2;
  uint16_t qcount;
  uint16_t acount;
  uint16_t nscount;
  uint16_t adcount;
  uint8_t name_len;
  char name[NBNS_MAX_HOSTNAME_LEN + 1];
  uint16_t type;
  uint16_t clas;
  uint32_t ttl;
  uint16_t data_len;
  uint16_t flags;
  uint32_t addr;
} __attribute__((packed)) nbns_answer_t;

#undef _USE_MALLOC_
// for some reason, I get data corruption issues with normal malloc() on arduino 0017
void *sf_malloc(unsigned s) {
#if defined(_BROKEN_MALLOC_)
  char* b = (char *)malloc(s + 2);
  if (b) b++;
  return (void *)b;
#else
  return malloc(s);
#endif
}
void sf_free(void *ptr) {
#if defined(_BROKEN_MALLOC_)
  char *b = (char *)ptr;
  if (b) b--;
  free(b);
#else
  free(ptr);
#endif
}

static void _getnbname(const char *nbname, char *name, uint8_t maxlen) {
  uint8_t b;
  uint8_t c = 0;
  while ((*nbname) && (c < maxlen)) {
    b = (*nbname++ - 'A') << 4;
    c++;
    if (*nbname) {
      b |= *nbname++ - 'A';
      c++;
    }
    if(!b || b == ' ') break;
    *name++ = b;
  }
  *name = 0;
}

static void append_16(void * dst, uint16_t value) {
  uint8_t * d = (uint8_t *)dst;
  *d++ = (value >> 8) & 0xFF;
  *d++ = value & 0xFF;
}

static void append_32(void * dst, uint32_t value) {
  uint8_t * d = (uint8_t *)dst;
  *d++ = (value >> 24) & 0xFF;
  *d++ = (value >> 16) & 0xFF;
  *d++ = (value >> 8) & 0xFF;
  *d++ = value & 0xFF;
}

void NetBIOS::_processUdpQuery() {
  uint16_t udp_len;
  uint8_t *udpBuffer;

  if (!(udp_len = _udp.parsePacket())) return;
  if (!(udpBuffer = (uint8_t *)sf_malloc(udp_len))) {
    _udp.flush();
    return;
  }
  _udp.read(udpBuffer, udp_len);

  if (udp_len >= sizeof(nbns_question_t)) {
    nbns_question_t *question = (nbns_question_t *)udpBuffer;
    if (0 == (question->flags1 & 0x80)) {
      char name[NBNS_MAX_HOSTNAME_LEN + 1];
      _getnbname(&question->name[0], (char *)&name, question->name_len);
      if (_name.equals(name)) {
        nbns_answer_t nbnsa;
        nbnsa.id = question->id;
        nbnsa.flags1 = 0x85;
        nbnsa.flags2 = 0;
        append_16((void *)&nbnsa.qcount, 0);
        append_16((void *)&nbnsa.acount, 1);
        append_16((void *)&nbnsa.nscount, 0);
        append_16((void *)&nbnsa.adcount, 0);
        nbnsa.name_len = question->name_len;
        memcpy(&nbnsa.name[0], &question->name[0], question->name_len + 1);
        append_16((void *)&nbnsa.type, 0x20);
        append_16((void *)&nbnsa.clas, 1);
        //append_32((void *)&nbnsa.ttl, 300000);
        append_32((void *)&nbnsa.ttl, 120);
        append_16((void *)&nbnsa.data_len, 6);
        append_16((void *)&nbnsa.flags, 0);
        nbnsa.addr = WiFi.localIP();
        _udp.beginPacket(_udp.remoteIP(), NBNS_PORT);
        _udp.write((uint8_t *)&nbnsa, sizeof(nbnsa));
        _udp.endPacket();
      }
    }
  }
  sf_free(udpBuffer);
}

NetBIOS::NetBIOS() {}
NetBIOS::~NetBIOS() {
  end();
}

bool NetBIOS::begin(const char *name){
  _name = name;
  _name.toUpperCase();
  return _udp.begin(NBNS_PORT);
}

void NetBIOS::run(){
  _processUdpQuery();
}

void NetBIOS::end(){
  _udp.stopAll();
}

#ifndef __NBNS_h__
#define __NBNS_h__

#include 
#include 

class NetBIOS {
protected:
  WiFiUDP _udp;
  String _name;
  void _processUdpQuery();

public:
  NetBIOS();
  ~NetBIOS();
  bool begin(const char *name);
  void run();
  void end();
};

#endif

●Ticker(Ticker.cpp/Ticker.h) ※どこか(覚えていない)からportingしたものです

#include "Ticker.h"

Ticker::Ticker() :
  _timer(WM_TIMER_ID_INVALID) {}

Ticker::~Ticker() {
  detach();
}

void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, tls_timer_irq_callback callback, uint32_t arg) {
  tls_timer_cfg _timerConfig;
  _timerConfig.unit = TLS_TIMER_UNIT_MS; // or TLS_TIMER_UNIT_US
  _timerConfig.timeout = milliseconds;
  _timerConfig.is_repeat = repeat;
  _timerConfig.callback = callback;
  _timerConfig.arg = reinterpret_cast(arg);
  if (_timer != WM_TIMER_ID_INVALID) {
    tls_timer_stop(_timer);
    tls_timer_destroy(_timer);
  }
  _timer = tls_timer_create(&_timerConfig);
  tls_timer_start(_timer);
}

void Ticker::detach() {
  if (_timer != WM_TIMER_ID_INVALID) {
    tls_timer_stop(_timer);
    tls_timer_destroy(_timer);
    _timer = WM_TIMER_ID_INVALID;
  }
}

bool Ticker::active() {
  if (_timer == WM_TIMER_ID_INVALID) return false;
  //return esp_timer_is_active(_timer);
  return true;
}

#ifndef TICKER_H
#define TICKER_H

#include 
extern "C" {
  #include "wm_timer.h"
}

class Ticker {
public:
  Ticker();
  ~Ticker();
  typedef void (*callback_t)(void);
  typedef void (*tls_timer_irq_callback)(void*);

  void attach(float seconds, callback_t callback) {
    _attach_ms(seconds * 1000, true, reinterpret_cast(callback), 0);
  }
  void attach_ms(uint32_t milliseconds, callback_t callback) {
    _attach_ms(milliseconds, true, reinterpret_cast(callback), 0);
  }
  template
  void attach(float seconds, void (*callback)(TArg), TArg arg) {
    static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach() callback argument size must be <= 4 bytes");
    uint32_t arg32 = (uint32_t)arg;
    _attach_ms(seconds * 1000, true, reinterpret_cast(callback), arg32);
  }
  template
  void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) {
    static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach_ms() callback argument size must be <= 4 bytes");
    uint32_t arg32 = (uint32_t)arg;
    _attach_ms(milliseconds, true, reinterpret_cast(callback), arg32);
  }

  void once(float seconds, callback_t callback) {
    _attach_ms(seconds * 1000, false, reinterpret_cast(callback), 0);
  }
  void once_ms(uint32_t milliseconds, callback_t callback) {
    _attach_ms(milliseconds, false, reinterpret_cast(callback), 0);	
  }
  template
  void once(float seconds, void (*callback)(TArg), TArg arg) {
    static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach() callback argument size must be <= 4 bytes");
    uint32_t arg32 = (uint32_t)(arg);
    _attach_ms(seconds * 1000, false, reinterpret_cast(callback), arg32);
  }
  template
  void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) {
    static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach_ms() callback argument size must be <= 4 bytes");
    uint32_t arg32 = (uint32_t)(arg);
    _attach_ms(milliseconds, false, reinterpret_cast(callback), arg32);
  }

  void detach();
  bool active();

protected:	
  void _attach_ms(uint32_t milliseconds, bool repeat, tls_timer_irq_callback callback, uint32_t arg);

protected:
  uint8_t _timer;
};

#endif  // TICKER_H

●localtime.h

struct tm {
  uint8_t tm_sec;
  uint8_t tm_min;
  uint8_t tm_hour;
  uint8_t tm_mday;
  uint8_t tm_mon;
  uint8_t tm_year;
  uint8_t tm_wday;
  uint16_t tm_yday;
  uint8_t tm_isdst;
} tm;

struct tm *localtime(time_t *t) {
  uint32_t t2 = *t - 946684800 - 2208988800; // - (2000 - 1970) - (1970 - 1900)
  tm.tm_sec = t2 % 60;
  tm.tm_min = (t2 /= 60) % 60;
  tm.tm_hour = (t2 /= 60) % 24;
  t2 = t2 / 24;
  tm.tm_year = 0;
  while (t2 > (tm.tm_year % 4 ? 364 : 365)) t2 -= (tm.tm_year++ % 4 ? 365 : 366);
  tm.tm_yday = t2;
  uint8_t days[12] = { 31, (uint8_t)(tm.tm_year % 4 ? 28 : 29), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  tm.tm_mon = 0;
  while (t2 >= days[tm.tm_mon]) t2 -= days[tm.tm_mon++];
  tm.tm_mday = t2 + 1;
  tm.tm_wday = ((uint16_t)tm.tm_year + (tm.tm_year - 1) / 4 + tm.tm_yday) % 7;
  tm.tm_year += 100;
  tm.tm_isdst = 0;
  return &tm;
}


ibunyan.com