| 808 | } |
| 809 | |
| 810 | fl::json AutoResearchRemoteControl::runParallelTestImpl(const fl::json& args) { |
| 811 | fl::json response = fl::json::object(); |
| 812 | |
| 813 | // Expects: {drivers: [{driver: "PARLIO", laneSizes: [100]}, {driver: "LCD_RGB", laneSizes: [100]}], |
| 814 | // pattern?: "MSB_LSB_A", iterations?: 1, timing?: "WS2812B-V5"} |
| 815 | if (!args.is_object()) { |
| 816 | response.set("success", false); |
| 817 | response.set("error", "InvalidArgs"); |
| 818 | response.set("message", "Expected {drivers: [{driver, laneSizes}, ...]}"); |
| 819 | return response; |
| 820 | } |
| 821 | |
| 822 | fl::json config = args; |
| 823 | |
| 824 | // 1. Extract drivers array (required) |
| 825 | if (!config.contains("drivers") || !config["drivers"].is_array()) { |
| 826 | response.set("success", false); |
| 827 | response.set("error", "MissingDrivers"); |
| 828 | response.set("message", "Required field 'drivers' (array of {driver, laneSizes}) missing"); |
| 829 | return response; |
| 830 | } |
| 831 | |
| 832 | fl::json drivers_json = config["drivers"]; |
| 833 | if (drivers_json.size() < 2) { |
| 834 | response.set("success", false); |
| 835 | response.set("error", "TooFewDrivers"); |
| 836 | response.set("message", "Parallel test requires at least 2 drivers"); |
| 837 | return response; |
| 838 | } |
| 839 | |
| 840 | // 2. Extract shared optional parameters |
| 841 | fl::string pattern = "MSB_LSB_A"; |
| 842 | if (config.contains("pattern") && config["pattern"].is_string()) { |
| 843 | pattern = config["pattern"].as_string().value(); |
| 844 | } |
| 845 | |
| 846 | int iterations = 1; |
| 847 | if (config.contains("iterations") && config["iterations"].is_int()) { |
| 848 | iterations = static_cast<int>(config["iterations"].as_int().value()); |
| 849 | if (iterations < 1) iterations = 1; |
| 850 | } |
| 851 | |
| 852 | fl::string timing_name = "WS2812B-V5"; |
| 853 | if (config.contains("timing") && config["timing"].is_string()) { |
| 854 | timing_name = config["timing"].as_string().value(); |
| 855 | } |
| 856 | |
| 857 | // Get timing configuration |
| 858 | fl::ChipsetTimingConfig resolved_timing; |
| 859 | fl::ClocklessEncoder resolved_encoder = fl::ClocklessEncoder::CLOCKLESS_ENCODER_WS2812; |
| 860 | if (timing_name == "UCS7604-800KHZ") { |
| 861 | resolved_timing = fl::makeTimingConfig<fl::TIMING_UCS7604_800KHZ>(); |
| 862 | resolved_encoder = fl::encoder_for<fl::TIMING_UCS7604_800KHZ>(); |
| 863 | } else { |
| 864 | resolved_timing = fl::makeTimingConfig<fl::TIMING_WS2812B_V5>(); |
| 865 | resolved_encoder = fl::encoder_for<fl::TIMING_WS2812B_V5>(); |
| 866 | } |
| 867 | fl::NamedTimingConfig timing_config(resolved_timing, timing_name.c_str(), resolved_encoder); |
no test coverage detected