New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Diagnostics service #1390
Diagnostics service #1390
Changes from 5 commits
919a770
defe19c
f4f445e
89734c2
58acf8a
1b90b54
ca4a396
8141455
4de2446
c4ce53a
ee742dd
ad996b9
77ae8ab
7cfe614
015b360
b101c09
afca0d7
75e8264
555c631
bcc4986
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
#include "../../../../hal/src/stm32/newlib.cpp" | ||
|
||
// Defining this in hal/src/stm32/newlib.cpp causes linker errors | ||
void *__dso_handle = NULL; | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* | ||
* Copyright (c) 2017 Particle Industries, Inc. All rights reserved. | ||
* | ||
* This library is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation, either | ||
* version 3 of the License, or (at your option) any later version. | ||
* | ||
* This library is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with this library; if not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <stdint.h> | ||
#include <stddef.h> | ||
|
||
// System data sources | ||
#define DIAG_SOURCE_INVALID 0 // Invalid source ID | ||
#define DIAG_SOURCE_USER 1024 // Base value for application-specific source IDs | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
// Data types | ||
typedef enum diag_type { | ||
DIAG_TYPE_INT = 1 // 32-bit integer | ||
} diag_type; | ||
|
||
// Data source and service commands | ||
typedef enum diag_cmd { | ||
DIAG_CMD_RESET = 1, | ||
DIAG_CMD_ENABLE = 2, | ||
DIAG_CMD_DISABLE = 3, | ||
DIAG_CMD_GET = 4 | ||
} diag_cmd; | ||
|
||
typedef struct diag_source diag_source; | ||
|
||
typedef int(*diag_source_cmd_callback)(const diag_source* src, int cmd, void* data); | ||
typedef void(*diag_enum_sources_callback)(const diag_source* src, void* data); | ||
|
||
typedef struct diag_source { | ||
size_t size; // Size of this structure | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
uint16_t id; // Source ID | ||
uint16_t type; // Data type | ||
const char* name; // Source name | ||
uint32_t flags; // Reserved (should be set to 0) | ||
void* data; // User data | ||
diag_source_cmd_callback callback; // Source callback | ||
} diag_source; | ||
|
||
typedef struct diag_source_get_cmd_data { | ||
size_t size; // Size of this structure | ||
void* data; // Data buffer | ||
size_t data_size; // Buffer size | ||
} diag_source_get_cmd_data; | ||
|
||
int diag_register_source(const diag_source* src, void* reserved); | ||
int diag_enum_sources(diag_enum_sources_callback callback, size_t* count, void* data, void* reserved); | ||
int diag_get_source(uint16_t id, const diag_source** src, void* reserved); | ||
int diag_service_cmd(int cmd, void* data, void* reserved); | ||
|
||
#ifdef __cplusplus | ||
} // extern "C" | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/* | ||
* Copyright (c) 2017 Particle Industries, Inc. All rights reserved. | ||
* | ||
* This library is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation, either | ||
* version 3 of the License, or (at your option) any later version. | ||
* | ||
* This library is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with this library; if not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include "diagnostics.h" | ||
|
||
#include "spark_wiring_vector.h" | ||
|
||
#include "system_error.h" | ||
|
||
#include <algorithm> | ||
|
||
namespace { | ||
|
||
using namespace spark; | ||
|
||
class Diagnostics { | ||
public: | ||
Diagnostics() : | ||
enabled_(0) { // The service is disabled initially | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what's the rationale for having enable/disable for the service? If it's to save expensive computation then perhaps we should move the enable flag to the diag_source? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The rationale is to avoid a race condition, which is possible when the system receives a request or a call querying diagnostic data but data sources are still being registered. The system explicitly enables the diagnostic service after invoking all global constructors in all system parts here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, that makes sense. The name Perhaps we should call it running, or started? Alternatively, you could add a comment to explain, since normally things are not usable while disabled, while here it's the opposite. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
srcs_.reserve(32); | ||
} | ||
|
||
int registerSource(const diag_source* src) { | ||
if (enabled_) { | ||
return SYSTEM_ERROR_INVALID_STATE; | ||
} | ||
const int index = indexForId(src->id); | ||
if (index < srcs_.size() && srcs_.at(index)->id == src->id) { | ||
return SYSTEM_ERROR_ALREADY_EXISTS; | ||
} | ||
if (!srcs_.insert(index, src)) { | ||
return SYSTEM_ERROR_NO_MEMORY; | ||
} | ||
return SYSTEM_ERROR_NONE; | ||
} | ||
|
||
int enumSources(diag_enum_sources_callback callback, size_t* count, void* data) { | ||
if (!enabled_) { | ||
return SYSTEM_ERROR_INVALID_STATE; | ||
} | ||
if (callback) { | ||
for (const diag_source* src: srcs_) { | ||
callback(src, data); | ||
} | ||
} | ||
if (count) { | ||
*count = srcs_.size(); | ||
} | ||
return SYSTEM_ERROR_NONE; | ||
} | ||
|
||
int getSource(uint16_t id, const diag_source** src) { | ||
if (!enabled_) { | ||
return SYSTEM_ERROR_INVALID_STATE; | ||
} | ||
const int index = indexForId(id); | ||
if (index >= srcs_.size() || srcs_.at(index)->id != id) { | ||
return SYSTEM_ERROR_NOT_FOUND; | ||
} | ||
if (src) { | ||
*src = srcs_.at(index); | ||
} | ||
return SYSTEM_ERROR_NONE; | ||
} | ||
|
||
int command(int cmd, void* data) { | ||
switch (cmd) { | ||
#if PLATFORM_ID == 3 | ||
// The RESET and DISABLE commands are used only for testing purposes | ||
case DIAG_CMD_RESET: | ||
srcs_.clear(); | ||
enabled_ = 0; | ||
break; | ||
case DIAG_CMD_DISABLE: | ||
enabled_ = 0; | ||
break; | ||
#endif | ||
case DIAG_CMD_ENABLE: | ||
enabled_ = 1; | ||
break; | ||
default: | ||
return SYSTEM_ERROR_NOT_SUPPORTED; | ||
} | ||
return SYSTEM_ERROR_NONE; | ||
} | ||
|
||
private: | ||
Vector<const diag_source*> srcs_; | ||
volatile uint8_t enabled_; | ||
|
||
int indexForId(uint16_t id) const { | ||
return std::distance(srcs_.begin(), std::lower_bound(srcs_.begin(), srcs_.end(), id, | ||
[](const diag_source* src, uint16_t id) { | ||
return (src->id < id); | ||
})); | ||
} | ||
}; | ||
|
||
Diagnostics g_diag; | ||
|
||
} // namespace | ||
|
||
int diag_register_source(const diag_source* src, void* reserved) { | ||
return g_diag.registerSource(src); | ||
} | ||
|
||
int diag_enum_sources(diag_enum_sources_callback callback, size_t* count, void* data, void* reserved) { | ||
return g_diag.enumSources(callback, count, data); | ||
} | ||
|
||
int diag_get_source(uint16_t id, const diag_source** src, void* reserved) { | ||
return g_diag.getSource(id, src); | ||
} | ||
|
||
int diag_service_cmd(int cmd, void* data, void* reserved) { | ||
return g_diag.command(cmd, data); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know what has changed to make this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
part1
now has a global variable (Diagnostics
) with a non-trivial destructor