// // Created by rhetenor on 04.10.18. // #include "OutputDriverFactory.h" #include "utility/LoggerFactory.h" #include "output/detail/DisplayController.h" #include "output/detail/SoundBoardPinController.h" #include "output/detail/DisplayBoardPinController.h" #include "output/detail/DriverBoardPinController.h" #include "output/items/detail/EightDigitDisplay.h" #include "output/items/detail/SevenDigitDisplay.h" #include "output/items/Flipper.h" namespace flippR_driver { namespace output { namespace OutputDriverFactory { using namespace nlohmann; std::shared_ptr get_OutputDriver(std::istream& solenoid_config, std::istream& lamp_config, std::istream& sound_config, std::istream& display_config) { utility::LoggerFactory::CreateOutputLogger(); std::shared_ptr output_pin_mutex; std::shared_ptr driver_board_pin_controller(new detail::DriverBoardPinController(output_pin_mutex)); auto solenoids = create_solenoids(solenoid_config, driver_board_pin_controller); auto flippers = create_flippers(solenoid_config, driver_board_pin_controller); auto lamps = create_lamps(lamp_config, driver_board_pin_controller); uint8_t sound_fire_address = get_sound_fire_address(sound_config); std::shared_ptr sound_board_pin_controller(new detail::SoundBoardPinController(output_pin_mutex, sound_fire_address)); auto sounds = create_sounds(sound_config, sound_board_pin_controller); std::unique_ptr display_board_pin_controller(new detail::DisplayBoardPinController(parse_pins_display_board(display_config))); auto displays = create_displays(display_config); std::unique_ptr display_controller(new detail::DisplayController(displays, std::move(display_board_pin_controller))); auto display_map = map_displays(displays); return std::make_shared(std::move(display_controller), solenoids, lamps, sounds, flippers, display_map); } std::map> create_solenoids(std::istream & solenoid_config, std::shared_ptr &pin_controller) { solenoid_config.clear(); json solenoid_config_json; solenoid_config >> solenoid_config_json; json port_extenders = get_element("port_extenders", solenoid_config_json, ""); initialize_port_extenders(port_extenders, pin_controller.get(), "solenoid_config.json"); json solenoids_json = get_element("solenoids", solenoid_config_json, "solenoid_config.json"); std::chrono::milliseconds deactivation_time{ get_value("deactivation_time_milliseconds", solenoid_config_json, "solenoid_config.json") }; std::map> solenoids; for(auto &solenoid_json : solenoids_json) { auto solenoid = create_solenoid(solenoid_json, port_extenders, pin_controller, deactivation_time); solenoids.emplace(solenoid->get_name(), solenoid); } return solenoids; } std::shared_ptr create_solenoid(nlohmann::json &solenoid_json, nlohmann::json &port_extenders, std::shared_ptr &pin_controller, std::chrono::milliseconds deactivation_time) { solenoid_json.clear(); std::string config_file_name = "solenoid_config.json"; uint8_t pin_base = get_pin_base(solenoid_json, port_extenders, config_file_name); auto name = get_value("name", solenoid_json, config_file_name); auto address = get_value("address", solenoid_json, config_file_name); if(solenoid_json.find("deactivation_time_milliseconds") != solenoid_json.end()) { deactivation_time = std::chrono::milliseconds(get_value("deactivation_time_milliseconds", solenoid_json, config_file_name)); } return std::make_shared(pin_controller, address, pin_base, name, deactivation_time); } std::map> create_flippers(std::istream &solenoid_config, std::shared_ptr &pin_controller) { solenoid_config.clear(); json solenoid_config_json; solenoid_config >> solenoid_config_json; json port_extenders = get_element("port_extenders", solenoid_config_json, "solenoid_config.json"); json flippers_json = get_element("flippers", solenoid_config_json, "solenoid_config.json"); std::chrono::milliseconds deactivation_time{ get_value("deactivation_time_milliseconds", solenoid_config_json, "solenoid_config.json") }; std::map> flippers; for(auto &flipper_json : flippers_json) { auto flipper = create_flipper(flipper_json, port_extenders, pin_controller); flippers.emplace(flipper->get_name(), flipper); } return flippers; } std::shared_ptr create_flipper(nlohmann::json &flipper_json, json &port_extenders, std::shared_ptr &pin_controller) { std::string config_file_name = "solenoid_config.json"; uint8_t pin_base = get_pin_base(flipper_json, port_extenders, config_file_name); auto address = get_value("address", flipper_json, config_file_name); auto name = get_value("name", flipper_json, config_file_name); return std::make_shared(pin_controller, address, pin_base, name); } std::map> create_lamps(std::istream &lamp_config, std::shared_ptr &pin_controller) { lamp_config.clear(); json lamp_config_json; lamp_config >> lamp_config_json; json port_extenders = get_element("port_extenders", lamp_config_json, "lamp_config.json"); initialize_port_extenders(port_extenders, pin_controller.get(), "lamp_config.json"); json solenoids_json = get_element("lamps", lamp_config_json, "lamp_config.json"); std::map> lamps; for(auto &solenoid_json : solenoids_json) { auto solenoid = create_lamp(solenoid_json, port_extenders, pin_controller); lamps.emplace(solenoid->get_name(), solenoid); } return lamps; } std::shared_ptr create_lamp(json &lamp_json, json & port_extenders, std::shared_ptr &pin_controller) { std::string config_file_name = "lamps_config.json"; uint8_t pin_base = get_pin_base(lamp_json, port_extenders, config_file_name); auto address = get_value("address", lamp_json, config_file_name); auto name = get_value("name", lamp_json, config_file_name); return std::make_shared(pin_controller, address, pin_base, name); } std::map> create_sounds(std::istream &sound_config, std::shared_ptr &pin_controller) { sound_config.clear(); json sound_config_json; sound_config >> sound_config_json; json port_extenders = get_element("port_extenders", sound_config_json, "sound_config.json"); initialize_port_extenders(port_extenders, pin_controller.get(), "sound_config.json"); std::chrono::milliseconds deactivation_time{ get_value("deactivation_time_milliseconds", sound_config_json, "solenoid_config.json") }; json solenoids_json = get_element("sounds", sound_config_json, "sound_config.json"); std::map> sounds; for(auto &solenoid_json : solenoids_json) { auto solenoid = create_sound(solenoid_json, port_extenders, pin_controller, deactivation_time); sounds.emplace(solenoid->get_name(), solenoid); } return sounds; } std::shared_ptr create_sound(json &sound_json, json &port_extenders, std::shared_ptr &pin_controller, std::chrono::milliseconds &deactivation_time) { std::string config_file_name = "sound_config.json"; uint8_t pin_base = get_pin_base(sound_json, port_extenders, config_file_name); auto address = get_value("address", sound_json, config_file_name); auto name = get_value("name", sound_json, config_file_name); auto id = get_value("id", sound_json, config_file_name); return std::make_shared(pin_controller, address, pin_base, name, deactivation_time, id); } uint8_t get_sound_fire_address(std::istream &sound_config) { sound_config.clear(); json sound_config_json; sound_config >> sound_config_json; json port_extenders = get_element("port_extenders", sound_config_json, "sound_config.json"); json fire_pin = get_element("fire_pin", sound_config_json, "sound_config.json"); auto pin_base = get_pin_base(fire_pin, port_extenders, "sound_config.json"); auto address = get_value("address", fire_pin, "sound_config.json"); return pin_base + address; } std::map parse_pins_display_board(std::istream &display_config) { display_config.clear(); std::string config_file = "display_config.json"; json display_config_json; display_config >> display_config_json; json display_board_config = get_element("display_board", display_config_json, config_file); std::map pins_display; pins_display["run"] = get_value("run", display_board_config, config_file); json display_select = display_board_config.at("display_select"); for(int i = 1; i < 6; i++) { pins_display["display_select" + std::to_string(i)] = get_value(std::to_string(i), display_select, config_file); } json segment_select = display_board_config.at("segment_select"); pins_display["segment_select_A"] = get_value("A", segment_select, config_file); pins_display["segment_select_B"] = get_value("B", segment_select, config_file); pins_display["segment_select_C"] = get_value("C", segment_select, config_file); json digit_select = display_board_config.at("digit_select"); pins_display["digit_select_A"] = get_value("A", digit_select, config_file); pins_display["digit_select_B"] = get_value("B", digit_select, config_file); pins_display["digit_select_C"] = get_value("C", digit_select, config_file); pins_display["digit_select_D"] = get_value("D", digit_select, config_file);; return pins_display; } std::vector> create_displays(std::istream &display_config) { display_config.clear(); json display_config_json; display_config >> display_config_json; json displays_json = get_element("displays", display_config_json, "display_config.json"); std::vector> displays; for(json &display_json : displays_json) { auto display = create_display(display_json); displays.push_back(display); } return displays; } std::shared_ptr create_display(json & display_json) { std::string config_file = "display_config.json"; auto id = get_value("id", display_json, config_file); auto address = get_value("address", display_json, config_file); auto digits = get_value("digits", display_json, config_file); if(digits == 8) return std::make_shared(address, id); else if(digits == 7) return std::make_shared(address, id); else throw new std::logic_error("Display digits can either be 7 or 8"); } std::map> map_displays(const std::vector> &displays) { std::map> display_map; for(auto &display : displays) { display_map.emplace(display->get_address(), display); } return display_map; } void initialize_port_extenders(json &port_extenders, PinController * pin_controller, const std::string & file_name) { for (auto & extender_json : port_extenders) { auto i2c_address = get_value("i2c_address", extender_json, file_name); auto pin_base = get_value("pin_base", extender_json, file_name); pin_controller->initialize_port_expander(i2c_address, pin_base); } } uint8_t get_pin_base(json & object, json & port_extenders, const std::string & config_file_name) { uint8_t pin_base{ 0 }; if(object.find("extender") != object.end()) { auto extender_name = get_value("extender", object, config_file_name); for (auto & extender : port_extenders) { auto actual_extender = get_value("name", extender, config_file_name); if (actual_extender == extender_name) { pin_base = get_value("pin_base", extender, config_file_name); } } } return pin_base; } json get_element(const std::string & name, json & object, const std::string & file_name) { json sub_object; try { sub_object = object.at(name); } catch(json::exception &e) { CLOG(ERROR, OUTPUT_LOGGER) << "File " << file_name << " seems to be corrupted at " << name << ": " << e.what(); exit(EXIT_FAILURE); } return sub_object; } template type get_value(const std::string & name, json & object, const std::string & file_name) { type element; try { element = object.at(name).get(); } catch(json::exception &e) { CLOG(ERROR, OUTPUT_LOGGER) << "File " << file_name << " seems to be corrupted at " << name << ": " << e.what(); exit(EXIT_FAILURE); } return element; } } } }