diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 2103b21..18b2617 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -25,7 +25,7 @@ jobs: uses: codespell-project/actions-codespell@master with: skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash - ignore_words_list: ser,dout,shiftIn + ignore_words_list: ser,dout,shiftIn,acount # Consistent style astyle: diff --git a/.gitmodules b/.gitmodules index 594b011..1dd137b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -40,3 +40,6 @@ [submodule "libraries/FatFS/lib/SPIFTL"] path = libraries/FatFS/lib/SPIFTL url = https://github.com/earlephilhower/SPIFTL.git +[submodule "libraries/AsyncUDP"] + path = libraries/AsyncUDP + url = https://github.com/earlephilhower/AsyncUDP.git diff --git a/libraries/AsyncUDP b/libraries/AsyncUDP new file mode 160000 index 0000000..dd32bfa --- /dev/null +++ b/libraries/AsyncUDP @@ -0,0 +1 @@ +Subproject commit dd32bfa7d92783cbbede75bb343853d317d3a6a8 diff --git a/libraries/NetBIOS/examples/PicoW_NetBIOS/PicoW_NetBIOS.ino b/libraries/NetBIOS/examples/PicoW_NetBIOS/PicoW_NetBIOS.ino new file mode 100644 index 0000000..68d405e --- /dev/null +++ b/libraries/NetBIOS/examples/PicoW_NetBIOS/PicoW_NetBIOS.ino @@ -0,0 +1,37 @@ +// Modified from the ESP32-NetBIOS example + +#include +#include + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +void setup() { + Serial.begin(115200); + + // Connect to WiFi network + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // Windows (and other OSes using WINS/NetBIOS resolution should now be able to find the device by name) + NBNS.begin("PicoW"); +} + +void loop() {} diff --git a/libraries/NetBIOS/keywords.txt b/libraries/NetBIOS/keywords.txt new file mode 100755 index 0000000..68bcbee --- /dev/null +++ b/libraries/NetBIOS/keywords.txt @@ -0,0 +1,25 @@ +####################################### +# Syntax Coloring Map For ESPNBNS +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +NetBIOS KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +NBNS KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/NetBIOS/library.properties b/libraries/NetBIOS/library.properties new file mode 100644 index 0000000..2365b93 --- /dev/null +++ b/libraries/NetBIOS/library.properties @@ -0,0 +1,9 @@ +name=NetBIOS +version=2.0.0 +author=Pablo@xpablo.cz +maintainer=Earle F. Philhower, III +sentence=Enables NBNS (NetBIOS) name resolution. +paragraph=With this library you can connect to your ESP from Windows using a short name +category=Communication +url=http://www.xpablo.cz/?p=751#more-751 +architectures=rp2040 diff --git a/libraries/NetBIOS/src/NetBIOS.cpp b/libraries/NetBIOS/src/NetBIOS.cpp new file mode 100644 index 0000000..e5751d4 --- /dev/null +++ b/libraries/NetBIOS/src/NetBIOS.cpp @@ -0,0 +1,141 @@ +#include "NetBIOS.h" +#include +#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; + +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::_onPacket(AsyncUDPPacket &packet) { + if (packet.length() >= sizeof(nbns_question_t)) { + nbns_question_t *question = (nbns_question_t *)packet.data(); + 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_16((void *)&nbnsa.data_len, 6); + append_16((void *)&nbnsa.flags, 0); + nbnsa.addr = packet.localIP(); // Wrong, but better than nothing + // Iterate over all netifs, see if the incoming address matches one of the netmaskes networks + // TODO - is there an easier way of seeing whicn netif produced a packet? + for (auto netif = netif_list; netif; netif = netif->next) { + auto maskedip = ip4_addr_get_u32(netif_ip4_addr(netif)) & ip4_addr_get_u32(netif_ip4_netmask(netif)); + auto maskedin = ((uint32_t)packet.localIP()) & ip4_addr_get_u32(netif_ip4_netmask(netif)); + if (maskedip == maskedin) { + nbnsa.addr = ip4_addr_get_u32(netif_ip4_addr(netif)); + break; + } + } + _udp.writeTo((uint8_t *)&nbnsa, sizeof(nbnsa), packet.remoteIP(), NBNS_PORT); + } + } + } +} + +NetBIOS::NetBIOS() {} + +NetBIOS::~NetBIOS() { + end(); +} + +bool NetBIOS::begin(const char *name) { + _name = name; + _name.toUpperCase(); + + if (_udp.connected()) { + return true; + } + + _udp.onPacket( + [](void *arg, AsyncUDPPacket & packet) { + ((NetBIOS *)(arg))->_onPacket(packet); + }, + this + ); + return _udp.listen(NBNS_PORT); +} + +void NetBIOS::end() { + if (_udp.connected()) { + _udp.close(); + } +} + +NetBIOS NBNS; diff --git a/libraries/NetBIOS/src/NetBIOS.h b/libraries/NetBIOS/src/NetBIOS.h new file mode 100644 index 0000000..b6770be --- /dev/null +++ b/libraries/NetBIOS/src/NetBIOS.h @@ -0,0 +1,21 @@ +// + +#pragma once + +#include +#include + +class NetBIOS { +protected: + AsyncUDP _udp; + String _name; + void _onPacket(AsyncUDPPacket &packet); + +public: + NetBIOS(); + ~NetBIOS(); + bool begin(const char *name); + void end(); +}; + +extern NetBIOS NBNS; diff --git a/tests/restyle.sh b/tests/restyle.sh index f3158bf..51fe372 100755 --- a/tests/restyle.sh +++ b/tests/restyle.sh @@ -16,7 +16,7 @@ for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S ./libraries/SingleF ./libraries/lwIP_w5500 ./libraries/lwIP_w5100 ./libraries/lwIP_enc28j60 \ ./libraries/SPISlave ./libraries/lwIP_ESPHost ./libraries/FatFS\ ./libraries/FatFSUSB ./libraries/BluetoothAudio ./libraries/BluetoothHCI \ - ./libraries/BluetoothHIDMaster; do + ./libraries/BluetoothHIDMaster ./libraries/NetBIOS; do find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" \) -a \! -path '*api*' -exec astyle --suffix=none --options=./tests/astyle_core.conf \{\} \; find $dir -type f -name "*.ino" -exec astyle --suffix=none --options=./tests/astyle_examples.conf \{\} \; done