Initial detection of modules

This commit is contained in:
ZodiusInfuser 2023-08-02 00:14:58 +01:00
parent fcd88de69b
commit 193211b772
4 changed files with 214 additions and 26 deletions

View File

@ -7,6 +7,7 @@ project(pico_examples C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(PICO_CXX_ENABLE_EXCEPTIONS 1)
set(PICO_CXX_ENABLE_RTTI 1)
# Initialize the SDK
pico_sdk_init()

View File

@ -26,6 +26,8 @@ Yukon y = Yukon();
int main() {
stdio_init_all();
y.change_logging(3);
// Initialise the servo
y.init();
@ -35,6 +37,17 @@ int main() {
sleep_ms(1000);
printf("tud_cdc_connected()\n");
y.find_slots_with_module(LEDStripModule::info());
y.find_slots_with_module(DualSwitchedModule::info());
y.find_slots_with_module(BenchPowerModule::info());
//y.detect_module(Yukon::SLOT1);
//y.detect_module(Yukon::SLOT2);
//y.detect_module(Yukon::SLOT3);
//y.detect_module(Yukon::SLOT4);
//y.detect_module(Yukon::SLOT5);
//y.detect_module(Yukon::SLOT6);
try {
y.enable_main_output();

View File

@ -91,6 +91,32 @@ namespace pimoroni {
10, // ADC2_TEMP_ADDR (0b1010)
};
bool LEDStripModule::is_module(uint adc_level, bool slow1, bool slow2, bool slow3) {
return adc_level == ADC_LOW && slow1 == HIGH && slow2 == HIGH && slow3 == HIGH;
}
bool DualMotorModule::is_module(uint adc_level, bool slow1, bool slow2, bool slow3) {
return adc_level == ADC_HIGH && slow2 == HIGH && slow3 == HIGH;
}
bool DualSwitchedModule::is_module(uint adc_level, bool slow1, bool slow2, bool slow3) {
return adc_level == ADC_FLOAT && slow1 == HIGH && slow2 == LOW && slow3 == HIGH;
}
bool BenchPowerModule::is_module(uint adc_level, bool slow1, bool slow2, bool slow3) {
return slow1 == HIGH && slow2 == LOW && slow3 == LOW;
}
//module_callback Yukon::KNOWN_MODULES[] = {&LEDStripModule::is_module, &DualMotorModule::is_module};
//const std::type_index Yukon::KNOWN_MODULES[] = {typeid(LEDStripModule), typeid(DualMotorModule)};
const ModuleInfo Yukon::KNOWN_MODULES[] = {
LEDStripModule::info(),
DualMotorModule::info(),
DualSwitchedModule::info(),
BenchPowerModule::info()
};
const TCA Yukon::MAIN_EN = {0, 6};
const TCA Yukon::USER_SW = {0, 7};
@ -253,25 +279,25 @@ namespace pimoroni {
return slot;
}
std::vector<uint> Yukon::find_slots_with_module(std::type_info module_type) {
std::vector<uint> Yukon::find_slots_with_module(ModuleInfo module_type) {
if(is_main_output()) {
throw std::runtime_error("Cannot find slots with modules whilst the main output is active\n");
}
logging.info("> Finding slots with '{module_type.NAME}' module\n");
logging.info("> Finding slots with '" + module_type.name + "' module\n");
std::vector<uint> slot_ids;
for(auto it = slot_assignments.begin(); it != slot_assignments.end(); it++) {
SLOT slot = it->first;
logging.info("[Slot" + std::to_string(slot.ID) + "] ");
std::type_info* detected = __detect_module(slot); // Need to have a return type that can be null
const ModuleInfo* detected = __detect_module(slot); // Need to have a return type that can be null
if(detected != nullptr && (*detected) == module_type) {
logging.info("Found '{detected.NAME}' module\n");
if(detected != nullptr && detected->type == module_type.type) {
logging.info("Found '" + detected->name + "' module\n");
slot_ids.push_back(slot.ID);
}
else {
logging.info("No '{module_type.NAME}` module\n");
logging.info("No '" + module_type.name + "' module\n");
}
}
@ -332,20 +358,72 @@ namespace pimoroni {
}
}
uint __match_module(uint adc_level, bool slow1, bool slow2, bool slow3) {
return 0; //TODO
const ModuleInfo* Yukon::__match_module(uint adc_level, bool slow1, bool slow2, bool slow3) {
for(uint i = 0; i < count_of(KNOWN_MODULES); i++) {
const ModuleInfo& m = KNOWN_MODULES[i];
//printf("%s\n", std::get<0>(KNOWN_MODULES[i]).name());
//printf("%s\n", std::get<1>(KNOWN_MODULES[i]).c_str());
//printf("%d\n", std::get<2>(KNOWN_MODULES[i])(adc_level, slow1, slow2, slow3));
//printf("%s\n", KNOWN_MODULES[i]..name());
if(m.is_module(adc_level, slow1, slow2, slow3)) {
return &m;
}
}
return nullptr;
}
std::type_info* __detect_module(uint slot_id) {
return nullptr; //TODO
const ModuleInfo* Yukon::__detect_module(SLOT slot) {
set_slow_config(slot.SLOW1, false);
set_slow_config(slot.SLOW2, false);
set_slow_config(slot.SLOW3, false);
get_slow_input(USER_SW);
__select_address(slot.ADC1_ADDR);
float adc_val = 0.0f;
for(uint i = 0; i < DETECTION_SAMPLES; i++) {
adc_val += __shared_adc_voltage();
}
adc_val /= DETECTION_SAMPLES;
bool slow1 = get_slow_input(slot.SLOW1);
bool slow2 = get_slow_input(slot.SLOW2);
bool slow3 = get_slow_input(slot.SLOW3);
logging.debug("ADC1 = " + std::to_string(adc_val) + ", SLOW1 = " + std::to_string((int)slow1) + ", SLOW2 = " + std::to_string((int)slow2) + ", SLOW3 = " + std::to_string((int)slow3) + ", ");
uint adc_level = ADC_FLOAT;
if(adc_val <= DETECTION_ADC_LOW) {
adc_level = ADC_LOW;
}
else if(adc_val >= DETECTION_ADC_HIGH) {
adc_level = ADC_HIGH;
}
const ModuleInfo* detected = __match_module(adc_level, slow1, slow2, slow3);
__deselect_address();
return detected;
}
std::type_info* __detect_module(SLOT slot) {
return nullptr; //TODO
const ModuleInfo* Yukon::detect_module(uint slot_id) {
if(is_main_output()) {
throw std::runtime_error("Cannot detect modules whilst the main output is active\n");
}
SLOT slot = __check_slot(slot_id);
return __detect_module(slot);
}
uint detect_module(uint slot) {
return 0;
}
uint detect_module(SLOT slot) {
return 0;
const ModuleInfo* Yukon::detect_module(SLOT slot) {
if(is_main_output()) {
throw std::runtime_error("Cannot detect modules whilst the main output is active\n");
}
slot = __check_slot(slot);
return __detect_module(slot);
}
void __expand_slot_list(std::vector<SLOT> slot_list) {
@ -535,8 +613,6 @@ namespace pimoroni {
return __shared_adc_voltage();
}
/*
float time();
void assign_monitor_action(void* callback_function);
*/
void Yukon::monitor() {

View File

@ -6,9 +6,101 @@
#include "errors.hpp"
#include <list>
#include <iostream>
#include <typeindex>
namespace pimoroni {
class YukonModule {
public:
//static const std::string NAME = "Unnamed";
static constexpr float ROOM_TEMP = 273.15f + 25.0f;
static constexpr float RESISTOR_AT_ROOM_TEMP = 10000.0f;
static constexpr float BETA = 3435;
static bool is_module(uint adc_level, bool slow1, bool slow2, bool slow3) {
return false;
}
};
enum ADC {
ADC_LOW = 0,
ADC_HIGH = 1,
ADC_FLOAT = 2,
ADC_ANY = 3
};
enum IO {
LOW = false,
HIGH = true
};
typedef bool (*module_callback)(uint, bool, bool, bool) ;
struct ModuleInfo {
std::type_index type;
std::string name;
module_callback is_module;
};
#define INFO_FUNC(module_name) \
static ModuleInfo info() { \
return { typeid(module_name), module_name::name(), &module_name::is_module }; \
}
class LEDStripModule : public YukonModule {
public:
//static const std::string NAME = "Unnamed";
static bool is_module(uint adc_level, bool slow1, bool slow2, bool slow3);
static std::string name() {
return "LED Strip";
}
INFO_FUNC(LEDStripModule)
};
class DualMotorModule : public YukonModule {
public:
//static const std::string NAME = "Unnamed";
static bool is_module(uint adc_level, bool slow1, bool slow2, bool slow3);
static std::string name() {
return "Dual Motor";
}
INFO_FUNC(DualMotorModule)
};
class DualSwitchedModule : public YukonModule {
public:
//static const std::string NAME = "Unnamed";
static bool is_module(uint adc_level, bool slow1, bool slow2, bool slow3);
static std::string name() {
return "Dual Switched Output";
}
INFO_FUNC(DualSwitchedModule)
};
class BenchPowerModule : public YukonModule {
public:
//static const std::string NAME = "Unnamed";
static bool is_module(uint adc_level, bool slow1, bool slow2, bool slow3);
static std::string name() {
return "Bench Power";
}
INFO_FUNC(BenchPowerModule)
};
struct TCA {
uint CHIP;
uint GPIO;
@ -67,6 +159,7 @@ namespace pimoroni {
}
};
class Yukon {
public:
static const SLOT SLOT1;
@ -126,6 +219,13 @@ namespace pimoroni {
static constexpr float DEFAULT_CURRENT_LIMIT = 20.0f;
static constexpr float DEFAULT_TEMPERATURE_LIMIT = 90.0f;
static constexpr float ABSOLUTE_MAX_VOLTAGE_LIMIT = 18.0f;
static const uint DETECTION_SAMPLES = 64;
static constexpr float DETECTION_ADC_LOW = 0.1f;
static constexpr float DETECTION_ADC_HIGH = 3.2f;
//static module_callback KNOWN_MODULES[];
static const ModuleInfo KNOWN_MODULES[];
private:
I2C i2c;
TCA9555 tca0;
@ -182,7 +282,6 @@ namespace pimoroni {
void set_slow_polarity(TCA gpio, bool polarity);
void change_output_mask(uint8_t chip, uint16_t mask, uint16_t state);
//--------------------------------------------------
void change_logging(uint logging_level);
@ -190,7 +289,7 @@ namespace pimoroni {
SLOT __check_slot(uint slot_id);
SLOT __check_slot(SLOT slot);
std::vector<uint> find_slots_with_module(std::type_info module_type);
std::vector<uint> find_slots_with_module(ModuleInfo module_type);
void register_with_slot(Module* module, uint slot_id);
void register_with_slot(Module* module, SLOT slot);
@ -198,11 +297,10 @@ namespace pimoroni {
void deregister_slot(uint slot_id);
void deregister_slot(SLOT slot);
uint __match_module(uint adc_level, bool slow1, bool slow2, bool slow3);
std::type_info* __detect_module(uint slot_id);
std::type_info* __detect_module(SLOT slot);
uint detect_module(uint slot_id);
uint detect_module(SLOT slot);
const ModuleInfo* __match_module(uint adc_level, bool slow1, bool slow2, bool slow3);
const ModuleInfo* __detect_module(SLOT slot);
const ModuleInfo* detect_module(uint slot_id);
const ModuleInfo* detect_module(SLOT slot);
void __expand_slot_list(std::vector<SLOT> slot_list);
void __verify_modules(bool allow_unregistered, bool allow_undetected, bool allow_discrepencies, bool allow_no_modules);