Skip to content

Commit cb74da3

Browse files
committed
Use a mutating page_iterator_t to map an offset to an entity, replace macros with functions.
1 parent a0406d0 commit cb74da3

File tree

3 files changed

+117
-130
lines changed

3 files changed

+117
-130
lines changed

speeduino/pages.cpp

Lines changed: 73 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -239,98 +239,57 @@ bool setEntityValue(page_iterator_t &entity, uint16_t offset, byte value)
239239
}
240240
}
241241

242-
// ========================= Static page size computation & checking ===================
243-
244-
// Since pages are a logical contiguous block, we can automatically compute the
245-
// logical start address of every item: the first one starts at zero, following
246-
// items must start at the end of the previous.
247-
#define ENTITY_START_VAR entityStartAddress
248-
// Compute the start address of the next entity. We need this to be a constexpr
249-
// so we can static assert on it later. So we cannot increment an exiting var.
250-
#define UPDATE_ENTITY_START(entitySize) ENTITY_START_VAR = ENTITY_START_VAR + (entitySize);
251-
//
252-
#define ITEM_INDEX_VAR itemIndex
253-
#define UPDATE_ITEM_INDEX() ++ITEM_INDEX_VAR;
254-
255-
// ========================= Logical page end processing ===================
242+
// ========================= Offset to entity support ===================
256243

257-
// The members of all page_iterator_t instances are compile time constants and
258-
// thus all page_iterator_t instances *could* be compile time constants.
259-
//
260-
// If we declare them inline as part of return statements, gcc recognises they
261-
// are constants (even without constexpr). Constants need to be stored somewhere:
262-
// gcc places them in the .data section, which is placed in SRAM :-(.
263-
//
264-
// So we would end up using several hundred bytes of SRAM.
265-
//
266-
// Instead we use this (and other) intermediate factory function(s) - it provides a barrier that
267-
// forces GCC to construct the page_iterator_t instance at runtime.
268-
static inline page_iterator_t create_end_iterator(uint8_t pageNum, uint8_t index, uint16_t start)
244+
void nextEntity(page_iterator_t &entity, uint16_t nextBlockSize)
269245
{
270-
return page_iterator_t( End,
271-
entity_page_location_t(pageNum, index),
272-
entity_page_address_t(start, 0U));
246+
++entity.location.index;
247+
entity.address = entity.address.next(nextBlockSize);
273248
}
274249

275-
// Signal the end of a page
276-
#define END_OF_PAGE(pageNum) return create_end_iterator((pageNum), ITEM_INDEX_VAR, ENTITY_START_VAR);
277-
278250
// ========================= Table processing ===================
279251

280-
static inline page_iterator_t create_table_iterator(void *pTable, table_type_t key, uint8_t pageNum, uint8_t index, uint16_t start, uint16_t size)
252+
template <class table_t>
253+
static void checkIsInTable(page_iterator_t &result, table_t *pTable, uint16_t offset)
281254
{
282-
return page_iterator_t( pTable, key,
283-
entity_page_location_t(pageNum, index),
284-
entity_page_address_t(start, size));
255+
if (result.type==End)
256+
{
257+
nextEntity(result, get_table_axisy_end(pTable));
258+
if (result.address.isOffsetInEntity(offset))
259+
{
260+
result.setTable(pTable, pTable->type_key);
261+
}
262+
}
285263
}
286264

287-
// If the offset is in range, create a Table entity_t
288-
#define CHECK_TABLE(pageNum, offset, pTable) \
289-
if (offset < ENTITY_START_VAR+get_table_axisy_end(pTable)) \
290-
{ \
291-
return create_table_iterator(pTable, (pTable)->type_key, \
292-
(pageNum), ITEM_INDEX_VAR, \
293-
ENTITY_START_VAR, get_table_axisy_end((pTable))); \
294-
} \
295-
UPDATE_ENTITY_START(get_table_axisy_end(pTable)) \
296-
UPDATE_ITEM_INDEX()
297-
298265
// ========================= Raw memory block processing ===================
299266

300-
static inline page_iterator_t create_raw_iterator(void *pBuffer, uint8_t pageNum, uint8_t index, uint16_t start, uint16_t size)
267+
static void checkIsInRaw(page_iterator_t &result, void *pEntity, uint16_t entitySize, uint16_t offset)
301268
{
302-
return page_iterator_t( pBuffer,
303-
entity_page_location_t(pageNum, index),
304-
entity_page_address_t(start, size));
269+
if (result.type==End)
270+
{
271+
nextEntity(result, entitySize);
272+
if (result.address.isOffsetInEntity(offset))
273+
{
274+
result.setRaw(pEntity);
275+
}
276+
}
305277
}
306278

307-
// If the offset is in range, create a Raw entity_t
308-
#define CHECK_RAW(pageNum, offset, pDataBlock, blockSize) \
309-
if (offset < ENTITY_START_VAR+blockSize) \
310-
{ \
311-
return create_raw_iterator((pDataBlock), (pageNum), ITEM_INDEX_VAR, ENTITY_START_VAR, (blockSize));\
312-
} \
313-
UPDATE_ENTITY_START(blockSize) \
314-
UPDATE_ITEM_INDEX()
315-
316279
// ========================= Empty entity processing ===================
317280

318-
static inline page_iterator_t create_empty_iterator(uint8_t pageNum, uint8_t index, uint16_t start, uint16_t size)
281+
static void checkIsInEmpty(page_iterator_t &result, uint16_t entitySize, uint16_t offset)
319282
{
320-
return page_iterator_t( NoEntity,
321-
entity_page_location_t(pageNum, index),
322-
entity_page_address_t(start, size));
283+
if (result.type==End)
284+
{
285+
nextEntity(result, entitySize);
286+
if (result.address.isOffsetInEntity(offset))
287+
{
288+
result.setNoEntity();
289+
}
290+
}
323291
}
324292

325-
// If the offset is in range, create a "no entity"
326-
#define CHECK_NOENTITY(pageNum, offset, blockSize) \
327-
if (offset < ENTITY_START_VAR+blockSize) \
328-
{ \
329-
return create_empty_iterator((pageNum), ITEM_INDEX_VAR, ENTITY_START_VAR, (blockSize));\
330-
} \
331-
UPDATE_ENTITY_START(blockSize) \
332-
UPDATE_ITEM_INDEX()
333-
334293
// ===============================================================================
335294

336295
// Does the heavy lifting of mapping page+offset to an entity
@@ -339,123 +298,130 @@ static inline page_iterator_t create_empty_iterator(uint8_t pageNum, uint8_t ind
339298
// That uses flash memory, which is scarce. And it was too slow.
340299
static page_iterator_t map_page_offset_to_entity(uint8_t pageNumber, uint16_t offset)
341300
{
342-
// The start address of the 1st entity in any page.
343-
uint16_t ENTITY_START_VAR = 0U;
344-
uint8_t ITEM_INDEX_VAR = 0U;
301+
// This is mutated by the checkIsIn* functions to return the entity that matches the offset
302+
page_iterator_t result( End, // Signal that no entity has been found yet
303+
entity_page_location_t(pageNumber, (uint8_t)-1 /* Deliberate, so we can increment index AND address as one operation */),
304+
entity_page_address_t(0U, 0U));
345305

346306
switch (pageNumber)
347307
{
348308
case veMapPage:
349309
// LCOV_EXCL_BR_START
350310
// The first entity on the page has a missing branch not covered
351-
// No idea why, so exclude froom branch coverage for the moment
352-
CHECK_TABLE(veMapPage, offset, &fuelTable)
311+
// No idea why, so exclude from branch coverage for the moment
312+
checkIsInTable(result, &fuelTable, offset);
353313
// LCOV_EXCL_BR_STOP
354314
break;
355315

356316
case ignMapPage: //Ignition settings page (Page 2)
357317
// LCOV_EXCL_BR_START
358-
CHECK_TABLE(ignMapPage, offset, &ignitionTable)
318+
checkIsInTable(result, &ignitionTable, offset);
359319
// LCOV_EXCL_BR_STOP
360320
break;
361321

362322
case afrMapPage: //Air/Fuel ratio target settings page
363323
// LCOV_EXCL_BR_START
364-
CHECK_TABLE(afrMapPage, offset, &afrTable)
324+
checkIsInTable(result, &afrTable, offset);
365325
// LCOV_EXCL_BR_STOP
366326
break;
367327

368328
case boostvvtPage: //Boost, VVT and staging maps (all 8x8)
369329
// LCOV_EXCL_BR_START
370-
CHECK_TABLE(boostvvtPage, offset, &boostTable)
330+
checkIsInTable(result, &boostTable, offset);
371331
// LCOV_EXCL_BR_STOP
372-
CHECK_TABLE(boostvvtPage, offset, &vvtTable)
373-
CHECK_TABLE(boostvvtPage, offset, &stagingTable)
332+
checkIsInTable(result, &vvtTable, offset);
333+
checkIsInTable(result, &stagingTable, offset);
374334
break;
375335

376336
case seqFuelPage:
377337
// LCOV_EXCL_BR_START
378-
CHECK_TABLE(seqFuelPage, offset, &trim1Table)
338+
checkIsInTable(result, &trim1Table, offset);
379339
// LCOV_EXCL_BR_STOP
380-
CHECK_TABLE(seqFuelPage, offset, &trim2Table)
381-
CHECK_TABLE(seqFuelPage, offset, &trim3Table)
382-
CHECK_TABLE(seqFuelPage, offset, &trim4Table)
383-
CHECK_TABLE(seqFuelPage, offset, &trim5Table)
384-
CHECK_TABLE(seqFuelPage, offset, &trim6Table)
385-
CHECK_TABLE(seqFuelPage, offset, &trim7Table)
386-
CHECK_TABLE(seqFuelPage, offset, &trim8Table)
340+
checkIsInTable(result, &trim2Table, offset);
341+
checkIsInTable(result, &trim3Table, offset);
342+
checkIsInTable(result, &trim4Table, offset);
343+
checkIsInTable(result, &trim5Table, offset);
344+
checkIsInTable(result, &trim6Table, offset);
345+
checkIsInTable(result, &trim7Table, offset);
346+
checkIsInTable(result, &trim8Table, offset);
387347
break;
388348

389349
case fuelMap2Page:
390350
// LCOV_EXCL_BR_START
391-
CHECK_TABLE(fuelMap2Page, offset, &fuelTable2)
351+
checkIsInTable(result, &fuelTable2, offset);
392352
// LCOV_EXCL_BR_STOP
393353
break;
394354

395355
case wmiMapPage:
396356
// LCOV_EXCL_BR_START
397-
CHECK_TABLE(wmiMapPage, offset, &wmiTable)
357+
checkIsInTable(result, &wmiTable, offset);
398358
// LCOV_EXCL_BR_STOP
399-
CHECK_TABLE(wmiMapPage, offset, &vvt2Table)
400-
CHECK_TABLE(wmiMapPage, offset, &dwellTable)
401-
CHECK_NOENTITY(wmiMapPage, offset, 8U)
359+
checkIsInTable(result, &vvt2Table, offset);
360+
checkIsInTable(result, &dwellTable, offset);
361+
checkIsInEmpty(result, 8U, offset);
402362
break;
403363

404364
case ignMap2Page:
405365
// LCOV_EXCL_BR_START
406-
CHECK_TABLE(ignMap2Page, offset, &ignitionTable2)
366+
checkIsInTable(result, &ignitionTable2, offset);
407367
// LCOV_EXCL_BR_STOP
408368
break;
409369

410370
case veSetPage:
411371
// LCOV_EXCL_BR_START
412-
CHECK_RAW(veSetPage, offset, &configPage2, sizeof(configPage2))
372+
checkIsInRaw(result, &configPage2, sizeof(configPage2), offset);
413373
// LCOV_EXCL_BR_STOP
414374
break;
415375

416376
case ignSetPage:
417377
// LCOV_EXCL_BR_START
418-
CHECK_RAW(ignSetPage, offset, &configPage4, sizeof(configPage4))
378+
checkIsInRaw(result, &configPage4, sizeof(configPage4), offset);
419379
// LCOV_EXCL_BR_STOP
420380
break;
421381

422382
case afrSetPage:
423383
// LCOV_EXCL_BR_START
424-
CHECK_RAW(afrSetPage, offset, &configPage6, sizeof(configPage6))
384+
checkIsInRaw(result, &configPage6, sizeof(configPage6), offset);
425385
// LCOV_EXCL_BR_STOP
426386
break;
427387

428388
case canbusPage:
429389
// LCOV_EXCL_BR_START
430-
CHECK_RAW(canbusPage, offset, &configPage9, sizeof(configPage9))
390+
checkIsInRaw(result, &configPage9, sizeof(configPage9), offset);
431391
// LCOV_EXCL_BR_STOP
432392
break;
433393

434394
case warmupPage:
435395
// LCOV_EXCL_BR_START
436-
CHECK_RAW(warmupPage, offset, &configPage10, sizeof(configPage10))
396+
checkIsInRaw(result, &configPage10, sizeof(configPage10), offset);
437397
// LCOV_EXCL_BR_STOP
438398
break;
439399

440400
case progOutsPage:
441401
// LCOV_EXCL_BR_START
442-
CHECK_RAW(progOutsPage, offset, &configPage13, sizeof(configPage13))
402+
checkIsInRaw(result, &configPage13, sizeof(configPage13), offset);
443403
// LCOV_EXCL_BR_STOP
444404
break;
445405

446406
case boostvvtPage2: //Boost, VVT and staging maps (all 8x8)
447407
// LCOV_EXCL_BR_START
448-
CHECK_TABLE(boostvvtPage2, offset, &boostTableLookupDuty)
408+
checkIsInTable(result, &boostTableLookupDuty, offset);
449409
// LCOV_EXCL_BR_STOP
450-
CHECK_RAW(boostvvtPage2, offset, &configPage15, sizeof(configPage15))
410+
checkIsInRaw(result, &configPage15, sizeof(configPage15), offset);
451411
break;
452412

453413
default:
454414
// Nothing to do
455415
break;
456416
}
457417

458-
END_OF_PAGE(pageNumber)
418+
// Nothing matched, so we are at the end of the known entities for the page.
419+
if (result.type==End)
420+
{
421+
nextEntity(result, 0U);
422+
}
423+
424+
return result;
459425
}
460426

461427

@@ -469,7 +435,7 @@ uint8_t getPageCount(void)
469435
uint16_t getPageSize(byte pageNum)
470436
{
471437
page_iterator_t entity = map_page_offset_to_entity(pageNum, UINT16_MAX);
472-
return entity.address.start + entity.address.size;;
438+
return entity.address.start + entity.address.size;
473439
}
474440

475441
static inline uint16_t pageOffsetToEntityOffset(const page_iterator_t &entity, uint16_t pageOffset)

speeduino/pages.h

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,40 +93,58 @@ struct entity_page_address_t {
9393
, size(length)
9494
{
9595
}
96+
97+
/**
98+
* @brief Check if the offset is within the entity address range
99+
*
100+
* @param offset Address offset from the start of the page
101+
* @return if the offset is within the entity address range, false otherwise
102+
*/
103+
bool isOffsetInEntity(uint16_t offset) const
104+
{
105+
return offset >= start && offset < start+size;
106+
}
107+
108+
entity_page_address_t next(uint16_t nextBlockSize) const
109+
{
110+
return entity_page_address_t(start+size, nextBlockSize);
111+
}
96112
};
97113

98114
// A entity on a logical page.
99115
struct page_iterator_t {
100-
void *pData;
116+
void *pData = nullptr;
101117
entity_type type;
102-
table_type_t table_key;
118+
table_type_t table_key = table_type_None;
103119
entity_page_location_t location;
104120
entity_page_address_t address;
105121

106122
page_iterator_t(entity_type theType, const entity_page_location_t &entityLocation, const entity_page_address_t &entityAddress)
107-
: pData(nullptr)
108-
, type(theType)
109-
, table_key(table_type_None)
123+
: type(theType)
110124
, location(entityLocation)
111125
, address(entityAddress)
112126
{
113127
}
114128

115-
page_iterator_t(void *pBuffer, const entity_page_location_t &entityLocation, const entity_page_address_t &entityAddress)
116-
: pData(pBuffer)
117-
, type(Raw)
118-
, table_key(table_type_None)
119-
, location(entityLocation)
120-
, address(entityAddress)
129+
void setNoEntity(void)
121130
{
131+
pData = nullptr;
132+
type = NoEntity;
133+
table_key = table_type_None;
122134
}
123-
page_iterator_t(void *pTable, table_type_t key, const entity_page_location_t &entityLocation, const entity_page_address_t &entityAddress)
124-
: pData(pTable)
125-
, type(Table)
126-
, table_key(key)
127-
, location(entityLocation)
128-
, address(entityAddress)
135+
136+
void setTable(void *pTable, table_type_t key)
137+
{
138+
pData = pTable;
139+
type = Table;
140+
table_key = key;
141+
}
142+
143+
void setRaw(void *pBuffer)
129144
{
145+
pData = pBuffer;
146+
type = Raw;
147+
table_key = table_type_None;
130148
}
131149
};
132150

0 commit comments

Comments
 (0)