Minor header/directrory cleanup (#802)

This commit is contained in:
Earle F. Philhower, III 2022-08-27 13:04:57 -07:00 committed by GitHub
parent 257db5ac7d
commit 064dd4794f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 1226 additions and 1116 deletions

View file

@ -71,8 +71,6 @@ static int __usb_task_irq;
#define EPNUM_HID 0x83 #define EPNUM_HID 0x83
#define EPNUM_MIDI 0x01
const uint8_t *tud_descriptor_device_cb(void) { const uint8_t *tud_descriptor_device_cb(void) {
static tusb_desc_device_t usbd_desc_device = { static tusb_desc_device_t usbd_desc_device = {
@ -91,7 +89,7 @@ const uint8_t *tud_descriptor_device_cb(void) {
.iSerialNumber = USBD_STR_SERIAL, .iSerialNumber = USBD_STR_SERIAL,
.bNumConfigurations = 1 .bNumConfigurations = 1
}; };
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick && !__USBInstallMIDI) { if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick) {
// Can use as-is, this is the default USB case // Can use as-is, this is the default USB case
return (const uint8_t *)&usbd_desc_device; return (const uint8_t *)&usbd_desc_device;
} }
@ -105,9 +103,6 @@ const uint8_t *tud_descriptor_device_cb(void) {
if (__USBInstallJoystick) { if (__USBInstallJoystick) {
usbd_desc_device.idProduct |= 0x0100; usbd_desc_device.idProduct |= 0x0100;
} }
if (__USBInstallMIDI) {
usbd_desc_device.idProduct |= 0x2000;
}
// Set the device class to 0 to indicate multiple device classes // Set the device class to 0 to indicate multiple device classes
usbd_desc_device.bDeviceClass = 0; usbd_desc_device.bDeviceClass = 0;
usbd_desc_device.bDeviceSubClass = 0; usbd_desc_device.bDeviceSubClass = 0;
@ -228,7 +223,7 @@ void __SetupUSBDescriptor() {
if (!usbd_desc_cfg) { if (!usbd_desc_cfg) {
bool hasHID = __USBInstallKeyboard || __USBInstallMouse || __USBInstallJoystick; bool hasHID = __USBInstallKeyboard || __USBInstallMouse || __USBInstallJoystick;
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0) + (__USBInstallMIDI ? 2 : 0); uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0);
uint8_t cdc_desc[TUD_CDC_DESC_LEN] = { uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
@ -243,13 +238,7 @@ void __SetupUSBDescriptor() {
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10) TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
}; };
uint8_t midi_itf = hid_itf + (hasHID ? 1 : 0); int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0);
uint8_t midi_desc[TUD_MIDI_DESC_LEN] = {
// Interface number, string index, EP Out & EP In address, EP size
TUD_MIDI_DESCRIPTOR(midi_itf, 0, EPNUM_MIDI, 0x80 | EPNUM_MIDI, 64)
};
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0) + (__USBInstallMIDI ? sizeof(midi_desc) : 0);
uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = { uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
// Config number, interface count, string index, total length, attribute, power in mA // Config number, interface count, string index, total length, attribute, power in mA
@ -271,9 +260,6 @@ void __SetupUSBDescriptor() {
memcpy(ptr, hid_desc, sizeof(hid_desc)); memcpy(ptr, hid_desc, sizeof(hid_desc));
ptr += sizeof(hid_desc); ptr += sizeof(hid_desc);
} }
if (__USBInstallMIDI) {
memcpy(ptr, midi_desc, sizeof(midi_desc));
}
} }
} }
} }

View file

@ -26,7 +26,6 @@ extern void __USBInstallSerial() __attribute__((weak));
extern void __USBInstallKeyboard() __attribute__((weak)); extern void __USBInstallKeyboard() __attribute__((weak));
extern void __USBInstallJoystick() __attribute__((weak)); extern void __USBInstallJoystick() __attribute__((weak));
extern void __USBInstallMouse() __attribute__((weak)); extern void __USBInstallMouse() __attribute__((weak));
extern void __USBInstallMIDI() __attribute__((weak));
// Big, global USB mutex, shared with all USB devices to make sure we don't // Big, global USB mutex, shared with all USB devices to make sure we don't
// have multiple cores updating the TUSB state in parallel // have multiple cores updating the TUSB state in parallel

View file

@ -1,3 +1,24 @@
/*
Arduino OTA.cpp - Simple Arduino IDE OTA handler
Modified 2022 Earle F. Philhower, III. All rights reserved.
Taken from the ESP8266 core libraries, (c) various authors.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <functional> #include <functional>
#include <WiFiUdp.h> #include <WiFiUdp.h>
#include "ArduinoOTA.h" #include "ArduinoOTA.h"

View file

@ -1,3 +1,24 @@
/*
Arduino OTA.h - Simple Arduino IDE OTA handler
Modified 2022 Earle F. Philhower, III. All rights reserved.
Taken from the ESP8266 core libraries, (c) various authors.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once #pragma once
#include <WiFi.h> #include <WiFi.h>

View file

@ -133,7 +133,9 @@ void loop() {
WiFi.disconnect(); WiFi.disconnect();
} }
} }
if (s == WL_CONNECTED) { MDNS.update(); } if (s == WL_CONNECTED) {
MDNS.update();
}
} }
// Do work: // Do work:
// DNS // DNS

View file

@ -57,21 +57,23 @@ void handleWifi() {
+ String(softAP_ssid) + F("</td></tr>" + String(softAP_ssid) + F("</td></tr>"
"<tr><td>IP ") "<tr><td>IP ")
+ toStringIp(WiFi.softAPIP()) + F("</td></tr>" + toStringIp(WiFi.softAPIP()) + F("</td></tr>"
"</table>" "</table>"
"\r\n<br />" "\r\n<br />"
"<table><tr><th align='left'>WLAN config</th></tr>" "<table><tr><th align='left'>WLAN config</th></tr>"
"<tr><td>SSID ") "<tr><td>SSID ")
+ String(ssid) + F("</td></tr>" + String(ssid) + F("</td></tr>"
"<tr><td>IP ") "<tr><td>IP ")
+ toStringIp(WiFi.localIP()) + F("</td></tr>" + toStringIp(WiFi.localIP()) + F("</td></tr>"
"</table>" "</table>"
"\r\n<br />" "\r\n<br />"
"<table><tr><th align='left'>WLAN list (refresh if any missing)</th></tr>"); "<table><tr><th align='left'>WLAN list (refresh if any missing)</th></tr>");
Serial.println("scan start"); Serial.println("scan start");
int n = WiFi.scanNetworks(); int n = WiFi.scanNetworks();
Serial.println("scan done"); Serial.println("scan done");
if (n > 0) { if (n > 0) {
for (int i = 0; i < n; i++) { Page += String(F("\r\n<tr><td>SSID ")) + WiFi.SSID(i) + ((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? F(" ") : F(" *")) + F(" (") + WiFi.RSSI(i) + F(")</td></tr>"); } for (int i = 0; i < n; i++) {
Page += String(F("\r\n<tr><td>SSID ")) + WiFi.SSID(i) + ((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? F(" ") : F(" *")) + F(" (") + WiFi.RSSI(i) + F(")</td></tr>");
}
} else { } else {
Page += F("<tr><td>No WLAN found</td></tr>"); Page += F("<tr><td>No WLAN found</td></tr>");
} }
@ -114,7 +116,9 @@ void handleNotFound() {
message += server.args(); message += server.args();
message += F("\n"); message += F("\n");
for (uint8_t i = 0; i < server.args(); i++) { message += String(F(" ")) + server.argName(i) + F(": ") + server.arg(i) + F("\n"); } for (uint8_t i = 0; i < server.args(); i++) {
message += String(F(" ")) + server.argName(i) + F(": ") + server.arg(i) + F("\n");
}
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache"); server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1"); server.sendHeader("Expires", "-1");

View file

@ -2,7 +2,9 @@
boolean isIp(String str) { boolean isIp(String str) {
for (size_t i = 0; i < str.length(); i++) { for (size_t i = 0; i < str.length(); i++) {
int c = str.charAt(i); int c = str.charAt(i);
if (c != '.' && (c < '0' || c > '9')) { return false; } if (c != '.' && (c < '0' || c > '9')) {
return false;
}
} }
return true; return true;
} }
@ -10,7 +12,9 @@ boolean isIp(String str) {
/** IP to String? */ /** IP to String? */
String toStringIp(IPAddress ip) { String toStringIp(IPAddress ip) {
String res = ""; String res = "";
for (int i = 0; i < 3; i++) { res += String((ip >> (8 * i)) & 0xFF) + "."; } for (int i = 0; i < 3; i++) {
res += String((ip >> (8 * i)) & 0xFF) + ".";
}
res += String(((ip >> 8 * 3)) & 0xFF); res += String(((ip >> 8 * 3)) & 0xFF);
return res; return res;
} }

View file

@ -1,10 +1,29 @@
/*
DNSServer.cpp - Simple DNS server for the Pico
Modified 2022 Earle F. Philhower, III. All rights reserved.
Taken from the ESP8266 core libraries, (c) various authors.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "WiFi.h" #include "WiFi.h"
#include "DNSServer.h" #include "DNSServer.h"
#include <lwip/def.h> #include <lwip/def.h>
#include <Arduino.h> #include <Arduino.h>
extern struct rst_info resetInfo;
#ifdef DEBUG_ESP_PORT #ifdef DEBUG_ESP_PORT
#define CONSOLE DEBUG_ESP_PORT #define CONSOLE DEBUG_ESP_PORT
#else #else
@ -49,399 +68,389 @@ extern struct rst_info resetInfo;
// Want to keep IDs unique across restarts and continquious // Want to keep IDs unique across restarts and continquious
static uint32_t _ids __attribute__((section(".noinit"))); static uint32_t _ids __attribute__((section(".noinit")));
DNSServer::DNSServer() DNSServer::DNSServer() {
{ // I have observed that using 0 for captive and non-zero (600) when
// I have observed that using 0 for captive and non-zero (600) when // forwarding, will help Android devices recognize the change in connectivity.
// forwarding, will help Android devices recognize the change in connectivity. // They will then report connected.
// They will then report connected. _ttl = lwip_htonl(60);
_ttl = lwip_htonl(60);
srand(rp2040.getCycleCount()); srand(rp2040.getCycleCount());
_ids = random(0, (1UL << 16) - 1); _ids = random(0, (1UL << 16) - 1);
_errorReplyCode = DNSReplyCode::NonExistentDomain; _errorReplyCode = DNSReplyCode::NonExistentDomain;
} }
void DNSServer::disableForwarder(const String &domainName, bool freeResources) void DNSServer::disableForwarder(const String &domainName, bool freeResources) {
{ _forwarder = false;
_forwarder = false; if (domainName != "") {
if (domainName != "") { _domainName = domainName;
_domainName = domainName; downcaseAndRemoveWwwPrefix(_domainName);
downcaseAndRemoveWwwPrefix(_domainName); }
} if (freeResources) {
if (freeResources) { _dns = (uint32_t)0;
_dns = (uint32_t)0; if (_que) {
if (_que) { _que = nullptr;
_que = nullptr; DEBUG_PRINTF("from stop, deleted _que\r\n");
DEBUG_PRINTF("from stop, deleted _que\r\n"); DEBUG_(({
DEBUG_(({ if (_que_ov) {
if (_que_ov) { DEBUG_PRINTLN2("DNS forwarder que overflow or no reply to request: ", (_que_ov));
DEBUG_PRINTLN2("DNS forwarder que overflow or no reply to request: ", (_que_ov)); }
} if (_que_drop) {
if (_que_drop) { DEBUG_PRINTLN2("DNS forwarder que wrapped, reply dropped: ", (_que_drop));
DEBUG_PRINTLN2("DNS forwarder que wrapped, reply dropped: ", (_que_drop)); }
} }));
})); }
} }
}
} }
bool DNSServer::enableForwarder(const String &domainName, const IPAddress &dns) bool DNSServer::enableForwarder(const String &domainName, const IPAddress &dns) {
{ disableForwarder(domainName, false); // Just happens to have the same logic needed here.
disableForwarder(domainName, false); // Just happens to have the same logic needed here.
if (dns.isSet()) { if (dns.isSet()) {
_dns = dns; _dns = dns;
} }
if (_dns.isSet()) { if (_dns.isSet()) {
if (!_que) { if (!_que) {
_que = std::unique_ptr<DNSS_REQUESTER[]> (new (std::nothrow) DNSS_REQUESTER[kDNSSQueSize]); _que = std::unique_ptr<DNSS_REQUESTER[]> (new (std::nothrow) DNSS_REQUESTER[kDNSSQueSize]);
DEBUG_PRINTF("Created new _que\r\n"); DEBUG_PRINTF("Created new _que\r\n");
if (_que) { if (_que) {
for (size_t i = 0; i < kDNSSQueSize; i++) { for (size_t i = 0; i < kDNSSQueSize; i++) {
_que[i].ip = 0; _que[i].ip = 0;
}
DEBUG_((_que_ov = 0));
DEBUG_((_que_drop = 0));
}
}
if (_que) {
_forwarder = true;
} }
DEBUG_((_que_ov = 0));
DEBUG_((_que_drop = 0));
}
} }
if (_que) { return _forwarder;
_forwarder = true;
}
}
return _forwarder;
} }
bool DNSServer::start(const uint16_t &port, const String &domainName, bool DNSServer::start(const uint16_t &port, const String &domainName,
const IPAddress &resolvedIP, const IPAddress &dns) const IPAddress &resolvedIP, const IPAddress &dns) {
{ _port = (port) ? port : IANA_DNS_PORT;
_port = (port) ? port : IANA_DNS_PORT;
_resolvedIP[0] = resolvedIP[0]; _resolvedIP[0] = resolvedIP[0];
_resolvedIP[1] = resolvedIP[1]; _resolvedIP[1] = resolvedIP[1];
_resolvedIP[2] = resolvedIP[2]; _resolvedIP[2] = resolvedIP[2];
_resolvedIP[3] = resolvedIP[3]; _resolvedIP[3] = resolvedIP[3];
if (!enableForwarder(domainName, dns) && (dns.isSet() || _dns.isSet())) { if (!enableForwarder(domainName, dns) && (dns.isSet() || _dns.isSet())) {
return false; return false;
}
return _udp.begin(_port) == 1;
}
void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode)
{
_errorReplyCode = replyCode;
}
void DNSServer::setTTL(const uint32_t &ttl)
{
_ttl = lwip_htonl(ttl);
}
uint32_t DNSServer::getTTL()
{
return lwip_ntohl(_ttl);
}
void DNSServer::stop()
{
_udp.stop();
disableForwarder("", true);
}
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
{
domainName.toLowerCase();
if (domainName.startsWith("www."))
domainName.remove(0, 4);
}
void DNSServer::forwardReply(uint8_t *buffer, size_t length)
{
if (!_forwarder || !_que) {
return;
}
DNSHeader *dnsHeader = (DNSHeader *)buffer;
uint16_t id = dnsHeader->ID;
// if (kDNSSQueSize <= (uint16_t)((uint16_t)_ids - id)) {
if ((uint16_t)kDNSSQueSize <= (uint16_t)_ids - id) {
DEBUG_((++_que_drop));
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" dropped!")));
return;
}
size_t i = id & (kDNSSQueSize - 1);
// Drop duplicate packets
if (0 == _que[i].ip) {
DEBUG_PRINTLN2("Duplicate reply dropped ID: 0x", String(id, HEX));
return;
}
dnsHeader->ID = _que[i].id;
_udp.beginPacket(_que[i].ip, _que[i].port);
_udp.write(buffer, length);
_udp.endPacket();
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" to ") + IPAddress(_que[i].ip).toString()));
_que[i].ip = 0; // This gets used to detect duplicate packets and overflow
}
void DNSServer::forwardRequest(uint8_t *buffer, size_t length)
{
if (!_forwarder || !_dns.isSet() || !_que) {
return;
}
DNSHeader *dnsHeader = (DNSHeader *)buffer;
++_ids;
size_t i = _ids & (kDNSSQueSize - 1);
DEBUG_(({
if (0 != _que[i].ip) {
++_que_ov;
} }
}));
_que[i].ip = _udp.remoteIP(); return _udp.begin(_port) == 1;
_que[i].port = _udp.remotePort();
_que[i].id = dnsHeader->ID;
dnsHeader->ID = (uint16_t)_ids;
_udp.beginPacket(_dns, IANA_DNS_PORT);
_udp.write(buffer, length);
_udp.endPacket();
DEBUG_PRINTLN2("Forward request ID: 0x", (String(dnsHeader->ID, HEX) + F(" to ") + _dns.toString()));
} }
bool DNSServer::respondToRequest(uint8_t *buffer, size_t length) void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) {
{ _errorReplyCode = replyCode;
DNSHeader *dnsHeader; }
uint8_t *query, *start;
const char *matchString;
size_t remaining, labelLength, queryLength;
uint16_t qtype, qclass;
dnsHeader = (DNSHeader *)buffer; void DNSServer::setTTL(const uint32_t &ttl) {
_ttl = lwip_htonl(ttl);
}
// Must be a query for us to do anything with it uint32_t DNSServer::getTTL() {
if (dnsHeader->QR != DNS_QR_QUERY) { return lwip_ntohl(_ttl);
return false; }
}
// If operation is anything other than query, we don't do it void DNSServer::stop() {
if (dnsHeader->OPCode != DNS_OPCODE_QUERY) { _udp.stop();
replyWithError(dnsHeader, DNSReplyCode::NotImplemented); disableForwarder("", true);
return false; }
}
// Only support requests containing single queries - everything else void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) {
// is badly defined domainName.toLowerCase();
if (dnsHeader->QDCount != lwip_htons(1)) { if (domainName.startsWith("www.")) {
replyWithError(dnsHeader, DNSReplyCode::FormError); domainName.remove(0, 4);
return false;
}
// We must return a FormError in the case of a non-zero ARCount to
// be minimally compatible with EDNS resolvers
if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0
|| dnsHeader->ARCount != 0) {
replyWithError(dnsHeader, DNSReplyCode::FormError);
return false;
}
// Even if we're not going to use the query, we need to parse it
// so we can check the address type that's being queried
query = start = buffer + DNS_HEADER_SIZE;
remaining = length - DNS_HEADER_SIZE;
while (remaining != 0 && *start != 0) {
labelLength = *start;
if (labelLength + 1 > remaining) {
replyWithError(dnsHeader, DNSReplyCode::FormError);
return false;
} }
remaining -= (labelLength + 1); }
start += (labelLength + 1);
}
// 1 octet labelLength, 2 octet qtype, 2 octet qclass void DNSServer::forwardReply(uint8_t *buffer, size_t length) {
if (remaining < 5) { if (!_forwarder || !_que) {
replyWithError(dnsHeader, DNSReplyCode::FormError); return;
return false;
}
start += 1; // Skip the 0 length label that we found above
memcpy(&qtype, start, sizeof(qtype));
start += 2;
memcpy(&qclass, start, sizeof(qclass));
start += 2;
queryLength = start - query;
if (qclass != lwip_htons(DNS_QCLASS_ANY)
&& qclass != lwip_htons(DNS_QCLASS_IN)) {
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
return false;
}
if (qtype != lwip_htons(DNS_QTYPE_A)
&& qtype != lwip_htons(DNS_QTYPE_ANY)) {
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
return false;
}
// If we have no domain name configured, just return an error
if (_domainName == "") {
if (_forwarder) {
return true;
} else {
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
} }
} DNSHeader *dnsHeader = (DNSHeader *)buffer;
uint16_t id = dnsHeader->ID;
// if (kDNSSQueSize <= (uint16_t)((uint16_t)_ids - id)) {
if ((uint16_t)kDNSSQueSize <= (uint16_t)_ids - id) {
DEBUG_((++_que_drop));
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" dropped!")));
return;
}
size_t i = id & (kDNSSQueSize - 1);
// If we're running with a wildcard we can just return a result now // Drop duplicate packets
if (_domainName == "*") { if (0 == _que[i].ip) {
DEBUG_PRINTF("dnsServer - replyWithIP\r\n"); DEBUG_PRINTLN2("Duplicate reply dropped ID: 0x", String(id, HEX));
replyWithIP(dnsHeader, query, queryLength); return;
return false; }
} dnsHeader->ID = _que[i].id;
_udp.beginPacket(_que[i].ip, _que[i].port);
_udp.write(buffer, length);
_udp.endPacket();
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" to ") + IPAddress(_que[i].ip).toString()));
_que[i].ip = 0; // This gets used to detect duplicate packets and overflow
}
matchString = _domainName.c_str(); void DNSServer::forwardRequest(uint8_t *buffer, size_t length) {
if (!_forwarder || !_dns.isSet() || !_que) {
start = query; return;
}
// If there's a leading 'www', skip it DNSHeader *dnsHeader = (DNSHeader *)buffer;
if (*start == 3 && strncasecmp("www", (char *) start + 1, 3) == 0) ++_ids;
start += 4; size_t i = _ids & (kDNSSQueSize - 1);
DEBUG_(({
while (*start != 0) { if (0 != _que[i].ip) {
labelLength = *start; ++_que_ov;
start += 1;
while (labelLength > 0) {
if (tolower(*start) != *matchString) {
if (_forwarder) {
return true;
} else {
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
} }
} }));
++start; _que[i].ip = _udp.remoteIP();
++matchString; _que[i].port = _udp.remotePort();
--labelLength; _que[i].id = dnsHeader->ID;
} dnsHeader->ID = (uint16_t)_ids;
if (*start == 0 && *matchString == '\0') { _udp.beginPacket(_dns, IANA_DNS_PORT);
replyWithIP(dnsHeader, query, queryLength); _udp.write(buffer, length);
return false; _udp.endPacket();
} DEBUG_PRINTLN2("Forward request ID: 0x", (String(dnsHeader->ID, HEX) + F(" to ") + _dns.toString()));
if (*matchString != '.') {
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
}
++matchString;
}
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
} }
void DNSServer::processNextRequest() bool DNSServer::respondToRequest(uint8_t *buffer, size_t length) {
{ DNSHeader *dnsHeader;
size_t currentPacketSize; uint8_t *query, *start;
const char *matchString;
size_t remaining, labelLength, queryLength;
uint16_t qtype, qclass;
currentPacketSize = _udp.parsePacket(); dnsHeader = (DNSHeader *)buffer;
if (currentPacketSize == 0)
return;
// The DNS RFC requires that DNS packets be less than 512 bytes in size, // Must be a query for us to do anything with it
// so just discard them if they are larger if (dnsHeader->QR != DNS_QR_QUERY) {
if (currentPacketSize > MAX_DNS_PACKETSIZE) return false;
return; }
// If the packet size is smaller than the DNS header, then someone is // If operation is anything other than query, we don't do it
// messing with us if (dnsHeader->OPCode != DNS_OPCODE_QUERY) {
if (currentPacketSize < DNS_HEADER_SIZE) replyWithError(dnsHeader, DNSReplyCode::NotImplemented);
return; return false;
}
std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[currentPacketSize]); // Only support requests containing single queries - everything else
if (buffer == nullptr) // is badly defined
return; if (dnsHeader->QDCount != lwip_htons(1)) {
replyWithError(dnsHeader, DNSReplyCode::FormError);
return false;
}
_udp.read(buffer.get(), currentPacketSize); // We must return a FormError in the case of a non-zero ARCount to
if (_dns.isSet() && _udp.remoteIP() == _dns) { // be minimally compatible with EDNS resolvers
// _forwarder may have been set to false; however, for now allow in-flight if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0
// replies to finish. //?? || dnsHeader->ARCount != 0) {
forwardReply(buffer.get(), currentPacketSize); replyWithError(dnsHeader, DNSReplyCode::FormError);
} else return false;
if (respondToRequest(buffer.get(), currentPacketSize)) { }
forwardRequest(buffer.get(), currentPacketSize);
} // Even if we're not going to use the query, we need to parse it
// so we can check the address type that's being queried
query = start = buffer + DNS_HEADER_SIZE;
remaining = length - DNS_HEADER_SIZE;
while (remaining != 0 && *start != 0) {
labelLength = *start;
if (labelLength + 1 > remaining) {
replyWithError(dnsHeader, DNSReplyCode::FormError);
return false;
}
remaining -= (labelLength + 1);
start += (labelLength + 1);
}
// 1 octet labelLength, 2 octet qtype, 2 octet qclass
if (remaining < 5) {
replyWithError(dnsHeader, DNSReplyCode::FormError);
return false;
}
start += 1; // Skip the 0 length label that we found above
memcpy(&qtype, start, sizeof(qtype));
start += 2;
memcpy(&qclass, start, sizeof(qclass));
start += 2;
queryLength = start - query;
if (qclass != lwip_htons(DNS_QCLASS_ANY)
&& qclass != lwip_htons(DNS_QCLASS_IN)) {
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
return false;
}
if (qtype != lwip_htons(DNS_QTYPE_A)
&& qtype != lwip_htons(DNS_QTYPE_ANY)) {
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
return false;
}
// If we have no domain name configured, just return an error
if (_domainName == "") {
if (_forwarder) {
return true;
} else {
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
}
}
// If we're running with a wildcard we can just return a result now
if (_domainName == "*") {
DEBUG_PRINTF("dnsServer - replyWithIP\r\n");
replyWithIP(dnsHeader, query, queryLength);
return false;
}
matchString = _domainName.c_str();
start = query;
// If there's a leading 'www', skip it
if (*start == 3 && strncasecmp("www", (char *) start + 1, 3) == 0) {
start += 4;
}
while (*start != 0) {
labelLength = *start;
start += 1;
while (labelLength > 0) {
if (tolower(*start) != *matchString) {
if (_forwarder) {
return true;
} else {
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
}
}
++start;
++matchString;
--labelLength;
}
if (*start == 0 && *matchString == '\0') {
replyWithIP(dnsHeader, query, queryLength);
return false;
}
if (*matchString != '.') {
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
}
++matchString;
}
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
return false;
} }
void DNSServer::writeNBOShort(uint16_t value) void DNSServer::processNextRequest() {
{ size_t currentPacketSize;
_udp.write((unsigned char *)&value, 2);
currentPacketSize = _udp.parsePacket();
if (currentPacketSize == 0) {
return;
}
// The DNS RFC requires that DNS packets be less than 512 bytes in size,
// so just discard them if they are larger
if (currentPacketSize > MAX_DNS_PACKETSIZE) {
return;
}
// If the packet size is smaller than the DNS header, then someone is
// messing with us
if (currentPacketSize < DNS_HEADER_SIZE) {
return;
}
std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[currentPacketSize]);
if (buffer == nullptr) {
return;
}
_udp.read(buffer.get(), currentPacketSize);
if (_dns.isSet() && _udp.remoteIP() == _dns) {
// _forwarder may have been set to false; however, for now allow in-flight
// replies to finish. //??
forwardReply(buffer.get(), currentPacketSize);
} else if (respondToRequest(buffer.get(), currentPacketSize)) {
forwardRequest(buffer.get(), currentPacketSize);
}
}
void DNSServer::writeNBOShort(uint16_t value) {
_udp.write((unsigned char *)&value, 2);
} }
void DNSServer::replyWithIP(DNSHeader *dnsHeader, void DNSServer::replyWithIP(DNSHeader *dnsHeader,
unsigned char * query, unsigned char * query,
size_t queryLength) size_t queryLength) {
{ uint16_t value;
uint16_t value;
dnsHeader->QR = DNS_QR_RESPONSE; dnsHeader->QR = DNS_QR_RESPONSE;
dnsHeader->QDCount = lwip_htons(1); dnsHeader->QDCount = lwip_htons(1);
dnsHeader->ANCount = lwip_htons(1); dnsHeader->ANCount = lwip_htons(1);
dnsHeader->NSCount = 0; dnsHeader->NSCount = 0;
dnsHeader->ARCount = 0; dnsHeader->ARCount = 0;
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); _udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
_udp.write((unsigned char *) dnsHeader, sizeof(DNSHeader)); _udp.write((unsigned char *) dnsHeader, sizeof(DNSHeader));
_udp.write(query, queryLength); _udp.write(query, queryLength);
// Rather than restate the name here, we use a pointer to the name contained // Rather than restate the name here, we use a pointer to the name contained
// in the query section. Pointers have the top two bits set. // in the query section. Pointers have the top two bits set.
value = 0xC000 | DNS_HEADER_SIZE; value = 0xC000 | DNS_HEADER_SIZE;
writeNBOShort(lwip_htons(value)); writeNBOShort(lwip_htons(value));
// Answer is type A (an IPv4 address) // Answer is type A (an IPv4 address)
writeNBOShort(lwip_htons(DNS_QTYPE_A)); writeNBOShort(lwip_htons(DNS_QTYPE_A));
// Answer is in the Internet Class // Answer is in the Internet Class
writeNBOShort(lwip_htons(DNS_QCLASS_IN)); writeNBOShort(lwip_htons(DNS_QCLASS_IN));
// Output TTL (already NBO) // Output TTL (already NBO)
_udp.write((unsigned char*)&_ttl, 4); _udp.write((unsigned char*)&_ttl, 4);
// Length of RData is 4 bytes (because, in this case, RData is IPv4) // Length of RData is 4 bytes (because, in this case, RData is IPv4)
writeNBOShort(lwip_htons(sizeof(_resolvedIP))); writeNBOShort(lwip_htons(sizeof(_resolvedIP)));
_udp.write(_resolvedIP, sizeof(_resolvedIP)); _udp.write(_resolvedIP, sizeof(_resolvedIP));
_udp.endPacket(); _udp.endPacket();
} }
void DNSServer::replyWithError(DNSHeader *dnsHeader, void DNSServer::replyWithError(DNSHeader *dnsHeader,
DNSReplyCode rcode, DNSReplyCode rcode,
unsigned char *query, unsigned char *query,
size_t queryLength) size_t queryLength) {
{ dnsHeader->QR = DNS_QR_RESPONSE;
dnsHeader->QR = DNS_QR_RESPONSE; dnsHeader->RCode = (unsigned char) rcode;
dnsHeader->RCode = (unsigned char) rcode; if (query) {
if (query) dnsHeader->QDCount = lwip_htons(1);
dnsHeader->QDCount = lwip_htons(1); } else {
else dnsHeader->QDCount = 0;
dnsHeader->QDCount = 0; }
dnsHeader->ANCount = 0; dnsHeader->ANCount = 0;
dnsHeader->NSCount = 0; dnsHeader->NSCount = 0;
dnsHeader->ARCount = 0; dnsHeader->ARCount = 0;
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); _udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
_udp.write((unsigned char *)dnsHeader, sizeof(DNSHeader)); _udp.write((unsigned char *)dnsHeader, sizeof(DNSHeader));
if (query != NULL) if (query != NULL) {
_udp.write(query, queryLength); _udp.write(query, queryLength);
_udp.endPacket(); }
_udp.endPacket();
} }
void DNSServer::replyWithError(DNSHeader *dnsHeader, void DNSServer::replyWithError(DNSHeader *dnsHeader,
DNSReplyCode rcode) DNSReplyCode rcode) {
{ replyWithError(dnsHeader, rcode, NULL, 0);
replyWithError(dnsHeader, rcode, NULL, 0);
} }

View file

@ -1,5 +1,25 @@
#ifndef DNSServer_h /*
#define DNSServer_h DNSServer.cwhcpp - Simple DNS server for the Pico
Modified 2022 Earle F. Philhower, III. All rights reserved.
Taken from the ESP8266 core libraries, (c) various authors.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <memory> #include <memory>
#include <WiFiUdp.h> #include <WiFiUdp.h>
@ -25,90 +45,97 @@ constexpr inline uint16_t kIanaDnsPort = IANA_DNS_PORT;
#define MAX_DNSNAME_LENGTH 253 #define MAX_DNSNAME_LENGTH 253
#define MAX_DNS_PACKETSIZE 512 #define MAX_DNS_PACKETSIZE 512
enum class DNSReplyCode enum class DNSReplyCode {
{ NoError = 0,
NoError = 0, FormError = 1,
FormError = 1, ServerFailure = 2,
ServerFailure = 2, NonExistentDomain = 3,
NonExistentDomain = 3, NotImplemented = 4,
NotImplemented = 4, Refused = 5,
Refused = 5, YXDomain = 6,
YXDomain = 6, YXRRSet = 7,
YXRRSet = 7, NXRRSet = 8
NXRRSet = 8
}; };
struct DNSHeader struct DNSHeader {
{ uint16_t ID; // identification number
uint16_t ID; // identification number unsigned char RD : 1; // recursion desired
unsigned char RD : 1; // recursion desired unsigned char TC : 1; // truncated message
unsigned char TC : 1; // truncated message unsigned char AA : 1; // authoritative answer
unsigned char AA : 1; // authoritative answer unsigned char OPCode : 4; // message_type
unsigned char OPCode : 4; // message_type unsigned char QR : 1; // query/response flag
unsigned char QR : 1; // query/response flag unsigned char RCode : 4; // response code
unsigned char RCode : 4; // response code unsigned char Z : 3; // its z! reserved
unsigned char Z : 3; // its z! reserved unsigned char RA : 1; // recursion available
unsigned char RA : 1; // recursion available uint16_t QDCount; // number of question entries
uint16_t QDCount; // number of question entries uint16_t ANCount; // number of answer entries
uint16_t ANCount; // number of answer entries uint16_t NSCount; // number of authority entries
uint16_t NSCount; // number of authority entries uint16_t ARCount; // number of resource entries
uint16_t ARCount; // number of resource entries
}; };
constexpr inline size_t kDNSSQueSizeAddrBits = 3; // The number of bits used to address que entries constexpr inline size_t kDNSSQueSizeAddrBits = 3; // The number of bits used to address que entries
constexpr inline size_t kDNSSQueSize = (1UL << (kDNSSQueSizeAddrBits)); constexpr inline size_t kDNSSQueSize = (1UL << (kDNSSQueSizeAddrBits));
struct DNSS_REQUESTER { struct DNSS_REQUESTER {
uint32_t ip; uint32_t ip;
uint16_t port; uint16_t port;
uint16_t id; uint16_t id;
}; };
class DNSServer class DNSServer {
{ public:
public:
DNSServer(); DNSServer();
~DNSServer() { ~DNSServer() {
stop(); stop();
}; };
/* /*
If specified, `enableForwarder` will update the `domainName` that is used If specified, `enableForwarder` will update the `domainName` that is used
to match DNS request to this AP's IP Address. A non-matching request will to match DNS request to this AP's IP Address. A non-matching request will
be forwarded to the DNS server specified by `dns`. be forwarded to the DNS server specified by `dns`.
Returns `true` on success. Returns `true` on success.
Returns `false`, Returns `false`,
* when forwarding `dns` is not set, or when forwarding `dns` is not set, or
* unable to allocate resources for managing the DNS forward function. unable to allocate resources for managing the DNS forward function.
*/ */
bool enableForwarder(const String &domainName = String(""), const IPAddress &dns = (uint32_t)0); bool enableForwarder(const String &domainName = String(""), const IPAddress &dns = (uint32_t)0);
/* /*
`disableForwarder` will stop forwarding DNS requests. If specified, `disableForwarder` will stop forwarding DNS requests. If specified,
updates the `domainName` that is matched for returning this AP's IP Address. updates the `domainName` that is matched for returning this AP's IP Address.
Optionally, resources used for the DNS forward function can be freed. Optionally, resources used for the DNS forward function can be freed.
*/ */
void disableForwarder(const String &domainName = String(""), bool freeResources = false); void disableForwarder(const String &domainName = String(""), bool freeResources = false);
bool isForwarding() { return _forwarder && _dns.isSet(); } bool isForwarding() {
void setDNS(const IPAddress& dns) { _dns = dns; } return _forwarder && _dns.isSet();
IPAddress getDNS() { return _dns; } }
bool isDNSSet() { return _dns.isSet(); } void setDNS(const IPAddress& dns) {
_dns = dns;
}
IPAddress getDNS() {
return _dns;
}
bool isDNSSet() {
return _dns.isSet();
}
void processNextRequest(); void processNextRequest();
void setErrorReplyCode(const DNSReplyCode &replyCode); void setErrorReplyCode(const DNSReplyCode &replyCode);
void setTTL(const uint32_t &ttl); void setTTL(const uint32_t &ttl);
uint32_t getTTL(); uint32_t getTTL();
String getDomainName() { return _domainName; } String getDomainName() {
return _domainName;
}
// Returns true if successful, false if there are no sockets available // Returns true if successful, false if there are no sockets available
bool start(const uint16_t &port, bool start(const uint16_t &port,
const String &domainName, const String &domainName,
const IPAddress &resolvedIP, const IPAddress &resolvedIP,
const IPAddress &dns = (uint32_t)0); const IPAddress &dns = (uint32_t)0);
// stops the DNS server // stops the DNS server
void stop(); void stop();
private: private:
WiFiUDP _udp; WiFiUDP _udp;
String _domainName; String _domainName;
IPAddress _dns; IPAddress _dns;
@ -128,17 +155,16 @@ class DNSServer
void downcaseAndRemoveWwwPrefix(String &domainName); void downcaseAndRemoveWwwPrefix(String &domainName);
void replyWithIP(DNSHeader *dnsHeader, void replyWithIP(DNSHeader *dnsHeader,
unsigned char * query, unsigned char * query,
size_t queryLength); size_t queryLength);
void replyWithError(DNSHeader *dnsHeader, void replyWithError(DNSHeader *dnsHeader,
DNSReplyCode rcode, DNSReplyCode rcode,
unsigned char *query, unsigned char *query,
size_t queryLength); size_t queryLength);
void replyWithError(DNSHeader *dnsHeader, void replyWithError(DNSHeader *dnsHeader,
DNSReplyCode rcode); DNSReplyCode rcode);
bool respondToRequest(uint8_t *buffer, size_t length); bool respondToRequest(uint8_t *buffer, size_t length);
void forwardRequest(uint8_t *buffer, size_t length); void forwardRequest(uint8_t *buffer, size_t length);
void forwardReply(uint8_t *buffer, size_t length); void forwardReply(uint8_t *buffer, size_t length);
void writeNBOShort(uint16_t value); void writeNBOShort(uint16_t value);
}; };
#endif

View file

@ -19,8 +19,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef EEPROM_h #pragma once
#define EEPROM_h
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -85,6 +84,3 @@ protected:
}; };
extern EEPROMClass EEPROM; extern EEPROMClass EEPROM;
#endif

View file

@ -1,3 +1,24 @@
/*
HTTPUpdateServer - Support simple web based OTA
Modified 2022 Earle F. Philhower, III. All rights reserved.
Ported from the ESP8266 Arduino core, (c) copyright multiple authors
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>

View file

@ -1,3 +1,24 @@
/*
HTTPUpdateServer - Support simple web based OTA
Modified 2022 Earle F. Philhower, III. All rights reserved.
Ported from the ESP8266 Arduino core, (c) copyright multiple authors
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once #pragma once
#include <WebServer.h> #include <WebServer.h>

View file

@ -22,8 +22,7 @@
*/ */
#ifndef MDNS_PRIV_H #pragma once
#define MDNS_PRIV_H
namespace esp8266 { namespace esp8266 {
@ -186,5 +185,3 @@ namespace MDNSImplementation {
// Include the main header, so the submodlues only need to include this header // Include the main header, so the submodlues only need to include this header
#include "LEAmDNS.h" #include "LEAmDNS.h"
#endif // MDNS_PRIV_H

View file

@ -22,9 +22,6 @@
*/ */
#ifndef MDNS_LWIPDEFS_H #pragma once
#define MDNS_LWIPDEFS_H
#include <lwip/prot/dns.h> // DNS_RRTYPE_xxx, DNS_MQUERY_PORT #include <lwip/prot/dns.h> // DNS_RRTYPE_xxx, DNS_MQUERY_PORT
#endif // MDNS_LWIPDEFS_H

View file

@ -23,9 +23,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#pragma once
#ifndef __LITTLEFS_H
#define __LITTLEFS_H
#include <limits> #include <limits>
#include <FS.h> #include <FS.h>
@ -681,6 +679,3 @@ protected:
extern FS LittleFS; extern FS LittleFS;
using littlefs_impl::LittleFSConfig; using littlefs_impl::LittleFSConfig;
#endif // ARDUINO #endif // ARDUINO
#endif // !defined(__LITTLEFS_H)

View file

@ -52,7 +52,7 @@ void loop() {
// Print samples to the serial monitor or plotter // Print samples to the serial monitor or plotter
for (int i = 0; i < samplesRead; i++) { for (int i = 0; i < samplesRead; i++) {
if(channels == 2) { if (channels == 2) {
Serial.print("L:"); Serial.print("L:");
Serial.print(sampleBuffer[i]); Serial.print(sampleBuffer[i]);
Serial.print(" R:"); Serial.print(" R:");
@ -67,9 +67,9 @@ void loop() {
} }
/** /**
* Callback function to process the data from the PDM microphone. Callback function to process the data from the PDM microphone.
* NOTE: This callback is executed as part of an ISR. NOTE: This callback is executed as part of an ISR.
* Therefore using `Serial` to print messages inside this function isn't supported. Therefore using `Serial` to print messages inside this function isn't supported.
* */ * */
void onPDMdata() { void onPDMdata() {
// Query the number of available bytes // Query the number of available bytes

View file

@ -1,74 +1,72 @@
/* /*
Copyright (c) 2019 Arduino LLC. All right reserved. Copyright (c) 2019 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef _PDM_H_INCLUDED #pragma once
#define _PDM_H_INCLUDED
#include <Arduino.h> #include <Arduino.h>
//#include <pinDefinitions.h> //#include <pinDefinitions.h>
#include "utility/PDMDoubleBuffer.h" #include "utility/PDMDoubleBuffer.h"
class PDMClass class PDMClass {
{
public: public:
PDMClass(int dinPin, int clkPin, int pwrPin); PDMClass(int dinPin, int clkPin, int pwrPin);
virtual ~PDMClass(); virtual ~PDMClass();
int begin(int channels, int sampleRate); int begin(int channels, int sampleRate);
void end(); void end();
virtual int available(); virtual int available();
virtual int read(void* buffer, size_t size); virtual int read(void* buffer, size_t size);
void onReceive(void(*)(void)); void onReceive(void(*)(void));
//PORTENTA_H7 min -12 max 51 //PORTENTA_H7 min -12 max 51
//NANO 33 BLE SENSe min 0 max 80 //NANO 33 BLE SENSe min 0 max 80
void setGain(int gain); void setGain(int gain);
void setBufferSize(int bufferSize); void setBufferSize(int bufferSize);
size_t getBufferSize(); size_t getBufferSize();
// private: // private:
void IrqHandler(bool halftranfer); void IrqHandler(bool halftranfer);
private: private:
int _dinPin; int _dinPin;
int _clkPin; int _clkPin;
int _pwrPin; int _pwrPin;
int _channels; int _channels;
int _samplerate; int _samplerate;
int _gain; int _gain;
int _init; int _init;
// Hardware peripherals used // Hardware peripherals used
uint _dmaChannel; uint _dmaChannel;
PIO _pio; PIO _pio;
int _smIdx; int _smIdx;
int _pgmOffset; int _pgmOffset;
PDMDoubleBuffer _doubleBuffer; PDMDoubleBuffer _doubleBuffer;
void (*_onReceive)(void); void (*_onReceive)(void);
}; };
#ifdef PIN_PDM_DIN #ifdef PIN_PDM_DIN
extern PDMClass PDM; extern PDMClass PDM;
#endif #endif
#endif

View file

@ -1,30 +1,30 @@
/** /**
******************************************************************************* *******************************************************************************
* @file OpenPDMFilter.c @file OpenPDMFilter.c
* @author CL @author CL
* @version V1.0.0 @version V1.0.0
* @date 9-September-2015 @date 9-September-2015
* @brief Open PDM audio software decoding Library. @brief Open PDM audio software decoding Library.
* This Library is used to decode and reconstruct the audio signal This Library is used to decode and reconstruct the audio signal
* produced by ST MEMS microphone (MP45Dxxx, MP34Dxxx). produced by ST MEMS microphone (MP45Dxxx, MP34Dxxx).
******************************************************************************* *******************************************************************************
* @attention @attention
*
* <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2> <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
******************************************************************************* *******************************************************************************
*/ */
/* Includes ------------------------------------------------------------------*/ /* Includes ------------------------------------------------------------------*/
@ -48,266 +48,255 @@ int32_t lut[256][DECIMATION_MAX / 8][SINCN];
/* Functions -----------------------------------------------------------------*/ /* Functions -----------------------------------------------------------------*/
#ifdef USE_LUT #ifdef USE_LUT
int32_t filter_table_mono_64(uint8_t *data, uint8_t sincn) int32_t filter_table_mono_64(uint8_t *data, uint8_t sincn) {
{ return (int32_t)
return (int32_t) lut[data[0]][0][sincn] +
lut[data[0]][0][sincn] + lut[data[1]][1][sincn] +
lut[data[1]][1][sincn] + lut[data[2]][2][sincn] +
lut[data[2]][2][sincn] + lut[data[3]][3][sincn] +
lut[data[3]][3][sincn] + lut[data[4]][4][sincn] +
lut[data[4]][4][sincn] + lut[data[5]][5][sincn] +
lut[data[5]][5][sincn] + lut[data[6]][6][sincn] +
lut[data[6]][6][sincn] + lut[data[7]][7][sincn];
lut[data[7]][7][sincn];
} }
int32_t filter_table_stereo_64(uint8_t *data, uint8_t sincn) int32_t filter_table_stereo_64(uint8_t *data, uint8_t sincn) {
{ return (int32_t)
return (int32_t) lut[data[0]][0][sincn] +
lut[data[0]][0][sincn] + lut[data[2]][1][sincn] +
lut[data[2]][1][sincn] + lut[data[4]][2][sincn] +
lut[data[4]][2][sincn] + lut[data[6]][3][sincn] +
lut[data[6]][3][sincn] + lut[data[8]][4][sincn] +
lut[data[8]][4][sincn] + lut[data[10]][5][sincn] +
lut[data[10]][5][sincn] + lut[data[12]][6][sincn] +
lut[data[12]][6][sincn] + lut[data[14]][7][sincn];
lut[data[14]][7][sincn];
} }
int32_t filter_table_mono_128(uint8_t *data, uint8_t sincn) int32_t filter_table_mono_128(uint8_t *data, uint8_t sincn) {
{ return (int32_t)
return (int32_t) lut[data[0]][0][sincn] +
lut[data[0]][0][sincn] + lut[data[1]][1][sincn] +
lut[data[1]][1][sincn] + lut[data[2]][2][sincn] +
lut[data[2]][2][sincn] + lut[data[3]][3][sincn] +
lut[data[3]][3][sincn] + lut[data[4]][4][sincn] +
lut[data[4]][4][sincn] + lut[data[5]][5][sincn] +
lut[data[5]][5][sincn] + lut[data[6]][6][sincn] +
lut[data[6]][6][sincn] + lut[data[7]][7][sincn] +
lut[data[7]][7][sincn] + lut[data[8]][8][sincn] +
lut[data[8]][8][sincn] + lut[data[9]][9][sincn] +
lut[data[9]][9][sincn] + lut[data[10]][10][sincn] +
lut[data[10]][10][sincn] + lut[data[11]][11][sincn] +
lut[data[11]][11][sincn] + lut[data[12]][12][sincn] +
lut[data[12]][12][sincn] + lut[data[13]][13][sincn] +
lut[data[13]][13][sincn] + lut[data[14]][14][sincn] +
lut[data[14]][14][sincn] + lut[data[15]][15][sincn];
lut[data[15]][15][sincn];
} }
int32_t filter_table_stereo_128(uint8_t *data, uint8_t sincn) int32_t filter_table_stereo_128(uint8_t *data, uint8_t sincn) {
{ return (int32_t)
return (int32_t) lut[data[0]][0][sincn] +
lut[data[0]][0][sincn] + lut[data[2]][1][sincn] +
lut[data[2]][1][sincn] + lut[data[4]][2][sincn] +
lut[data[4]][2][sincn] + lut[data[6]][3][sincn] +
lut[data[6]][3][sincn] + lut[data[8]][4][sincn] +
lut[data[8]][4][sincn] + lut[data[10]][5][sincn] +
lut[data[10]][5][sincn] + lut[data[12]][6][sincn] +
lut[data[12]][6][sincn] + lut[data[14]][7][sincn] +
lut[data[14]][7][sincn] + lut[data[16]][8][sincn] +
lut[data[16]][8][sincn] + lut[data[18]][9][sincn] +
lut[data[18]][9][sincn] + lut[data[20]][10][sincn] +
lut[data[20]][10][sincn] + lut[data[22]][11][sincn] +
lut[data[22]][11][sincn] + lut[data[24]][12][sincn] +
lut[data[24]][12][sincn] + lut[data[26]][13][sincn] +
lut[data[26]][13][sincn] + lut[data[28]][14][sincn] +
lut[data[28]][14][sincn] + lut[data[30]][15][sincn];
lut[data[30]][15][sincn];
} }
int32_t (* filter_tables_64[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_64, filter_table_stereo_64}; int32_t (* filter_tables_64[2])(uint8_t *data, uint8_t sincn) = {filter_table_mono_64, filter_table_stereo_64};
int32_t (* filter_tables_128[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_128, filter_table_stereo_128}; int32_t (* filter_tables_128[2])(uint8_t *data, uint8_t sincn) = {filter_table_mono_128, filter_table_stereo_128};
#else #else
int32_t filter_table(uint8_t *data, uint8_t sincn, TPDMFilter_InitStruct *param) int32_t filter_table(uint8_t *data, uint8_t sincn, TPDMFilter_InitStruct *param) {
{ uint8_t c, i;
uint8_t c, i; uint16_t data_index = 0;
uint16_t data_index = 0; uint32_t *coef_p = &coef[sincn][0];
uint32_t *coef_p = &coef[sincn][0]; int32_t F = 0;
int32_t F = 0; uint8_t decimation = param->Decimation;
uint8_t decimation = param->Decimation; uint8_t channels = param->In_MicChannels;
uint8_t channels = param->In_MicChannels;
for (i = 0; i < decimation; i += 8) { for (i = 0; i < decimation; i += 8) {
c = data[data_index]; c = data[data_index];
F += ((c >> 7) ) * coef_p[i ] + F += ((c >> 7)) * coef_p[i ] +
((c >> 6) & 0x01) * coef_p[i + 1] + ((c >> 6) & 0x01) * coef_p[i + 1] +
((c >> 5) & 0x01) * coef_p[i + 2] + ((c >> 5) & 0x01) * coef_p[i + 2] +
((c >> 4) & 0x01) * coef_p[i + 3] + ((c >> 4) & 0x01) * coef_p[i + 3] +
((c >> 3) & 0x01) * coef_p[i + 4] + ((c >> 3) & 0x01) * coef_p[i + 4] +
((c >> 2) & 0x01) * coef_p[i + 5] + ((c >> 2) & 0x01) * coef_p[i + 5] +
((c >> 1) & 0x01) * coef_p[i + 6] + ((c >> 1) & 0x01) * coef_p[i + 6] +
((c ) & 0x01) * coef_p[i + 7]; ((c) & 0x01) * coef_p[i + 7];
data_index += channels; data_index += channels;
} }
return F; return F;
} }
#endif #endif
void convolve(uint32_t Signal[/* SignalLen */], unsigned short SignalLen, void convolve(uint32_t Signal[/* SignalLen */], unsigned short SignalLen,
uint32_t Kernel[/* KernelLen */], unsigned short KernelLen, uint32_t Kernel[/* KernelLen */], unsigned short KernelLen,
uint32_t Result[/* SignalLen + KernelLen - 1 */]) uint32_t Result[/* SignalLen + KernelLen - 1 */]) {
{ uint16_t n;
uint16_t n;
for (n = 0; n < SignalLen + KernelLen - 1; n++) for (n = 0; n < SignalLen + KernelLen - 1; n++) {
{ unsigned short kmin, kmax, k;
unsigned short kmin, kmax, k;
Result[n] = 0; Result[n] = 0;
kmin = (n >= KernelLen - 1) ? n - (KernelLen - 1) : 0; kmin = (n >= KernelLen - 1) ? n - (KernelLen - 1) : 0;
kmax = (n < SignalLen - 1) ? n : SignalLen - 1; kmax = (n < SignalLen - 1) ? n : SignalLen - 1;
for (k = kmin; k <= kmax; k++) { for (k = kmin; k <= kmax; k++) {
Result[n] += Signal[k] * Kernel[n - k]; Result[n] += Signal[k] * Kernel[n - k];
}
} }
}
} }
void Open_PDM_Filter_Init(TPDMFilter_InitStruct *Param) void Open_PDM_Filter_Init(TPDMFilter_InitStruct *Param) {
{ uint16_t i, j;
uint16_t i, j; int64_t sum = 0;
int64_t sum = 0;
uint8_t decimation = Param->Decimation; uint8_t decimation = Param->Decimation;
for (i = 0; i < SINCN; i++) { for (i = 0; i < SINCN; i++) {
Param->Coef[i] = 0; Param->Coef[i] = 0;
Param->bit[i] = 0; Param->bit[i] = 0;
} }
for (i = 0; i < decimation; i++) {
sinc1[i] = 1;
}
Param->OldOut = Param->OldIn = Param->OldZ = 0;
Param->LP_ALFA = (Param->LP_HZ != 0 ? (uint16_t) (Param->LP_HZ * 256 / (Param->LP_HZ + Param->Fs / (2 * 3.14159))) : 0);
Param->HP_ALFA = (Param->HP_HZ != 0 ? (uint16_t) (Param->Fs * 256 / (2 * 3.14159 * Param->HP_HZ + Param->Fs)) : 0);
Param->FilterLen = decimation * SINCN;
sinc[0] = 0;
sinc[decimation * SINCN - 1] = 0;
convolve(sinc1, decimation, sinc1, decimation, sinc2);
convolve(sinc2, decimation * 2 - 1, sinc1, decimation, &sinc[1]);
for(j = 0; j < SINCN; j++) {
for (i = 0; i < decimation; i++) { for (i = 0; i < decimation; i++) {
coef[j][i] = sinc[j * decimation + i]; sinc1[i] = 1;
sum += sinc[j * decimation + i];
} }
}
sub_const = sum >> 1; Param->OldOut = Param->OldIn = Param->OldZ = 0;
div_const = sub_const * Param->MaxVolume / 32768 / Param->filterGain; Param->LP_ALFA = (Param->LP_HZ != 0 ? (uint16_t)(Param->LP_HZ * 256 / (Param->LP_HZ + Param->Fs / (2 * 3.14159))) : 0);
div_const = (div_const == 0 ? 1 : div_const); Param->HP_ALFA = (Param->HP_HZ != 0 ? (uint16_t)(Param->Fs * 256 / (2 * 3.14159 * Param->HP_HZ + Param->Fs)) : 0);
Param->FilterLen = decimation * SINCN;
sinc[0] = 0;
sinc[decimation * SINCN - 1] = 0;
convolve(sinc1, decimation, sinc1, decimation, sinc2);
convolve(sinc2, decimation * 2 - 1, sinc1, decimation, &sinc[1]);
for (j = 0; j < SINCN; j++) {
for (i = 0; i < decimation; i++) {
coef[j][i] = sinc[j * decimation + i];
sum += sinc[j * decimation + i];
}
}
sub_const = sum >> 1;
div_const = sub_const * Param->MaxVolume / 32768 / Param->filterGain;
div_const = (div_const == 0 ? 1 : div_const);
#ifdef USE_LUT #ifdef USE_LUT
/* Look-Up Table. */ /* Look-Up Table. */
uint16_t c, d, s; uint16_t c, d, s;
for (s = 0; s < SINCN; s++) for (s = 0; s < SINCN; s++) {
{ uint32_t *coef_p = &coef[s][0];
uint32_t *coef_p = &coef[s][0]; for (c = 0; c < 256; c++)
for (c = 0; c < 256; c++) for (d = 0; d < decimation / 8; d++)
for (d = 0; d < decimation / 8; d++) lut[c][d][s] = ((c >> 7)) * coef_p[d * 8 ] +
lut[c][d][s] = ((c >> 7) ) * coef_p[d * 8 ] + ((c >> 6) & 0x01) * coef_p[d * 8 + 1] +
((c >> 6) & 0x01) * coef_p[d * 8 + 1] + ((c >> 5) & 0x01) * coef_p[d * 8 + 2] +
((c >> 5) & 0x01) * coef_p[d * 8 + 2] + ((c >> 4) & 0x01) * coef_p[d * 8 + 3] +
((c >> 4) & 0x01) * coef_p[d * 8 + 3] + ((c >> 3) & 0x01) * coef_p[d * 8 + 4] +
((c >> 3) & 0x01) * coef_p[d * 8 + 4] + ((c >> 2) & 0x01) * coef_p[d * 8 + 5] +
((c >> 2) & 0x01) * coef_p[d * 8 + 5] + ((c >> 1) & 0x01) * coef_p[d * 8 + 6] +
((c >> 1) & 0x01) * coef_p[d * 8 + 6] + ((c) & 0x01) * coef_p[d * 8 + 7];
((c ) & 0x01) * coef_p[d * 8 + 7]; }
}
#endif #endif
} }
void Open_PDM_Filter_64(uint8_t* data, int16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param) void Open_PDM_Filter_64(uint8_t* data, int16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param) {
{ uint8_t i, data_out_index;
uint8_t i, data_out_index; uint8_t channels = Param->In_MicChannels;
uint8_t channels = Param->In_MicChannels; uint8_t data_inc = ((DECIMATION_MAX >> 4) * channels);
uint8_t data_inc = ((DECIMATION_MAX >> 4) * channels); int64_t Z, Z0, Z1, Z2;
int64_t Z, Z0, Z1, Z2; int64_t OldOut, OldIn, OldZ;
int64_t OldOut, OldIn, OldZ;
OldOut = Param->OldOut; OldOut = Param->OldOut;
OldIn = Param->OldIn; OldIn = Param->OldIn;
OldZ = Param->OldZ; OldZ = Param->OldZ;
#ifdef USE_LUT #ifdef USE_LUT
uint8_t j = channels - 1; uint8_t j = channels - 1;
#endif #endif
for (i = 0, data_out_index = 0; i < Param->nSamples; i++, data_out_index += channels) { for (i = 0, data_out_index = 0; i < Param->nSamples; i++, data_out_index += channels) {
#ifdef USE_LUT #ifdef USE_LUT
Z0 = filter_tables_64[j](data, 0); Z0 = filter_tables_64[j](data, 0);
Z1 = filter_tables_64[j](data, 1); Z1 = filter_tables_64[j](data, 1);
Z2 = filter_tables_64[j](data, 2); Z2 = filter_tables_64[j](data, 2);
#else #else
Z0 = filter_table(data, 0, Param); Z0 = filter_table(data, 0, Param);
Z1 = filter_table(data, 1, Param); Z1 = filter_table(data, 1, Param);
Z2 = filter_table(data, 2, Param); Z2 = filter_table(data, 2, Param);
#endif #endif
Z = Param->Coef[1] + Z2 - sub_const; Z = Param->Coef[1] + Z2 - sub_const;
Param->Coef[1] = Param->Coef[0] + Z1; Param->Coef[1] = Param->Coef[0] + Z1;
Param->Coef[0] = Z0; Param->Coef[0] = Z0;
OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8; OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;
OldIn = Z; OldIn = Z;
OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8; OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;
Z = OldZ * volume; Z = OldZ * volume;
Z = RoundDiv(Z, div_const); Z = RoundDiv(Z, div_const);
Z = SaturaLH(Z, -32700, 32700); Z = SaturaLH(Z, -32700, 32700);
dataOut[data_out_index] = Z; dataOut[data_out_index] = Z;
data += data_inc; data += data_inc;
} }
Param->OldOut = OldOut; Param->OldOut = OldOut;
Param->OldIn = OldIn; Param->OldIn = OldIn;
Param->OldZ = OldZ; Param->OldZ = OldZ;
} }
void Open_PDM_Filter_128(uint8_t* data, int16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param) void Open_PDM_Filter_128(uint8_t* data, int16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param) {
{ uint8_t i, data_out_index;
uint8_t i, data_out_index; uint8_t channels = Param->In_MicChannels;
uint8_t channels = Param->In_MicChannels; uint8_t data_inc = ((DECIMATION_MAX >> 3) * channels);
uint8_t data_inc = ((DECIMATION_MAX >> 3) * channels); int64_t Z, Z0, Z1, Z2;
int64_t Z, Z0, Z1, Z2; int64_t OldOut, OldIn, OldZ;
int64_t OldOut, OldIn, OldZ;
OldOut = Param->OldOut; OldOut = Param->OldOut;
OldIn = Param->OldIn; OldIn = Param->OldIn;
OldZ = Param->OldZ; OldZ = Param->OldZ;
#ifdef USE_LUT #ifdef USE_LUT
uint8_t j = channels - 1; uint8_t j = channels - 1;
#endif #endif
for (i = 0, data_out_index = 0; i < Param->nSamples; i++, data_out_index += channels) { for (i = 0, data_out_index = 0; i < Param->nSamples; i++, data_out_index += channels) {
#ifdef USE_LUT #ifdef USE_LUT
Z0 = filter_tables_128[j](data, 0); Z0 = filter_tables_128[j](data, 0);
Z1 = filter_tables_128[j](data, 1); Z1 = filter_tables_128[j](data, 1);
Z2 = filter_tables_128[j](data, 2); Z2 = filter_tables_128[j](data, 2);
#else #else
Z0 = filter_table(data, 0, Param); Z0 = filter_table(data, 0, Param);
Z1 = filter_table(data, 1, Param); Z1 = filter_table(data, 1, Param);
Z2 = filter_table(data, 2, Param); Z2 = filter_table(data, 2, Param);
#endif #endif
Z = Param->Coef[1] + Z2 - sub_const; Z = Param->Coef[1] + Z2 - sub_const;
Param->Coef[1] = Param->Coef[0] + Z1; Param->Coef[1] = Param->Coef[0] + Z1;
Param->Coef[0] = Z0; Param->Coef[0] = Z0;
OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8; OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;
OldIn = Z; OldIn = Z;
OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8; OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;
Z = OldZ * volume; Z = OldZ * volume;
Z = RoundDiv(Z, div_const); Z = RoundDiv(Z, div_const);
Z = SaturaLH(Z, -32700, 32700); Z = SaturaLH(Z, -32700, 32700);
dataOut[data_out_index] = Z; dataOut[data_out_index] = Z;
data += data_inc; data += data_inc;
} }
Param->OldOut = OldOut; Param->OldOut = OldOut;
Param->OldIn = OldIn; Param->OldIn = OldIn;
Param->OldZ = OldZ; Param->OldZ = OldZ;
} }

View file

@ -1,30 +1,30 @@
/** /**
******************************************************************************* *******************************************************************************
* @file OpenPDMFilter.h @file OpenPDMFilter.h
* @author CL @author CL
* @version V1.0.0 @version V1.0.0
* @date 9-September-2015 @date 9-September-2015
* @brief Header file for Open PDM audio software decoding Library. @brief Header file for Open PDM audio software decoding Library.
* This Library is used to decode and reconstruct the audio signal This Library is used to decode and reconstruct the audio signal
* produced by ST MEMS microphone (MP45Dxxx, MP34Dxxx). produced by ST MEMS microphone (MP45Dxxx, MP34Dxxx).
******************************************************************************* *******************************************************************************
* @attention @attention
*
* <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2> <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
******************************************************************************* *******************************************************************************
*/ */
/* Define to prevent recursive inclusion -------------------------------------*/ /* Define to prevent recursive inclusion -------------------------------------*/
@ -33,7 +33,7 @@
#define __OPENPDMFILTER_H #define __OPENPDMFILTER_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -45,10 +45,10 @@
/* Definitions ---------------------------------------------------------------*/ /* Definitions ---------------------------------------------------------------*/
/* /*
* Enable to use a Look-Up Table to improve performances while using more FLASH Enable to use a Look-Up Table to improve performances while using more FLASH
* and RAM memory. and RAM memory.
* Note: Without Look-Up Table up to stereo@16KHz configuration is supported. Note: Without Look-Up Table up to stereo@16KHz configuration is supported.
*/ */
#define USE_LUT #define USE_LUT
#define SINCN 3 #define SINCN 3
@ -63,24 +63,24 @@
/* Types ---------------------------------------------------------------------*/ /* Types ---------------------------------------------------------------------*/
typedef struct { typedef struct {
/* Public */ /* Public */
float LP_HZ; float LP_HZ;
float HP_HZ; float HP_HZ;
uint16_t Fs; uint16_t Fs;
unsigned int nSamples; unsigned int nSamples;
uint8_t In_MicChannels; uint8_t In_MicChannels;
uint8_t Out_MicChannels; uint8_t Out_MicChannels;
uint8_t Decimation; uint8_t Decimation;
uint8_t MaxVolume; uint8_t MaxVolume;
/* Private */ /* Private */
uint32_t Coef[SINCN]; uint32_t Coef[SINCN];
uint16_t FilterLen; uint16_t FilterLen;
int64_t OldOut, OldIn, OldZ; int64_t OldOut, OldIn, OldZ;
uint16_t LP_ALFA; uint16_t LP_ALFA;
uint16_t HP_ALFA; uint16_t HP_ALFA;
uint16_t bit[5]; uint16_t bit[5];
uint16_t byte; uint16_t byte;
uint16_t filterGain; uint16_t filterGain;
} TPDMFilter_InitStruct; } TPDMFilter_InitStruct;

View file

@ -30,179 +30,168 @@ int16_t* volatile finalBuffer;
TPDMFilter_InitStruct filter; TPDMFilter_InitStruct filter;
extern "C" { extern "C" {
__attribute__((__used__)) void dmaHandler(void) __attribute__((__used__)) void dmaHandler(void) {
{ PDM.IrqHandler(true);
PDM.IrqHandler(true); }
}
} }
PDMClass::PDMClass(int dinPin, int clkPin, int pwrPin) : PDMClass::PDMClass(int dinPin, int clkPin, int pwrPin) :
_dinPin(dinPin), _dinPin(dinPin),
_clkPin(clkPin), _clkPin(clkPin),
_pwrPin(pwrPin), _pwrPin(pwrPin),
_onReceive(NULL), _onReceive(NULL),
_gain(-1), _gain(-1),
_channels(-1), _channels(-1),
_samplerate(-1), _samplerate(-1),
_init(-1), _init(-1),
_dmaChannel(0), _dmaChannel(0),
_pio(nullptr), _pio(nullptr),
_smIdx(-1), _smIdx(-1),
_pgmOffset(-1) _pgmOffset(-1) {
{
} }
PDMClass::~PDMClass() PDMClass::~PDMClass() {
{
} }
int PDMClass::begin(int channels, int sampleRate) int PDMClass::begin(int channels, int sampleRate) {
{ //_channels = channels; // only one channel available
//_channels = channels; // only one channel available
// clear the final buffers // clear the final buffers
_doubleBuffer.reset(); _doubleBuffer.reset();
finalBuffer = (int16_t*)_doubleBuffer.data(); finalBuffer = (int16_t*)_doubleBuffer.data();
int finalBufferLength = _doubleBuffer.availableForWrite() / sizeof(int16_t); int finalBufferLength = _doubleBuffer.availableForWrite() / sizeof(int16_t);
_doubleBuffer.swap(0); _doubleBuffer.swap(0);
int rawBufferLength = RAW_BUFFER_SIZE / (decimation / 8); int rawBufferLength = RAW_BUFFER_SIZE / (decimation / 8);
// Saturate number of samples. Remaining bytes are dropped. // Saturate number of samples. Remaining bytes are dropped.
if (rawBufferLength > finalBufferLength) { if (rawBufferLength > finalBufferLength) {
rawBufferLength = finalBufferLength; rawBufferLength = finalBufferLength;
} }
/* Initialize Open PDM library */ /* Initialize Open PDM library */
filter.Fs = sampleRate; filter.Fs = sampleRate;
filter.nSamples = rawBufferLength; filter.nSamples = rawBufferLength;
filter.LP_HZ = sampleRate/2; filter.LP_HZ = sampleRate / 2;
filter.HP_HZ = 10; filter.HP_HZ = 10;
filter.In_MicChannels = 1; filter.In_MicChannels = 1;
filter.Out_MicChannels = 1; filter.Out_MicChannels = 1;
filter.Decimation = decimation; filter.Decimation = decimation;
if(_gain == -1) { if (_gain == -1) {
_gain = FILTER_GAIN; _gain = FILTER_GAIN;
} }
filter.filterGain = _gain;
Open_PDM_Filter_Init(&filter);
// Configure PIO state machine
float clkDiv = (float)clock_get_hz(clk_sys) / sampleRate / decimation / 2;
if (!_pdmPgm.prepare(&_pio, &_smIdx, &_pgmOffset)) {
// ERROR, no free slots
return -1;
}
pdm_pio_program_init(_pio, _smIdx, _pgmOffset, _clkPin, _dinPin, clkDiv);
// Wait for microphone
delay(100);
// Configure DMA for transferring PIO rx buffer to raw buffers
_dmaChannel = dma_claim_unused_channel(false);
dma_channel_config c = dma_channel_get_default_config(_dmaChannel);
channel_config_set_read_increment(&c, false);
channel_config_set_write_increment(&c, true);
channel_config_set_dreq(&c, pio_get_dreq(_pio, _smIdx, false));
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
// Clear DMA interrupts
dma_hw->ints0 = 1u << _dmaChannel;
// Enable DMA interrupts
dma_channel_set_irq0_enabled(_dmaChannel, true);
// Share but allocate a high priority to the interrupt
irq_add_shared_handler(DMA_IRQ_0, dmaHandler, 0);
irq_set_enabled(DMA_IRQ_0, true);
dma_channel_configure(_dmaChannel, &c,
rawBuffer[rawBufferIndex], // Destinatinon pointer
&_pio->rxf[_smIdx], // Source pointer
RAW_BUFFER_SIZE, // Number of transfers
true // Start immediately
);
_init = 1;
return 1;
}
void PDMClass::end()
{
dma_channel_abort(_dmaChannel);
pinMode(_clkPin, INPUT);
}
int PDMClass::available()
{
//NVIC_DisableIRQ(DMA_IRQ_0n);
//uint32_t interrupts = save_and_disable_interrupts();
irq_set_enabled(DMA_IRQ_0, false);
size_t avail = _doubleBuffer.available();
irq_set_enabled(DMA_IRQ_0, true);
//restore_interrupts(interrupts);
//NVIC_EnableIRQ(DMA_IRQ_0n);
return avail;
}
int PDMClass::read(void* buffer, size_t size)
{
irq_set_enabled(DMA_IRQ_0, false);
int read = _doubleBuffer.read(buffer, size);
irq_set_enabled(DMA_IRQ_0, true);
return read;
}
void PDMClass::onReceive(void(*function)(void))
{
_onReceive = function;
}
void PDMClass::setGain(int gain)
{
_gain = gain;
if(_init == 1) {
filter.filterGain = _gain; filter.filterGain = _gain;
Open_PDM_Filter_Init(&filter); Open_PDM_Filter_Init(&filter);
}
// Configure PIO state machine
float clkDiv = (float)clock_get_hz(clk_sys) / sampleRate / decimation / 2;
if (!_pdmPgm.prepare(&_pio, &_smIdx, &_pgmOffset)) {
// ERROR, no free slots
return -1;
}
pdm_pio_program_init(_pio, _smIdx, _pgmOffset, _clkPin, _dinPin, clkDiv);
// Wait for microphone
delay(100);
// Configure DMA for transferring PIO rx buffer to raw buffers
_dmaChannel = dma_claim_unused_channel(false);
dma_channel_config c = dma_channel_get_default_config(_dmaChannel);
channel_config_set_read_increment(&c, false);
channel_config_set_write_increment(&c, true);
channel_config_set_dreq(&c, pio_get_dreq(_pio, _smIdx, false));
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
// Clear DMA interrupts
dma_hw->ints0 = 1u << _dmaChannel;
// Enable DMA interrupts
dma_channel_set_irq0_enabled(_dmaChannel, true);
// Share but allocate a high priority to the interrupt
irq_add_shared_handler(DMA_IRQ_0, dmaHandler, 0);
irq_set_enabled(DMA_IRQ_0, true);
dma_channel_configure(_dmaChannel, &c,
rawBuffer[rawBufferIndex], // Destinatinon pointer
&_pio->rxf[_smIdx], // Source pointer
RAW_BUFFER_SIZE, // Number of transfers
true // Start immediately
);
_init = 1;
return 1;
} }
void PDMClass::setBufferSize(int bufferSize) void PDMClass::end() {
{ dma_channel_abort(_dmaChannel);
_doubleBuffer.setSize(bufferSize); pinMode(_clkPin, INPUT);
} }
void PDMClass::IrqHandler(bool halftranfer) int PDMClass::available() {
{ //NVIC_DisableIRQ(DMA_IRQ_0n);
static int cutSamples = 100; //uint32_t interrupts = save_and_disable_interrupts();
irq_set_enabled(DMA_IRQ_0, false);
size_t avail = _doubleBuffer.available();
irq_set_enabled(DMA_IRQ_0, true);
//restore_interrupts(interrupts);
//NVIC_EnableIRQ(DMA_IRQ_0n);
return avail;
}
// Clear the interrupt request. int PDMClass::read(void* buffer, size_t size) {
dma_hw->ints0 = 1u << _dmaChannel; irq_set_enabled(DMA_IRQ_0, false);
// Restart dma pointing to the other buffer int read = _doubleBuffer.read(buffer, size);
int shadowIndex = rawBufferIndex ^ 1; irq_set_enabled(DMA_IRQ_0, true);
dma_channel_set_write_addr(_dmaChannel, rawBuffer[shadowIndex], true); return read;
}
if (_doubleBuffer.available()) { void PDMClass::onReceive(void(*function)(void)) {
// buffer overflow, stop _onReceive = function;
return end(); }
}
// fill final buffer with PCM samples void PDMClass::setGain(int gain) {
Open_PDM_Filter_64(rawBuffer[rawBufferIndex], finalBuffer, 1, &filter); _gain = gain;
if (_init == 1) {
filter.filterGain = _gain;
Open_PDM_Filter_Init(&filter);
}
}
if (cutSamples) { void PDMClass::setBufferSize(int bufferSize) {
memset(finalBuffer, 0, cutSamples); _doubleBuffer.setSize(bufferSize);
cutSamples = 0; }
}
// swap final buffer and raw buffers' indexes void PDMClass::IrqHandler(bool halftranfer) {
finalBuffer = (int16_t*)_doubleBuffer.data(); static int cutSamples = 100;
_doubleBuffer.swap(filter.nSamples * sizeof(int16_t));
rawBufferIndex = shadowIndex;
if (_onReceive) { // Clear the interrupt request.
_onReceive(); dma_hw->ints0 = 1u << _dmaChannel;
} // Restart dma pointing to the other buffer
int shadowIndex = rawBufferIndex ^ 1;
dma_channel_set_write_addr(_dmaChannel, rawBuffer[shadowIndex], true);
if (_doubleBuffer.available()) {
// buffer overflow, stop
return end();
}
// fill final buffer with PCM samples
Open_PDM_Filter_64(rawBuffer[rawBufferIndex], finalBuffer, 1, &filter);
if (cutSamples) {
memset(finalBuffer, 0, cutSamples);
cutSamples = 0;
}
// swap final buffer and raw buffers' indexes
finalBuffer = (int16_t*)_doubleBuffer.data();
_doubleBuffer.swap(filter.nSamples * sizeof(int16_t));
rawBufferIndex = shadowIndex;
if (_onReceive) {
_onReceive();
}
} }
#ifdef PIN_PDM_DIN #ifdef PIN_PDM_DIN
PDMClass PDM(PIN_PDM_DIN, PIN_PDM_CLK, -1); PDMClass PDM(PIN_PDM_DIN, PIN_PDM_CLK, -1);

View file

@ -14,10 +14,10 @@
#define pdm_pio_wrap 1 #define pdm_pio_wrap 1
static const uint16_t pdm_pio_program_instructions[] = { static const uint16_t pdm_pio_program_instructions[] = {
// .wrap_target // .wrap_target
0x9040, // 0: push iffull noblock side 1 0x9040, // 0: push iffull noblock side 1
0x4001, // 1: in pins, 1 side 0 0x4001, // 1: in pins, 1 side 0
// .wrap // .wrap
}; };
#if !PICO_NO_HARDWARE #if !PICO_NO_HARDWARE
@ -36,21 +36,21 @@ static inline pio_sm_config pdm_pio_program_get_default_config(uint offset) {
#include "hardware/gpio.h" #include "hardware/gpio.h"
static inline void pdm_pio_program_init(PIO pio, uint sm, uint offset, uint clkPin, uint dataPin, float clkDiv) { static inline void pdm_pio_program_init(PIO pio, uint sm, uint offset, uint clkPin, uint dataPin, float clkDiv) {
pio_sm_config c = pdm_pio_program_get_default_config(offset); pio_sm_config c = pdm_pio_program_get_default_config(offset);
sm_config_set_sideset(&c, 1, false, false); sm_config_set_sideset(&c, 1, false, false);
//sm_config_set_in_shift(&c, false, true, 8); //sm_config_set_in_shift(&c, false, true, 8);
sm_config_set_in_shift(&c, false, false, 8); sm_config_set_in_shift(&c, false, false, 8);
sm_config_set_in_pins(&c, dataPin); sm_config_set_in_pins(&c, dataPin);
sm_config_set_sideset_pins(&c, clkPin); sm_config_set_sideset_pins(&c, clkPin);
sm_config_set_clkdiv(&c, clkDiv); sm_config_set_clkdiv(&c, clkDiv);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
pio_sm_set_consecutive_pindirs(pio, sm, dataPin, 1, false); pio_sm_set_consecutive_pindirs(pio, sm, dataPin, 1, false);
pio_sm_set_consecutive_pindirs(pio, sm, clkPin, 1, true); pio_sm_set_consecutive_pindirs(pio, sm, clkPin, 1, true);
pio_sm_set_pins_with_mask(pio, sm, 0, (1u << clkPin) ); pio_sm_set_pins_with_mask(pio, sm, 0, (1u << clkPin));
//pio_gpio_init(pio, dataPin); //pio_gpio_init(pio, dataPin);
pio_gpio_init(pio, clkPin); pio_gpio_init(pio, clkPin);
pio_sm_init(pio, sm, offset, &c); pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true); pio_sm_set_enabled(pio, sm, true);
} }
#endif #endif

View file

@ -1,19 +1,19 @@
/* /*
Copyright (c) 2016 Arduino LLC. All right reserved. Copyright (c) 2016 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -22,118 +22,106 @@
#include "PDMDoubleBuffer.h" #include "PDMDoubleBuffer.h"
PDMDoubleBuffer::PDMDoubleBuffer() : PDMDoubleBuffer::PDMDoubleBuffer() :
_size(DEFAULT_PDM_BUFFER_SIZE) _size(DEFAULT_PDM_BUFFER_SIZE) {
{ reset();
reset();
} }
PDMDoubleBuffer::~PDMDoubleBuffer() PDMDoubleBuffer::~PDMDoubleBuffer() {
{
} }
void PDMDoubleBuffer::setSize(int size) void PDMDoubleBuffer::setSize(int size) {
{ _size = size;
_size = size; reset();
reset();
} }
size_t PDMDoubleBuffer::getSize() size_t PDMDoubleBuffer::getSize() {
{ return _size;
return _size;
} }
void PDMDoubleBuffer::reset() void PDMDoubleBuffer::reset() {
{ _buffer[0] = (uint8_t*)realloc(_buffer[0], _size);
_buffer[0] = (uint8_t*)realloc(_buffer[0], _size); _buffer[1] = (uint8_t*)realloc(_buffer[1], _size);
_buffer[1] = (uint8_t*)realloc(_buffer[1], _size);
memset(_buffer[0], 0x00, _size); memset(_buffer[0], 0x00, _size);
memset(_buffer[1], 0x00, _size); memset(_buffer[1], 0x00, _size);
_index = 0;
_length[0] = 0;
_length[1] = 0;
_readOffset[0] = 0;
_readOffset[1] = 0;
}
size_t PDMDoubleBuffer::availableForWrite()
{
return (_size - (_length[_index] - _readOffset[_index]));
}
size_t PDMDoubleBuffer::write(const void *buffer, size_t size)
{
size_t space = availableForWrite();
if (size > space) {
size = space;
}
if (size == 0) {
return 0;
}
memcpy(&_buffer[_index][_length[_index]], buffer, size);
_length[_index] += size;
return size;
}
size_t PDMDoubleBuffer::read(void *buffer, size_t size)
{
size_t avail = available();
if (size > avail) {
size = avail;
}
if (size == 0) {
return 0;
}
memcpy(buffer, &_buffer[_index][_readOffset[_index]], size);
_readOffset[_index] += size;
return size;
}
size_t PDMDoubleBuffer::peek(void *buffer, size_t size)
{
size_t avail = available();
if (size > avail) {
size = avail;
}
if (size == 0) {
return 0;
}
memcpy(buffer, &_buffer[_index][_readOffset[_index]], size);
return size;
}
void* PDMDoubleBuffer::data()
{
return (void*)_buffer[_index];
}
size_t PDMDoubleBuffer::available()
{
return _length[_index] - _readOffset[_index];
}
void PDMDoubleBuffer::swap(int length)
{
if (_index == 0) {
_index = 1;
} else {
_index = 0; _index = 0;
} _length[0] = 0;
_length[1] = 0;
_length[_index] = length; _readOffset[0] = 0;
_readOffset[_index] = 0; _readOffset[1] = 0;
}
size_t PDMDoubleBuffer::availableForWrite() {
return (_size - (_length[_index] - _readOffset[_index]));
}
size_t PDMDoubleBuffer::write(const void *buffer, size_t size) {
size_t space = availableForWrite();
if (size > space) {
size = space;
}
if (size == 0) {
return 0;
}
memcpy(&_buffer[_index][_length[_index]], buffer, size);
_length[_index] += size;
return size;
}
size_t PDMDoubleBuffer::read(void *buffer, size_t size) {
size_t avail = available();
if (size > avail) {
size = avail;
}
if (size == 0) {
return 0;
}
memcpy(buffer, &_buffer[_index][_readOffset[_index]], size);
_readOffset[_index] += size;
return size;
}
size_t PDMDoubleBuffer::peek(void *buffer, size_t size) {
size_t avail = available();
if (size > avail) {
size = avail;
}
if (size == 0) {
return 0;
}
memcpy(buffer, &_buffer[_index][_readOffset[_index]], size);
return size;
}
void* PDMDoubleBuffer::data() {
return (void*)_buffer[_index];
}
size_t PDMDoubleBuffer::available() {
return _length[_index] - _readOffset[_index];
}
void PDMDoubleBuffer::swap(int length) {
if (_index == 0) {
_index = 1;
} else {
_index = 0;
}
_length[_index] = length;
_readOffset[_index] = 0;
} }

View file

@ -1,19 +1,19 @@
/* /*
Copyright (c) 2016 Arduino LLC. All right reserved. Copyright (c) 2016 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef _PDM_DOUBLE_BUFFER_H_INCLUDED #ifndef _PDM_DOUBLE_BUFFER_H_INCLUDED
@ -24,31 +24,30 @@
#define DEFAULT_PDM_BUFFER_SIZE 512 #define DEFAULT_PDM_BUFFER_SIZE 512
class PDMDoubleBuffer class PDMDoubleBuffer {
{
public: public:
PDMDoubleBuffer(); PDMDoubleBuffer();
virtual ~PDMDoubleBuffer(); virtual ~PDMDoubleBuffer();
void setSize(int size); void setSize(int size);
size_t getSize(); size_t getSize();
void reset(); void reset();
size_t availableForWrite(); size_t availableForWrite();
size_t write(const void *buffer, size_t size); size_t write(const void *buffer, size_t size);
size_t read(void *buffer, size_t size); size_t read(void *buffer, size_t size);
size_t peek(void *buffer, size_t size); size_t peek(void *buffer, size_t size);
void* data(); void* data();
size_t available(); size_t available();
void swap(int length = 0); void swap(int length = 0);
private: private:
uint8_t* _buffer[2] __attribute__((aligned (16))); uint8_t* _buffer[2] __attribute__((aligned(16)));
int _size; int _size;
volatile int _length[2]; volatile int _length[2];
volatile int _readOffset[2]; volatile int _readOffset[2];
volatile int _index; volatile int _index;
}; };
#endif #endif

View file

@ -17,8 +17,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef __SD_H__ #pragma once
#define __SD_H__
#include <Arduino.h> #include <Arduino.h>
#include <FS.h> #include <FS.h>
@ -218,5 +217,3 @@ static inline uint8_t FAT_SECOND(uint16_t fatTime) {
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SD) #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SD)
extern SDClass SD; extern SDClass SD;
#endif #endif
#endif

View file

@ -1,6 +1,3 @@
#ifndef SDFS_H
#define SDFS_H
/* /*
SDFS.h - file system wrapper for SdLib SDFS.h - file system wrapper for SdLib
Copyright (c) 2019 Earle F. Philhower, III. All rights reserved. Copyright (c) 2019 Earle F. Philhower, III. All rights reserved.
@ -27,6 +24,9 @@
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#pragma once
#include <limits> #include <limits>
#include <assert.h> #include <assert.h>
#include "FS.h" #include "FS.h"
@ -508,5 +508,3 @@ protected:
extern FS SDFS; extern FS SDFS;
using sdfs::SDFSConfig; using sdfs::SDFSConfig;
#endif #endif
#endif // SDFS.h

View file

@ -37,8 +37,7 @@
detach() - Stops an attached servos from pulsing its i/o pin. detach() - Stops an attached servos from pulsing its i/o pin.
*/ */
#ifndef Servo_h #pragma once
#define Servo_h
#include <Arduino.h> #include <Arduino.h>
#include <hardware/pio.h> #include <hardware/pio.h>
@ -89,5 +88,3 @@ private:
}; };
#endif

View file

@ -1,3 +1,22 @@
/*
StackThunk - Implements a simple 2nd stack for BSSL and others
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>

View file

@ -1,3 +1,22 @@
/*
StackThunk - Implements a simple 2nd stack for BSSL and others
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>

View file

@ -72,8 +72,7 @@
} }
*/ */
#ifndef __ADDRLIST_H #pragma once
#define __ADDRLIST_H
#include <IPAddress.h> #include <IPAddress.h>
#include <api/String.h> #include <api/String.h>
@ -254,6 +253,3 @@ inline AddressList::const_iterator end(const AddressList& a) {
} // esp8266 } // esp8266
extern esp8266::AddressListImplementation::AddressList addrList; extern esp8266::AddressListImplementation::AddressList addrList;
#endif

View file

@ -1,3 +1,25 @@
/*
LwipEthernet.h
Arduino interface for lwIP generic callbacks and functions
Original Copyright (c) 2020 esp8266 Arduino All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
//#include <ESP8266WiFi.h> // tcp API //#include <ESP8266WiFi.h> // tcp API
//#include <debug.h> //#include <debug.h>

View file

@ -3,12 +3,12 @@
for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S \ for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S \
./libraries/LittleFS/src ./libraries/LittleFS/examples \ ./libraries/LittleFS/src ./libraries/LittleFS/examples \
./libraries/rp2040 ./libraries/SD ./libraries/ESP8266SdFat \ ./libraries/rp2040 ./libraries/SD ./libraries/ESP8266SdFat \
./libraries/Servo ./libraries/SPI ./libraries/Wire \ ./libraries/Servo ./libraries/SPI ./libraries/Wire ./libraries/PDM \
./libraries/WiFi ./libraries/lwIP_Ethernet ./libraries/lwIP_CYW43 \ ./libraries/WiFi ./libraries/lwIP_Ethernet ./libraries/lwIP_CYW43 \
./libraries/FreeRTOS/src ./libraries/LEAmDNS ./libraries/MD5Builder \ ./libraries/FreeRTOS/src ./libraries/LEAmDNS ./libraries/MD5Builder \
./libraries/PicoOTA ./libraries/SDFS ./libraries/ArduinoOTA \ ./libraries/PicoOTA ./libraries/SDFS ./libraries/ArduinoOTA \
./libraries/Updater ./libraries/HTTPClient ./libraries/HTTPUpdate \ ./libraries/Updater ./libraries/HTTPClient ./libraries/HTTPUpdate \
./libraries/WebServer ./libraries/HTTPUpdateServer ; do ./libraries/WebServer ./libraries/HTTPUpdateServer ./libraries/DNSServer ; 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 "*.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 \{\} \; find $dir -type f -name "*.ino" -exec astyle --suffix=none --options=./tests/astyle_examples.conf \{\} \;
done done