Replaced project configuration format from JSON to YAML

This commit is contained in:
Nav
2022-07-23 15:37:22 +01:00
parent cb577c7acd
commit ae5747e79b
13 changed files with 215 additions and 133 deletions

2
.gitignore vendored
View File

@@ -5,7 +5,7 @@ build/cmake-build-debug
build/cmake-build-release build/cmake-build-release
build/resources build/resources
build/bin/bloom build/bin/bloom
build/bin/bloom.json build/bin/bloom.yaml
*.deb *.deb
*.rpm *.rpm
*.pkg.tar.zst *.pkg.tar.zst

View File

@@ -10,6 +10,6 @@ Commands:
--help, -h Displays this help text. --help, -h Displays this help text.
--version, -v Displays Bloom's version number. --version, -v Displays Bloom's version number.
--version-machine Outputs Bloom's version number in JSON format. --version-machine Outputs Bloom's version number in JSON format.
init Creates a new Bloom project configuration file (bloom.json), in the working directory. init Creates a new Bloom project configuration file (bloom.yaml), in the working directory.
For more information on getting started with Bloom, please visit https://bloom.oscillate.io/docs/getting-started. For more information on getting started with Bloom, please visit https://bloom.oscillate.io/docs/getting-started.

View File

@@ -234,22 +234,22 @@ namespace Bloom
} }
void Application::loadProjectConfiguration() { void Application::loadProjectConfiguration() {
auto jsonConfigFile = QFile(QString::fromStdString(Paths::projectConfigPath())); auto configFile = QFile(QString::fromStdString(Paths::projectConfigPath()));
if (!jsonConfigFile.exists()) { if (!configFile.exists()) {
throw InvalidConfig("Bloom configuration file (bloom.json) not found. Working directory: " throw InvalidConfig("Bloom configuration file (bloom.yaml) not found. Working directory: "
+ Paths::projectDirPath()); + Paths::projectDirPath());
} }
if (!jsonConfigFile.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
throw InvalidConfig("Failed to load Bloom configuration file (bloom.json) Working directory: " throw InvalidConfig("Failed to open Bloom configuration file (bloom.yaml) Working directory: "
+ Paths::projectDirPath()); + Paths::projectDirPath());
} }
const auto jsonObject = QJsonDocument::fromJson(jsonConfigFile.readAll()).object(); const auto configNode = YAML::Load(configFile.readAll().toStdString());
jsonConfigFile.close(); configFile.close();
this->projectConfig = ProjectConfig(jsonObject); this->projectConfig = ProjectConfig(configNode);
// Validate the selected environment // Validate the selected environment
if (!this->projectConfig->environments.contains(this->selectedEnvironmentName)) { if (!this->projectConfig->environments.contains(this->selectedEnvironmentName)) {
@@ -337,7 +337,7 @@ namespace Bloom
auto configFile = QFile(QString::fromStdString(Paths::projectConfigPath())); auto configFile = QFile(QString::fromStdString(Paths::projectConfigPath()));
if (configFile.exists()) { if (configFile.exists()) {
throw Exception("Bloom configuration file (bloom.json) already exists in working directory."); throw Exception("Bloom configuration file (bloom.yaml) already exists in working directory.");
} }
/* /*
@@ -358,7 +358,7 @@ namespace Bloom
} }
if (!configFile.open(QIODevice::ReadWrite)) { if (!configFile.open(QIODevice::ReadWrite)) {
throw Exception("Failed to create Bloom configuration file (bloom.json)"); throw Exception("Failed to create Bloom configuration file (bloom.yaml)");
} }
configFile.write(templateConfigFile.readAll()); configFile.write(templateConfigFile.readAll());
@@ -366,7 +366,7 @@ namespace Bloom
configFile.close(); configFile.close();
templateConfigFile.close(); templateConfigFile.close();
Logger::info("Bloom configuration file (bloom.json) created in working directory."); Logger::info("Bloom configuration file (bloom.yaml) created in working directory.");
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -43,7 +43,7 @@ namespace Bloom::DebugServer
EventListenerPointer eventListener = std::make_shared<EventListener>("DebugServerEventListener"); EventListenerPointer eventListener = std::make_shared<EventListener>("DebugServerEventListener");
/** /**
* Project configuration for the debug server (extracted from the user project's bloom.json). * Project configuration for the debug server (extracted from the user project's bloom.yaml).
*/ */
DebugServerConfig debugServerConfig; DebugServerConfig debugServerConfig;
@@ -62,7 +62,7 @@ namespace Bloom::DebugServer
/** /**
* Returns a mapping of server configuration names to lambdas/std::functions. * Returns a mapping of server configuration names to lambdas/std::functions.
* *
* The server configuration name is what the user will use in their project configuration (bloom.json), when * The server configuration name is what the user will use in their project configuration (bloom.yaml), when
* selecting a debug server. It *must* be lower-case. * selecting a debug server. It *must* be lower-case.
* *
* The lambda should return an instance of the server implementation. * The lambda should return an instance of the server implementation.

View File

@@ -1,18 +1,27 @@
#include "GdbDebugServerConfig.hpp" #include "GdbDebugServerConfig.hpp"
#include "src/Helpers/YamlUtilities.hpp"
#include "src/Logger/Logger.hpp"
namespace Bloom::DebugServer::Gdb namespace Bloom::DebugServer::Gdb
{ {
GdbDebugServerConfig::GdbDebugServerConfig(const DebugServerConfig& debugServerConfig) GdbDebugServerConfig::GdbDebugServerConfig(const DebugServerConfig& debugServerConfig)
: DebugServerConfig(debugServerConfig) : DebugServerConfig(debugServerConfig)
{ {
if (debugServerConfig.jsonObject.contains("ipAddress")) { if (debugServerConfig.debugServerNode["ipAddress"]) {
this->listeningAddress = debugServerConfig.jsonObject.value("ipAddress").toString().toStdString(); if (!YamlUtilities::isType<std::string>(debugServerConfig.debugServerNode["ipAddress"])) {
Logger::error(
"Invalid GDB debug server config parameter ('ipAddress') provided - must be a string. The "
"parameter will be ignored."
);
} }
if (debugServerConfig.jsonObject.contains("port")) { this->listeningAddress = debugServerConfig.debugServerNode["ipAddress"].as<std::string>();
const auto portValue = debugServerConfig.jsonObject.value("port"); }
if (debugServerConfig.debugServerNode["port"]) {
this->listeningPortNumber = static_cast<std::uint16_t>( this->listeningPortNumber = static_cast<std::uint16_t>(
portValue.isString() ? portValue.toString().toInt(nullptr, 10) : portValue.toInt() debugServerConfig.debugServerNode["port"].as<int>()
); );
} }
} }

View File

@@ -11,7 +11,7 @@ connected AVR target, by implementing the
Each server must implement the interface defined in the [`ServerInterface` class](./ServerInterface.hpp). Each server must implement the interface defined in the [`ServerInterface` class](./ServerInterface.hpp).
At startup, the DebugServer will select the appropriate server implementation, based on the user's project At startup, the DebugServer will select the appropriate server implementation, based on the user's project
configuration (bloom.json - see [`DebugServerConfig`](../ProjectConfig.hpp)). Each server implementation is mapped to a configuration (bloom.yaml - see [`DebugServerConfig`](../ProjectConfig.hpp)). Each server implementation is mapped to a
config name, which is to be used in the project configuration file. For the mapping, see config name, which is to be used in the project configuration file. For the mapping, see
`DebugServerComponent::getAvailableServersByName()`. After initialising the server (via `ServerInterface::init()`), `DebugServerComponent::getAvailableServersByName()`. After initialising the server (via `ServerInterface::init()`),
control of the DebugServer thread will then be handed over to the server implementation (via `ServerInterface::run()`). control of the DebugServer thread will then be handed over to the server implementation (via `ServerInterface::run()`).

View File

@@ -34,12 +34,12 @@ namespace Bloom
} }
/** /**
* Returns the path to the current project's configuration file (bloom.json). * Returns the path to the current project's configuration file (bloom.yaml).
* *
* @return * @return
*/ */
static std::string projectConfigPath() { static std::string projectConfigPath() {
return Paths::projectDirPath() + "/bloom.json"; return Paths::projectDirPath() + "/bloom.yaml";
} }
/** /**

View File

@@ -1,111 +1,168 @@
#include "ProjectConfig.hpp" #include "ProjectConfig.hpp"
#include "src/Helpers/String.hpp"
#include "src/Logger/Logger.hpp" #include "src/Logger/Logger.hpp"
#include "src/Exceptions/InvalidConfig.hpp" #include "src/Exceptions/InvalidConfig.hpp"
namespace Bloom namespace Bloom
{ {
ProjectConfig::ProjectConfig(const QJsonObject& jsonObject) { ProjectConfig::ProjectConfig(const YAML::Node& configNode) {
if (!jsonObject.contains("environments")) { if (!configNode["environments"]) {
throw Exceptions::InvalidConfig( throw Exceptions::InvalidConfig(
"No environments found - please review the bloom.json configuration file and ensure that " "No environments found - please review the bloom.yaml configuration file and ensure that "
"no syntax errors are present." "no syntax errors are present."
); );
} }
// Extract all environment objects from JSON config. if (!configNode["environments"].IsMap()) {
auto environments = jsonObject.find("environments").value().toObject(); throw Exceptions::InvalidConfig(
"Invalid environments configuration provided - 'environments' must be of mapping type."
);
}
const auto& environments = configNode["environments"];
for (auto environmentIt = environments.begin(); environmentIt != environments.end(); environmentIt++) { for (auto environmentIt = environments.begin(); environmentIt != environments.end(); environmentIt++) {
auto environmentName = environmentIt.key().toStdString(); auto environmentName = std::optional<std::string>(std::nullopt);
try { try {
environmentName = environmentIt->first.as<std::string>();
if (!String::isAscii(environmentName.value())) {
throw Exceptions::InvalidConfig(
"Environment name ('" + environmentName.value() + "') is not in ASCII form."
);
}
this->environments.insert( this->environments.insert(
std::pair( std::pair(
environmentName, environmentName.value(),
EnvironmentConfig(environmentName, environmentIt.value().toObject()) EnvironmentConfig(environmentName.value(), environmentIt->second)
) )
); );
} catch (Exceptions::InvalidConfig& exception) { } catch (Exceptions::InvalidConfig& exception) {
Logger::error("Invalid environment config for environment '" + environmentName + "': " Logger::error(
+ exception.getMessage() + " Environment will be ignored."); "Invalid environment config for environment '" + environmentName.value() + "': "
+ exception.getMessage() + " Environment will be ignored."
);
} catch (YAML::BadConversion& exception) {
Logger::error(
"Invalid environment name provided. Environment names must be ASCII strings. Environment will be "
"ignored"
);
} }
} }
if (jsonObject.contains("debugServer")) { if (configNode["debugServer"]) {
this->debugServerConfig = DebugServerConfig(jsonObject.find("debugServer")->toObject()); this->debugServerConfig = DebugServerConfig(configNode["debugServer"]);
} }
if (jsonObject.contains("insight")) { if (configNode["insight"]) {
this->insightConfig = InsightConfig(jsonObject.find("insight")->toObject()); this->insightConfig = InsightConfig(configNode["insight"]);
} }
if (jsonObject.contains("debugLoggingEnabled")) { if (configNode["debugLoggingEnabled"]) {
this->debugLoggingEnabled = jsonObject.find("debugLoggingEnabled").value().toBool(); this->debugLoggingEnabled = configNode["debugLoggingEnabled"].as<bool>(this->debugLoggingEnabled);
} }
} }
InsightConfig::InsightConfig(const QJsonObject& jsonObject) { InsightConfig::InsightConfig(const YAML::Node& insightNode) {
if (jsonObject.contains("enabled")) { if (insightNode["enabled"]) {
this->insightEnabled = jsonObject.find("enabled").value().toBool(); this->insightEnabled = insightNode["enabled"].as<bool>(this->insightEnabled);
} }
} }
EnvironmentConfig::EnvironmentConfig(std::string name, QJsonObject jsonObject) { EnvironmentConfig::EnvironmentConfig(std::string name, const YAML::Node& environmentNode)
if (!jsonObject.contains("debugTool")) { : name(std::move(name))
throw Exceptions::InvalidConfig("No debug tool configuration provided."); {
if (!environmentNode["debugTool"]) {
throw Exceptions::InvalidConfig("Missing debug tool configuration.");
} }
if (!jsonObject.contains("target")) { if (!environmentNode["debugTool"].IsMap()) {
throw Exceptions::InvalidConfig("No target configuration provided."); throw Exceptions::InvalidConfig(
"Invalid debug tool configuration provided - 'debugTool' must be of mapping type."
);
} }
this->name = std::move(name); if (!environmentNode["target"]) {
this->shutdownPostDebugSession = jsonObject.value( throw Exceptions::InvalidConfig("Missing target configuration.");
"shutdownPostDebugSession"
).toBool(this->shutdownPostDebugSession);
this->debugToolConfig = DebugToolConfig(jsonObject.find("debugTool")->toObject());
this->targetConfig = TargetConfig(jsonObject.find("target")->toObject());
if (jsonObject.contains("debugServer")) {
this->debugServerConfig = DebugServerConfig(jsonObject.find("debugServer")->toObject());
} }
if (jsonObject.contains("insight")) { if (!environmentNode["target"].IsMap()) {
this->insightConfig = InsightConfig(jsonObject.find("insight")->toObject()); throw Exceptions::InvalidConfig(
"Invalid target configuration provided - 'target' must be of mapping type."
);
}
this->debugToolConfig = DebugToolConfig(environmentNode["debugTool"]);
this->targetConfig = TargetConfig(environmentNode["target"]);
if (environmentNode["debugServer"]) {
if (!environmentNode["debugServer"].IsMap()) {
throw Exceptions::InvalidConfig(
"Invalid debug server configuration provided - 'debugServer' must be of mapping type."
);
}
this->debugServerConfig = DebugServerConfig(environmentNode["debugServer"]);
}
if (environmentNode["insight"]) {
if (!environmentNode["insight"].IsMap()) {
throw Exceptions::InvalidConfig(
"Invalid insight configuration provided - 'insight' must be of mapping type."
);
}
this->insightConfig = InsightConfig(environmentNode["insight"]);
}
if (environmentNode["shutdownPostDebugSession"]) {
this->shutdownPostDebugSession = environmentNode["shutdownPostDebugSession"].as<bool>(
this->shutdownPostDebugSession
);
} }
} }
TargetConfig::TargetConfig(const QJsonObject& jsonObject) { TargetConfig::TargetConfig(const YAML::Node& targetNode) {
if (!jsonObject.contains("name")) { if (!targetNode["name"]) {
throw Exceptions::InvalidConfig("No target name found."); throw Exceptions::InvalidConfig("No target name found.");
} }
this->name = jsonObject.find("name")->toString().toLower().toStdString(); this->name = String::asciiToLower(targetNode["name"].as<std::string>());
if (jsonObject.contains("variantName")) { if (targetNode["variantName"]) {
this->variantName = jsonObject.find("variantName").value().toString().toLower().toStdString(); this->variantName = String::asciiToLower(targetNode["variantName"].as<std::string>());
} }
this->jsonObject = jsonObject; this->targetNode = targetNode;
} }
DebugToolConfig::DebugToolConfig(const QJsonObject& jsonObject) { DebugToolConfig::DebugToolConfig(const YAML::Node& debugToolNode) {
if (!jsonObject.contains("name")) { if (!debugToolNode["name"]) {
throw Exceptions::InvalidConfig("No debug tool name found."); throw Exceptions::InvalidConfig("No debug tool name found.");
} }
this->name = jsonObject.find("name")->toString().toLower().toStdString(); this->name = String::asciiToLower(debugToolNode["name"].as<std::string>());
if (jsonObject.contains("releasePostDebugSession")) { if (debugToolNode["releasePostDebugSession"]) {
this->releasePostDebugSession = jsonObject.find("releasePostDebugSession").value().toBool(); this->releasePostDebugSession = debugToolNode["releasePostDebugSession"].as<bool>(
this->releasePostDebugSession
);
} }
this->jsonObject = jsonObject; this->debugToolNode = debugToolNode;
} }
DebugServerConfig::DebugServerConfig(const QJsonObject& jsonObject) { DebugServerConfig::DebugServerConfig(const YAML::Node& debugServerNode) {
this->name = jsonObject.find("name")->toString().toLower().toStdString(); if (!debugServerNode["name"]) {
this->jsonObject = jsonObject; throw Exceptions::InvalidConfig("No debug server name found.");
}
this->name = String::asciiToLower(debugServerNode["name"].as<std::string>());
this->debugServerNode = debugServerNode;
} }
} }

View File

@@ -3,41 +3,44 @@
#include <memory> #include <memory>
#include <map> #include <map>
#include <string> #include <string>
#include <QJsonObject> #include <yaml-cpp/yaml.h>
namespace Bloom namespace Bloom
{ {
/* /*
* Currently, all user configuration is stored in a JSON file (bloom.json), in the user's project directory. * Currently, all user configuration is stored in a YAML file (bloom.yaml), in the user's project directory.
* *
* The JSON config file should define debugging environment objects. A debugging environment object is just * The YAML config file should define parameters for specific debug environments. Because a config file can define
* a user defined JSON object that holds parameters relating to a specific debugging environment (e.g config params * multiple debug environments, each environment must be assigned a unique name that can be used to identify the
* for the DebugTool, Target configuration and any debug server config). Because a config file * environment. This is why the 'environments' parameter is a YAML map, with the key being the environment name.
* can define multiple debugging environments, each object should be assigned a key in the config file. We use this
* key to allow users to select different debugging environments between debugging sessions.
* *
* On application startup, we extract the config from this JSON file and generate an ProjectConfig object. * On application startup, we extract the config from this YAML file and generate a ProjectConfig object.
* See Application::loadProjectConfiguration() for more on this. * See Application::loadProjectConfiguration() for more on this.
* *
* Some config parameters are specific to certain entities within Bloom, but have no significance across the * Some config parameters are specific to certain entities within Bloom, but have no significance across the
* rest of the application. For example, AVR8 targets require the 'physicalInterface' and other AVR8 specific * rest of the application. For example, AVR8 targets require the 'physicalInterface' and other AVR8 specific
* parameters. These are used to configure AVR8 targets, but have no significance across the rest of the * parameters. These are used to configure AVR8 targets, but have no significance across the rest of the
* application. This is why some configuration structs (like TargetConfig) include a QJsonObject member, typically * application. This is why some configuration structs (like TargetConfig) include a YAML::Node member.
* named jsonObject. When instances of these structs are passed to the appropriate entities, any configuration * When instances of these structs are passed to the appropriate entities, any configuration required by those
* required by those entities is extracted from the jsonObject member. This means we don't have to worry about any * entities is extracted from the YAML::Node member. This means we don't have to worry about any entity specific
* entity specific config parameters at the application level. We can simply extract what we need at an entity * config parameters at the application level. We can simply extract what we need at an entity level and the rest
* level and the rest of the application can remain oblivious. For an example on extracting entity specific * of the application can remain oblivious. For an example on extracting entity specific config, see
* config, see AVR8::preActivationConfigure(). * Avr8TargetConfig::Avr8TargetConfig() and Avr8::preActivationConfigure().
* *
* For more on project configuration, see Bloom documentation at https://bloom.oscillate.io/docs/configuration * For more on project configuration, see Bloom documentation at https://bloom.oscillate.io/docs/configuration
*/ */
/*
* Initially, we used the JSON format for project configuration files, but this was changed in version 0.11.0.
* See https://github.com/navnavnav/Bloom/issues/50 for more.
*/
/** /**
* Configuration relating to a specific target. * Configuration relating to a specific target.
* *
* Please don't define any target specific configuration here, unless it applies to *all* targets across * Please don't define any target specific configuration here, unless it applies to *all* targets across
* the application. If a target requires specific config, it should be extracted from the jsonObject member. * the application. If a target requires specific config, it should be extracted from the YAML::Node (targetNode)
* This should be done in Target::preActivationConfigure(), to which an instance of TargetConfig is passed. * member. This should be done in Target::preActivationConfigure(), to which an instance of TargetConfig is passed.
* See the comment above on entity specific config for more on this. * See the comment above on entity specific config for more on this.
*/ */
struct TargetConfig struct TargetConfig
@@ -54,16 +57,20 @@ namespace Bloom
*/ */
std::optional<std::string> variantName; std::optional<std::string> variantName;
QJsonObject jsonObject; /**
* For extracting any target specific configuration. See Avr8TargetConfig::Avr8TargetConfig() and
* Avr8::preActivationConfigure() for an example of this.
*/
YAML::Node targetNode;
TargetConfig() = default; TargetConfig() = default;
/** /**
* Obtains config parameters from JSON object. * Obtains config parameters from YAML node.
* *
* @param jsonObject * @param targetNode
*/ */
explicit TargetConfig(const QJsonObject& jsonObject); explicit TargetConfig(const YAML::Node& targetNode);
}; };
/** /**
@@ -71,7 +78,7 @@ namespace Bloom
* *
* As with the TargetConfig struct, please don't add any manufacture/model specific configuration here. This * As with the TargetConfig struct, please don't add any manufacture/model specific configuration here. This
* configuration should apply to all supported debug tools. Specific configuration can be extracted from the * configuration should apply to all supported debug tools. Specific configuration can be extracted from the
* jsonObject member, as described in the TargetConfig comment above. * YAML::Node (debugToolNode) member, as described in the TargetConfig comment above.
*/ */
struct DebugToolConfig struct DebugToolConfig
{ {
@@ -89,16 +96,19 @@ namespace Bloom
*/ */
bool releasePostDebugSession = true; bool releasePostDebugSession = true;
QJsonObject jsonObject; /**
* For extracting any debug tool specific configuration.
*/
YAML::Node debugToolNode;
DebugToolConfig() = default; DebugToolConfig() = default;
/** /**
* Obtains config parameters from JSON object. * Obtains config parameters from YAML node.
* *
* @param jsonObject * @param debugToolNode
*/ */
explicit DebugToolConfig(const QJsonObject& jsonObject); explicit DebugToolConfig(const YAML::Node& debugToolNode);
}; };
/** /**
@@ -106,17 +116,25 @@ namespace Bloom
*/ */
struct DebugServerConfig struct DebugServerConfig
{ {
/**
* The name of the selected debug server.
*/
std::string name; std::string name;
QJsonObject jsonObject;
/**
* For extracting any debug server specific configuration. See GdbDebugServerConfig::GdbDebugServerConfig() and
* GdbRspDebugServer::GdbRspDebugServer() for an example of this.
*/
YAML::Node debugServerNode;
DebugServerConfig() = default; DebugServerConfig() = default;
/** /**
* Obtains config parameters from JSON object. * Obtains config parameters from YAML node.
* *
* @param jsonObject * @param debugServerNode
*/ */
explicit DebugServerConfig(const QJsonObject& jsonObject); explicit DebugServerConfig(const YAML::Node& debugServerNode);
}; };
struct InsightConfig struct InsightConfig
@@ -126,11 +144,11 @@ namespace Bloom
InsightConfig() = default; InsightConfig() = default;
/** /**
* Obtains config parameters from JSON object. * Obtains config parameters from YAML node.
* *
* @param jsonObject * @param insightNode
*/ */
explicit InsightConfig(const QJsonObject& jsonObject); explicit InsightConfig(const YAML::Node& insightNode);
}; };
/** /**
@@ -142,7 +160,7 @@ namespace Bloom
struct EnvironmentConfig struct EnvironmentConfig
{ {
/** /**
* The environment name is stored as the key to the JSON object containing the environment parameters. * The environment name is stored as the key to the YAML map containing the environment parameters.
* *
* Environment names must be unique. * Environment names must be unique.
*/ */
@@ -179,11 +197,12 @@ namespace Bloom
std::optional<InsightConfig> insightConfig; std::optional<InsightConfig> insightConfig;
/** /**
* Obtains config parameters from JSON object. * Obtains config parameters from YAML node.
* *
* @param jsonObject * @param name
* @param environmentNode
*/ */
EnvironmentConfig(std::string name, QJsonObject jsonObject); EnvironmentConfig(std::string name, const YAML::Node& environmentNode);
}; };
/** /**
@@ -211,10 +230,10 @@ namespace Bloom
bool debugLoggingEnabled = false; bool debugLoggingEnabled = false;
/** /**
* Obtains config parameters from JSON object. * Obtains config parameters from YAML node.
* *
* @param jsonObject * @param configNode
*/ */
explicit ProjectConfig(const QJsonObject& jsonObject); explicit ProjectConfig(const YAML::Node& configNode);
}; };
} }

View File

@@ -82,7 +82,7 @@ The TargetController possesses the ability to go into a suspended state. In this
hardware is surrendered - Bloom will no longer be able to interact with the debug tool or target. The purpose of this hardware is surrendered - Bloom will no longer be able to interact with the debug tool or target. The purpose of this
state is to allow other programs access to the hardware, without requiring the termination of the Bloom process. The state is to allow other programs access to the hardware, without requiring the termination of the Bloom process. The
TargetController goes into a suspended state at the end of a debug session, if the user has enabled this via the TargetController goes into a suspended state at the end of a debug session, if the user has enabled this via the
`releasePostDebugSession` debug tool parameter, in their project configuration file (bloom.json). See `releasePostDebugSession` debug tool parameter, in their project configuration file (bloom.yaml). See
`TargetControllerComponent::onDebugSessionFinishedEvent()` for more. `TargetControllerComponent::onDebugSessionFinishedEvent()` for more.
When in a suspended state, the TargetController will reject most commands. More specifically, any command that When in a suspended state, the TargetController will reject most commands. More specifically, any command that

View File

@@ -26,6 +26,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
void Avr8::preActivationConfigure(const TargetConfig& targetConfig) { void Avr8::preActivationConfigure(const TargetConfig& targetConfig) {
Target::preActivationConfigure(targetConfig); Target::preActivationConfigure(targetConfig);
// Extract AVR8 specific target config
this->targetConfig = Avr8TargetConfig(targetConfig); this->targetConfig = Avr8TargetConfig(targetConfig);
if (this->family.has_value()) { if (this->family.has_value()) {
@@ -87,7 +88,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
"Failed to validate connected target - target signature mismatch.\nThe target signature" "Failed to validate connected target - target signature mismatch.\nThe target signature"
" (\"" + targetSignature.toHex() + "\") does not match the AVR8 target description signature (\"" " (\"" + targetSignature.toHex() + "\") does not match the AVR8 target description signature (\""
+ tdSignature.toHex() + "\"). This will likely be due to an incorrect target name in the configuration" + tdSignature.toHex() + "\"). This will likely be due to an incorrect target name in the configuration"
+ " file (bloom.json)." + " file (bloom.yaml)."
); );
} }
} }

View File

@@ -1,6 +1,6 @@
#include "Avr8TargetConfig.hpp" #include "Avr8TargetConfig.hpp"
#include "src/Logger/Logger.hpp" #include "src/Helpers/String.hpp"
#include "src/Exceptions/InvalidConfig.hpp" #include "src/Exceptions/InvalidConfig.hpp"
namespace Bloom::Targets::Microchip::Avr::Avr8Bit namespace Bloom::Targets::Microchip::Avr::Avr8Bit
@@ -8,12 +8,13 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
Avr8TargetConfig::Avr8TargetConfig(const TargetConfig& targetConfig): TargetConfig(targetConfig) { Avr8TargetConfig::Avr8TargetConfig(const TargetConfig& targetConfig): TargetConfig(targetConfig) {
using Bloom::Exceptions::InvalidConfig; using Bloom::Exceptions::InvalidConfig;
if (!targetConfig.jsonObject.contains("physicalInterface")) { const auto& targetNode = targetConfig.targetNode;
if (!targetNode["physicalInterface"]) {
throw InvalidConfig("Missing physical interface config parameter for AVR8 target."); throw InvalidConfig("Missing physical interface config parameter for AVR8 target.");
} }
const auto physicalInterfaceName = targetConfig.jsonObject.value("physicalInterface").toString().toLower() const auto physicalInterfaceName = String::asciiToLower(targetNode["physicalInterface"].as<std::string>());
.toStdString();
static const auto physicalInterfacesByName = Avr8TargetConfig::getPhysicalInterfacesByName(); static const auto physicalInterfacesByName = Avr8TargetConfig::getPhysicalInterfacesByName();
@@ -23,26 +24,20 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
this->physicalInterface = physicalInterfacesByName.at(physicalInterfaceName); this->physicalInterface = physicalInterfacesByName.at(physicalInterfaceName);
if (targetConfig.jsonObject.contains("updateDwenFuseBit")) { if (targetNode["updateDwenFuseBit"]) {
this->updateDwenFuseBit = targetConfig.jsonObject.value("updateDwenFuseBit").toBool(); this->updateDwenFuseBit = targetNode["updateDwenFuseBit"].as<bool>();
} }
if (targetConfig.jsonObject.contains("cycleTargetPowerPostDwenUpdate")) { if (targetNode["cycleTargetPowerPostDwenUpdate"]) {
this->cycleTargetPowerPostDwenUpdate = targetConfig.jsonObject.value( this->cycleTargetPowerPostDwenUpdate = targetNode["cycleTargetPowerPostDwenUpdate"].as<bool>();
"cycleTargetPowerPostDwenUpdate"
).toBool();
} }
if (targetConfig.jsonObject.contains("disableDebugWirePreDisconnect")) { if (targetNode["disableDebugWirePreDisconnect"]) {
this->disableDebugWireOnDeactivate = targetConfig.jsonObject.value( this->disableDebugWireOnDeactivate = targetNode["disableDebugWirePreDisconnect"].as<bool>();
"disableDebugWirePreDisconnect"
).toBool();
} }
if (targetConfig.jsonObject.contains("targetPowerCycleDelay")) { if (targetNode["targetPowerCycleDelay"]) {
this->targetPowerCycleDelay = std::chrono::milliseconds(targetConfig.jsonObject.value( this->targetPowerCycleDelay = std::chrono::milliseconds(targetNode["targetPowerCycleDelay"].as<int>());
"targetPowerCycleDelay"
).toInt(static_cast<int>(this->targetPowerCycleDelay.count())));
} }
} }
} }

View File

@@ -2,6 +2,7 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject>
#include "src/Helpers/Paths.hpp" #include "src/Helpers/Paths.hpp"
#include "src/Logger/Logger.hpp" #include "src/Logger/Logger.hpp"
@@ -46,7 +47,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
if (targetName.has_value() && matchingDescriptionFiles.empty()) { if (targetName.has_value() && matchingDescriptionFiles.empty()) {
throw Exception("Failed to resolve target description file for target \"" + targetName.value() throw Exception("Failed to resolve target description file for target \"" + targetName.value()
+ "\" - target signature \"" + targetSignatureHex + "\" does not belong to target with name \"" + + "\" - target signature \"" + targetSignatureHex + "\" does not belong to target with name \"" +
targetName.value() + "\". Please review your bloom.json configuration."); targetName.value() + "\". Please review your bloom.yaml configuration.");
} }
if (matchingDescriptionFiles.size() == 1) { if (matchingDescriptionFiles.size() == 1) {