mirror of
https://github.com/wled/WLED.git
synced 2025-07-23 10:46:33 +00:00
Merge branch 'master' into multifix
This commit is contained in:
commit
2b666ab9f7
11
.github/workflows/nightly.yml
vendored
11
.github/workflows/nightly.yml
vendored
@ -39,8 +39,9 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
*.bin
|
*.bin
|
||||||
*.bin.gz
|
*.bin.gz
|
||||||
# - name: Repository Dispatch
|
- name: Repository Dispatch
|
||||||
# uses: peter-evans/repository-dispatch@v3
|
uses: peter-evans/repository-dispatch@v3
|
||||||
# with:
|
with:
|
||||||
# repository: wled-dev/WLED-WebInstaller
|
repository: wled/WLED-WebInstaller
|
||||||
# event-type: release-nightly
|
event-type: release-nightly
|
||||||
|
token: ${{ secrets.PAT_PUBLIC }}
|
||||||
|
13
.github/workflows/pr-merge.yaml
vendored
Normal file
13
.github/workflows/pr-merge.yaml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
name: Notify Discord on PR Merge
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [closed]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
notify:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Send Discord notification
|
||||||
|
if: github.event.pull_request.merged == true
|
||||||
|
run: |
|
||||||
|
curl -H "Content-Type: application/json" -d '{"content": "Pull Request #{{ github.event.pull_request.number }} merged by {{ github.actor }}"}' ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }}
|
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@ -18,9 +18,16 @@ jobs:
|
|||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
|
- name: "✏️ Generate release changelog"
|
||||||
|
id: changelog
|
||||||
|
uses: janheinrichmerker/action-github-changelog-generator@v2.3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
sinceTag: v0.15.0
|
||||||
- name: Create draft release
|
- name: Create draft release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
|
body: ${{ steps.changelog.outputs.changelog }}
|
||||||
draft: True
|
draft: True
|
||||||
files: |
|
files: |
|
||||||
*.bin
|
*.bin
|
||||||
|
13
.github/workflows/test.yaml
vendored
Normal file
13
.github/workflows/test.yaml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dispatch:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Repository Dispatch
|
||||||
|
uses: peter-evans/repository-dispatch@v3
|
||||||
|
with:
|
||||||
|
repository: wled/WLED-WebInstaller
|
||||||
|
event-type: release-nightly
|
||||||
|
token: ${{ secrets.PAT_PUBLIC }}
|
@ -10,7 +10,7 @@ if node_ex is None:
|
|||||||
else:
|
else:
|
||||||
# Install the necessary node packages for the pre-build asset bundling script
|
# Install the necessary node packages for the pre-build asset bundling script
|
||||||
print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m')
|
print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m')
|
||||||
env.Execute("npm install")
|
env.Execute("npm ci")
|
||||||
|
|
||||||
# Call the bundling script
|
# Call the bundling script
|
||||||
exitCode = env.Execute("npm run build")
|
exitCode = env.Execute("npm run build")
|
||||||
|
138
wled00/FX.cpp
138
wled00/FX.cpp
@ -7467,42 +7467,86 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@
|
|||||||
//Soap
|
//Soap
|
||||||
//@Stepko
|
//@Stepko
|
||||||
//Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick
|
//Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick
|
||||||
// adapted for WLED by @blazoncek
|
// adapted for WLED by @blazoncek, optimization by @dedehai
|
||||||
|
static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) {
|
||||||
|
const int cols = SEG_W;
|
||||||
|
const int rows = SEG_H;
|
||||||
|
const auto XY = [&](int x, int y) { return x + y * cols; };
|
||||||
|
const auto abs = [](int x) { return x<0 ? -x : x; };
|
||||||
|
const int tRC = isRow ? rows : cols; // transpose if isRow
|
||||||
|
const int tCR = isRow ? cols : rows; // transpose if isRow
|
||||||
|
const int amplitude = max(1, (tCR - 8) >> 3) * (1 + (SEGMENT.custom1 >> 5));
|
||||||
|
const int shift = 0; //(128 - SEGMENT.custom2)*2;
|
||||||
|
|
||||||
|
CRGB ledsbuff[tCR];
|
||||||
|
|
||||||
|
for (int i = 0; i < tRC; i++) {
|
||||||
|
int amount = ((int)noise3d[isRow ? i*cols : i] - 128) * amplitude + shift; // use first row/column: XY(0,i)/XY(i,0)
|
||||||
|
int delta = abs(amount) >> 8;
|
||||||
|
int fraction = abs(amount) & 255;
|
||||||
|
for (int j = 0; j < tCR; j++) {
|
||||||
|
int zD, zF;
|
||||||
|
if (amount < 0) {
|
||||||
|
zD = j - delta;
|
||||||
|
zF = zD - 1;
|
||||||
|
} else {
|
||||||
|
zD = j + delta;
|
||||||
|
zF = zD + 1;
|
||||||
|
}
|
||||||
|
int yA = abs(zD)%tCR;
|
||||||
|
int yB = abs(zF)%tCR;
|
||||||
|
int xA = i;
|
||||||
|
int xB = i;
|
||||||
|
if (isRow) {
|
||||||
|
std::swap(xA,yA);
|
||||||
|
std::swap(xB,yB);
|
||||||
|
}
|
||||||
|
const int indxA = XY(xA,yA);
|
||||||
|
const int indxB = XY(xB,yB);
|
||||||
|
CRGB PixelA;
|
||||||
|
CRGB PixelB;
|
||||||
|
if ((zD >= 0) && (zD < tCR)) PixelA = pixels[indxA];
|
||||||
|
else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[indxA]*3);
|
||||||
|
if ((zF >= 0) && (zF < tCR)) PixelB = pixels[indxB];
|
||||||
|
else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[indxB]*3);
|
||||||
|
ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
|
||||||
|
}
|
||||||
|
for (int j = 0; j < tCR; j++) {
|
||||||
|
CRGB c = ledsbuff[j];
|
||||||
|
if (isRow) std::swap(j,i);
|
||||||
|
SEGMENT.setPixelColorXY(i, j, pixels[XY(i,j)] = c);
|
||||||
|
if (isRow) std::swap(j,i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t mode_2Dsoap() {
|
uint16_t mode_2Dsoap() {
|
||||||
if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up
|
if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up
|
||||||
|
|
||||||
const int cols = SEG_W;
|
const int cols = SEG_W;
|
||||||
const int rows = SEG_H;
|
const int rows = SEG_H;
|
||||||
const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; };
|
const auto XY = [&](int x, int y) { return x + y * cols; };
|
||||||
|
|
||||||
const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped
|
const size_t segSize = SEGMENT.width() * SEGMENT.height(); // prevent reallocation if mirrored or grouped
|
||||||
|
const size_t dataSize = segSize * (sizeof(uint8_t) + sizeof(CRGB)); // pixels and noise
|
||||||
if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed
|
if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed
|
||||||
|
|
||||||
uint8_t *noise3d = reinterpret_cast<uint8_t*>(SEGENV.data);
|
uint8_t *noise3d = reinterpret_cast<uint8_t*>(SEGENV.data);
|
||||||
uint32_t *noise32_x = reinterpret_cast<uint32_t*>(SEGENV.data + dataSize);
|
CRGB *pixels = reinterpret_cast<CRGB*>(SEGENV.data + segSize * sizeof(uint8_t));
|
||||||
uint32_t *noise32_y = reinterpret_cast<uint32_t*>(SEGENV.data + dataSize + sizeof(uint32_t));
|
uint32_t *noisecoord = reinterpret_cast<uint32_t*>(SEGENV.data + dataSize); // x, y, z coordinates
|
||||||
uint32_t *noise32_z = reinterpret_cast<uint32_t*>(SEGENV.data + dataSize + sizeof(uint32_t)*2);
|
|
||||||
const uint32_t scale32_x = 160000U/cols;
|
const uint32_t scale32_x = 160000U/cols;
|
||||||
const uint32_t scale32_y = 160000U/rows;
|
const uint32_t scale32_y = 160000U/rows;
|
||||||
const uint32_t mov = MIN(cols,rows)*(SEGMENT.speed+2)/2;
|
const uint32_t mov = MIN(cols,rows)*(SEGMENT.speed+2)/2;
|
||||||
const uint8_t smoothness = MIN(250,SEGMENT.intensity); // limit as >250 produces very little changes
|
const uint8_t smoothness = MIN(250,SEGMENT.intensity); // limit as >250 produces very little changes
|
||||||
|
|
||||||
// init
|
if (SEGENV.call == 0) for (int i = 0; i < 3; i++) noisecoord[i] = hw_random(); // init
|
||||||
if (SEGENV.call == 0) {
|
else for (int i = 0; i < 3; i++) noisecoord[i] += mov;
|
||||||
*noise32_x = hw_random();
|
|
||||||
*noise32_y = hw_random();
|
|
||||||
*noise32_z = hw_random();
|
|
||||||
} else {
|
|
||||||
*noise32_x += mov;
|
|
||||||
*noise32_y += mov;
|
|
||||||
*noise32_z += mov;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < cols; i++) {
|
for (int i = 0; i < cols; i++) {
|
||||||
int32_t ioffset = scale32_x * (i - cols / 2);
|
int32_t ioffset = scale32_x * (i - cols / 2);
|
||||||
for (int j = 0; j < rows; j++) {
|
for (int j = 0; j < rows; j++) {
|
||||||
int32_t joffset = scale32_y * (j - rows / 2);
|
int32_t joffset = scale32_y * (j - rows / 2);
|
||||||
uint8_t data = inoise16(*noise32_x + ioffset, *noise32_y + joffset, *noise32_z) >> 8;
|
uint8_t data = inoise16(noisecoord[0] + ioffset, noisecoord[1] + joffset, noisecoord[2]) >> 8;
|
||||||
noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], smoothness) + scale8(data, 255 - smoothness);
|
noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], smoothness) + scale8(data, 255 - smoothness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7517,64 +7561,12 @@ uint16_t mode_2Dsoap() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int zD;
|
soapPixels(true, noise3d, pixels); // rows
|
||||||
int zF;
|
soapPixels(false, noise3d, pixels); // cols
|
||||||
int amplitude;
|
|
||||||
int shiftX = 0; //(SEGMENT.custom1 - 128) / 4;
|
|
||||||
int shiftY = 0; //(SEGMENT.custom2 - 128) / 4;
|
|
||||||
CRGB ledsbuff[MAX(cols,rows)];
|
|
||||||
|
|
||||||
amplitude = (cols >= 16) ? (cols-8)/8 : 1;
|
|
||||||
for (int y = 0; y < rows; y++) {
|
|
||||||
int amount = ((int)noise3d[XY(0,y)] - 128) * 2 * amplitude + 256*shiftX;
|
|
||||||
int delta = abs(amount) >> 8;
|
|
||||||
int fraction = abs(amount) & 255;
|
|
||||||
for (int x = 0; x < cols; x++) {
|
|
||||||
if (amount < 0) {
|
|
||||||
zD = x - delta;
|
|
||||||
zF = zD - 1;
|
|
||||||
} else {
|
|
||||||
zD = x + delta;
|
|
||||||
zF = zD + 1;
|
|
||||||
}
|
|
||||||
CRGB PixelA = CRGB::Black;
|
|
||||||
if ((zD >= 0) && (zD < cols)) PixelA = SEGMENT.getPixelColorXY(zD, y);
|
|
||||||
else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zD),y)]*3);
|
|
||||||
CRGB PixelB = CRGB::Black;
|
|
||||||
if ((zF >= 0) && (zF < cols)) PixelB = SEGMENT.getPixelColorXY(zF, y);
|
|
||||||
else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zF),y)]*3);
|
|
||||||
ledsbuff[x] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
|
|
||||||
}
|
|
||||||
for (int x = 0; x < cols; x++) SEGMENT.setPixelColorXY(x, y, ledsbuff[x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
amplitude = (rows >= 16) ? (rows-8)/8 : 1;
|
|
||||||
for (int x = 0; x < cols; x++) {
|
|
||||||
int amount = ((int)noise3d[XY(x,0)] - 128) * 2 * amplitude + 256*shiftY;
|
|
||||||
int delta = abs(amount) >> 8;
|
|
||||||
int fraction = abs(amount) & 255;
|
|
||||||
for (int y = 0; y < rows; y++) {
|
|
||||||
if (amount < 0) {
|
|
||||||
zD = y - delta;
|
|
||||||
zF = zD - 1;
|
|
||||||
} else {
|
|
||||||
zD = y + delta;
|
|
||||||
zF = zD + 1;
|
|
||||||
}
|
|
||||||
CRGB PixelA = CRGB::Black;
|
|
||||||
if ((zD >= 0) && (zD < rows)) PixelA = SEGMENT.getPixelColorXY(x, zD);
|
|
||||||
else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zD))]*3);
|
|
||||||
CRGB PixelB = CRGB::Black;
|
|
||||||
if ((zF >= 0) && (zF < rows)) PixelB = SEGMENT.getPixelColorXY(x, zF);
|
|
||||||
else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zF))]*3);
|
|
||||||
ledsbuff[y] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction)));
|
|
||||||
}
|
|
||||||
for (int y = 0; y < rows; y++) SEGMENT.setPixelColorXY(x, y, ledsbuff[y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2;pal=11";
|
static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11";
|
||||||
|
|
||||||
|
|
||||||
//Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21
|
//Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21
|
||||||
|
@ -1138,12 +1138,9 @@ void Segment::refreshLightCapabilities() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned b = 0; b < BusManager::getNumBusses(); b++) {
|
for (unsigned b = 0; b < BusManager::getNumBusses(); b++) {
|
||||||
Bus *bus = BusManager::getBus(b);
|
const Bus *bus = BusManager::getBus(b);
|
||||||
if (bus == nullptr || bus->getLength()==0) break;
|
if (!bus || !bus->isOk()) break;
|
||||||
if (!bus->isOk()) continue;
|
if (bus->getStart() >= segStopIdx || bus->getStart() + bus->getLength() <= segStartIdx) continue;
|
||||||
if (bus->getStart() >= segStopIdx) continue;
|
|
||||||
if (bus->getStart() + bus->getLength() <= segStartIdx) continue;
|
|
||||||
|
|
||||||
if (bus->hasRGB() || (strip.cctFromRgb && bus->hasCCT())) capabilities |= SEG_CAPABILITY_RGB;
|
if (bus->hasRGB() || (strip.cctFromRgb && bus->hasCCT())) capabilities |= SEG_CAPABILITY_RGB;
|
||||||
if (!strip.cctFromRgb && bus->hasCCT()) capabilities |= SEG_CAPABILITY_CCT;
|
if (!strip.cctFromRgb && bus->hasCCT()) capabilities |= SEG_CAPABILITY_CCT;
|
||||||
if (strip.correctWB && (bus->hasRGB() || bus->hasCCT())) capabilities |= SEG_CAPABILITY_CCT; //white balance correction (CCT slider)
|
if (strip.correctWB && (bus->hasRGB() || bus->hasCCT())) capabilities |= SEG_CAPABILITY_CCT; //white balance correction (CCT slider)
|
||||||
@ -1478,8 +1475,7 @@ void WS2812FX::finalizeInit() {
|
|||||||
_length = 0;
|
_length = 0;
|
||||||
for (int i=0; i<BusManager::getNumBusses(); i++) {
|
for (int i=0; i<BusManager::getNumBusses(); i++) {
|
||||||
Bus *bus = BusManager::getBus(i);
|
Bus *bus = BusManager::getBus(i);
|
||||||
if (bus == nullptr) continue;
|
if (!bus || !bus->isOk() || bus->getStart() + bus->getLength() > MAX_LEDS) break;
|
||||||
if (bus->getStart() + bus->getLength() > MAX_LEDS) break;
|
|
||||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||||
_hasWhiteChannel |= bus->hasWhite();
|
_hasWhiteChannel |= bus->hasWhite();
|
||||||
//refresh is required to remain off if at least one of the strips requires the refresh.
|
//refresh is required to remain off if at least one of the strips requires the refresh.
|
||||||
@ -1489,6 +1485,7 @@ void WS2812FX::finalizeInit() {
|
|||||||
|
|
||||||
// This must be done after all buses have been created, as some kinds (parallel I2S) interact
|
// This must be done after all buses have been created, as some kinds (parallel I2S) interact
|
||||||
bus->begin();
|
bus->begin();
|
||||||
|
bus->setBrightness(bri);
|
||||||
}
|
}
|
||||||
DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap());
|
DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap());
|
||||||
|
|
||||||
@ -1794,8 +1791,8 @@ uint16_t WS2812FX::getLengthPhysical() const {
|
|||||||
//not influenced by auto-white mode, also true if white slider does not affect output white channel
|
//not influenced by auto-white mode, also true if white slider does not affect output white channel
|
||||||
bool WS2812FX::hasRGBWBus() const {
|
bool WS2812FX::hasRGBWBus() const {
|
||||||
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
||||||
Bus *bus = BusManager::getBus(b);
|
const Bus *bus = BusManager::getBus(b);
|
||||||
if (bus == nullptr || bus->getLength()==0) break;
|
if (!bus || !bus->isOk()) break;
|
||||||
if (bus->hasRGB() && bus->hasWhite()) return true;
|
if (bus->hasRGB() && bus->hasWhite()) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1804,8 +1801,8 @@ bool WS2812FX::hasRGBWBus() const {
|
|||||||
bool WS2812FX::hasCCTBus() const {
|
bool WS2812FX::hasCCTBus() const {
|
||||||
if (cctFromRgb && !correctWB) return false;
|
if (cctFromRgb && !correctWB) return false;
|
||||||
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
||||||
Bus *bus = BusManager::getBus(b);
|
const Bus *bus = BusManager::getBus(b);
|
||||||
if (bus == nullptr || bus->getLength()==0) break;
|
if (!bus || !bus->isOk()) break;
|
||||||
if (bus->hasCCT()) return true;
|
if (bus->hasCCT()) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1858,10 +1855,11 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (size_t i = s; i < BusManager::getNumBusses(); i++) {
|
for (size_t i = s; i < BusManager::getNumBusses(); i++) {
|
||||||
Bus* b = BusManager::getBus(i);
|
const Bus *bus = BusManager::getBus(i);
|
||||||
|
if (!bus || !bus->isOk()) break;
|
||||||
|
|
||||||
segStarts[s] = b->getStart();
|
segStarts[s] = bus->getStart();
|
||||||
segStops[s] = segStarts[s] + b->getLength();
|
segStops[s] = segStarts[s] + bus->getLength();
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (isMatrix && segStops[s] <= Segment::maxWidth*Segment::maxHeight) continue; // ignore buses comprising matrix
|
if (isMatrix && segStops[s] <= Segment::maxWidth*Segment::maxHeight) continue; // ignore buses comprising matrix
|
||||||
@ -1951,7 +1949,8 @@ bool WS2812FX::checkSegmentAlignment() const {
|
|||||||
bool aligned = false;
|
bool aligned = false;
|
||||||
for (const segment &seg : _segments) {
|
for (const segment &seg : _segments) {
|
||||||
for (unsigned b = 0; b<BusManager::getNumBusses(); b++) {
|
for (unsigned b = 0; b<BusManager::getNumBusses(); b++) {
|
||||||
Bus *bus = BusManager::getBus(b);
|
const Bus *bus = BusManager::getBus(b);
|
||||||
|
if (!bus || !bus->isOk()) break;
|
||||||
if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
|
if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true;
|
||||||
}
|
}
|
||||||
if (seg.start == 0 && seg.stop == _length) aligned = true;
|
if (seg.start == 0 && seg.stop == _length) aligned = true;
|
||||||
@ -2048,12 +2047,17 @@ bool WS2812FX::deserializeMap(unsigned n) {
|
|||||||
|
|
||||||
if (!isFile || !requestJSONBufferLock(7)) return false;
|
if (!isFile || !requestJSONBufferLock(7)) return false;
|
||||||
|
|
||||||
if (!readObjectFromFile(fileName, nullptr, pDoc)) {
|
StaticJsonDocument<64> filter;
|
||||||
|
filter[F("width")] = true;
|
||||||
|
filter[F("height")] = true;
|
||||||
|
if (!readObjectFromFile(fileName, nullptr, pDoc, &filter)) {
|
||||||
DEBUG_PRINT(F("ERROR Invalid ledmap in ")); DEBUG_PRINTLN(fileName);
|
DEBUG_PRINT(F("ERROR Invalid ledmap in ")); DEBUG_PRINTLN(fileName);
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
return false; // if file does not load properly then exit
|
return false; // if file does not load properly then exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend();
|
||||||
|
|
||||||
JsonObject root = pDoc->as<JsonObject>();
|
JsonObject root = pDoc->as<JsonObject>();
|
||||||
// if we are loading default ledmap (at boot) set matrix width and height from the ledmap (compatible with WLED MM ledmaps)
|
// if we are loading default ledmap (at boot) set matrix width and height from the ledmap (compatible with WLED MM ledmaps)
|
||||||
if (isMatrix && n == 0 && (!root[F("width")].isNull() || !root[F("height")].isNull())) {
|
if (isMatrix && n == 0 && (!root[F("width")].isNull() || !root[F("height")].isNull())) {
|
||||||
@ -2066,16 +2070,52 @@ bool WS2812FX::deserializeMap(unsigned n) {
|
|||||||
|
|
||||||
if (customMappingTable) {
|
if (customMappingTable) {
|
||||||
DEBUG_PRINT(F("Reading LED map from ")); DEBUG_PRINTLN(fileName);
|
DEBUG_PRINT(F("Reading LED map from ")); DEBUG_PRINTLN(fileName);
|
||||||
|
File f = WLED_FS.open(fileName, "r");
|
||||||
|
f.find("\"map\":[");
|
||||||
|
while (f.available()) { // f.position() < f.size() - 1
|
||||||
|
char number[32];
|
||||||
|
size_t numRead = f.readBytesUntil(',', number, sizeof(number)-1); // read a single number (may include array terminating "]" but not number separator ',')
|
||||||
|
number[numRead] = 0;
|
||||||
|
if (numRead > 0) {
|
||||||
|
char *end = strchr(number,']'); // we encountered end of array so stop processing if no digit found
|
||||||
|
bool foundDigit = (end == nullptr);
|
||||||
|
int i = 0;
|
||||||
|
if (end != nullptr) do {
|
||||||
|
if (number[i] >= '0' && number[i] <= '9') foundDigit = true;
|
||||||
|
if (foundDigit || &number[i++] == end) break;
|
||||||
|
} while (i < 32);
|
||||||
|
if (!foundDigit) break;
|
||||||
|
int index = atoi(number);
|
||||||
|
if (index < 0 || index > 16384) index = 0xFFFF;
|
||||||
|
customMappingTable[customMappingSize++] = index;
|
||||||
|
if (customMappingSize > getLengthTotal()) break;
|
||||||
|
} else break; // there was nothing to read, stop
|
||||||
|
}
|
||||||
|
currentLedmap = n;
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
|
DEBUG_PRINT(F("Loaded ledmap:"));
|
||||||
|
for (unsigned i=0; i<customMappingSize; i++) {
|
||||||
|
if (!(i%Segment::maxWidth)) DEBUG_PRINTLN();
|
||||||
|
DEBUG_PRINTF_P(PSTR("%4d,"), customMappingTable[i]);
|
||||||
|
}
|
||||||
|
DEBUG_PRINTLN();
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
JsonArray map = root[F("map")];
|
JsonArray map = root[F("map")];
|
||||||
if (!map.isNull() && map.size()) { // not an empty map
|
if (!map.isNull() && map.size()) { // not an empty map
|
||||||
customMappingSize = min((unsigned)map.size(), (unsigned)getLengthTotal());
|
customMappingSize = min((unsigned)map.size(), (unsigned)getLengthTotal());
|
||||||
for (unsigned i=0; i<customMappingSize; i++) customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]);
|
for (unsigned i=0; i<customMappingSize; i++) customMappingTable[i] = (uint16_t) (map[i]<0 ? 0xFFFFU : map[i]);
|
||||||
currentLedmap = n;
|
currentLedmap = n;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTLN(F("ERROR LED map allocation error."));
|
DEBUG_PRINTLN(F("ERROR LED map allocation error."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resume();
|
||||||
|
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
return (customMappingSize > 0);
|
return (customMappingSize > 0);
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,8 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const
|
|||||||
#define W(c) (byte((c) >> 24))
|
#define W(c) (byte((c) >> 24))
|
||||||
|
|
||||||
|
|
||||||
|
static ColorOrderMap _colorOrderMap = {};
|
||||||
|
|
||||||
bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) {
|
bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) {
|
||||||
if (count() >= WLED_MAX_COLOR_ORDER_MAPPINGS || len == 0 || (colorOrder & 0x0F) > COL_ORDER_MAX) return false; // upper nibble contains W swap information
|
if (count() >= WLED_MAX_COLOR_ORDER_MAPPINGS || len == 0 || (colorOrder & 0x0F) > COL_ORDER_MAX) return false; // upper nibble contains W swap information
|
||||||
_mappings.push_back({start,len,colorOrder});
|
_mappings.push_back({start,len,colorOrder});
|
||||||
@ -53,10 +55,8 @@ bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) {
|
|||||||
uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const {
|
uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const {
|
||||||
// upper nibble contains W swap information
|
// upper nibble contains W swap information
|
||||||
// when ColorOrderMap's upper nibble contains value >0 then swap information is used from it, otherwise global swap is used
|
// when ColorOrderMap's upper nibble contains value >0 then swap information is used from it, otherwise global swap is used
|
||||||
for (unsigned i = 0; i < count(); i++) {
|
for (const auto& map : _mappings) {
|
||||||
if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) {
|
if (pix >= map.start && pix < (map.start + map.len)) return map.colorOrder | ((map.colorOrder >> 4) ? 0 : (defaultColorOrder & 0xF0));
|
||||||
return _mappings[i].colorOrder | ((_mappings[i].colorOrder >> 4) ? 0 : (defaultColorOrder & 0xF0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return defaultColorOrder;
|
return defaultColorOrder;
|
||||||
}
|
}
|
||||||
@ -99,23 +99,14 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) const {
|
|||||||
return RGBW32(r, g, b, w);
|
return RGBW32(r, g, b, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *Bus::allocateData(size_t size) {
|
|
||||||
freeData(); // should not happen, but for safety
|
|
||||||
return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Bus::freeData() {
|
BusDigital::BusDigital(const BusConfig &bc, uint8_t nr)
|
||||||
if (_data) free(_data);
|
|
||||||
_data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
|
||||||
: Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814))
|
: Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814))
|
||||||
, _skip(bc.skipAmount) //sacrificial pixels
|
, _skip(bc.skipAmount) //sacrificial pixels
|
||||||
, _colorOrder(bc.colorOrder)
|
, _colorOrder(bc.colorOrder)
|
||||||
, _milliAmpsPerLed(bc.milliAmpsPerLed)
|
, _milliAmpsPerLed(bc.milliAmpsPerLed)
|
||||||
, _milliAmpsMax(bc.milliAmpsMax)
|
, _milliAmpsMax(bc.milliAmpsMax)
|
||||||
, _colorOrderMap(com)
|
, _data(nullptr)
|
||||||
{
|
{
|
||||||
DEBUGBUS_PRINTLN(F("Bus: Creating digital bus."));
|
DEBUGBUS_PRINTLN(F("Bus: Creating digital bus."));
|
||||||
if (!isDigital(bc.type) || !bc.count) { DEBUGBUS_PRINTLN(F("Not digial or empty bus!")); return; }
|
if (!isDigital(bc.type) || !bc.count) { DEBUGBUS_PRINTLN(F("Not digial or empty bus!")); return; }
|
||||||
@ -136,12 +127,14 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com
|
|||||||
_hasRgb = hasRGB(bc.type);
|
_hasRgb = hasRGB(bc.type);
|
||||||
_hasWhite = hasWhite(bc.type);
|
_hasWhite = hasWhite(bc.type);
|
||||||
_hasCCT = hasCCT(bc.type);
|
_hasCCT = hasCCT(bc.type);
|
||||||
if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) { DEBUGBUS_PRINTLN(F("Buffer allocation failed!")); return; }
|
if (bc.doubleBuffer) {
|
||||||
//_buffering = bc.doubleBuffer;
|
_data = (uint8_t*)calloc(_len, Bus::getNumberOfChannels(_type));
|
||||||
|
if (!_data) DEBUGBUS_PRINTLN(F("Bus: Buffer allocation failed!"));
|
||||||
|
}
|
||||||
uint16_t lenToCreate = bc.count;
|
uint16_t lenToCreate = bc.count;
|
||||||
if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus
|
if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus
|
||||||
_busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr);
|
_busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr);
|
||||||
_valid = (_busPtr != nullptr);
|
_valid = (_busPtr != nullptr) && bc.count > 0;
|
||||||
DEBUGBUS_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"),
|
DEBUGBUS_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"),
|
||||||
_valid?"S":"Uns",
|
_valid?"S":"Uns",
|
||||||
(int)nr,
|
(int)nr,
|
||||||
@ -268,7 +261,7 @@ void BusDigital::show() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PolyBus::show(_busPtr, _iType, !_data); // faster if buffer consistency is not important (use !_buffering this causes 20% FPS drop)
|
PolyBus::show(_busPtr, _iType, !_data); // faster if buffer consistency is not important
|
||||||
// restore bus brightness to its original value
|
// restore bus brightness to its original value
|
||||||
// this is done right after show, so this is only OK if LED updates are completed before show() returns
|
// this is done right after show, so this is only OK if LED updates are completed before show() returns
|
||||||
// or async show has a separate buffer (ESP32 RMT and I2S are ok)
|
// or async show has a separate buffer (ESP32 RMT and I2S are ok)
|
||||||
@ -421,11 +414,11 @@ void BusDigital::begin() {
|
|||||||
void BusDigital::cleanup() {
|
void BusDigital::cleanup() {
|
||||||
DEBUGBUS_PRINTLN(F("Digital Cleanup."));
|
DEBUGBUS_PRINTLN(F("Digital Cleanup."));
|
||||||
PolyBus::cleanup(_busPtr, _iType);
|
PolyBus::cleanup(_busPtr, _iType);
|
||||||
|
free(_data);
|
||||||
|
_data = nullptr;
|
||||||
_iType = I_NONE;
|
_iType = I_NONE;
|
||||||
_valid = false;
|
_valid = false;
|
||||||
_busPtr = nullptr;
|
_busPtr = nullptr;
|
||||||
freeData();
|
|
||||||
//PinManager::deallocateMultiplePins(_pins, 2, PinOwner::BusDigital);
|
|
||||||
PinManager::deallocatePin(_pins[1], PinOwner::BusDigital);
|
PinManager::deallocatePin(_pins[1], PinOwner::BusDigital);
|
||||||
PinManager::deallocatePin(_pins[0], PinOwner::BusDigital);
|
PinManager::deallocatePin(_pins[0], PinOwner::BusDigital);
|
||||||
}
|
}
|
||||||
@ -497,7 +490,6 @@ BusPwm::BusPwm(const BusConfig &bc)
|
|||||||
_hasRgb = hasRGB(bc.type);
|
_hasRgb = hasRGB(bc.type);
|
||||||
_hasWhite = hasWhite(bc.type);
|
_hasWhite = hasWhite(bc.type);
|
||||||
_hasCCT = hasCCT(bc.type);
|
_hasCCT = hasCCT(bc.type);
|
||||||
_data = _pwmdata; // avoid malloc() and use already allocated memory
|
|
||||||
_valid = true;
|
_valid = true;
|
||||||
DEBUGBUS_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]);
|
DEBUGBUS_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]);
|
||||||
}
|
}
|
||||||
@ -561,7 +553,7 @@ uint32_t BusPwm::getPixelColor(unsigned pix) const {
|
|||||||
|
|
||||||
void BusPwm::show() {
|
void BusPwm::show() {
|
||||||
if (!_valid) return;
|
if (!_valid) return;
|
||||||
const unsigned numPins = getPins();
|
const size_t numPins = getPins();
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
const unsigned analogPeriod = F_CPU / _frequency;
|
const unsigned analogPeriod = F_CPU / _frequency;
|
||||||
const unsigned maxBri = analogPeriod; // compute to clock cycle accuracy
|
const unsigned maxBri = analogPeriod; // compute to clock cycle accuracy
|
||||||
@ -648,7 +640,7 @@ std::vector<LEDType> BusPwm::getLEDTypes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BusPwm::deallocatePins() {
|
void BusPwm::deallocatePins() {
|
||||||
unsigned numPins = getPins();
|
size_t numPins = getPins();
|
||||||
for (unsigned i = 0; i < numPins; i++) {
|
for (unsigned i = 0; i < numPins; i++) {
|
||||||
PinManager::deallocatePin(_pins[i], PinOwner::BusPwm);
|
PinManager::deallocatePin(_pins[i], PinOwner::BusPwm);
|
||||||
if (!PinManager::isPinOk(_pins[i])) continue;
|
if (!PinManager::isPinOk(_pins[i])) continue;
|
||||||
@ -666,7 +658,7 @@ void BusPwm::deallocatePins() {
|
|||||||
|
|
||||||
BusOnOff::BusOnOff(const BusConfig &bc)
|
BusOnOff::BusOnOff(const BusConfig &bc)
|
||||||
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
|
: Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed)
|
||||||
, _onoffdata(0)
|
, _data(0)
|
||||||
{
|
{
|
||||||
if (!Bus::isOnOff(bc.type)) return;
|
if (!Bus::isOnOff(bc.type)) return;
|
||||||
|
|
||||||
@ -679,7 +671,6 @@ BusOnOff::BusOnOff(const BusConfig &bc)
|
|||||||
_hasRgb = false;
|
_hasRgb = false;
|
||||||
_hasWhite = false;
|
_hasWhite = false;
|
||||||
_hasCCT = false;
|
_hasCCT = false;
|
||||||
_data = &_onoffdata; // avoid malloc() and use stack
|
|
||||||
_valid = true;
|
_valid = true;
|
||||||
DEBUGBUS_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin);
|
DEBUGBUS_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin);
|
||||||
}
|
}
|
||||||
@ -691,17 +682,17 @@ void BusOnOff::setPixelColor(unsigned pix, uint32_t c) {
|
|||||||
uint8_t g = G(c);
|
uint8_t g = G(c);
|
||||||
uint8_t b = B(c);
|
uint8_t b = B(c);
|
||||||
uint8_t w = W(c);
|
uint8_t w = W(c);
|
||||||
_data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
_data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t BusOnOff::getPixelColor(unsigned pix) const {
|
uint32_t BusOnOff::getPixelColor(unsigned pix) const {
|
||||||
if (!_valid) return 0;
|
if (!_valid) return 0;
|
||||||
return RGBW32(_data[0], _data[0], _data[0], _data[0]);
|
return RGBW32(_data, _data, _data, _data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusOnOff::show() {
|
void BusOnOff::show() {
|
||||||
if (!_valid) return;
|
if (!_valid) return;
|
||||||
digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]);
|
digitalWrite(_pin, _reversed ? !(bool)_data : (bool)_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned BusOnOff::getPins(uint8_t* pinArray) const {
|
unsigned BusOnOff::getPins(uint8_t* pinArray) const {
|
||||||
@ -740,7 +731,8 @@ BusNetwork::BusNetwork(const BusConfig &bc)
|
|||||||
_hasCCT = false;
|
_hasCCT = false;
|
||||||
_UDPchannels = _hasWhite + 3;
|
_UDPchannels = _hasWhite + 3;
|
||||||
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
|
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
|
||||||
_valid = (allocateData(_len * _UDPchannels) != nullptr);
|
_data = (uint8_t*)calloc(_len, _UDPchannels);
|
||||||
|
_valid = (_data != nullptr);
|
||||||
DEBUGBUS_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]);
|
DEBUGBUS_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,9 +782,10 @@ std::vector<LEDType> BusNetwork::getLEDTypes() {
|
|||||||
|
|
||||||
void BusNetwork::cleanup() {
|
void BusNetwork::cleanup() {
|
||||||
DEBUGBUS_PRINTLN(F("Virtual Cleanup."));
|
DEBUGBUS_PRINTLN(F("Virtual Cleanup."));
|
||||||
|
free(_data);
|
||||||
|
_data = nullptr;
|
||||||
_type = I_NONE;
|
_type = I_NONE;
|
||||||
_valid = false;
|
_valid = false;
|
||||||
freeData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -844,17 +837,17 @@ int BusManager::add(const BusConfig &bc) {
|
|||||||
unsigned numDigital = 0;
|
unsigned numDigital = 0;
|
||||||
for (const auto &bus : busses) if (bus->isDigital() && !bus->is2Pin()) numDigital++;
|
for (const auto &bus : busses) if (bus->isDigital() && !bus->is2Pin()) numDigital++;
|
||||||
if (Bus::isVirtual(bc.type)) {
|
if (Bus::isVirtual(bc.type)) {
|
||||||
//busses.push_back(std::make_unique<BusNetwork>(bc)); // when C++ >11
|
busses.push_back(make_unique<BusNetwork>(bc));
|
||||||
busses.push_back(new BusNetwork(bc));
|
//busses.push_back(new BusNetwork(bc));
|
||||||
} else if (Bus::isDigital(bc.type)) {
|
} else if (Bus::isDigital(bc.type)) {
|
||||||
//busses.push_back(std::make_unique<BusDigital>(bc, numDigital, colorOrderMap));
|
busses.push_back(make_unique<BusDigital>(bc, numDigital));
|
||||||
busses.push_back(new BusDigital(bc, numDigital, colorOrderMap));
|
//busses.push_back(new BusDigital(bc, numDigital));
|
||||||
} else if (Bus::isOnOff(bc.type)) {
|
} else if (Bus::isOnOff(bc.type)) {
|
||||||
//busses.push_back(std::make_unique<BusOnOff>(bc));
|
busses.push_back(make_unique<BusOnOff>(bc));
|
||||||
busses.push_back(new BusOnOff(bc));
|
//busses.push_back(new BusOnOff(bc));
|
||||||
} else {
|
} else {
|
||||||
//busses.push_back(std::make_unique<BusPwm>(bc));
|
busses.push_back(make_unique<BusPwm>(bc));
|
||||||
busses.push_back(new BusPwm(bc));
|
//busses.push_back(new BusPwm(bc));
|
||||||
}
|
}
|
||||||
return busses.size();
|
return busses.size();
|
||||||
}
|
}
|
||||||
@ -898,7 +891,7 @@ void BusManager::removeAll() {
|
|||||||
DEBUGBUS_PRINTLN(F("Removing all."));
|
DEBUGBUS_PRINTLN(F("Removing all."));
|
||||||
//prevents crashes due to deleting busses while in use.
|
//prevents crashes due to deleting busses while in use.
|
||||||
while (!canAllShow()) yield();
|
while (!canAllShow()) yield();
|
||||||
for (auto &bus : busses) delete bus; // needed when not using std::unique_ptr C++ >11
|
//for (auto &bus : busses) delete bus; // needed when not using std::unique_ptr C++ >11
|
||||||
busses.clear();
|
busses.clear();
|
||||||
PolyBus::setParallelI2S1Output(false);
|
PolyBus::setParallelI2S1Output(false);
|
||||||
}
|
}
|
||||||
@ -949,8 +942,8 @@ void BusManager::on() {
|
|||||||
uint8_t pins[2] = {255,255};
|
uint8_t pins[2] = {255,255};
|
||||||
if (bus->isDigital() && bus->getPins(pins)) {
|
if (bus->isDigital() && bus->getPins(pins)) {
|
||||||
if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) {
|
if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) {
|
||||||
BusDigital *b = static_cast<BusDigital*>(bus);
|
BusDigital &b = static_cast<BusDigital&>(*bus);
|
||||||
b->begin();
|
b.begin();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -978,17 +971,13 @@ void BusManager::off() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BusManager::show() {
|
void BusManager::show() {
|
||||||
_milliAmpsUsed = 0;
|
_gMilliAmpsUsed = 0;
|
||||||
for (auto &bus : busses) {
|
for (auto &bus : busses) {
|
||||||
bus->show();
|
bus->show();
|
||||||
_milliAmpsUsed += bus->getUsedCurrent();
|
_gMilliAmpsUsed += bus->getUsedCurrent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusManager::setStatusPixel(uint32_t c) {
|
|
||||||
for (auto &bus : busses) bus->setStatusPixel(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) {
|
void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) {
|
||||||
for (auto &bus : busses) {
|
for (auto &bus : busses) {
|
||||||
unsigned bstart = bus->getStart();
|
unsigned bstart = bus->getStart();
|
||||||
@ -997,10 +986,6 @@ void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusManager::setBrightness(uint8_t b) {
|
|
||||||
for (auto &bus : busses) bus->setBrightness(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
||||||
if (cct > 255) cct = 255;
|
if (cct > 255) cct = 255;
|
||||||
if (cct >= 0) {
|
if (cct >= 0) {
|
||||||
@ -1024,17 +1009,8 @@ bool BusManager::canAllShow() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bus* BusManager::getBus(uint8_t busNr) {
|
ColorOrderMap& BusManager::getColorOrderMap() { return _colorOrderMap; }
|
||||||
if (busNr >= busses.size()) return nullptr;
|
|
||||||
return busses[busNr];
|
|
||||||
}
|
|
||||||
|
|
||||||
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
|
||||||
uint16_t BusManager::getTotalLength() {
|
|
||||||
unsigned len = 0;
|
|
||||||
for (const auto &bus : busses) len += bus->getLength();
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PolyBus::_useParallelI2S = false;
|
bool PolyBus::_useParallelI2S = false;
|
||||||
|
|
||||||
@ -1045,8 +1021,7 @@ uint8_t Bus::_gAWM = 255;
|
|||||||
|
|
||||||
uint16_t BusDigital::_milliAmpsTotal = 0;
|
uint16_t BusDigital::_milliAmpsTotal = 0;
|
||||||
|
|
||||||
//std::vector<std::unique_ptr<Bus>> BusManager::busses;
|
std::vector<std::unique_ptr<Bus>> BusManager::busses;
|
||||||
std::vector<Bus*> BusManager::busses;
|
//std::vector<Bus*> BusManager::busses;
|
||||||
ColorOrderMap BusManager::colorOrderMap = {};
|
uint16_t BusManager::_gMilliAmpsUsed = 0;
|
||||||
uint16_t BusManager::_milliAmpsUsed = 0;
|
uint16_t BusManager::_gMilliAmpsMax = ABL_MILLIAMPS_DEFAULT;
|
||||||
uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT;
|
|
||||||
|
@ -11,6 +11,18 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#if __cplusplus >= 201402L
|
||||||
|
using std::make_unique;
|
||||||
|
#else
|
||||||
|
// Really simple C++11 shim for non-array case; implementation from cppreference.com
|
||||||
|
template<class T, class... Args>
|
||||||
|
std::unique_ptr<T>
|
||||||
|
make_unique(Args&&... args)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// enable additional debug output
|
// enable additional debug output
|
||||||
#if defined(WLED_DEBUG_HOST)
|
#if defined(WLED_DEBUG_HOST)
|
||||||
#include "net_debug.h"
|
#include "net_debug.h"
|
||||||
@ -94,11 +106,10 @@ class Bus {
|
|||||||
: _type(type)
|
: _type(type)
|
||||||
, _bri(255)
|
, _bri(255)
|
||||||
, _start(start)
|
, _start(start)
|
||||||
, _len(len)
|
, _len(std::max(len,(uint16_t)1))
|
||||||
, _reversed(reversed)
|
, _reversed(reversed)
|
||||||
, _valid(false)
|
, _valid(false)
|
||||||
, _needsRefresh(refresh)
|
, _needsRefresh(refresh)
|
||||||
, _data(nullptr) // keep data access consistent across all types of buses
|
|
||||||
{
|
{
|
||||||
_autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY;
|
_autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY;
|
||||||
};
|
};
|
||||||
@ -202,7 +213,6 @@ class Bus {
|
|||||||
bool _hasCCT;// : 1;
|
bool _hasCCT;// : 1;
|
||||||
//} __attribute__ ((packed));
|
//} __attribute__ ((packed));
|
||||||
uint8_t _autoWhiteMode;
|
uint8_t _autoWhiteMode;
|
||||||
uint8_t *_data;
|
|
||||||
// global Auto White Calculation override
|
// global Auto White Calculation override
|
||||||
static uint8_t _gAWM;
|
static uint8_t _gAWM;
|
||||||
// _cct has the following menaings (see calculateCCT() & BusManager::setSegmentCCT()):
|
// _cct has the following menaings (see calculateCCT() & BusManager::setSegmentCCT()):
|
||||||
@ -217,14 +227,12 @@ class Bus {
|
|||||||
static uint8_t _cctBlend;
|
static uint8_t _cctBlend;
|
||||||
|
|
||||||
uint32_t autoWhiteCalc(uint32_t c) const;
|
uint32_t autoWhiteCalc(uint32_t c) const;
|
||||||
uint8_t *allocateData(size_t size = 1);
|
|
||||||
void freeData();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class BusDigital : public Bus {
|
class BusDigital : public Bus {
|
||||||
public:
|
public:
|
||||||
BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
|
BusDigital(const BusConfig &bc, uint8_t nr);
|
||||||
~BusDigital() { cleanup(); }
|
~BusDigital() { cleanup(); }
|
||||||
|
|
||||||
void show() override;
|
void show() override;
|
||||||
@ -248,15 +256,15 @@ class BusDigital : public Bus {
|
|||||||
static std::vector<LEDType> getLEDTypes();
|
static std::vector<LEDType> getLEDTypes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t _skip;
|
uint8_t _skip;
|
||||||
uint8_t _colorOrder;
|
uint8_t _colorOrder;
|
||||||
uint8_t _pins[2];
|
uint8_t _pins[2];
|
||||||
uint8_t _iType;
|
uint8_t _iType;
|
||||||
uint16_t _frequencykHz;
|
uint16_t _frequencykHz;
|
||||||
uint8_t _milliAmpsPerLed;
|
uint8_t _milliAmpsPerLed;
|
||||||
uint16_t _milliAmpsMax;
|
uint16_t _milliAmpsMax;
|
||||||
void * _busPtr;
|
uint8_t *_data;
|
||||||
const ColorOrderMap &_colorOrderMap;
|
void *_busPtr;
|
||||||
|
|
||||||
static uint16_t _milliAmpsTotal; // is overwitten/recalculated on each show()
|
static uint16_t _milliAmpsTotal; // is overwitten/recalculated on each show()
|
||||||
|
|
||||||
@ -286,13 +294,13 @@ class BusPwm : public Bus {
|
|||||||
uint16_t getFrequency() const override { return _frequency; }
|
uint16_t getFrequency() const override { return _frequency; }
|
||||||
unsigned getBusSize() const override { return sizeof(BusPwm); }
|
unsigned getBusSize() const override { return sizeof(BusPwm); }
|
||||||
void show() override;
|
void show() override;
|
||||||
inline void cleanup() { deallocatePins(); _data = nullptr; }
|
inline void cleanup() { deallocatePins(); }
|
||||||
|
|
||||||
static std::vector<LEDType> getLEDTypes();
|
static std::vector<LEDType> getLEDTypes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t _pins[OUTPUT_MAX_PINS];
|
uint8_t _pins[OUTPUT_MAX_PINS];
|
||||||
uint8_t _pwmdata[OUTPUT_MAX_PINS];
|
uint8_t _data[OUTPUT_MAX_PINS];
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
uint8_t _ledcStart;
|
uint8_t _ledcStart;
|
||||||
#endif
|
#endif
|
||||||
@ -313,13 +321,13 @@ class BusOnOff : public Bus {
|
|||||||
unsigned getPins(uint8_t* pinArray) const override;
|
unsigned getPins(uint8_t* pinArray) const override;
|
||||||
unsigned getBusSize() const override { return sizeof(BusOnOff); }
|
unsigned getBusSize() const override { return sizeof(BusOnOff); }
|
||||||
void show() override;
|
void show() override;
|
||||||
inline void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); _data = nullptr; }
|
inline void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); }
|
||||||
|
|
||||||
static std::vector<LEDType> getLEDTypes();
|
static std::vector<LEDType> getLEDTypes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t _pin;
|
uint8_t _pin;
|
||||||
uint8_t _onoffdata;
|
uint8_t _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -343,6 +351,7 @@ class BusNetwork : public Bus {
|
|||||||
uint8_t _UDPtype;
|
uint8_t _UDPtype;
|
||||||
uint8_t _UDPchannels;
|
uint8_t _UDPchannels;
|
||||||
bool _broadcastLock;
|
bool _broadcastLock;
|
||||||
|
uint8_t *_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -363,7 +372,7 @@ struct BusConfig {
|
|||||||
uint16_t milliAmpsMax;
|
uint16_t milliAmpsMax;
|
||||||
|
|
||||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY, uint16_t clock_kHz=0U, bool dblBfr=false, uint8_t maPerLed=LED_MILLIAMPS_DEFAULT, uint16_t maMax=ABL_MILLIAMPS_DEFAULT)
|
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY, uint16_t clock_kHz=0U, bool dblBfr=false, uint8_t maPerLed=LED_MILLIAMPS_DEFAULT, uint16_t maMax=ABL_MILLIAMPS_DEFAULT)
|
||||||
: count(len)
|
: count(std::max(len,(uint16_t)1))
|
||||||
, start(pstart)
|
, start(pstart)
|
||||||
, colorOrder(pcolorOrder)
|
, colorOrder(pcolorOrder)
|
||||||
, reversed(rev)
|
, reversed(rev)
|
||||||
@ -416,59 +425,58 @@ struct BusConfig {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class BusManager {
|
namespace BusManager {
|
||||||
public:
|
|
||||||
BusManager() {};
|
|
||||||
|
|
||||||
static unsigned memUsage();
|
extern std::vector<std::unique_ptr<Bus>> busses;
|
||||||
static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; }
|
//extern std::vector<Bus*> busses;
|
||||||
static uint16_t ablMilliampsMax() { return _milliAmpsMax; }
|
extern uint16_t _gMilliAmpsUsed;
|
||||||
|
extern uint16_t _gMilliAmpsMax;
|
||||||
|
|
||||||
static int add(const BusConfig &bc);
|
#ifdef ESP32_DATA_IDLE_HIGH
|
||||||
static void useParallelOutput(); // workaround for inaccessible PolyBus
|
void esp32RMTInvertIdle() ;
|
||||||
static bool hasParallelOutput(); // workaround for inaccessible PolyBus
|
#endif
|
||||||
|
inline size_t getNumVirtualBusses() {
|
||||||
|
size_t j = 0;
|
||||||
|
for (const auto &bus : busses) j += bus->isVirtual();
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
//do not call this method from system context (network callback)
|
size_t memUsage();
|
||||||
static void removeAll();
|
inline uint16_t currentMilliamps() { return _gMilliAmpsUsed + MA_FOR_ESP; }
|
||||||
|
//inline uint16_t ablMilliampsMax() { unsigned sum = 0; for (auto &bus : busses) sum += bus->getMaxCurrent(); return sum; }
|
||||||
|
inline uint16_t ablMilliampsMax() { return _gMilliAmpsMax; } // used for compatibility reasons (and enabling virtual global ABL)
|
||||||
|
inline void setMilliampsMax(uint16_t max) { _gMilliAmpsMax = max;}
|
||||||
|
|
||||||
static void on();
|
void useParallelOutput(); // workaround for inaccessible PolyBus
|
||||||
static void off();
|
bool hasParallelOutput(); // workaround for inaccessible PolyBus
|
||||||
|
|
||||||
static void show();
|
//do not call this method from system context (network callback)
|
||||||
static bool canAllShow();
|
void removeAll();
|
||||||
static void setStatusPixel(uint32_t c);
|
int add(const BusConfig &bc);
|
||||||
[[gnu::hot]] static void setPixelColor(unsigned pix, uint32_t c);
|
|
||||||
static void setBrightness(uint8_t b);
|
|
||||||
// for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K
|
|
||||||
// WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT()
|
|
||||||
static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
|
||||||
static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
|
|
||||||
[[gnu::hot]] static uint32_t getPixelColor(unsigned pix);
|
|
||||||
static inline int16_t getSegmentCCT() { return Bus::getCCT(); }
|
|
||||||
|
|
||||||
static Bus* getBus(uint8_t busNr);
|
void on();
|
||||||
|
void off();
|
||||||
|
|
||||||
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
[[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c);
|
||||||
static uint16_t getTotalLength();
|
[[gnu::hot]] uint32_t getPixelColor(unsigned pix);
|
||||||
static inline uint8_t getNumBusses() { return busses.size(); }
|
void show();
|
||||||
static String getLEDTypesJSONString();
|
bool canAllShow();
|
||||||
|
inline void setStatusPixel(uint32_t c) { for (auto &bus : busses) bus->setStatusPixel(c);}
|
||||||
|
inline void setBrightness(uint8_t b) { for (auto &bus : busses) bus->setBrightness(b); }
|
||||||
|
// for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K
|
||||||
|
// WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT()
|
||||||
|
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||||
|
inline int16_t getSegmentCCT() { return Bus::getCCT(); }
|
||||||
|
inline Bus* getBus(size_t busNr) { return busNr < busses.size() ? busses[busNr].get() : nullptr; }
|
||||||
|
inline size_t getNumBusses() { return busses.size(); }
|
||||||
|
|
||||||
static inline ColorOrderMap& getColorOrderMap() { return colorOrderMap; }
|
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
||||||
|
inline uint16_t getTotalLength(bool onlyPhysical = false) {
|
||||||
private:
|
unsigned len = 0;
|
||||||
//static std::vector<std::unique_ptr<Bus>> busses; // we'd need C++ >11
|
for (const auto &bus : busses) if (!(bus->isVirtual() && onlyPhysical)) len += bus->getLength();
|
||||||
static std::vector<Bus*> busses;
|
return len;
|
||||||
static ColorOrderMap colorOrderMap;
|
}
|
||||||
static uint16_t _milliAmpsUsed;
|
String getLEDTypesJSONString();
|
||||||
static uint16_t _milliAmpsMax;
|
ColorOrderMap& getColorOrderMap();
|
||||||
|
|
||||||
#ifdef ESP32_DATA_IDLE_HIGH
|
|
||||||
static void esp32RMTInvertIdle() ;
|
|
||||||
#endif
|
|
||||||
static uint8_t getNumVirtualBusses() {
|
|
||||||
int j = 0;
|
|
||||||
for (const auto &bus : busses) j += bus->isVirtual();
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,11 +20,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
|
|
||||||
//long vid = doc[F("vid")]; // 2010020
|
//long vid = doc[F("vid")]; // 2010020
|
||||||
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||||
JsonObject ethernet = doc[F("eth")];
|
JsonObject ethernet = doc[F("eth")];
|
||||||
CJSON(ethernetType, ethernet["type"]);
|
CJSON(ethernetType, ethernet["type"]);
|
||||||
// NOTE: Ethernet configuration takes priority over other use of pins
|
// NOTE: Ethernet configuration takes priority over other use of pins
|
||||||
WLED::instance().initEthernet();
|
initEthernet();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JsonObject id = doc["id"];
|
JsonObject id = doc["id"];
|
||||||
@ -53,9 +53,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
JsonArray sn = wifi["sn"];
|
JsonArray sn = wifi["sn"];
|
||||||
char ssid[33] = "";
|
char ssid[33] = "";
|
||||||
char pass[65] = "";
|
char pass[65] = "";
|
||||||
|
char bssid[13] = "";
|
||||||
IPAddress nIP = (uint32_t)0U, nGW = (uint32_t)0U, nSN = (uint32_t)0x00FFFFFF; // little endian
|
IPAddress nIP = (uint32_t)0U, nGW = (uint32_t)0U, nSN = (uint32_t)0x00FFFFFF; // little endian
|
||||||
getStringFromJson(ssid, wifi[F("ssid")], 33);
|
getStringFromJson(ssid, wifi[F("ssid")], 33);
|
||||||
getStringFromJson(pass, wifi["psk"], 65); // password is not normally present but if it is, use it
|
getStringFromJson(pass, wifi["psk"], 65); // password is not normally present but if it is, use it
|
||||||
|
getStringFromJson(bssid, wifi[F("bssid")], 13);
|
||||||
for (size_t i = 0; i < 4; i++) {
|
for (size_t i = 0; i < 4; i++) {
|
||||||
CJSON(nIP[i], ip[i]);
|
CJSON(nIP[i], ip[i]);
|
||||||
CJSON(nGW[i], gw[i]);
|
CJSON(nGW[i], gw[i]);
|
||||||
@ -63,6 +65,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
}
|
}
|
||||||
if (strlen(ssid) > 0) strlcpy(multiWiFi[n].clientSSID, ssid, 33); // this will keep old SSID intact if not present in JSON
|
if (strlen(ssid) > 0) strlcpy(multiWiFi[n].clientSSID, ssid, 33); // this will keep old SSID intact if not present in JSON
|
||||||
if (strlen(pass) > 0) strlcpy(multiWiFi[n].clientPass, pass, 65); // this will keep old password intact if not present in JSON
|
if (strlen(pass) > 0) strlcpy(multiWiFi[n].clientPass, pass, 65); // this will keep old password intact if not present in JSON
|
||||||
|
if (strlen(bssid) > 0) fillStr2MAC(multiWiFi[n].bssid, bssid);
|
||||||
multiWiFi[n].staticIP = nIP;
|
multiWiFi[n].staticIP = nIP;
|
||||||
multiWiFi[n].staticGW = nGW;
|
multiWiFi[n].staticGW = nGW;
|
||||||
multiWiFi[n].staticSN = nSN;
|
multiWiFi[n].staticSN = nSN;
|
||||||
@ -167,7 +170,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback
|
if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback
|
||||||
|
|
||||||
for (JsonObject elm : ins) {
|
for (JsonObject elm : ins) {
|
||||||
if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break;
|
if (s >= WLED_MAX_BUSSES) break;
|
||||||
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
||||||
JsonArray pinArr = elm["pin"];
|
JsonArray pinArr = elm["pin"];
|
||||||
if (pinArr.size() == 0) continue;
|
if (pinArr.size() == 0) continue;
|
||||||
@ -196,12 +199,13 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
}
|
}
|
||||||
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
|
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
|
||||||
|
|
||||||
busConfigs.push_back(std::move(BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax)));
|
//busConfigs.push_back(std::move(BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax)));
|
||||||
|
busConfigs.emplace_back(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax);
|
||||||
doInitBusses = true; // finalization done in beginStrip()
|
doInitBusses = true; // finalization done in beginStrip()
|
||||||
s++;
|
if (!Bus::isVirtual(ledType)) s++; // have as many virtual buses as you want
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
|
if (hw_led["rev"] && BusManager::getNumBusses()) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus
|
||||||
|
|
||||||
// read color order map configuration
|
// read color order map configuration
|
||||||
JsonArray hw_com = hw[F("com")];
|
JsonArray hw_com = hw[F("com")];
|
||||||
@ -669,8 +673,8 @@ void deserializeConfigFromFS() {
|
|||||||
UsermodManager::readFromConfig(empty);
|
UsermodManager::readFromConfig(empty);
|
||||||
serializeConfig();
|
serializeConfig();
|
||||||
// init Ethernet (in case default type is set at compile time)
|
// init Ethernet (in case default type is set at compile time)
|
||||||
#ifdef WLED_USE_ETHERNET
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||||
WLED::instance().initEthernet();
|
initEthernet();
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -718,6 +722,9 @@ void serializeConfig() {
|
|||||||
JsonObject wifi = nw_ins.createNestedObject();
|
JsonObject wifi = nw_ins.createNestedObject();
|
||||||
wifi[F("ssid")] = multiWiFi[n].clientSSID;
|
wifi[F("ssid")] = multiWiFi[n].clientSSID;
|
||||||
wifi[F("pskl")] = strlen(multiWiFi[n].clientPass);
|
wifi[F("pskl")] = strlen(multiWiFi[n].clientPass);
|
||||||
|
char bssid[13];
|
||||||
|
fillMAC2Str(bssid, multiWiFi[n].bssid);
|
||||||
|
wifi[F("bssid")] = bssid;
|
||||||
JsonArray wifi_ip = wifi.createNestedArray("ip");
|
JsonArray wifi_ip = wifi.createNestedArray("ip");
|
||||||
JsonArray wifi_gw = wifi.createNestedArray("gw");
|
JsonArray wifi_gw = wifi.createNestedArray("gw");
|
||||||
JsonArray wifi_sn = wifi.createNestedArray("sn");
|
JsonArray wifi_sn = wifi.createNestedArray("sn");
|
||||||
@ -753,7 +760,7 @@ void serializeConfig() {
|
|||||||
wifi[F("txpwr")] = txPower;
|
wifi[F("txpwr")] = txPower;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||||
JsonObject ethernet = root.createNestedObject("eth");
|
JsonObject ethernet = root.createNestedObject("eth");
|
||||||
ethernet["type"] = ethernetType;
|
ethernet["type"] = ethernetType;
|
||||||
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
||||||
@ -818,8 +825,8 @@ void serializeConfig() {
|
|||||||
|
|
||||||
for (size_t s = 0; s < BusManager::getNumBusses(); s++) {
|
for (size_t s = 0; s < BusManager::getNumBusses(); s++) {
|
||||||
DEBUG_PRINTF_P(PSTR("Cfg: Saving bus #%u\n"), s);
|
DEBUG_PRINTF_P(PSTR("Cfg: Saving bus #%u\n"), s);
|
||||||
Bus *bus = BusManager::getBus(s);
|
const Bus *bus = BusManager::getBus(s);
|
||||||
if (!bus || bus->getLength()==0) break;
|
if (!bus || !bus->isOk()) break;
|
||||||
DEBUG_PRINTF_P(PSTR(" (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"),
|
DEBUG_PRINTF_P(PSTR(" (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"),
|
||||||
(int)bus->getStart(), (int)(bus->getStart()+bus->getLength()),
|
(int)bus->getStart(), (int)(bus->getStart()+bus->getLength()),
|
||||||
(int)(bus->getType() & 0x7F),
|
(int)(bus->getType() & 0x7F),
|
||||||
@ -832,28 +839,27 @@ void serializeConfig() {
|
|||||||
);
|
);
|
||||||
JsonObject ins = hw_led_ins.createNestedObject();
|
JsonObject ins = hw_led_ins.createNestedObject();
|
||||||
ins["start"] = bus->getStart();
|
ins["start"] = bus->getStart();
|
||||||
ins["len"] = bus->getLength();
|
ins["len"] = bus->getLength();
|
||||||
JsonArray ins_pin = ins.createNestedArray("pin");
|
JsonArray ins_pin = ins.createNestedArray("pin");
|
||||||
uint8_t pins[5];
|
uint8_t pins[5];
|
||||||
uint8_t nPins = bus->getPins(pins);
|
uint8_t nPins = bus->getPins(pins);
|
||||||
for (int i = 0; i < nPins; i++) ins_pin.add(pins[i]);
|
for (int i = 0; i < nPins; i++) ins_pin.add(pins[i]);
|
||||||
ins[F("order")] = bus->getColorOrder();
|
ins[F("order")] = bus->getColorOrder();
|
||||||
ins["rev"] = bus->isReversed();
|
ins["rev"] = bus->isReversed();
|
||||||
ins[F("skip")] = bus->skippedLeds();
|
ins[F("skip")] = bus->skippedLeds();
|
||||||
ins["type"] = bus->getType() & 0x7F;
|
ins["type"] = bus->getType() & 0x7F;
|
||||||
ins["ref"] = bus->isOffRefreshRequired();
|
ins["ref"] = bus->isOffRefreshRequired();
|
||||||
ins[F("rgbwm")] = bus->getAutoWhiteMode();
|
ins[F("rgbwm")] = bus->getAutoWhiteMode();
|
||||||
ins[F("freq")] = bus->getFrequency();
|
ins[F("freq")] = bus->getFrequency();
|
||||||
ins[F("maxpwr")] = bus->getMaxCurrent();
|
ins[F("maxpwr")] = bus->getMaxCurrent();
|
||||||
ins[F("ledma")] = bus->getLEDCurrent();
|
ins[F("ledma")] = bus->getLEDCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray hw_com = hw.createNestedArray(F("com"));
|
JsonArray hw_com = hw.createNestedArray(F("com"));
|
||||||
const ColorOrderMap& com = BusManager::getColorOrderMap();
|
const ColorOrderMap& com = BusManager::getColorOrderMap();
|
||||||
for (size_t s = 0; s < com.count(); s++) {
|
for (size_t s = 0; s < com.count(); s++) {
|
||||||
const ColorOrderMapEntry *entry = com.get(s);
|
const ColorOrderMapEntry *entry = com.get(s);
|
||||||
if (!entry) break;
|
if (!entry || !entry->len) break;
|
||||||
|
|
||||||
JsonObject co = hw_com.createNestedObject();
|
JsonObject co = hw_com.createNestedObject();
|
||||||
co["start"] = entry->start;
|
co["start"] = entry->start;
|
||||||
co["len"] = entry->len;
|
co["len"] = entry->len;
|
||||||
|
@ -49,31 +49,31 @@
|
|||||||
#define WLED_MAX_DIGITAL_CHANNELS 3
|
#define WLED_MAX_DIGITAL_CHANNELS 3
|
||||||
#define WLED_MAX_ANALOG_CHANNELS 5
|
#define WLED_MAX_ANALOG_CHANNELS 5
|
||||||
#define WLED_MAX_BUSSES 4 // will allow 3 digital & 1 analog RGB
|
#define WLED_MAX_BUSSES 4 // will allow 3 digital & 1 analog RGB
|
||||||
#define WLED_MIN_VIRTUAL_BUSSES 3
|
#define WLED_MIN_VIRTUAL_BUSSES 3 // no longer used for bus creation but used to distinguish S2/S3 in UI
|
||||||
#else
|
#else
|
||||||
#define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX)
|
#define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX)
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM
|
#if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM
|
||||||
#define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white
|
#define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white
|
||||||
#define WLED_MAX_DIGITAL_CHANNELS 2
|
#define WLED_MAX_DIGITAL_CHANNELS 2
|
||||||
//#define WLED_MAX_ANALOG_CHANNELS 6
|
//#define WLED_MAX_ANALOG_CHANNELS 6
|
||||||
#define WLED_MIN_VIRTUAL_BUSSES 4
|
#define WLED_MIN_VIRTUAL_BUSSES 4 // no longer used for bus creation but used to distinguish S2/S3 in UI
|
||||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB
|
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB
|
||||||
// the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though)
|
// the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though)
|
||||||
#define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB
|
#define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog RGB
|
||||||
#define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x1/x8 I2S0
|
#define WLED_MAX_DIGITAL_CHANNELS 5
|
||||||
//#define WLED_MAX_ANALOG_CHANNELS 8
|
//#define WLED_MAX_ANALOG_CHANNELS 8
|
||||||
#define WLED_MIN_VIRTUAL_BUSSES 4
|
#define WLED_MIN_VIRTUAL_BUSSES 4 // no longer used for bus creation but used to distinguish S2/S3 in UI
|
||||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1
|
#elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1
|
||||||
#define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB
|
#define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB
|
||||||
#define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x8 I2S-LCD
|
#define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x8 I2S-LCD
|
||||||
//#define WLED_MAX_ANALOG_CHANNELS 8
|
//#define WLED_MAX_ANALOG_CHANNELS 8
|
||||||
#define WLED_MIN_VIRTUAL_BUSSES 6
|
#define WLED_MIN_VIRTUAL_BUSSES 6 // no longer used for bus creation but used to distinguish S2/S3 in UI
|
||||||
#else
|
#else
|
||||||
// the last digital bus (I2S0) will prevent Audioreactive usermod from functioning
|
// the last digital bus (I2S0) will prevent Audioreactive usermod from functioning
|
||||||
#define WLED_MAX_BUSSES 19 // will allow 16 digital & 3 analog RGB
|
#define WLED_MAX_BUSSES 19 // will allow 16 digital & 3 analog RGB
|
||||||
#define WLED_MAX_DIGITAL_CHANNELS 16 // x1/x8 I2S1 + x8 RMT
|
#define WLED_MAX_DIGITAL_CHANNELS 16 // x1/x8 I2S1 + x8 RMT
|
||||||
//#define WLED_MAX_ANALOG_CHANNELS 16
|
//#define WLED_MAX_ANALOG_CHANNELS 16
|
||||||
#define WLED_MIN_VIRTUAL_BUSSES 6
|
#define WLED_MIN_VIRTUAL_BUSSES 6 // no longer used for bus creation but used to distinguish S2/S3 in UI
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
@ -87,7 +87,7 @@
|
|||||||
#ifndef WLED_MAX_DIGITAL_CHANNELS
|
#ifndef WLED_MAX_DIGITAL_CHANNELS
|
||||||
#error You must also define WLED_MAX_DIGITAL_CHANNELS.
|
#error You must also define WLED_MAX_DIGITAL_CHANNELS.
|
||||||
#endif
|
#endif
|
||||||
#define WLED_MIN_VIRTUAL_BUSSES (5-WLED_MAX_BUSSES)
|
#define WLED_MIN_VIRTUAL_BUSSES 3
|
||||||
#else
|
#else
|
||||||
#if WLED_MAX_BUSSES > 20
|
#if WLED_MAX_BUSSES > 20
|
||||||
#error Maximum number of buses is 20.
|
#error Maximum number of buses is 20.
|
||||||
@ -98,7 +98,11 @@
|
|||||||
#ifndef WLED_MAX_DIGITAL_CHANNELS
|
#ifndef WLED_MAX_DIGITAL_CHANNELS
|
||||||
#error You must also define WLED_MAX_DIGITAL_CHANNELS.
|
#error You must also define WLED_MAX_DIGITAL_CHANNELS.
|
||||||
#endif
|
#endif
|
||||||
#define WLED_MIN_VIRTUAL_BUSSES (20-WLED_MAX_BUSSES)
|
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES 4
|
||||||
|
#else
|
||||||
|
#define WLED_MIN_VIRTUAL_BUSSES 6
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -43,10 +43,10 @@
|
|||||||
if (loc) d.Sf.action = getURL('/settings/leds');
|
if (loc) d.Sf.action = getURL('/settings/leds');
|
||||||
}
|
}
|
||||||
function bLimits(b,v,p,m,l,o=5,d=2,a=6) {
|
function bLimits(b,v,p,m,l,o=5,d=2,a=6) {
|
||||||
oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S): 19 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266
|
oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S): 20 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266
|
||||||
maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 16 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266
|
maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 17 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266
|
||||||
maxA = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266
|
maxA = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266
|
||||||
maxV = v; // maxV - min virtual buses: 4 - ESP32/S3, 3 - S2/C3, 2 - ESP8266
|
maxV = v; // maxV - min virtual buses: 6 - ESP32/S3, 4 - S2/C3, 3 - ESP8266 (only used to distinguish S2/S3)
|
||||||
maxPB = p; // maxPB - max LEDs per bus
|
maxPB = p; // maxPB - max LEDs per bus
|
||||||
maxM = m; // maxM - max LED memory
|
maxM = m; // maxM - max LED memory
|
||||||
maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32)
|
maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32)
|
||||||
@ -360,8 +360,9 @@
|
|||||||
gId("prl").classList.add("hide");
|
gId("prl").classList.add("hide");
|
||||||
} else
|
} else
|
||||||
gId("prl").classList.remove("hide");
|
gId("prl").classList.remove("hide");
|
||||||
|
// S2 supports mono I2S as well as parallel so we need to take that into account; S3 only supports parallel
|
||||||
maxD = (S2 || S3 ? 4 : 8) + (d.Sf["PR"].checked ? 8 : S2); // TODO: use bLimits() : 4/8RMT + (x1/x8 parallel) I2S1
|
maxD = (S2 || S3 ? 4 : 8) + (d.Sf["PR"].checked ? 8 : S2); // TODO: use bLimits() : 4/8RMT + (x1/x8 parallel) I2S1
|
||||||
maxB = oMaxB - (d.Sf["PR"].checked ? 0 : 7 + S3); // S2 (maxV==3) does support single I2S
|
maxB = oMaxB - (d.Sf["PR"].checked ? 0 : 7 + S3); // S2 (maxV==4) does support mono I2S
|
||||||
}
|
}
|
||||||
// distribute ABL current if not using PPL
|
// distribute ABL current if not using PPL
|
||||||
enPPL(sDI);
|
enPPL(sDI);
|
||||||
@ -422,7 +423,7 @@
|
|||||||
if (isVir(t)) virtB++;
|
if (isVir(t)) virtB++;
|
||||||
});
|
});
|
||||||
|
|
||||||
if ((n==1 && i>=maxB+maxV) || (n==-1 && i==0)) return;
|
if ((n==1 && i>=36) || (n==-1 && i==0)) return; // used to be i>=maxB+maxV when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
var s = chrID(i);
|
var s = chrID(i);
|
||||||
|
|
||||||
if (n==1) {
|
if (n==1) {
|
||||||
@ -496,7 +497,7 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
|
|||||||
o[i].querySelector("[name^=LT]").disabled = false;
|
o[i].querySelector("[name^=LT]").disabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
gId("+").style.display = (i<maxB+maxV-1) ? "inline":"none";
|
gId("+").style.display = (i<35) ? "inline":"none"; // was maxB+maxV-1 when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
gId("-").style.display = (i>0) ? "inline":"none";
|
gId("-").style.display = (i>0) ? "inline":"none";
|
||||||
|
|
||||||
if (!init) {
|
if (!init) {
|
||||||
@ -617,22 +618,32 @@ Swap: <select id="xw${s}" name="XW${s}">
|
|||||||
|
|
||||||
function receivedText(e) {
|
function receivedText(e) {
|
||||||
let lines = e.target.result;
|
let lines = e.target.result;
|
||||||
var c = JSON.parse(lines);
|
let c = JSON.parse(lines);
|
||||||
if (c.hw) {
|
if (c.hw) {
|
||||||
if (c.hw.led) {
|
if (c.hw.led) {
|
||||||
for (var i=0; i<oMaxB+maxV; i++) addLEDs(-1);
|
// remove all existing outputs
|
||||||
var l = c.hw.led;
|
for (const i=0; i<36; i++) addLEDs(-1); // was i<maxb+maxV when number of virtual buses was limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
let l = c.hw.led;
|
||||||
l.ins.forEach((v,i,a)=>{
|
l.ins.forEach((v,i,a)=>{
|
||||||
addLEDs(1);
|
addLEDs(1);
|
||||||
for (var j=0; j<v.pin.length; j++) d.getElementsByName(`L${j}${i}`)[0].value = v.pin[j];
|
for (var j=0; j<v.pin.length; j++) d.getElementsByName(`L${j}${i}`)[0].value = v.pin[j];
|
||||||
d.getElementsByName("LT"+i)[0].value = v.type;
|
d.getElementsByName("LT"+i)[0].value = v.type;
|
||||||
d.getElementsByName("LS"+i)[0].value = v.start;
|
d.getElementsByName("LS"+i)[0].value = v.start;
|
||||||
d.getElementsByName("LC"+i)[0].value = v.len;
|
d.getElementsByName("LC"+i)[0].value = v.len;
|
||||||
d.getElementsByName("CO"+i)[0].value = v.order;
|
d.getElementsByName("CO"+i)[0].value = v.order & 0x0F;
|
||||||
d.getElementsByName("SL"+i)[0].value = v.skip;
|
d.getElementsByName("SL"+i)[0].value = v.skip;
|
||||||
d.getElementsByName("RF"+i)[0].checked = v.ref;
|
d.getElementsByName("RF"+i)[0].checked = v.ref;
|
||||||
d.getElementsByName("CV"+i)[0].checked = v.rev;
|
d.getElementsByName("CV"+i)[0].checked = v.rev;
|
||||||
|
d.getElementsByName("AW"+i)[0].value = v.rgbwm;
|
||||||
|
d.getElementsByName("WO"+i)[0].value = (v.order>>4) & 0x0F;
|
||||||
|
d.getElementsByName("SP"+i)[0].value = v.freq;
|
||||||
|
d.getElementsByName("LA"+i)[0].value = v.ledma;
|
||||||
|
d.getElementsByName("MA"+i)[0].value = v.maxpwr;
|
||||||
});
|
});
|
||||||
|
d.getElementsByName("PR")[0].checked = l.prl | 0;
|
||||||
|
d.getElementsByName("LD")[0].checked = l.ld;
|
||||||
|
d.getElementsByName("MA")[0].value = l.maxpwr;
|
||||||
|
d.getElementsByName("ABL")[0].checked = l.maxpwr > 0;
|
||||||
}
|
}
|
||||||
if(c.hw.com) {
|
if(c.hw.com) {
|
||||||
resetCOM();
|
resetCOM();
|
||||||
@ -640,22 +651,28 @@ Swap: <select id="xw${s}" name="XW${s}">
|
|||||||
addCOM(e.start, e.len, e.order);
|
addCOM(e.start, e.len, e.order);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (c.hw.btn) {
|
let b = c.hw.btn;
|
||||||
var b = c.hw.btn;
|
if (b) {
|
||||||
if (Array.isArray(b.ins)) gId("btns").innerHTML = "";
|
if (Array.isArray(b.ins)) gId("btns").innerHTML = "";
|
||||||
b.ins.forEach((v,i,a)=>{
|
b.ins.forEach((v,i,a)=>{
|
||||||
addBtn(i,v.pin[0],v.type);
|
addBtn(i,v.pin[0],v.type);
|
||||||
});
|
});
|
||||||
d.getElementsByName("TT")[0].value = b.tt;
|
d.getElementsByName("TT")[0].value = b.tt;
|
||||||
}
|
}
|
||||||
if (c.hw.ir) {
|
let ir = c.hw.ir;
|
||||||
d.getElementsByName("IR")[0].value = c.hw.ir.pin;
|
if (ir) {
|
||||||
d.getElementsByName("IT")[0].value = c.hw.ir.type;
|
d.getElementsByName("IR")[0].value = ir.pin;
|
||||||
|
d.getElementsByName("IT")[0].value = ir.type;
|
||||||
}
|
}
|
||||||
if (c.hw.relay) {
|
let rl = c.hw.relay;
|
||||||
d.getElementsByName("RL")[0].value = c.hw.relay.pin;
|
if (rl) {
|
||||||
d.getElementsByName("RM")[0].checked = c.hw.relay.rev;
|
d.getElementsByName("RL")[0].value = rl.pin;
|
||||||
d.getElementsByName("RO")[0].checked = c.hw.relay.odrain;
|
d.getElementsByName("RM")[0].checked = rl.rev;
|
||||||
|
d.getElementsByName("RO")[0].checked = rl.odrain;
|
||||||
|
}
|
||||||
|
let li = c.light;
|
||||||
|
if (li) {
|
||||||
|
d.getElementsByName("MS")[0].checked = li.aseg;
|
||||||
}
|
}
|
||||||
UI();
|
UI();
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
scanLoops = 0;
|
scanLoops = 0;
|
||||||
|
|
||||||
if (networks.length > 0) {
|
if (networks.length > 0) {
|
||||||
let cs = d.querySelectorAll("#wifi_entries input[type=text]");
|
let cs = d.querySelectorAll("#wifi_entries input[type=text][name^=CS]");
|
||||||
for (let input of (cs||[])) {
|
for (let input of (cs||[])) {
|
||||||
let found = false;
|
let found = false;
|
||||||
let select = cE("select");
|
let select = cE("select");
|
||||||
@ -64,7 +64,7 @@
|
|||||||
const option = cE("option");
|
const option = cE("option");
|
||||||
|
|
||||||
option.setAttribute("value", networks[i].ssid);
|
option.setAttribute("value", networks[i].ssid);
|
||||||
option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm)`;
|
option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm)`; // [${networks[i].bssid.replaceAll(':','')}]
|
||||||
|
|
||||||
if (networks[i].ssid === input.value) {
|
if (networks[i].ssid === input.value) {
|
||||||
option.setAttribute("selected", "selected");
|
option.setAttribute("selected", "selected");
|
||||||
@ -109,12 +109,13 @@
|
|||||||
gId("wifi_add").style.display = (i<maxNetworks) ? "inline":"none";
|
gId("wifi_add").style.display = (i<maxNetworks) ? "inline":"none";
|
||||||
gId("wifi_rem").style.display = (i>1) ? "inline":"none";
|
gId("wifi_rem").style.display = (i>1) ? "inline":"none";
|
||||||
}
|
}
|
||||||
function addWiFi(ssid="",pass="",ip=0,gw=0,sn=0x00ffffff) { // little endian
|
function addWiFi(ssid="",pass="",bssid="",ip=0,gw=0,sn=0x00ffffff) { // little endian
|
||||||
var i = gId("wifi_entries").childNodes.length;
|
var i = gId("wifi_entries").childNodes.length;
|
||||||
if (i >= maxNetworks) return;
|
if (i >= maxNetworks) return;
|
||||||
var b = `<div id="net${i}"><hr class="sml">
|
var b = `<div id="net${i}"><hr class="sml">
|
||||||
Network name (SSID${i==0?", empty to not connect":""}):<br><input type="text" id="CS${i}" name="CS${i}" maxlength="32" value="${ssid}" ${i>0?"required":""}><br>
|
Network name (SSID${i==0?", empty to not connect":""}):<br><input type="text" id="CS${i}" name="CS${i}" maxlength="32" value="${ssid}" ${i>0?"required":""}><br>
|
||||||
Network password:<br><input type="password" name="PW${i}" maxlength="64" value="${pass}"><br>
|
Network password:<br><input type="password" name="PW${i}" maxlength="64" value="${pass}"><br>
|
||||||
|
BSSID (optional):<br><input type="text" id="BS${i}" name="BS${i}" maxlength="12" value="${bssid}"><br>
|
||||||
Static IP (leave at 0.0.0.0 for DHCP)${i==0?"<br>Also used by Ethernet":""}:<br>
|
Static IP (leave at 0.0.0.0 for DHCP)${i==0?"<br>Also used by Ethernet":""}:<br>
|
||||||
<input name="IP${i}0" type="number" class="s" min="0" max="255" value="${ip&0xFF}" required>.<input name="IP${i}1" type="number" class="s" min="0" max="255" value="${(ip>>8)&0xFF}" required>.<input name="IP${i}2" type="number" class="s" min="0" max="255" value="${(ip>>16)&0xFF}" required>.<input name="IP${i}3" type="number" class="s" min="0" max="255" value="${(ip>>24)&0xFF}" required><br>
|
<input name="IP${i}0" type="number" class="s" min="0" max="255" value="${ip&0xFF}" required>.<input name="IP${i}1" type="number" class="s" min="0" max="255" value="${(ip>>8)&0xFF}" required>.<input name="IP${i}2" type="number" class="s" min="0" max="255" value="${(ip>>16)&0xFF}" required>.<input name="IP${i}3" type="number" class="s" min="0" max="255" value="${(ip>>24)&0xFF}" required><br>
|
||||||
Static gateway:<br>
|
Static gateway:<br>
|
||||||
|
@ -53,6 +53,7 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
|||||||
typedef struct WiFiConfig {
|
typedef struct WiFiConfig {
|
||||||
char clientSSID[33];
|
char clientSSID[33];
|
||||||
char clientPass[65];
|
char clientPass[65];
|
||||||
|
uint8_t bssid[6];
|
||||||
IPAddress staticIP;
|
IPAddress staticIP;
|
||||||
IPAddress staticGW;
|
IPAddress staticGW;
|
||||||
IPAddress staticSN;
|
IPAddress staticSN;
|
||||||
@ -63,6 +64,7 @@ typedef struct WiFiConfig {
|
|||||||
{
|
{
|
||||||
strncpy(clientSSID, ssid, 32); clientSSID[32] = 0;
|
strncpy(clientSSID, ssid, 32); clientSSID[32] = 0;
|
||||||
strncpy(clientPass, pass, 64); clientPass[64] = 0;
|
strncpy(clientPass, pass, 64); clientPass[64] = 0;
|
||||||
|
memset(bssid, 0, sizeof(bssid));
|
||||||
}
|
}
|
||||||
} wifi_config;
|
} wifi_config;
|
||||||
|
|
||||||
@ -203,14 +205,14 @@ void sendArtnetPollReply(ArtPollReply* reply, IPAddress ipAddress, uint16_t port
|
|||||||
bool handleFileRead(AsyncWebServerRequest*, String path);
|
bool handleFileRead(AsyncWebServerRequest*, String path);
|
||||||
bool writeObjectToFileUsingId(const char* file, uint16_t id, const JsonDocument* content);
|
bool writeObjectToFileUsingId(const char* file, uint16_t id, const JsonDocument* content);
|
||||||
bool writeObjectToFile(const char* file, const char* key, const JsonDocument* content);
|
bool writeObjectToFile(const char* file, const char* key, const JsonDocument* content);
|
||||||
bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest);
|
bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest, const JsonDocument* filter = nullptr);
|
||||||
bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest);
|
bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest, const JsonDocument* filter = nullptr);
|
||||||
void updateFSInfo();
|
void updateFSInfo();
|
||||||
void closeFile();
|
void closeFile();
|
||||||
inline bool writeObjectToFileUsingId(const String &file, uint16_t id, const JsonDocument* content) { return writeObjectToFileUsingId(file.c_str(), id, content); };
|
inline bool writeObjectToFileUsingId(const String &file, uint16_t id, const JsonDocument* content) { return writeObjectToFileUsingId(file.c_str(), id, content); };
|
||||||
inline bool writeObjectToFile(const String &file, const char* key, const JsonDocument* content) { return writeObjectToFile(file.c_str(), key, content); };
|
inline bool writeObjectToFile(const String &file, const char* key, const JsonDocument* content) { return writeObjectToFile(file.c_str(), key, content); };
|
||||||
inline bool readObjectFromFileUsingId(const String &file, uint16_t id, JsonDocument* dest) { return readObjectFromFileUsingId(file.c_str(), id, dest); };
|
inline bool readObjectFromFileUsingId(const String &file, uint16_t id, JsonDocument* dest, const JsonDocument* filter = nullptr) { return readObjectFromFileUsingId(file.c_str(), id, dest); };
|
||||||
inline bool readObjectFromFile(const String &file, const char* key, JsonDocument* dest) { return readObjectFromFile(file.c_str(), key, dest); };
|
inline bool readObjectFromFile(const String &file, const char* key, JsonDocument* dest, const JsonDocument* filter = nullptr) { return readObjectFromFile(file.c_str(), key, dest); };
|
||||||
|
|
||||||
//hue.cpp
|
//hue.cpp
|
||||||
void handleHue();
|
void handleHue();
|
||||||
@ -361,7 +363,12 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//network.cpp
|
//network.cpp
|
||||||
int getSignalQuality(int rssi);
|
bool initEthernet(); // result is informational
|
||||||
|
int getSignalQuality(int rssi);
|
||||||
|
void fillMAC2Str(char *str, const uint8_t *mac);
|
||||||
|
void fillStr2MAC(uint8_t *mac, const char *str);
|
||||||
|
int findWiFi(bool doScan = false);
|
||||||
|
bool isWiFiConfigured();
|
||||||
void WiFiEvent(WiFiEvent_t event);
|
void WiFiEvent(WiFiEvent_t event);
|
||||||
|
|
||||||
//um_manager.cpp
|
//um_manager.cpp
|
||||||
@ -482,6 +489,7 @@ void userLoop();
|
|||||||
#include "soc/wdev_reg.h"
|
#include "soc/wdev_reg.h"
|
||||||
#define HW_RND_REGISTER REG_READ(WDEV_RND_REG)
|
#define HW_RND_REGISTER REG_READ(WDEV_RND_REG)
|
||||||
#endif
|
#endif
|
||||||
|
#define hex2int(a) (((a)>='0' && (a)<='9') ? (a)-'0' : ((a)>='A' && (a)<='F') ? (a)-'A'+10 : ((a)>='a' && (a)<='f') ? (a)-'a'+10 : 0)
|
||||||
[[gnu::pure]] int getNumVal(const String* req, uint16_t pos);
|
[[gnu::pure]] int getNumVal(const String* req, uint16_t pos);
|
||||||
void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255);
|
void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255);
|
||||||
bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form)
|
bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form)
|
||||||
|
@ -325,15 +325,15 @@ bool writeObjectToFile(const char* file, const char* key, const JsonDocument* co
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest)
|
bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest, const JsonDocument* filter)
|
||||||
{
|
{
|
||||||
char objKey[10];
|
char objKey[10];
|
||||||
sprintf(objKey, "\"%d\":", id);
|
sprintf(objKey, "\"%d\":", id);
|
||||||
return readObjectFromFile(file, objKey, dest);
|
return readObjectFromFile(file, objKey, dest, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if the key is a nullptr, deserialize entire object
|
//if the key is a nullptr, deserialize entire object
|
||||||
bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest)
|
bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest, const JsonDocument* filter)
|
||||||
{
|
{
|
||||||
if (doCloseFile) closeFile();
|
if (doCloseFile) closeFile();
|
||||||
#ifdef WLED_DEBUG_FS
|
#ifdef WLED_DEBUG_FS
|
||||||
@ -352,7 +352,8 @@ bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
deserializeJson(*dest, f);
|
if (filter) deserializeJson(*dest, f, DeserializationOption::Filter(*filter));
|
||||||
|
else deserializeJson(*dest, f);
|
||||||
|
|
||||||
f.close();
|
f.close();
|
||||||
DEBUGFS_PRINTF("Read, took %d ms\n", millis() - s);
|
DEBUGFS_PRINTF("Read, took %d ms\n", millis() - s);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "wled_ethernet.h"
|
#include "wled_ethernet.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||||
// The following six pins are neither configurable nor
|
// The following six pins are neither configurable nor
|
||||||
// can they be re-assigned through IOMUX / GPIO matrix.
|
// can they be re-assigned through IOMUX / GPIO matrix.
|
||||||
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
|
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
|
||||||
@ -146,6 +146,101 @@ const ethernet_settings ethernetBoards[] = {
|
|||||||
ETH_CLOCK_GPIO0_OUT // eth_clk_mode
|
ETH_CLOCK_GPIO0_OUT // eth_clk_mode
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool initEthernet()
|
||||||
|
{
|
||||||
|
static bool successfullyConfiguredEthernet = false;
|
||||||
|
|
||||||
|
if (successfullyConfiguredEthernet) {
|
||||||
|
// DEBUG_PRINTLN(F("initE: ETH already successfully configured, ignoring"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ethernetType == WLED_ETH_NONE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ethernetType >= WLED_NUM_ETH_TYPES) {
|
||||||
|
DEBUG_PRINTF_P(PSTR("initE: Ignoring attempt for invalid ethernetType (%d)\n"), ethernetType);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_PRINTF_P(PSTR("initE: Attempting ETH config: %d\n"), ethernetType);
|
||||||
|
|
||||||
|
// Ethernet initialization should only succeed once -- else reboot required
|
||||||
|
ethernet_settings es = ethernetBoards[ethernetType];
|
||||||
|
managed_pin_type pinsToAllocate[10] = {
|
||||||
|
// first six pins are non-configurable
|
||||||
|
esp32_nonconfigurable_ethernet_pins[0],
|
||||||
|
esp32_nonconfigurable_ethernet_pins[1],
|
||||||
|
esp32_nonconfigurable_ethernet_pins[2],
|
||||||
|
esp32_nonconfigurable_ethernet_pins[3],
|
||||||
|
esp32_nonconfigurable_ethernet_pins[4],
|
||||||
|
esp32_nonconfigurable_ethernet_pins[5],
|
||||||
|
{ (int8_t)es.eth_mdc, true }, // [6] = MDC is output and mandatory
|
||||||
|
{ (int8_t)es.eth_mdio, true }, // [7] = MDIO is bidirectional and mandatory
|
||||||
|
{ (int8_t)es.eth_power, true }, // [8] = optional pin, not all boards use
|
||||||
|
{ ((int8_t)0xFE), false }, // [9] = replaced with eth_clk_mode, mandatory
|
||||||
|
};
|
||||||
|
// update the clock pin....
|
||||||
|
if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) {
|
||||||
|
pinsToAllocate[9].pin = 0;
|
||||||
|
pinsToAllocate[9].isOutput = false;
|
||||||
|
} else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) {
|
||||||
|
pinsToAllocate[9].pin = 0;
|
||||||
|
pinsToAllocate[9].isOutput = true;
|
||||||
|
} else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) {
|
||||||
|
pinsToAllocate[9].pin = 16;
|
||||||
|
pinsToAllocate[9].isOutput = true;
|
||||||
|
} else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) {
|
||||||
|
pinsToAllocate[9].pin = 17;
|
||||||
|
pinsToAllocate[9].isOutput = true;
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINTF_P(PSTR("initE: Failing due to invalid eth_clk_mode (%d)\n"), es.eth_clk_mode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PinManager::allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) {
|
||||||
|
DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
For LAN8720 the most correct way is to perform clean reset each time before init
|
||||||
|
applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59)
|
||||||
|
ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in
|
||||||
|
/components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280)
|
||||||
|
but ESP_IDF < V4 does not. Lets do it:
|
||||||
|
[not always needed, might be relevant in some EMI situations at startup and for hot resets]
|
||||||
|
*/
|
||||||
|
#if ESP_IDF_VERSION_MAJOR==3
|
||||||
|
if(es.eth_power>0 && es.eth_type==ETH_PHY_LAN8720) {
|
||||||
|
pinMode(es.eth_power, OUTPUT);
|
||||||
|
digitalWrite(es.eth_power, 0);
|
||||||
|
delayMicroseconds(150);
|
||||||
|
digitalWrite(es.eth_power, 1);
|
||||||
|
delayMicroseconds(10);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!ETH.begin(
|
||||||
|
(uint8_t) es.eth_address,
|
||||||
|
(int) es.eth_power,
|
||||||
|
(int) es.eth_mdc,
|
||||||
|
(int) es.eth_mdio,
|
||||||
|
(eth_phy_type_t) es.eth_type,
|
||||||
|
(eth_clock_mode_t) es.eth_clk_mode
|
||||||
|
)) {
|
||||||
|
DEBUG_PRINTLN(F("initC: ETH.begin() failed"));
|
||||||
|
// de-allocate the allocated pins
|
||||||
|
for (managed_pin_type mpt : pinsToAllocate) {
|
||||||
|
PinManager::deallocatePin(mpt.pin, PinOwner::Ethernet);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
successfullyConfiguredEthernet = true;
|
||||||
|
DEBUG_PRINTLN(F("initC: *** Ethernet successfully configured! ***"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -170,19 +265,136 @@ int getSignalQuality(int rssi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fillMAC2Str(char *str, const uint8_t *mac) {
|
||||||
|
sprintf_P(str, PSTR("%02x%02x%02x%02x%02x%02x"), MAC2STR(mac));
|
||||||
|
byte nul = 0;
|
||||||
|
for (int i = 0; i < 6; i++) nul |= *mac++; // do we have 0
|
||||||
|
if (!nul) str[0] = '\0'; // empty string
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillStr2MAC(uint8_t *mac, const char *str) {
|
||||||
|
for (int i = 0; i < 6; i++) *mac++ = 0; // clear
|
||||||
|
if (!str) return; // null string
|
||||||
|
uint64_t MAC = strtoull(str, nullptr, 16);
|
||||||
|
for (int i = 0; i < 6; i++) { *--mac = MAC & 0xFF; MAC >>= 8; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// performs asynchronous scan for available networks (which may take couple of seconds to finish)
|
||||||
|
// returns configured WiFi ID with the strongest signal (or default if no configured networks available)
|
||||||
|
int findWiFi(bool doScan) {
|
||||||
|
if (multiWiFi.size() <= 1) {
|
||||||
|
DEBUG_PRINTF_P(PSTR("WiFi: Defaulf SSID (%s) used.\n"), multiWiFi[0].clientSSID);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = WiFi.scanComplete(); // complete scan may take as much as several seconds (usually <6s with not very crowded air)
|
||||||
|
|
||||||
|
if (doScan || status == WIFI_SCAN_FAILED) {
|
||||||
|
DEBUG_PRINTF_P(PSTR("WiFi: Scan started. @ %lus\n"), millis()/1000);
|
||||||
|
WiFi.scanNetworks(true); // start scanning in asynchronous mode (will delete old scan)
|
||||||
|
} else if (status >= 0) { // status contains number of found networks (including duplicate SSIDs with different BSSID)
|
||||||
|
DEBUG_PRINTF_P(PSTR("WiFi: Found %d SSIDs. @ %lus\n"), status, millis()/1000);
|
||||||
|
int rssi = -9999;
|
||||||
|
int selected = selectedWiFi;
|
||||||
|
for (int o = 0; o < status; o++) {
|
||||||
|
DEBUG_PRINTF_P(PSTR(" SSID: %s (BSSID: %s) RSSI: %ddB\n"), WiFi.SSID(o).c_str(), WiFi.BSSIDstr(o).c_str(), WiFi.RSSI(o));
|
||||||
|
for (unsigned n = 0; n < multiWiFi.size(); n++)
|
||||||
|
if (!strcmp(WiFi.SSID(o).c_str(), multiWiFi[n].clientSSID)) {
|
||||||
|
bool foundBSSID = memcmp(multiWiFi[n].bssid, WiFi.BSSID(o), 6) == 0;
|
||||||
|
// find the WiFi with the strongest signal (but keep priority of entry if signal difference is not big)
|
||||||
|
if (foundBSSID || (n < selected && WiFi.RSSI(o) > rssi-10) || WiFi.RSSI(o) > rssi) {
|
||||||
|
rssi = foundBSSID ? 0 : WiFi.RSSI(o); // RSSI is only ever negative
|
||||||
|
selected = n;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DEBUG_PRINTF_P(PSTR("WiFi: Selected SSID: %s RSSI: %ddB\n"), multiWiFi[selected].clientSSID, rssi);
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
//DEBUG_PRINT(F("WiFi scan running."));
|
||||||
|
return status; // scan is still running or there was an error
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool isWiFiConfigured() {
|
||||||
|
return multiWiFi.size() > 1 || (strlen(multiWiFi[0].clientSSID) >= 1 && strcmp_P(multiWiFi[0].clientSSID, PSTR(DEFAULT_CLIENT_SSID)) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(ESP8266)
|
||||||
|
#define ARDUINO_EVENT_WIFI_AP_STADISCONNECTED WIFI_EVENT_SOFTAPMODE_STADISCONNECTED
|
||||||
|
#define ARDUINO_EVENT_WIFI_AP_STACONNECTED WIFI_EVENT_SOFTAPMODE_STACONNECTED
|
||||||
|
#define ARDUINO_EVENT_WIFI_STA_GOT_IP WIFI_EVENT_STAMODE_GOT_IP
|
||||||
|
#define ARDUINO_EVENT_WIFI_STA_CONNECTED WIFI_EVENT_STAMODE_CONNECTED
|
||||||
|
#define ARDUINO_EVENT_WIFI_STA_DISCONNECTED WIFI_EVENT_STAMODE_DISCONNECTED
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP32) && !defined(ESP_ARDUINO_VERSION_MAJOR) //ESP_IDF_VERSION_MAJOR==3
|
||||||
|
// not strictly IDF v3 but Arduino core related
|
||||||
|
#define ARDUINO_EVENT_WIFI_AP_STADISCONNECTED SYSTEM_EVENT_AP_STADISCONNECTED
|
||||||
|
#define ARDUINO_EVENT_WIFI_AP_STACONNECTED SYSTEM_EVENT_AP_STACONNECTED
|
||||||
|
#define ARDUINO_EVENT_WIFI_STA_GOT_IP SYSTEM_EVENT_STA_GOT_IP
|
||||||
|
#define ARDUINO_EVENT_WIFI_STA_CONNECTED SYSTEM_EVENT_STA_CONNECTED
|
||||||
|
#define ARDUINO_EVENT_WIFI_STA_DISCONNECTED SYSTEM_EVENT_STA_DISCONNECTED
|
||||||
|
#define ARDUINO_EVENT_WIFI_AP_START SYSTEM_EVENT_AP_START
|
||||||
|
#define ARDUINO_EVENT_WIFI_AP_STOP SYSTEM_EVENT_AP_STOP
|
||||||
|
#define ARDUINO_EVENT_WIFI_SCAN_DONE SYSTEM_EVENT_SCAN_DONE
|
||||||
|
#define ARDUINO_EVENT_ETH_START SYSTEM_EVENT_ETH_START
|
||||||
|
#define ARDUINO_EVENT_ETH_CONNECTED SYSTEM_EVENT_ETH_CONNECTED
|
||||||
|
#define ARDUINO_EVENT_ETH_DISCONNECTED SYSTEM_EVENT_ETH_DISCONNECTED
|
||||||
|
#endif
|
||||||
|
|
||||||
//handle Ethernet connection event
|
//handle Ethernet connection event
|
||||||
void WiFiEvent(WiFiEvent_t event)
|
void WiFiEvent(WiFiEvent_t event)
|
||||||
{
|
{
|
||||||
switch (event) {
|
switch (event) {
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:
|
||||||
case SYSTEM_EVENT_ETH_START:
|
// AP client disconnected
|
||||||
DEBUG_PRINTLN(F("ETH Started"));
|
if (--apClients == 0 && isWiFiConfigured()) forceReconnect = true; // no clients reconnect WiFi if awailable
|
||||||
|
DEBUG_PRINTF_P(PSTR("WiFi-E: AP Client Disconnected (%d) @ %lus.\n"), (int)apClients, millis()/1000);
|
||||||
break;
|
break;
|
||||||
case SYSTEM_EVENT_ETH_CONNECTED:
|
case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
|
||||||
|
// AP client connected
|
||||||
|
apClients++;
|
||||||
|
DEBUG_PRINTF_P(PSTR("WiFi-E: AP Client Connected (%d) @ %lus.\n"), (int)apClients, millis()/1000);
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||||
|
DEBUG_PRINT(F("WiFi-E: IP address: ")); DEBUG_PRINTLN(Network.localIP());
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||||
|
// followed by IDLE and SCAN_DONE
|
||||||
|
DEBUG_PRINTF_P(PSTR("WiFi-E: Connected! @ %lus\n"), millis()/1000);
|
||||||
|
wasConnected = true;
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||||
|
if (wasConnected && interfacesInited) {
|
||||||
|
DEBUG_PRINTF_P(PSTR("WiFi-E: Disconnected! @ %lus\n"), millis()/1000);
|
||||||
|
if (interfacesInited && multiWiFi.size() > 1 && WiFi.scanComplete() >= 0) {
|
||||||
|
findWiFi(true); // reinit WiFi scan
|
||||||
|
forceReconnect = true;
|
||||||
|
}
|
||||||
|
interfacesInited = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
case ARDUINO_EVENT_WIFI_SCAN_DONE:
|
||||||
|
// also triggered when connected to selected SSID
|
||||||
|
DEBUG_PRINTLN(F("WiFi-E: SSID scan completed."));
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_WIFI_AP_START:
|
||||||
|
DEBUG_PRINTLN(F("WiFi-E: AP Started"));
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_WIFI_AP_STOP:
|
||||||
|
DEBUG_PRINTLN(F("WiFi-E: AP Stopped"));
|
||||||
|
break;
|
||||||
|
#if defined(WLED_USE_ETHERNET)
|
||||||
|
case ARDUINO_EVENT_ETH_START:
|
||||||
|
DEBUG_PRINTLN(F("ETH-E: Started"));
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||||
{
|
{
|
||||||
DEBUG_PRINTLN(F("ETH Connected"));
|
DEBUG_PRINTLN(F("ETH-E: Connected"));
|
||||||
if (!apActive) {
|
if (!apActive) {
|
||||||
WiFi.disconnect(true);
|
WiFi.disconnect(true); // disable WiFi entirely
|
||||||
}
|
}
|
||||||
if (multiWiFi[0].staticIP != (uint32_t)0x00000000 && multiWiFi[0].staticGW != (uint32_t)0x00000000) {
|
if (multiWiFi[0].staticIP != (uint32_t)0x00000000 && multiWiFi[0].staticGW != (uint32_t)0x00000000) {
|
||||||
ETH.config(multiWiFi[0].staticIP, multiWiFi[0].staticGW, multiWiFi[0].staticSN, dnsAddress);
|
ETH.config(multiWiFi[0].staticIP, multiWiFi[0].staticGW, multiWiFi[0].staticSN, dnsAddress);
|
||||||
@ -196,18 +408,20 @@ void WiFiEvent(WiFiEvent_t event)
|
|||||||
showWelcomePage = false;
|
showWelcomePage = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||||
DEBUG_PRINTLN(F("ETH Disconnected"));
|
DEBUG_PRINTLN(F("ETH-E: Disconnected"));
|
||||||
// This doesn't really affect ethernet per se,
|
// This doesn't really affect ethernet per se,
|
||||||
// as it's only configured once. Rather, it
|
// as it's only configured once. Rather, it
|
||||||
// may be necessary to reconnect the WiFi when
|
// may be necessary to reconnect the WiFi when
|
||||||
// ethernet disconnects, as a way to provide
|
// ethernet disconnects, as a way to provide
|
||||||
// alternative access to the device.
|
// alternative access to the device.
|
||||||
|
if (interfacesInited && WiFi.scanComplete() >= 0) findWiFi(true); // reinit WiFi scan
|
||||||
forceReconnect = true;
|
forceReconnect = true;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
DEBUG_PRINTF_P(PSTR("Network event: %d\n"), (int)event);
|
DEBUG_PRINTF_P(PSTR("WiFi-E: Event %d\n"), (int)event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
for (size_t n = 0; n < WLED_MAX_WIFI_COUNT; n++) {
|
for (size_t n = 0; n < WLED_MAX_WIFI_COUNT; n++) {
|
||||||
char cs[4] = "CS"; cs[2] = 48+n; cs[3] = 0; //client SSID
|
char cs[4] = "CS"; cs[2] = 48+n; cs[3] = 0; //client SSID
|
||||||
char pw[4] = "PW"; pw[2] = 48+n; pw[3] = 0; //client password
|
char pw[4] = "PW"; pw[2] = 48+n; pw[3] = 0; //client password
|
||||||
|
char bs[4] = "BS"; bs[2] = 48+n; bs[3] = 0; //BSSID
|
||||||
char ip[5] = "IP"; ip[2] = 48+n; ip[4] = 0; //IP address
|
char ip[5] = "IP"; ip[2] = 48+n; ip[4] = 0; //IP address
|
||||||
char gw[5] = "GW"; gw[2] = 48+n; gw[4] = 0; //GW address
|
char gw[5] = "GW"; gw[2] = 48+n; gw[4] = 0; //GW address
|
||||||
char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask
|
char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask
|
||||||
@ -39,6 +40,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
strlcpy(multiWiFi[n].clientPass, request->arg(pw).c_str(), 65);
|
strlcpy(multiWiFi[n].clientPass, request->arg(pw).c_str(), 65);
|
||||||
forceReconnect = true;
|
forceReconnect = true;
|
||||||
}
|
}
|
||||||
|
fillStr2MAC(multiWiFi[n].bssid, request->arg(bs).c_str());
|
||||||
for (size_t i = 0; i < 4; i++) {
|
for (size_t i = 0; i < 4; i++) {
|
||||||
ip[3] = 48+i;
|
ip[3] = 48+i;
|
||||||
gw[3] = 48+i;
|
gw[3] = 48+i;
|
||||||
@ -93,9 +95,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
strlwr(linked_remote); //Normalize MAC format to lowercase
|
strlwr(linked_remote); //Normalize MAC format to lowercase
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||||
ethernetType = request->arg(F("ETH")).toInt();
|
ethernetType = request->arg(F("ETH")).toInt();
|
||||||
WLED::instance().initEthernet();
|
initEthernet();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +145,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool busesChanged = false;
|
bool busesChanged = false;
|
||||||
for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) {
|
for (int s = 0; s < 36; s++) { // theoretical limit is 36 : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
int offset = s < 10 ? '0' : 'A';
|
int offset = s < 10 ? '0' : 'A';
|
||||||
char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin
|
||||||
char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length
|
char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length
|
||||||
@ -159,7 +161,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
char la[4] = "LA"; la[2] = offset+s; la[3] = 0; //LED mA
|
char la[4] = "LA"; la[2] = offset+s; la[3] = 0; //LED mA
|
||||||
char ma[4] = "MA"; ma[2] = offset+s; ma[3] = 0; //max mA
|
char ma[4] = "MA"; ma[2] = offset+s; ma[3] = 0; //max mA
|
||||||
if (!request->hasArg(lp)) {
|
if (!request->hasArg(lp)) {
|
||||||
DEBUG_PRINTF_P(PSTR("No data for %d\n"), s);
|
DEBUG_PRINTF_P(PSTR("# of buses: %d\n"), s+1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
@ -210,7 +212,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
type |= request->hasArg(rf) << 7; // off refresh override
|
type |= request->hasArg(rf) << 7; // off refresh override
|
||||||
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
// actual finalization is done in WLED::loop() (removing old busses and adding new)
|
||||||
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
|
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
|
||||||
busConfigs.push_back(std::move(BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax)));
|
busConfigs.emplace_back(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax);
|
||||||
busesChanged = true;
|
busesChanged = true;
|
||||||
}
|
}
|
||||||
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
|
||||||
|
@ -530,6 +530,8 @@ um_data_t* simulateSound(uint8_t simulationId)
|
|||||||
static const char s_ledmap_tmpl[] PROGMEM = "ledmap%d.json";
|
static const char s_ledmap_tmpl[] PROGMEM = "ledmap%d.json";
|
||||||
// enumerate all ledmapX.json files on FS and extract ledmap names if existing
|
// enumerate all ledmapX.json files on FS and extract ledmap names if existing
|
||||||
void enumerateLedmaps() {
|
void enumerateLedmaps() {
|
||||||
|
StaticJsonDocument<64> filter;
|
||||||
|
filter["n"] = true;
|
||||||
ledMaps = 1;
|
ledMaps = 1;
|
||||||
for (size_t i=1; i<WLED_MAX_LEDMAPS; i++) {
|
for (size_t i=1; i<WLED_MAX_LEDMAPS; i++) {
|
||||||
char fileName[33] = "/";
|
char fileName[33] = "/";
|
||||||
@ -548,7 +550,7 @@ void enumerateLedmaps() {
|
|||||||
|
|
||||||
#ifndef ESP8266
|
#ifndef ESP8266
|
||||||
if (requestJSONBufferLock(21)) {
|
if (requestJSONBufferLock(21)) {
|
||||||
if (readObjectFromFile(fileName, nullptr, pDoc)) {
|
if (readObjectFromFile(fileName, nullptr, pDoc, &filter)) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
JsonObject root = pDoc->as<JsonObject>();
|
JsonObject root = pDoc->as<JsonObject>();
|
||||||
if (!root["n"].isNull()) {
|
if (!root["n"].isNull()) {
|
||||||
|
140
wled00/wled.cpp
140
wled00/wled.cpp
@ -607,146 +607,6 @@ void WLED::initAP(bool resetAP)
|
|||||||
apActive = true;
|
apActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WLED::initEthernet()
|
|
||||||
{
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
|
||||||
|
|
||||||
static bool successfullyConfiguredEthernet = false;
|
|
||||||
|
|
||||||
if (successfullyConfiguredEthernet) {
|
|
||||||
// DEBUG_PRINTLN(F("initE: ETH already successfully configured, ignoring"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ethernetType == WLED_ETH_NONE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ethernetType >= WLED_NUM_ETH_TYPES) {
|
|
||||||
DEBUG_PRINTF_P(PSTR("initE: Ignoring attempt for invalid ethernetType (%d)\n"), ethernetType);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_PRINTF_P(PSTR("initE: Attempting ETH config: %d\n"), ethernetType);
|
|
||||||
|
|
||||||
// Ethernet initialization should only succeed once -- else reboot required
|
|
||||||
ethernet_settings es = ethernetBoards[ethernetType];
|
|
||||||
managed_pin_type pinsToAllocate[10] = {
|
|
||||||
// first six pins are non-configurable
|
|
||||||
esp32_nonconfigurable_ethernet_pins[0],
|
|
||||||
esp32_nonconfigurable_ethernet_pins[1],
|
|
||||||
esp32_nonconfigurable_ethernet_pins[2],
|
|
||||||
esp32_nonconfigurable_ethernet_pins[3],
|
|
||||||
esp32_nonconfigurable_ethernet_pins[4],
|
|
||||||
esp32_nonconfigurable_ethernet_pins[5],
|
|
||||||
{ (int8_t)es.eth_mdc, true }, // [6] = MDC is output and mandatory
|
|
||||||
{ (int8_t)es.eth_mdio, true }, // [7] = MDIO is bidirectional and mandatory
|
|
||||||
{ (int8_t)es.eth_power, true }, // [8] = optional pin, not all boards use
|
|
||||||
{ ((int8_t)0xFE), false }, // [9] = replaced with eth_clk_mode, mandatory
|
|
||||||
};
|
|
||||||
// update the clock pin....
|
|
||||||
if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) {
|
|
||||||
pinsToAllocate[9].pin = 0;
|
|
||||||
pinsToAllocate[9].isOutput = false;
|
|
||||||
} else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) {
|
|
||||||
pinsToAllocate[9].pin = 0;
|
|
||||||
pinsToAllocate[9].isOutput = true;
|
|
||||||
} else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) {
|
|
||||||
pinsToAllocate[9].pin = 16;
|
|
||||||
pinsToAllocate[9].isOutput = true;
|
|
||||||
} else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) {
|
|
||||||
pinsToAllocate[9].pin = 17;
|
|
||||||
pinsToAllocate[9].isOutput = true;
|
|
||||||
} else {
|
|
||||||
DEBUG_PRINTF_P(PSTR("initE: Failing due to invalid eth_clk_mode (%d)\n"), es.eth_clk_mode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PinManager::allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) {
|
|
||||||
DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
For LAN8720 the most correct way is to perform clean reset each time before init
|
|
||||||
applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59)
|
|
||||||
ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in
|
|
||||||
/components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280)
|
|
||||||
but ESP_IDF < V4 does not. Lets do it:
|
|
||||||
[not always needed, might be relevant in some EMI situations at startup and for hot resets]
|
|
||||||
*/
|
|
||||||
#if ESP_IDF_VERSION_MAJOR==3
|
|
||||||
if(es.eth_power>0 && es.eth_type==ETH_PHY_LAN8720) {
|
|
||||||
pinMode(es.eth_power, OUTPUT);
|
|
||||||
digitalWrite(es.eth_power, 0);
|
|
||||||
delayMicroseconds(150);
|
|
||||||
digitalWrite(es.eth_power, 1);
|
|
||||||
delayMicroseconds(10);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!ETH.begin(
|
|
||||||
(uint8_t) es.eth_address,
|
|
||||||
(int) es.eth_power,
|
|
||||||
(int) es.eth_mdc,
|
|
||||||
(int) es.eth_mdio,
|
|
||||||
(eth_phy_type_t) es.eth_type,
|
|
||||||
(eth_clock_mode_t) es.eth_clk_mode
|
|
||||||
)) {
|
|
||||||
DEBUG_PRINTLN(F("initC: ETH.begin() failed"));
|
|
||||||
// de-allocate the allocated pins
|
|
||||||
for (managed_pin_type mpt : pinsToAllocate) {
|
|
||||||
PinManager::deallocatePin(mpt.pin, PinOwner::Ethernet);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
successfullyConfiguredEthernet = true;
|
|
||||||
DEBUG_PRINTLN(F("initC: *** Ethernet successfully configured! ***"));
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return false; // Ethernet not enabled for build
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// performs asynchronous scan for available networks (which may take couple of seconds to finish)
|
|
||||||
// returns configured WiFi ID with the strongest signal (or default if no configured networks available)
|
|
||||||
int8_t WLED::findWiFi(bool doScan) {
|
|
||||||
if (multiWiFi.size() <= 1) {
|
|
||||||
DEBUG_PRINTLN(F("Defaulf WiFi used."));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doScan) WiFi.scanDelete(); // restart scan
|
|
||||||
|
|
||||||
int status = WiFi.scanComplete(); // complete scan may take as much as several seconds (usually <3s with not very crowded air)
|
|
||||||
|
|
||||||
if (status == WIFI_SCAN_FAILED) {
|
|
||||||
DEBUG_PRINTLN(F("WiFi scan started."));
|
|
||||||
WiFi.scanNetworks(true); // start scanning in asynchronous mode
|
|
||||||
} else if (status >= 0) { // status contains number of found networks
|
|
||||||
DEBUG_PRINT(F("WiFi scan completed: ")); DEBUG_PRINTLN(status);
|
|
||||||
int rssi = -9999;
|
|
||||||
unsigned selected = selectedWiFi;
|
|
||||||
for (int o = 0; o < status; o++) {
|
|
||||||
DEBUG_PRINT(F(" WiFi available: ")); DEBUG_PRINT(WiFi.SSID(o));
|
|
||||||
DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(WiFi.RSSI(o)); DEBUG_PRINTLN(F("dB"));
|
|
||||||
for (unsigned n = 0; n < multiWiFi.size(); n++)
|
|
||||||
if (!strcmp(WiFi.SSID(o).c_str(), multiWiFi[n].clientSSID)) {
|
|
||||||
// find the WiFi with the strongest signal (but keep priority of entry if signal difference is not big)
|
|
||||||
if ((n < selected && WiFi.RSSI(o) > rssi-10) || WiFi.RSSI(o) > rssi) {
|
|
||||||
rssi = WiFi.RSSI(o);
|
|
||||||
selected = n;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUG_PRINT(F("Selected: ")); DEBUG_PRINT(multiWiFi[selected].clientSSID);
|
|
||||||
DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(rssi); DEBUG_PRINTLN(F("dB"));
|
|
||||||
return selected;
|
|
||||||
}
|
|
||||||
//DEBUG_PRINT(F("WiFi scan running."));
|
|
||||||
return status; // scan is still running or there was an error
|
|
||||||
}
|
|
||||||
|
|
||||||
void WLED::initConnection()
|
void WLED::initConnection()
|
||||||
{
|
{
|
||||||
DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000);
|
DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000);
|
||||||
|
@ -217,6 +217,10 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
|||||||
#define WLED_AP_PASS DEFAULT_AP_PASS
|
#define WLED_AP_PASS DEFAULT_AP_PASS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef WLED_PIN
|
||||||
|
#define WLED_PIN ""
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SPIFFS_EDITOR_AIRCOOOKIE
|
#ifndef SPIFFS_EDITOR_AIRCOOOKIE
|
||||||
#error You are not using the Aircoookie fork of the ESPAsyncWebserver library.\
|
#error You are not using the Aircoookie fork of the ESPAsyncWebserver library.\
|
||||||
Using upstream puts your WiFi password at risk of being served by the filesystem.\
|
Using upstream puts your WiFi password at risk of being served by the filesystem.\
|
||||||
@ -277,7 +281,11 @@ WLED_GLOBAL char releaseString[] _INIT(WLED_RELEASE_NAME); // must include the q
|
|||||||
|
|
||||||
// AP and OTA default passwords (for maximum security change them!)
|
// AP and OTA default passwords (for maximum security change them!)
|
||||||
WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS);
|
WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS);
|
||||||
|
#ifdef WLED_OTA_PASS
|
||||||
|
WLED_GLOBAL char otaPass[33] _INIT(WLED_OTA_PASS);
|
||||||
|
#else
|
||||||
WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
|
WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Hardware and pin config
|
// Hardware and pin config
|
||||||
#ifndef BTNPIN
|
#ifndef BTNPIN
|
||||||
@ -359,7 +367,7 @@ WLED_GLOBAL wifi_options_t wifiOpt _INIT_N(({0, 1, false, AP_BEHAVIOR_BOOT_NO_CO
|
|||||||
#define noWifiSleep wifiOpt.noWifiSleep
|
#define noWifiSleep wifiOpt.noWifiSleep
|
||||||
#define force802_3g wifiOpt.force802_3g
|
#define force802_3g wifiOpt.force802_3g
|
||||||
#else
|
#else
|
||||||
WLED_GLOBAL uint8_t selectedWiFi _INIT(0);
|
WLED_GLOBAL int8_t selectedWiFi _INIT(0);
|
||||||
WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13)
|
WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13)
|
||||||
WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID
|
WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID
|
||||||
WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default
|
WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default
|
||||||
@ -377,9 +385,9 @@ WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm);
|
|||||||
WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm);
|
WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#define WLED_WIFI_CONFIGURED (strlen(multiWiFi[0].clientSSID) >= 1 && strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) != 0)
|
#define WLED_WIFI_CONFIGURED isWiFiConfigured()
|
||||||
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||||
#ifdef WLED_ETH_DEFAULT // default ethernet board type if specified
|
#ifdef WLED_ETH_DEFAULT // default ethernet board type if specified
|
||||||
WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type
|
WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type
|
||||||
#else
|
#else
|
||||||
@ -570,11 +578,15 @@ WLED_GLOBAL byte macroLongPress[WLED_MAX_BUTTONS] _INIT({0});
|
|||||||
WLED_GLOBAL byte macroDoublePress[WLED_MAX_BUTTONS] _INIT({0});
|
WLED_GLOBAL byte macroDoublePress[WLED_MAX_BUTTONS] _INIT({0});
|
||||||
|
|
||||||
// Security CONFIG
|
// Security CONFIG
|
||||||
WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks
|
#ifdef WLED_OTA_PASS
|
||||||
WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled
|
WLED_GLOBAL bool otaLock _INIT(true); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks
|
||||||
WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on
|
#else
|
||||||
WLED_GLOBAL char settingsPIN[5] _INIT(""); // PIN for settings pages
|
WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks
|
||||||
WLED_GLOBAL bool correctPIN _INIT(true);
|
#endif
|
||||||
|
WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled
|
||||||
|
WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on
|
||||||
|
WLED_GLOBAL char settingsPIN[5] _INIT(WLED_PIN); // PIN for settings pages
|
||||||
|
WLED_GLOBAL bool correctPIN _INIT(!strlen(settingsPIN));
|
||||||
WLED_GLOBAL unsigned long lastEditTime _INIT(0);
|
WLED_GLOBAL unsigned long lastEditTime _INIT(0);
|
||||||
|
|
||||||
WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use in usermod
|
WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use in usermod
|
||||||
@ -582,6 +594,7 @@ WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use i
|
|||||||
// internal global variable declarations
|
// internal global variable declarations
|
||||||
// wifi
|
// wifi
|
||||||
WLED_GLOBAL bool apActive _INIT(false);
|
WLED_GLOBAL bool apActive _INIT(false);
|
||||||
|
WLED_GLOBAL byte apClients _INIT(0);
|
||||||
WLED_GLOBAL bool forceReconnect _INIT(false);
|
WLED_GLOBAL bool forceReconnect _INIT(false);
|
||||||
WLED_GLOBAL unsigned long lastReconnectAttempt _INIT(0);
|
WLED_GLOBAL unsigned long lastReconnectAttempt _INIT(0);
|
||||||
WLED_GLOBAL bool interfacesInited _INIT(false);
|
WLED_GLOBAL bool interfacesInited _INIT(false);
|
||||||
@ -894,12 +907,11 @@ WLED_GLOBAL ESPAsyncE131 ddp _INIT_N(((handleE131Packet)));
|
|||||||
WLED_GLOBAL bool e131NewData _INIT(false);
|
WLED_GLOBAL bool e131NewData _INIT(false);
|
||||||
|
|
||||||
// led fx library object
|
// led fx library object
|
||||||
WLED_GLOBAL BusManager busses _INIT(BusManager());
|
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
||||||
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
WLED_GLOBAL std::vector<BusConfig> busConfigs; //temporary, to remember values from network callback until after
|
||||||
WLED_GLOBAL std::vector<BusConfig> busConfigs; //temporary, to remember values from network callback until after
|
WLED_GLOBAL bool doInitBusses _INIT(false);
|
||||||
WLED_GLOBAL bool doInitBusses _INIT(false);
|
WLED_GLOBAL int8_t loadLedmap _INIT(-1);
|
||||||
WLED_GLOBAL int8_t loadLedmap _INIT(-1);
|
WLED_GLOBAL uint8_t currentLedmap _INIT(0);
|
||||||
WLED_GLOBAL uint8_t currentLedmap _INIT(0);
|
|
||||||
#ifndef ESP8266
|
#ifndef ESP8266
|
||||||
WLED_GLOBAL char *ledmapNames[WLED_MAX_LEDMAPS-1] _INIT_N(({nullptr}));
|
WLED_GLOBAL char *ledmapNames[WLED_MAX_LEDMAPS-1] _INIT_N(({nullptr}));
|
||||||
#endif
|
#endif
|
||||||
@ -1049,11 +1061,9 @@ public:
|
|||||||
|
|
||||||
void beginStrip();
|
void beginStrip();
|
||||||
void handleConnection();
|
void handleConnection();
|
||||||
bool initEthernet(); // result is informational
|
|
||||||
void initAP(bool resetAP = false);
|
void initAP(bool resetAP = false);
|
||||||
void initConnection();
|
void initConnection();
|
||||||
void initInterfaces();
|
void initInterfaces();
|
||||||
int8_t findWiFi(bool doScan = false);
|
|
||||||
#if defined(STATUSLED)
|
#if defined(STATUSLED)
|
||||||
void handleStatusLED();
|
void handleStatusLED();
|
||||||
#endif
|
#endif
|
||||||
|
@ -567,13 +567,14 @@ void serveSettings(AsyncWebServerRequest* request, bool post) {
|
|||||||
//else if (url.indexOf("/edit") >= 0) subPage = 10;
|
//else if (url.indexOf("/edit") >= 0) subPage = 10;
|
||||||
else subPage = SUBPAGE_WELCOME;
|
else subPage = SUBPAGE_WELCOME;
|
||||||
|
|
||||||
if (!correctPIN && strlen(settingsPIN) > 0 && (subPage > 0 && subPage < 11)) {
|
bool pinRequired = !correctPIN && strlen(settingsPIN) > 0 && (subPage > (WLED_WIFI_CONFIGURED ? SUBPAGE_MENU : SUBPAGE_WIFI) && subPage < SUBPAGE_LOCK);
|
||||||
|
if (pinRequired) {
|
||||||
originalSubPage = subPage;
|
originalSubPage = subPage;
|
||||||
subPage = SUBPAGE_PINREQ; // require PIN
|
subPage = SUBPAGE_PINREQ; // require PIN
|
||||||
}
|
}
|
||||||
|
|
||||||
// if OTA locked or too frequent PIN entry requests fail hard
|
// if OTA locked or too frequent PIN entry requests fail hard
|
||||||
if ((subPage == SUBPAGE_WIFI && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < PIN_RETRY_COOLDOWN))
|
if ((subPage == SUBPAGE_WIFI && wifiLock && otaLock) || (post && pinRequired && millis()-lastEditTime < PIN_RETRY_COOLDOWN))
|
||||||
{
|
{
|
||||||
serveMessage(request, 401, FPSTR(s_accessdenied), FPSTR(s_unlock_ota), 254); return;
|
serveMessage(request, 401, FPSTR(s_accessdenied), FPSTR(s_unlock_ota), 254); return;
|
||||||
}
|
}
|
||||||
@ -609,7 +610,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) {
|
|||||||
if (!s2[0]) strcpy_P(s2, s_redirecting);
|
if (!s2[0]) strcpy_P(s2, s_redirecting);
|
||||||
|
|
||||||
bool redirectAfter9s = (subPage == SUBPAGE_WIFI || ((subPage == SUBPAGE_SEC || subPage == SUBPAGE_UM) && doReboot));
|
bool redirectAfter9s = (subPage == SUBPAGE_WIFI || ((subPage == SUBPAGE_SEC || subPage == SUBPAGE_UM) && doReboot));
|
||||||
serveMessage(request, (correctPIN ? 200 : 401), s, s2, redirectAfter9s ? 129 : (correctPIN ? 1 : 3));
|
serveMessage(request, (!pinRequired ? 200 : 401), s, s2, redirectAfter9s ? 129 : (!pinRequired ? 1 : 3));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ void appendGPIOinfo(Print& settingsScript) {
|
|||||||
settingsScript.print(hardwareTX); // debug output (TX) pin
|
settingsScript.print(hardwareTX); // debug output (TX) pin
|
||||||
firstPin = false;
|
firstPin = false;
|
||||||
#endif
|
#endif
|
||||||
#ifdef WLED_USE_ETHERNET
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||||
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
||||||
if (!firstPin) settingsScript.print(',');
|
if (!firstPin) settingsScript.print(',');
|
||||||
for (unsigned p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) { settingsScript.printf("%d,",esp32_nonconfigurable_ethernet_pins[p].pin); }
|
for (unsigned p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) { settingsScript.printf("%d,",esp32_nonconfigurable_ethernet_pins[p].pin); }
|
||||||
@ -178,9 +178,12 @@ void getSettingsJS(byte subPage, Print& settingsScript)
|
|||||||
char fpass[l+1]; //fill password field with ***
|
char fpass[l+1]; //fill password field with ***
|
||||||
fpass[l] = 0;
|
fpass[l] = 0;
|
||||||
memset(fpass,'*',l);
|
memset(fpass,'*',l);
|
||||||
settingsScript.printf_P(PSTR("addWiFi(\"%s\",\"%s\",0x%X,0x%X,0x%X);"),
|
char bssid[13];
|
||||||
|
fillMAC2Str(bssid, multiWiFi[n].bssid);
|
||||||
|
settingsScript.printf_P(PSTR("addWiFi(\"%s\",\"%s\",\"%s\",0x%X,0x%X,0x%X);"),
|
||||||
multiWiFi[n].clientSSID,
|
multiWiFi[n].clientSSID,
|
||||||
fpass,
|
fpass,
|
||||||
|
bssid,
|
||||||
(uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct
|
(uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct
|
||||||
(uint32_t) multiWiFi[n].staticGW,
|
(uint32_t) multiWiFi[n].staticGW,
|
||||||
(uint32_t) multiWiFi[n].staticSN);
|
(uint32_t) multiWiFi[n].staticSN);
|
||||||
@ -219,7 +222,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
|
|||||||
settingsScript.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting
|
settingsScript.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
|
||||||
printSetFormValue(settingsScript,PSTR("ETH"),ethernetType);
|
printSetFormValue(settingsScript,PSTR("ETH"),ethernetType);
|
||||||
#else
|
#else
|
||||||
//hide ethernet setting if not compiled in
|
//hide ethernet setting if not compiled in
|
||||||
@ -272,7 +275,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
|
|||||||
// set limits
|
// set limits
|
||||||
settingsScript.printf_P(PSTR("bLimits(%d,%d,%d,%d,%d,%d,%d,%d);"),
|
settingsScript.printf_P(PSTR("bLimits(%d,%d,%d,%d,%d,%d,%d,%d);"),
|
||||||
WLED_MAX_BUSSES,
|
WLED_MAX_BUSSES,
|
||||||
WLED_MIN_VIRTUAL_BUSSES,
|
WLED_MIN_VIRTUAL_BUSSES, // irrelevant, but kept to distinguish S2/S3 in UI
|
||||||
MAX_LEDS_PER_BUS,
|
MAX_LEDS_PER_BUS,
|
||||||
MAX_LED_MEMORY,
|
MAX_LED_MEMORY,
|
||||||
MAX_LEDS,
|
MAX_LEDS,
|
||||||
@ -358,7 +361,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
|
|||||||
const ColorOrderMap& com = BusManager::getColorOrderMap();
|
const ColorOrderMap& com = BusManager::getColorOrderMap();
|
||||||
for (int s = 0; s < com.count(); s++) {
|
for (int s = 0; s < com.count(); s++) {
|
||||||
const ColorOrderMapEntry* entry = com.get(s);
|
const ColorOrderMapEntry* entry = com.get(s);
|
||||||
if (entry == nullptr) break;
|
if (!entry || !entry->len) break;
|
||||||
settingsScript.printf_P(PSTR("addCOM(%d,%d,%d);"), entry->start, entry->len, entry->colorOrder);
|
settingsScript.printf_P(PSTR("addCOM(%d,%d,%d);"), entry->start, entry->len, entry->colorOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user