Alex2ESP/keywords.txt
David 6fe8311a6f Queue up to eight directives for loop(); drop the repeat of a directive while it arrives
8ea7778 kept one directive for loop() and recognised the repeat that the broker mirror delivers in two ways: bytes compared with the directive that still waited, and the messageId once loop() had parsed it. A repeat that arrived after its directive had been read therefore took the one place until the next loop(), and a different directive behind it was dropped. Alexa sends a group command as one directive per endpoint, so a board with several endpoints lost directives whenever they arrived faster than loop() ran; 1.1.0 queued five tokens.

AlexaDirectiveBuffer is now a queue. The arriving message is collected in a heap block of its own and hashed (FNV-1a, 64 bit) as its fragments come in. At the last fragment it is one of three things: a repeat, when the hash is among the last 16 that were queued, and then it is freed and never takes a place; a directive, which is queued; or lost, when eight directives (ALEX2ESP_MAX_QUEUED_DIRECTIVES) or 8188 bytes (ALEX2ESP_MAX_QUEUED_BYTES, four times the largest directive) already wait. Whether there is a place is decided at the last fragment, because loop() may have read a directive by then. A message for which there is no memory is still hashed, so its loss is reported only when it is not a repeat. loop() parses one directive per call, in the order of arrival, and frees its block before the handler runs.

The messageId check stays for a directive that comes again with other bytes; it remembers 16 ids instead of 4 and shares the ring with the buffer (AlexaRecentHashes). The two limits are in src/AlexaLimits.h, with #error for values that cannot work. The constructor of the buffer takes the allocator, malloc by default, so the tests can let it fail.

For a sketch: nothing to change. The error line of a directive that finds no place reads "directive of N bytes on <topic> dropped: 8 directives, M bytes, already wait for loop()". The heap holds up to 8188 bytes of waiting directives and one arriving directive of up to 2048, where it held one directive.

Measured with the bridge built for the host against a fake MQTT client (not in the repository), directives of 793 bytes, every message delivered twice, 8ea7778 -> this commit:
  repeat of D1 and a new D2 after D1 was handled   D2 dropped -> D2 handled
  group of 5 in one burst                          1 of 5 handled, 8 error lines -> 5 of 5, none
  group of 8 in one burst                          8 of 8 handled, no error line
  group of 10 in one burst, not mirrored           8 of 10 handled, 2 error lines
  group of 10, a loop() after every fourth message 10 of 10 handled, no error line

Tests: 41 host tests (33 before). New: the order of the queue and the reuse of its places, the ninth directive, a place that becomes free while a directive arrives, the limit in bytes, the largest directive in an empty queue, the repeat of a waiting directive and of one that was read, a group of five with repeats, a repeat when no place is free, a directive that differs in one byte, how long a repeat is remembered, a directive and a repeat without memory, the FNV-1a test vectors. They also pass under -fsanitize=address,undefined. Seven faults planted in a copy of AlexaBridgeLogic.cpp (no repeat check, no limit in bytes, no limit in places, no bounds check, a lost directive remembered, release() that keeps the bytes, last in first out) were each noticed: six by failing tests, the missing bounds check by AddressSanitizer as a heap-buffer-overflow.

Built for d1_mini with empty credentials (PlatformIO 6.2.0, espressif8266 4.2.1), static RAM / flash in bytes, e48f858 -> this commit, no warnings:
  basicLight           34,116 / 336,757 -> 34,444 / 337,145
  lightWithBrightness  34,232 / 340,517 -> 34,560 / 340,921
  lightWithColorTemp   34,380 / 341,177 -> 34,708 / 341,581
  tempSensor           34,024 / 335,457 -> 34,352 / 335,845
  blindControl         34,256 / 338,925 -> 34,584 / 339,313
The 328 bytes of RAM are the two rings of 16 hashes (256) and the eight places of the queue.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-28 15:57:03 +00:00

96 lines
2.3 KiB
Text

#######################################
# Syntax Coloring Map For Alex2ESP
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Alex2ESP KEYWORD1
Alex2ESPState KEYWORD1
AlexaDevice KEYWORD1
AlexaInterface KEYWORD1
AlexaInterfaceType KEYWORD1
AlexaInterfaceUtils KEYWORD1
AlexaStatusMessage KEYWORD1
ActionMapping KEYWORD1
AlexaActions KEYWORD1
AlexaActionsUtils KEYWORD1
FriendlyName KEYWORD1
DisplayCategory KEYWORD1
DisplayCategoryUtils KEYWORD1
EndpointHealth KEYWORD1
PowerController KEYWORD1
TemperatureSensorScale KEYWORD1
AlexaUtils KEYWORD1
AlexaLog KEYWORD1
AlexaLogLevel KEYWORD1
AlexaSendResult KEYWORD1
AlexaTransport KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
loop KEYWORD2
getState KEYWORD2
getDisconnectReason KEYWORD2
getDevice KEYWORD2
setLogLevel KEYWORD2
setTimeSource KEYWORD2
publish KEYWORD2
timestamp KEYWORD2
setName KEYWORD2
getName KEYWORD2
getEndpointId KEYWORD2
hasEndpointId KEYWORD2
setDisplayCategory KEYWORD2
getDisplayCategory KEYWORD2
setDescription KEYWORD2
getDescription KEYWORD2
setManufacturerName KEYWORD2
getManufacturerName KEYWORD2
setManufacturer KEYWORD2
getManufacturer KEYWORD2
setModel KEYWORD2
getModel KEYWORD2
getSoftwareVersion KEYWORD2
getDeviceJSON KEYWORD2
addCapability KEYWORD2
registerEvent KEYWORD2
triggerEvent KEYWORD2
buildStatusMessage KEYWORD2
getType KEYWORD2
getTypeString KEYWORD2
getVersion KEYWORD2
getProps KEYWORD2
setInstance KEYWORD2
addFriendlyName KEYWORD2
isRetrievable KEYWORD2
isProactivelyReported KEYWORD2
setRetrievable KEYWORD2
setProactivelyReported KEYWORD2
addActionMapping KEYWORD2
getJSON KEYWORD2
AddHealthProp KEYWORD2
AddPowerControllerProp KEYWORD2
AddTemperatureSensorProp KEYWORD2
AddBrightnessControllerProp KEYWORD2
AddColorTemperatureControllerProp KEYWORD2
AddToggleControllerProp KEYWORD2
AddContextProp KEYWORD2
send KEYWORD2
printMemoryInfo KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
ALEX2ESP_MAX_DIRECTIVE LITERAL1
ALEX2ESP_MAX_MESSAGE LITERAL1
ALEX2ESP_MAX_QUEUED_DIRECTIVES LITERAL1
ALEX2ESP_MAX_QUEUED_BYTES LITERAL1
ALEX2ESP_LOG_MAX LITERAL1
ALEXA_TIMESTAMP_SIZE LITERAL1
MAX_EVENTS LITERAL1