Skip to content

Commit b50c475

Browse files
authored
feat(cli): warn when a UART's configured dmaopt loses its DMA claim (#1400)
* feat(cli): warn when a UART's configured dmaopt loses its DMA claim serialUART() silently falls back to IRQ-driven mode when uartDmaClaim() loses a stream/channel to another peripheral, leaving no CLI or log signal. Cross-checks a resolved dmaopt against dmaGetOwner()'s live ownership state at both get/list time (printDmaoptEntry) and set time (cliDmaopt), printing a warning on mismatch. Closes #1388. * fix(cli): flag unmapped DMA identifiers, shrink dmaopt claim strings dmaGetIdentifier() returning DMA_NONE means a reqmap table entry points at a stream missing from dmaDescriptors[]. It read identically to the benign OWNER_FREE case. Adds a distinct DMA MAP ERROR line for it. Collapses the two CLAIMED BY message branches into one shared format string, cutting duplicate string literals from flash. Closes #1388.
1 parent a4ca6ad commit b50c475

1 file changed

Lines changed: 33 additions & 0 deletions

File tree

src/main/interface/cli.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4053,6 +4053,31 @@ static dmaoptValue_t *dmaoptAddr(const dmaoptEntry_t *entry, int index) {
40534053
return (dmaoptValue_t *)(base + entry->stride * index + entry->offset);
40544054
}
40554055

4056+
// Surfaces serialUART()'s otherwise-silent IRQ-driven fallback via dmaAllocate()'s live ownership state.
4057+
static void printDmaoptClaimStatus(const dmaoptEntry_t *entry, int index, const dmaChannelSpec_t *dmaChannelSpec) {
4058+
const dmaIdentifier_e identifier = dmaGetIdentifier((DMA_Stream_TypeDef *)dmaChannelSpec->ref);
4059+
if (identifier == DMA_NONE) {
4060+
// reqmap table points at a stream absent from dmaDescriptors[] -- a map bug, not a live contention case.
4061+
cliPrintLinef("# %s %d: DMA MAP ERROR", entry->device, index + 1);
4062+
return;
4063+
}
4064+
const resourceOwner_e expectedOwner = (entry->peripheral == DMA_PERIPH_UART_TX) ? OWNER_SERIAL_TX : OWNER_SERIAL_RX;
4065+
const resourceOwner_e actualOwner = dmaGetOwner(identifier);
4066+
const uint8_t actualIndex = dmaGetResourceIndex(identifier);
4067+
if (actualOwner == expectedOwner && actualIndex == RESOURCE_INDEX(index)) {
4068+
return;
4069+
}
4070+
// OWNER_FREE is indistinguishable from "this UART not opened this boot" (unassigned serial function) -- skip to avoid false positives on every unused UART slot.
4071+
if (actualOwner == OWNER_FREE) {
4072+
return;
4073+
}
4074+
char idxSuffix[DMA_OPT_STRING_BUFSIZE] = "";
4075+
if (actualIndex > 0) {
4076+
tfp_sprintf(idxSuffix, " %d", actualIndex);
4077+
}
4078+
cliPrintLinef("# %s %d: CLAIMED BY %s%s", entry->device, index + 1, ownerNames[actualOwner], idxSuffix);
4079+
}
4080+
40564081
static void printDmaoptEntry(const dmaoptEntry_t *entry, int index) {
40574082
const dmaoptValue_t *addr = dmaoptAddr(entry, index);
40584083
if (!addr) {
@@ -4066,6 +4091,7 @@ static void printDmaoptEntry(const dmaoptEntry_t *entry, int index) {
40664091
if (dmaChannelSpec) {
40674092
cliPrintLinef("# %s %d: " DMASPEC_FORMAT_STRING, entry->device, index + 1,
40684093
DMA_CODE_CONTROLLER(dmaChannelSpec->code), DMA_CODE_STREAM(dmaChannelSpec->code), DMA_CODE_CHANNEL(dmaChannelSpec->code));
4094+
printDmaoptClaimStatus(entry, index, dmaChannelSpec);
40694095
}
40704096
} else {
40714097
cliPrintLinef("dma %s %d NONE", entry->device, index + 1);
@@ -4162,6 +4188,13 @@ static void cliDmaopt(char *cmdline) {
41624188
} else {
41634189
cliPrintLinef("# dma %s %d: no change: %s", entry->device, index + 1, orgvalString);
41644190
}
4191+
4192+
if (optval != DMA_OPT_UNUSED) {
4193+
const dmaChannelSpec_t *dmaChannelSpec = dmaGetChannelSpecByPeripheral(entry->peripheral, index, optval);
4194+
if (dmaChannelSpec) {
4195+
printDmaoptClaimStatus(entry, index, dmaChannelSpec);
4196+
}
4197+
}
41654198
}
41664199
#endif // STM32F4 || STM32F7 || STM32H7
41674200

0 commit comments

Comments
 (0)