-
Notifications
You must be signed in to change notification settings - Fork 102
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
1 changed file
with
142 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
/* | ||
* lookup_tables.c | ||
* | ||
* Created on: Nov. 17, 2023 | ||
* Author: Kenneth | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "functions.h" | ||
#include "stdbool.h" | ||
|
||
|
||
//setup circular dependence | ||
void __scale_t_SetResult(scale_t * scale, scale_result_t * result) { | ||
scale->Result = result; | ||
result->Scale = scale; | ||
} | ||
|
||
void ScaleSearchBinary(scale_t * scale, scale_functions_t * functions); | ||
|
||
void Scale(scale_t * scale, scale_functions_t * functions) { | ||
scale_result_t * result = scale->Result; | ||
|
||
functions->SetValue(result->ScaledValue, scale->SourceValue); //ensure value is maintained from here | ||
|
||
result->IndexHigh = scale->Length - 1; | ||
result->IndexLow = 0; | ||
|
||
void * scaleHigh = functions->GetArrayValue(scale->Data, result->IndexHigh); | ||
void * scaleLow = functions->GetArrayValue(scale->Data, result->IndexLow); | ||
|
||
bool boundHigh = functions->Compare(result->ScaledValue, scaleHigh) >= 0; | ||
bool boundLow = functions->Compare(result->ScaledValue, scaleLow) <= 0; | ||
|
||
|
||
if (boundHigh || boundLow) { | ||
if (boundHigh) { | ||
result->IndexLow = result->IndexHigh; | ||
} else { | ||
result->IndexHigh = result->IndexLow; | ||
} | ||
functions->SetValue(result->ScaledValue, scaleLow); //bring within scale limits | ||
} else { | ||
ScaleSearchBinary(scale, functions); | ||
} | ||
} | ||
|
||
|
||
/* | ||
Scale lookup using binary search pattern. | ||
Uses recursion to minimise FLASH at the expense of stack use. | ||
NOTE: If you could gaurantee the scale data was linear, this could be simplified a long way as follows | ||
Low index = Data length (items in array) * input value / highest value in the array: LI = (DL * IV) / HV | ||
*/ | ||
void Scale_rec(scale_result_t * result, void * data, void * toFind, uint8_t min, uint8_t max, scale_functions_t * functions); | ||
|
||
void ScaleSearchBinary(scale_t * scale, scale_functions_t * functions) | ||
{ | ||
scale_result_t * result = scale->Result; | ||
Scale_rec(result, scale->Data, result->ScaledValue, result->IndexLow, result->IndexHigh, functions); | ||
} | ||
|
||
|
||
void Scale_rec(scale_result_t * result, void * data, void * toFind, uint8_t min, uint8_t max, scale_functions_t * functions) | ||
{ | ||
uint8_t index = (min + max) >> 1; //find the half way point between min and max, efectively using a binary search | ||
|
||
void * value = functions->GetArrayValue(data, index); | ||
int cmp = functions->Compare(value, toFind); | ||
|
||
if (cmp == 0) { | ||
min = index; | ||
max = index; | ||
} else if (cmp > 0) { | ||
max = index--; // set high pointer to current place in table, decrement current to check one below | ||
value = functions->GetArrayValue(data, index); | ||
if (functions->Compare(value, toFind) < 0) | ||
{ | ||
min = index; | ||
} | ||
} else if (cmp < 0) { | ||
min = index++; //set min point to current, then increment to test if max found too. | ||
value = functions->GetArrayValue(data, index); | ||
if (functions->Compare(value, toFind) > 0) | ||
{ | ||
max = index; | ||
} | ||
} | ||
// Indicates either values are found, or we are at the end of the search (min or max) | ||
if (max - min < 2) { | ||
result->IndexLow = min; | ||
result->IndexHigh = max; | ||
} else { | ||
Scale_rec(result, data, toFind, min, max, functions); | ||
} | ||
} | ||
|
||
|
||
void MapLookup(map_t * map, void * result, scale_functions_t * functions) { | ||
scale_result_t * scaleResult = map->ScaledValue; | ||
uint8_t low = scaleResult->IndexLow; | ||
uint8_t high = scaleResult->IndexHigh; | ||
void * scaleHigh = functions->GetArrayValue(scaleResult->Scale->Data, high); | ||
void * scaleLow = functions->GetArrayValue(scaleResult->Scale->Data, low); | ||
|
||
void * scaleValue = scaleResult->ScaledValue; | ||
|
||
//No need to do interpolation if we have a direct map | ||
if (high == low) { | ||
functions->SetValue(result, functions->GetArrayValue(map->Data, low)); | ||
} else { | ||
functions->MapValue(result, scaleResult->ScaledValue, scaleLow, scaleHigh, functions->GetArrayValue(map->Data, low), functions->GetArrayValue(map->Data, high)); | ||
} | ||
} | ||
|
||
void __scale_functions_t_map_int(void * result, void * source, void * sourceLow, void * sourceHigh, void * mapLow, void * mapHigh) { | ||
int32_t scaleFactor = (*(int16_t*)mapHigh - *(int16_t*)mapLow) * (*(int16_t*)source - *(int16_t*)sourceLow); | ||
int32_t scaleRange = *(int16_t*)sourceHigh - *(int16_t*)sourceLow; | ||
int offset = (scaleFactor / scaleRange); | ||
*(int16_t*)result = offset + *(int16_t*)mapLow; | ||
} | ||
void * __scale_functions_t_get_array_value_int(void * data, uint8_t index) { | ||
int16_t * intData = (int16_t*)data; //need to cast the array first, so that you get the right data size. | ||
return &(intData[index]); | ||
} | ||
|
||
int __scale_functions_t_compare_int(const void * a, const void * b ) { | ||
return *(int16_t*)a - *(int16_t*)b; | ||
} | ||
void __scale_functions_t_set_value_int(const void * a, const void * b ) { | ||
*(uint16_t*)a = *(uint16_t*)b; | ||
} | ||
|
||
void SetScaleFunctions_int(scale_functions_t * functions) { | ||
functions->Compare = __scale_functions_t_compare_int; | ||
functions->GetArrayValue = __scale_functions_t_get_array_value_int; | ||
functions->MapValue = __scale_functions_t_map_int; | ||
functions->SetValue = __scale_functions_t_set_value_int; | ||
} |