mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-15 04:15:44 +03:00
Add flash ready state to MSP response, add flash async block write
This commit is contained in:
parent
5651e65a0b
commit
80ea5e4419
6 changed files with 65 additions and 36 deletions
|
@ -789,7 +789,8 @@ static bool sendFieldDefinition(const char * const *headerNames, unsigned int he
|
||||||
|
|
||||||
charsWritten = blackboxPrint("H Field ");
|
charsWritten = blackboxPrint("H Field ");
|
||||||
charsWritten += blackboxPrint(headerNames[xmitState.headerIndex]);
|
charsWritten += blackboxPrint(headerNames[xmitState.headerIndex]);
|
||||||
charsWritten += blackboxPrint(":");
|
blackboxWrite(':');
|
||||||
|
charsWritten++;
|
||||||
|
|
||||||
xmitState.u.fieldIndex++;
|
xmitState.u.fieldIndex++;
|
||||||
needComma = false;
|
needComma = false;
|
||||||
|
|
|
@ -73,7 +73,7 @@ void blackboxWrite(uint8_t value)
|
||||||
switch (masterConfig.blackbox_device) {
|
switch (masterConfig.blackbox_device) {
|
||||||
#ifdef FLASHFS
|
#ifdef FLASHFS
|
||||||
case BLACKBOX_DEVICE_FLASH:
|
case BLACKBOX_DEVICE_FLASH:
|
||||||
flashfsWriteByte(value);
|
flashfsWriteByte(value); // Write byte asynchronously
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case BLACKBOX_DEVICE_SERIAL:
|
case BLACKBOX_DEVICE_SERIAL:
|
||||||
|
@ -109,7 +109,7 @@ int blackboxPrint(const char *s)
|
||||||
#ifdef FLASHFS
|
#ifdef FLASHFS
|
||||||
case BLACKBOX_DEVICE_FLASH:
|
case BLACKBOX_DEVICE_FLASH:
|
||||||
length = strlen(s);
|
length = strlen(s);
|
||||||
flashfsWrite((const uint8_t*) s, length);
|
flashfsWrite((const uint8_t*) s, length, false); // Write asynchronously
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "drivers/flash_m25p16.h"
|
#include "drivers/flash_m25p16.h"
|
||||||
#include "flashfs.h"
|
#include "flashfs.h"
|
||||||
|
@ -56,6 +57,11 @@ static void flashfsClearBuffer()
|
||||||
shouldFlush = false;
|
shouldFlush = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool flashfsBufferIsEmpty()
|
||||||
|
{
|
||||||
|
return bufferTail == bufferHead;
|
||||||
|
}
|
||||||
|
|
||||||
static void flashfsSetTailAddress(uint32_t address)
|
static void flashfsSetTailAddress(uint32_t address)
|
||||||
{
|
{
|
||||||
tailAddress = address;
|
tailAddress = address;
|
||||||
|
@ -101,6 +107,14 @@ void flashfsEraseRange(uint32_t start, uint32_t end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the flash is not currently occupied with an operation.
|
||||||
|
*/
|
||||||
|
bool flashfsIsReady()
|
||||||
|
{
|
||||||
|
return m25p16_isReady();
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t flashfsGetSize()
|
uint32_t flashfsGetSize()
|
||||||
{
|
{
|
||||||
return m25p16_getGeometry()->totalSize;
|
return m25p16_getGeometry()->totalSize;
|
||||||
|
@ -261,12 +275,13 @@ static void flashfsAdvanceTailInBuffer(uint32_t delta)
|
||||||
{
|
{
|
||||||
bufferTail += delta;
|
bufferTail += delta;
|
||||||
|
|
||||||
if (bufferTail > FLASHFS_WRITE_BUFFER_SIZE) {
|
// Wrap tail around the end of the buffer
|
||||||
|
if (bufferTail >= FLASHFS_WRITE_BUFFER_SIZE) {
|
||||||
bufferTail -= FLASHFS_WRITE_BUFFER_SIZE;
|
bufferTail -= FLASHFS_WRITE_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferTail == bufferHead) {
|
if (flashfsBufferIsEmpty()) {
|
||||||
flashfsClearBuffer();
|
flashfsClearBuffer(); // Bring buffer pointers back to the start to be tidier
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +291,7 @@ static void flashfsAdvanceTailInBuffer(uint32_t delta)
|
||||||
*/
|
*/
|
||||||
void flashfsFlushAsync()
|
void flashfsFlushAsync()
|
||||||
{
|
{
|
||||||
if (bufferHead == bufferTail) {
|
if (flashfsBufferIsEmpty()) {
|
||||||
shouldFlush = false;
|
shouldFlush = false;
|
||||||
return; // Nothing to flush
|
return; // Nothing to flush
|
||||||
}
|
}
|
||||||
|
@ -289,7 +304,7 @@ void flashfsFlushAsync()
|
||||||
bytesWritten = flashfsWriteBuffers(buffers, bufferSizes, 2, false);
|
bytesWritten = flashfsWriteBuffers(buffers, bufferSizes, 2, false);
|
||||||
flashfsAdvanceTailInBuffer(bytesWritten);
|
flashfsAdvanceTailInBuffer(bytesWritten);
|
||||||
|
|
||||||
shouldFlush = bufferTail != bufferHead;
|
shouldFlush = !flashfsBufferIsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -300,9 +315,9 @@ void flashfsFlushAsync()
|
||||||
*/
|
*/
|
||||||
void flashfsFlushSync()
|
void flashfsFlushSync()
|
||||||
{
|
{
|
||||||
if (bufferHead == bufferTail) {
|
if (flashfsBufferIsEmpty()) {
|
||||||
shouldFlush = false;
|
shouldFlush = false;
|
||||||
return; // Nothing to write
|
return; // Nothing to flush
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t const * buffers[2];
|
uint8_t const * buffers[2];
|
||||||
|
@ -329,6 +344,9 @@ void flashfsSeekRel(int32_t offset)
|
||||||
flashfsSetTailAddress(tailAddress + offset);
|
flashfsSetTailAddress(tailAddress + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the given byte asynchronously to the flash. If the buffer overflows, data is silently discarded.
|
||||||
|
*/
|
||||||
void flashfsWriteByte(uint8_t byte)
|
void flashfsWriteByte(uint8_t byte)
|
||||||
{
|
{
|
||||||
flashWriteBuffer[bufferHead++] = byte;
|
flashWriteBuffer[bufferHead++] = byte;
|
||||||
|
@ -342,7 +360,13 @@ void flashfsWriteByte(uint8_t byte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flashfsWrite(const uint8_t *data, unsigned int len)
|
/**
|
||||||
|
* Write the given buffer to the flash either synchronously or asynchronously depending on the 'sync' parameter.
|
||||||
|
*
|
||||||
|
* If writing asynchronously, data will be silently discarded if the buffer overflows.
|
||||||
|
* If writing synchronously, the routine will block waiting for the flash to become ready so will never drop data.
|
||||||
|
*/
|
||||||
|
void flashfsWrite(const uint8_t *data, unsigned int len, bool sync)
|
||||||
{
|
{
|
||||||
uint8_t const * buffers[3];
|
uint8_t const * buffers[3];
|
||||||
uint32_t bufferSizes[3];
|
uint32_t bufferSizes[3];
|
||||||
|
@ -377,16 +401,18 @@ void flashfsWrite(const uint8_t *data, unsigned int len)
|
||||||
flashfsAdvanceTailInBuffer(bytesWritten);
|
flashfsAdvanceTailInBuffer(bytesWritten);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is the remainder of the data to be written too big to fit in the buffers?
|
||||||
if (bufferSizes[0] + bufferSizes[1] + bufferSizes[2] > FLASHFS_WRITE_BUFFER_USABLE) {
|
if (bufferSizes[0] + bufferSizes[1] + bufferSizes[2] > FLASHFS_WRITE_BUFFER_USABLE) {
|
||||||
/*
|
if (sync) {
|
||||||
* We don't have enough room to store the new data in the buffer without blocking waiting for the flash to
|
// Write it through synchronously
|
||||||
* become ready, so we're forced to write it through synchronously.
|
flashfsWriteBuffers(buffers, bufferSizes, 3, true);
|
||||||
*
|
flashfsClearBuffer();
|
||||||
* TODO we can skip this code and just drop the data for this write instead if the caller wants to
|
} else {
|
||||||
* prioritize predictable response time over reliable data delivery (i.e. sync/async)
|
/*
|
||||||
*/
|
* Silently drop the data the user asked to write (i.e. no-op) since we can't buffer it and they
|
||||||
flashfsWriteBuffers(buffers, bufferSizes, 3, true);
|
* requested async.
|
||||||
flashfsClearBuffer();
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -399,24 +425,22 @@ void flashfsWrite(const uint8_t *data, unsigned int len)
|
||||||
// Buffer up the data the user supplied instead of writing it right away
|
// Buffer up the data the user supplied instead of writing it right away
|
||||||
|
|
||||||
// First write the portion before we wrap around the end of the circular buffer
|
// First write the portion before we wrap around the end of the circular buffer
|
||||||
unsigned int bufferBytesBeforeLoop = FLASHFS_WRITE_BUFFER_SIZE - bufferHead;
|
unsigned int bufferBytesBeforeWrap = FLASHFS_WRITE_BUFFER_SIZE - bufferHead;
|
||||||
|
|
||||||
unsigned int firstPortion = len < bufferBytesBeforeLoop ? len : bufferBytesBeforeLoop;
|
unsigned int firstPortion = len < bufferBytesBeforeWrap ? len : bufferBytesBeforeWrap;
|
||||||
unsigned int remainder = firstPortion < len ? len - firstPortion : 0;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < firstPortion; i++) {
|
memcpy(flashWriteBuffer + bufferHead, data, firstPortion);
|
||||||
flashWriteBuffer[bufferHead++] = *data;
|
|
||||||
data++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bufferHead += firstPortion;
|
||||||
|
|
||||||
|
data += firstPortion;
|
||||||
|
len -= firstPortion;
|
||||||
|
|
||||||
|
// If we wrap the head around, write the remainder to the start of the buffer (if any)
|
||||||
if (bufferHead == FLASHFS_WRITE_BUFFER_SIZE) {
|
if (bufferHead == FLASHFS_WRITE_BUFFER_SIZE) {
|
||||||
bufferHead = 0;
|
memcpy(flashWriteBuffer + 0, data, len);
|
||||||
}
|
|
||||||
|
|
||||||
// Then the remainder (if any)
|
bufferHead = len;
|
||||||
for (unsigned int i = 0; i < remainder; i++) {
|
|
||||||
flashWriteBuffer[bufferHead++] = *data;
|
|
||||||
data++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ void flashfsSeekAbs(uint32_t offset);
|
||||||
void flashfsSeekRel(int32_t offset);
|
void flashfsSeekRel(int32_t offset);
|
||||||
|
|
||||||
void flashfsWriteByte(uint8_t byte);
|
void flashfsWriteByte(uint8_t byte);
|
||||||
void flashfsWrite(const uint8_t *data, unsigned int len);
|
void flashfsWrite(const uint8_t *data, unsigned int len, bool sync);
|
||||||
|
|
||||||
int flashfsReadAbs(uint32_t offset, uint8_t *data, unsigned int len);
|
int flashfsReadAbs(uint32_t offset, uint8_t *data, unsigned int len);
|
||||||
|
|
||||||
|
@ -47,3 +47,5 @@ void flashfsFlushAsync();
|
||||||
void flashfsFlushSync();
|
void flashfsFlushSync();
|
||||||
|
|
||||||
void flashfsInit();
|
void flashfsInit();
|
||||||
|
|
||||||
|
bool flashfsIsReady();
|
||||||
|
|
|
@ -775,7 +775,7 @@ static void cliFlashWrite(char *cmdline)
|
||||||
printf("Missing text to write.\r\n");
|
printf("Missing text to write.\r\n");
|
||||||
} else {
|
} else {
|
||||||
flashfsSeekAbs(address);
|
flashfsSeekAbs(address);
|
||||||
flashfsWrite((uint8_t*)text, strlen(text));
|
flashfsWrite((uint8_t*)text, strlen(text), true);
|
||||||
flashfsFlushSync();
|
flashfsFlushSync();
|
||||||
|
|
||||||
printf("Wrote %u bytes at %u.\r\n", strlen(text), address);
|
printf("Wrote %u bytes at %u.\r\n", strlen(text), address);
|
||||||
|
|
|
@ -533,13 +533,15 @@ reset:
|
||||||
|
|
||||||
static void serializeDataflashSummaryReply(void)
|
static void serializeDataflashSummaryReply(void)
|
||||||
{
|
{
|
||||||
headSerialReply(3 * 4);
|
headSerialReply(1 + 3 * 4);
|
||||||
#ifdef FLASHFS
|
#ifdef FLASHFS
|
||||||
const flashGeometry_t *geometry = flashfsGetGeometry();
|
const flashGeometry_t *geometry = flashfsGetGeometry();
|
||||||
|
serialize8(flashfsIsReady() ? 1 : 0);
|
||||||
serialize32(geometry->sectors);
|
serialize32(geometry->sectors);
|
||||||
serialize32(geometry->totalSize);
|
serialize32(geometry->totalSize);
|
||||||
serialize32(flashfsGetOffset()); // Effectively the current number of bytes stored on the volume
|
serialize32(flashfsGetOffset()); // Effectively the current number of bytes stored on the volume
|
||||||
#else
|
#else
|
||||||
|
serialize8(0);
|
||||||
serialize32(0);
|
serialize32(0);
|
||||||
serialize32(0);
|
serialize32(0);
|
||||||
serialize32(0);
|
serialize32(0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue