diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ebe85c735e..0c0e2bd094 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -67,21 +67,11 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/environment-setup - - name: Install and start redis server - run: | - wget http://download.redis.io/redis-stable.tar.gz - tar xvzf redis-stable.tar.gz >/dev/null - cd redis-stable - make >/dev/null - make install >/dev/null - redis-server --daemonize yes - - - name: Stop redis server + - name: Environment Setup run: | - redis-cli shutdown - + "${GITHUB_WORKSPACE}"/environment_setup/setup_software.sh + - name: Jetson Nano Build run: | cd src diff --git a/docs/getting-started.md b/docs/getting-started.md index a55602907c..8a1ac8a0a1 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -376,16 +376,26 @@ Where `` is the robot platform you are deploying to (`PI` or `NANO`), It is possible to run Thunderloop without having a fully-working robot. Using this mode is useful when testing features that don't require the power board or motors. 1. To run Thunderloop locally on your computer - 1. First, you must ensure that `redis` is installed. Installation instructions can be found [here](https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/). The result of these installation directions will likely enable `redis-server` as a service that starts on boot. You may want to run `sudo systemctl disable redis-server` to prevent this. - 2. Next, run the command `redis-server` in a terminal. - 3. Set up the following required REDIS constants by running the following commands in the terminal: - - `redis-cli set /robot_id "{robot_id}"` where `{robot_id}` is the robot's ID (e.g. `1`, `2`, etc.) - - `redis-cli set /network_interface "{network_interface}"` where `{network_interface}` is one of the interfaces listed by `ip a`. - - `redis-cli set /channel_id "{channel_id}"` where `{channel_id}` is the channel id of the robot (e.g. `1`, `2`, etc.) - - `redis-cli set /kick_coeff "{kick_coeff}"` where `{kick_coeff}` is a calibrated kicking parameter. When running locally, this parameter doesn't matter so `0` is fine. - - `redis-cli set /kick_constant "{kick_constant}"` where `{kick_constant}` is a calibrated kicking parameter. When running locally, this parameter doesn't matter so `0` is fine. - - `redis-cli set /chip_pulse_width "{chip_pulse_width}"` where `{chip_pulse_width}` is a calibrated kicking parameter. When running locally, this parameter doesn't matter so `0` is fine. - 4. Now, run Thunderloop with the following command: + 1. Create a TOML configuration file in the opt/tbotspython directory with the following content (replace values as needed): + ```toml + robot_id = "1" + channel_id = "0" + network_interface = "tbotswifi5" + kick_constant = "0" + kick_coeff = "0.0" + chip_pulse_width = "0" + battery_voltage = "0.0" + current_draw = "0.0" + cap_voltage = "0.0" + ``` + Where: + - `robot_id` is the robot's ID (e.g. `1`, `2`, etc.) + - `network_interface` is one of the interfaces listed by `ip a`. + - `channel_id` is the channel id of the robot (e.g. `1`, `2`, etc.) + - `kick_coeff` is a calibrated kicking parameter. When running locally, this parameter doesn't matter so `0` is fine. + - `kick_constant` is a calibrated kicking parameter. When running locally, this parameter doesn't matter so `0` is fine. + - `chip_pulse_width` is a calibrated kicking parameter. When running locally, this parameter doesn't matter so `0` is fine. + 2. Now, run Thunderloop with the following command: - `bazel run //software/embedded:thunderloop_main --//software/embedded:host_platform=LIMITED` 2. If you have a robot PC that doesn't have proper communication with the power or motor board, you can still run Thunderloop in a limited capacity to test software features (eg. networking). diff --git a/docs/robot-software-architecture.md b/docs/robot-software-architecture.md index 08f9ecd6bd..0bbb47a106 100644 --- a/docs/robot-software-architecture.md +++ b/docs/robot-software-architecture.md @@ -9,7 +9,7 @@ - [Tools](#tools) - [Ansible](#ansible) - [Systemd](#systemd) - - [Redis](#redis) + - [TOML Configuration](#toml-configuration) - [Thunderloop](#thunderloop) @@ -39,9 +39,9 @@ More commands available [here](useful-robot-commands.md#off-robot-commands) To learn more about how it works, [see the RFC](https://docs.google.com/document/d/1hN3Us2Vjr8z6ihqUVp_3L7rrjKc-EZ-l2hZJc31gNOc/edit) -## Redis +## TOML Configuration -[Redis](https://redis.io/docs/about/) is an in-memory key-value store. This allows us to share state between processes as well as modify values dynamically through the provided [cli](useful-robot-commands#redis). Values also persists between boots. +Robot configuration is stored in a TOML file in home directory. This file contains both static configuration values and dynamic runtime values. # Thunderloop diff --git a/docs/useful-robot-commands.md b/docs/useful-robot-commands.md index cf9415ab38..af7046a678 100644 --- a/docs/useful-robot-commands.md +++ b/docs/useful-robot-commands.md @@ -21,7 +21,6 @@ - [On Robot Commands](#on-robot-commands) - [Systemd Services](#systemd-services) - [Debugging Uart](#debugging-uart) - - [Redis](#redis) @@ -63,14 +62,6 @@ flowchart TD `service thunderloop restart`) tloop_status --> |Running| tloop_logs(Check Thunderloop logs for errors `journalctl -fu thunderloop -n 300`) - tloop_logs --> |No Errors| check_redis(Does `redis-cli get /network_interface` return 'wlan0' or 'tbots', - and does `redis-cli get /channel_id` return '0'?) - tloop_logs --> |Contains Errors| rip2("Fix errors or check errors with a lead") - check_redis --> |No| update_redis("Update Redis constants by running: - `redis-cli set /network_interface 'wlan0'` (for Nanos) OR `redis-cli set /network_interface 'tbots'` (for Pis) - `redis-cli set /channel_id '0'`") - check_redis --> |Yes| rip3(Check with a lead) - update_redis --> tloop_restart tloop_restart --> tloop_status end ``` @@ -256,36 +247,3 @@ If the serial_port is busy, screen will not launch and instead says `screen is t Powerloop uart communication is encoded so you can't read it from screen and will appear as a mix of foreign characters Pressing the reset button once will send a status msg over its connected port. This is useful for sanity checking. - -## Redis - -Current redis keys that are used are available in `software/constants.h`. Official Documentation [here](https://redis.io/docs/manual/cli/). - -Values should be strings. For example `set \ROBOT_ID "0"` - -Redis repl can be accessed through the following command. - -```bash -redis-cli -``` - -Other common commands (once inside redis repl): - -```bash -get -set -``` - -To Exit: - -```bash -quit -``` - -Alternative (without entering redis repl): - -```bash -redis-cli get -redis-cli set -``` - diff --git a/src/MODULE.bazel b/src/MODULE.bazel index 7c1597ca68..55c6885afb 100644 --- a/src/MODULE.bazel +++ b/src/MODULE.bazel @@ -89,22 +89,12 @@ use_repo(pybind11_configure, "pybind11") ########################################################################### http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -# Dep for cpp_redis http_archive( - name = "tacopie", - sha256 = "bbdebecdb68d5f9eb64170217000daf844e0aee18b8c4d3dd373d07efd9f7316", - strip_prefix = "tacopie-master", - url = "https://github.com/cylix/tacopie/archive/master.zip", -) - -# TODO(#3315): Used for on-robot value storage - deprecation soon -http_archive( - name = "cpp_redis", - sha256 = "12a6fc86ba4ca3d4537a3eee82c094f385b8e03e283c664c976f16d421f17f7d", - strip_prefix = "cpp_redis-fc2c43fa07e45e1ef0f77cbda6a240e7890ae5aa", - urls = [ - "https://github.com/cpp-redis/cpp_redis/archive/fc2c43fa07e45e1ef0f77cbda6a240e7890ae5aa.zip", - ], + name = "tomlplusplus", + build_file = "@//extlibs:tomlplusplus.BUILD", + sha256 = "8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155", + strip_prefix = "tomlplusplus-3.4.0", + urls = ["https://github.com/marzer/tomlplusplus/archive/refs/tags/v3.4.0.tar.gz"], ) http_archive( diff --git a/src/MODULE.bazel.lock b/src/MODULE.bazel.lock index ce4bc12db9..e5b5b960cc 100644 --- a/src/MODULE.bazel.lock +++ b/src/MODULE.bazel.lock @@ -427,27 +427,995 @@ ] } }, + "@@gazelle+//:extensions.bzl%go_deps": { + "general": { + "bzlTransitiveDigest": "nDcDFEcG7tN0i2Jdps7UVS2RRj+FCMDIIw8BhLX7d/4=", + "usagesDigest": "5t506i9t6CVUs7clrVP3jUCLxQgMdijw9PGnmaqrgGg=", + "recordedFileInputs": { + "@@gazelle+//go.mod": "5346019bf0673364b383d56ffbc9fced98b7b4ee921e865dfe905a1ebe82d326", + "@@gazelle+//go.sum": "c9624aa41e5ffd61a8581d57a3c4046e62b46630dddc8b191e65017f34ff12a5", + "@@rules_go+//go.mod": "a7143f329c2a3e0b983ce74a96c0c25b0d0c59d236d75f7e1b069aadd988d55e", + "@@rules_go+//go.sum": "022d36c9ebcc7b5dee1e9b85b3da9c9f3a529ee6f979946d66e4955b8d54614a" + }, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_gogo_protobuf": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "github.com/gogo/protobuf", + "sum": "h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=", + "replace": "", + "version": "v1.3.2", + "build_directives": [ + "gazelle:proto disable" + ] + } + }, + "com_github_golang_mock": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "github.com/golang/mock", + "sum": "h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=", + "replace": "", + "version": "v1.6.0", + "build_directives": [] + } + }, + "com_github_golang_protobuf": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "github.com/golang/protobuf", + "sum": "h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=", + "replace": "", + "version": "v1.5.2", + "build_directives": [] + } + }, + "org_golang_google_protobuf": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "google.golang.org/protobuf", + "sum": "h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=", + "replace": "", + "version": "v1.28.0", + "build_directives": [] + } + }, + "org_golang_x_net": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "golang.org/x/net", + "sum": "h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=", + "replace": "", + "version": "v0.0.0-20210405180319-a5a99cb37ef4", + "build_directives": [] + } + }, + "org_golang_x_sys": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "golang.org/x/sys", + "sum": "h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=", + "replace": "", + "version": "v0.6.0", + "build_directives": [] + } + }, + "org_golang_x_text": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "golang.org/x/text", + "sum": "h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=", + "replace": "", + "version": "v0.3.3", + "build_directives": [] + } + }, + "org_golang_google_genproto": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "google.golang.org/genproto", + "sum": "h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=", + "replace": "", + "version": "v0.0.0-20200526211855-cb27e3aa2013", + "build_directives": [] + } + }, + "org_golang_google_grpc": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "google.golang.org/grpc", + "sum": "h1:fPVVDxY9w++VjTZsYvXWqEf9Rqar/e+9zYfxKK+W+YU=", + "replace": "", + "version": "v1.50.0", + "build_directives": [ + "gazelle:proto disable" + ] + } + }, + "com_github_bazelbuild_buildtools": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "github.com/bazelbuild/buildtools", + "sum": "h1:XmPu4mXICgdGnC5dXGjUGbwUD/kUmS0l5Aop3LaevBM=", + "replace": "", + "version": "v0.0.0-20230317132445-9c3c1fc0106e", + "build_directives": [] + } + }, + "com_github_bmatcuk_doublestar_v4": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "github.com/bmatcuk/doublestar/v4", + "sum": "h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=", + "replace": "", + "version": "v4.6.0", + "build_directives": [] + } + }, + "com_github_fsnotify_fsnotify": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "github.com/fsnotify/fsnotify", + "sum": "h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=", + "replace": "", + "version": "v1.6.0", + "build_directives": [] + } + }, + "com_github_google_go_cmp": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "github.com/google/go-cmp", + "sum": "h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=", + "replace": "", + "version": "v0.5.9", + "build_directives": [] + } + }, + "com_github_pelletier_go_toml": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "github.com/pelletier/go-toml", + "sum": "h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=", + "replace": "", + "version": "v1.9.5", + "build_directives": [] + } + }, + "com_github_pmezard_go_difflib": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "github.com/pmezard/go-difflib", + "sum": "h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=", + "replace": "", + "version": "v1.0.0", + "build_directives": [] + } + }, + "org_golang_x_mod": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "golang.org/x/mod", + "sum": "h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=", + "replace": "", + "version": "v0.9.0", + "build_directives": [] + } + }, + "org_golang_x_sync": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "golang.org/x/sync", + "sum": "h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=", + "replace": "", + "version": "v0.1.0", + "build_directives": [] + } + }, + "org_golang_x_tools": { + "repoRuleId": "@@gazelle+//internal:go_repository.bzl%go_repository", + "attributes": { + "importpath": "golang.org/x/tools", + "sum": "h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=", + "replace": "", + "version": "v0.7.0", + "build_directives": [] + } + }, + "bazel_gazelle_go_repository_config": { + "repoRuleId": "@@gazelle+//internal/bzlmod:go_deps.bzl%_go_repository_config", + "attributes": { + "importpaths": { + "com_github_gogo_protobuf": "github.com/gogo/protobuf", + "com_github_golang_mock": "github.com/golang/mock", + "com_github_golang_protobuf": "github.com/golang/protobuf", + "org_golang_google_protobuf": "google.golang.org/protobuf", + "org_golang_x_net": "golang.org/x/net", + "org_golang_x_sys": "golang.org/x/sys", + "org_golang_x_text": "golang.org/x/text", + "org_golang_google_genproto": "google.golang.org/genproto", + "org_golang_google_grpc": "google.golang.org/grpc", + "com_github_bazelbuild_buildtools": "github.com/bazelbuild/buildtools", + "com_github_bmatcuk_doublestar_v4": "github.com/bmatcuk/doublestar/v4", + "com_github_fsnotify_fsnotify": "github.com/fsnotify/fsnotify", + "com_github_google_go_cmp": "github.com/google/go-cmp", + "com_github_pelletier_go_toml": "github.com/pelletier/go-toml", + "com_github_pmezard_go_difflib": "github.com/pmezard/go-difflib", + "org_golang_x_mod": "golang.org/x/mod", + "org_golang_x_sync": "golang.org/x/sync", + "org_golang_x_tools": "golang.org/x/tools" + }, + "build_naming_conventions": {} + } + } + }, + "recordedRepoMappingEntries": [ + [ + "gazelle+", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@gazelle+//internal/bzlmod:non_module_deps.bzl%non_module_deps": { + "general": { + "bzlTransitiveDigest": "30wev+wJfzc4s72MCfbP9U8W+3Js2b+Xbo5ofgZbHw8=", + "usagesDigest": "n9iSPUDFMBuAV//lfZYtddl/7aihTb+8uSPRwE81fOM=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "bazel_gazelle_go_repository_cache": { + "repoRuleId": "@@gazelle+//internal:go_repository_cache.bzl%go_repository_cache", + "attributes": { + "go_sdk_name": "go_default_sdk", + "go_env": {} + } + }, + "bazel_gazelle_go_repository_tools": { + "repoRuleId": "@@gazelle+//internal:go_repository_tools.bzl%go_repository_tools", + "attributes": { + "go_cache": "@@gazelle++non_module_deps+bazel_gazelle_go_repository_cache//:go.env" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "gazelle+", + "bazel_gazelle_go_repository_cache", + "gazelle++non_module_deps+bazel_gazelle_go_repository_cache" + ] + ] + } + }, + "@@grpc+//bazel:grpc_deps.bzl%grpc_repo_deps_ext": { + "general": { + "bzlTransitiveDigest": "mcyDA0lHK6hTy6PlDFj4+lGpuyTkf7ePBPrlwF8+udM=", + "usagesDigest": "xS2qe/7xYEc+234OodvQ7dM5a+N5+D8ta5tLS29jwto=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "boringssl": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "f150aa2d73017fe8576a8a335f29030488d851c94368a79ac56142d107bf9e9a", + "strip_prefix": "boringssl-e46383fc18d08def901b2ed5a194295693e905c7", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/boringssl/archive/e46383fc18d08def901b2ed5a194295693e905c7.tar.gz", + "https://github.com/google/boringssl/archive/e46383fc18d08def901b2ed5a194295693e905c7.tar.gz" + ] + } + }, + "zlib": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file": "@@grpc+//third_party:zlib.BUILD", + "sha256": "90f43a9c998740e8a0db24b0af0147033db2aaaa99423129abbd76640757cac9", + "strip_prefix": "zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/madler/zlib/archive/04f42ceca40f73e2978b50e93806c2a18c1281fc.tar.gz", + "https://github.com/madler/zlib/archive/04f42ceca40f73e2978b50e93806c2a18c1281fc.tar.gz" + ] + } + }, + "com_google_googletest": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "c8de6c60e12ad014a28225c5247ee735861d85cf906df617f6a29954ca05f547", + "strip_prefix": "googletest-0e402173c97aea7a00749e825b194bfede4f2e45", + "urls": [ + "https://github.com/google/googletest/archive/0e402173c97aea7a00749e825b194bfede4f2e45.tar.gz" + ] + } + }, + "com_google_fuzztest": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "cdf8d8cd3cdc77280a7c59b310edf234e489a96b6e727cb271e7dfbeb9bcca8d", + "strip_prefix": "fuzztest-4ecaeb5084a061a862af8f86789ee184cd3d3f18", + "urls": [ + "https://github.com/google/fuzztest/archive/4ecaeb5084a061a862af8f86789ee184cd3d3f18.tar.gz" + ] + } + }, + "rules_cc": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "3d9e271e2876ba42e114c9b9bc51454e379cbf0ec9ef9d40e2ae4cec61a31b40", + "strip_prefix": "rules_cc-0.0.6", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/bazelbuild/rules_cc/releases/download/0.0.6/rules_cc-0.0.6.tar.gz", + "https://github.com/bazelbuild/rules_cc/releases/download/0.0.6/rules_cc-0.0.6.tar.gz" + ] + } + }, + "com_github_google_benchmark": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "3a43368d3ec48afe784573cf962fe98c084e89a1e3d176c00715a84366316e7d", + "strip_prefix": "benchmark-361e8d1cfe0c6c36d30b39f1b61302ece5507320", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/benchmark/archive/361e8d1cfe0c6c36d30b39f1b61302ece5507320.tar.gz", + "https://github.com/google/benchmark/archive/361e8d1cfe0c6c36d30b39f1b61302ece5507320.tar.gz" + ] + } + }, + "com_googlesource_code_re2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "1ae8ccfdb1066a731bba6ee0881baad5efd2cd661acd9569b689f2586e1a50e9", + "strip_prefix": "re2-2022-04-01", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/re2/archive/2022-04-01.tar.gz", + "https://github.com/google/re2/archive/2022-04-01.tar.gz" + ] + } + }, + "com_github_cares_cares": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file": "@@grpc+//third_party:cares/cares.BUILD", + "sha256": "bf26e5b25e259911914a85ae847b6d723488adb5af4f8bdeb9d0871a318476e3", + "strip_prefix": "c-ares-6360e96b5cf8e5980c887ce58ef727e53d77243a", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/c-ares/c-ares/archive/6360e96b5cf8e5980c887ce58ef727e53d77243a.tar.gz", + "https://github.com/c-ares/c-ares/archive/6360e96b5cf8e5980c887ce58ef727e53d77243a.tar.gz" + ] + } + }, + "com_google_absl": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "5366d7e7fa7ba0d915014d387b66d0d002c03236448e1ba9ef98122c13b35c36", + "strip_prefix": "abseil-cpp-20230125.3", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/abseil/abseil-cpp/archive/20230125.3.tar.gz", + "https://github.com/abseil/abseil-cpp/archive/20230125.3.tar.gz" + ] + } + }, + "bazel_toolchains": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "179ec02f809e86abf56356d8898c8bd74069f1bd7c56044050c2cd3d79d0e024", + "strip_prefix": "bazel-toolchains-4.1.0", + "urls": [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/releases/download/4.1.0/bazel-toolchains-4.1.0.tar.gz", + "https://github.com/bazelbuild/bazel-toolchains/releases/download/4.1.0/bazel-toolchains-4.1.0.tar.gz" + ] + } + }, + "bazel_skylib": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz" + ], + "sha256": "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44" + } + }, + "bazel_compdb": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "bcecfd622c4ef272fd4ba42726a52e140b961c4eac23025f18b346c968a8cfb4", + "strip_prefix": "bazel-compilation-database-0.4.5", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/grailbio/bazel-compilation-database/archive/0.4.5.tar.gz", + "https://github.com/grailbio/bazel-compilation-database/archive/0.4.5.tar.gz" + ] + } + }, + "io_opencensus_cpp": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "46b3b5812c150a21bacf860c2f76fc42b89773ed77ee954c32adeb8593aa2a8e", + "strip_prefix": "opencensus-cpp-5501a1a255805e0be83a41348bb5f2630d5ed6b3", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/census-instrumentation/opencensus-cpp/archive/5501a1a255805e0be83a41348bb5f2630d5ed6b3.tar.gz", + "https://github.com/census-instrumentation/opencensus-cpp/archive/5501a1a255805e0be83a41348bb5f2630d5ed6b3.tar.gz" + ] + } + }, + "upb": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "7d19f2ac9c1e508a86a272913d9aa67c8147827f949035828910bb05d9f2cf03", + "strip_prefix": "upb-61a97efa24a5ce01fb8cc73c9d1e6e7060f8ea98", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/protocolbuffers/upb/archive/61a97efa24a5ce01fb8cc73c9d1e6e7060f8ea98.tar.gz", + "https://github.com/protocolbuffers/upb/archive/61a97efa24a5ce01fb8cc73c9d1e6e7060f8ea98.tar.gz" + ] + } + }, + "envoy_api": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "3c7372b5cb33e5e5cc3afd82573fc6275f9a2cac8b1530e1af14f52f34047328", + "strip_prefix": "data-plane-api-68d4315167352ffac71f149a43b8088397d3f33d", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/envoyproxy/data-plane-api/archive/68d4315167352ffac71f149a43b8088397d3f33d.tar.gz", + "https://github.com/envoyproxy/data-plane-api/archive/68d4315167352ffac71f149a43b8088397d3f33d.tar.gz" + ] + } + }, + "build_bazel_rules_apple": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "f94e6dddf74739ef5cb30f000e13a2a613f6ebfa5e63588305a71fce8a8a9911", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/bazelbuild/rules_apple/releases/download/1.1.3/rules_apple.1.1.3.tar.gz", + "https://github.com/bazelbuild/rules_apple/releases/download/1.1.3/rules_apple.1.1.3.tar.gz" + ] + } + }, + "build_bazel_apple_support": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "f4fdf5c9b42b92ea12f229b265d74bb8cedb8208ca7a445b383c9f866cf53392", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/bazelbuild/apple_support/releases/download/1.3.1/apple_support.1.3.1.tar.gz", + "https://github.com/bazelbuild/apple_support/releases/download/1.3.1/apple_support.1.3.1.tar.gz" + ] + } + }, + "com_github_libuv_libuv": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file": "@@grpc+//third_party:libuv.BUILD", + "sha256": "5ca4e9091f3231d8ad8801862dc4e851c23af89c69141d27723157776f7291e7", + "strip_prefix": "libuv-02a9e1be252b623ee032a3137c0b0c94afbe6809", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/libuv/libuv/archive/02a9e1be252b623ee032a3137c0b0c94afbe6809.tar.gz", + "https://github.com/libuv/libuv/archive/02a9e1be252b623ee032a3137c0b0c94afbe6809.tar.gz" + ] + } + }, + "com_google_googleapis": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "5bb6b0253ccf64b53d6c7249625a7e3f6c3bc6402abd52d3778bfa48258703a0", + "strip_prefix": "googleapis-2f9af297c84c55c8b871ba4495e01ade42476c92", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/googleapis/googleapis/archive/2f9af297c84c55c8b871ba4495e01ade42476c92.tar.gz", + "https://github.com/googleapis/googleapis/archive/2f9af297c84c55c8b871ba4495e01ade42476c92.tar.gz" + ] + } + }, + "bazel_gazelle": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "de69a09dc70417580aabf20a28619bb3ef60d038470c7cf8442fafcf627c21cb", + "urls": [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.24.0/bazel-gazelle-v0.24.0.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.24.0/bazel-gazelle-v0.24.0.tar.gz" + ] + } + }, + "opencensus_proto": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "b7e13f0b4259e80c3070b583c2f39e53153085a6918718b1c710caf7037572b0", + "strip_prefix": "opencensus-proto-0.3.0/src", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/census-instrumentation/opencensus-proto/archive/v0.3.0.tar.gz", + "https://github.com/census-instrumentation/opencensus-proto/archive/v0.3.0.tar.gz" + ], + "patches": [ + "@@grpc+//third_party:opencensus-proto.patch" + ], + "patch_args": [ + "-p2" + ] + } + }, + "com_envoyproxy_protoc_gen_validate": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "strip_prefix": "protoc-gen-validate-4694024279bdac52b77e22dc87808bd0fd732b69", + "sha256": "1e490b98005664d149b379a9529a6aa05932b8a11b76b4cd86f3d22d76346f47", + "urls": [ + "https://github.com/envoyproxy/protoc-gen-validate/archive/4694024279bdac52b77e22dc87808bd0fd732b69.tar.gz" + ], + "patches": [ + "@@grpc+//third_party:protoc-gen-validate.patch" + ], + "patch_args": [ + "-p1" + ] + } + }, + "com_github_cncf_udpa": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "0d33b83f8c6368954e72e7785539f0d272a8aba2f6e2e336ed15fd1514bc9899", + "strip_prefix": "xds-e9ce68804cb4e64cab5a52e3c8baf840d4ff87b7", + "urls": [ + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/cncf/xds/archive/e9ce68804cb4e64cab5a52e3c8baf840d4ff87b7.tar.gz", + "https://github.com/cncf/xds/archive/e9ce68804cb4e64cab5a52e3c8baf840d4ff87b7.tar.gz" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "grpc+", + "bazel_tools", + "bazel_tools" + ], + [ + "grpc+", + "com_github_grpc_grpc", + "grpc+" + ] + ] + } + }, + "@@grpc+//bazel:grpc_extra_deps.bzl%grpc_extra_deps_ext": { + "general": { + "bzlTransitiveDigest": "d6eh/xunjpWewtas5Ojo3x/mxFzl3rDbYwq3euBxIDI=", + "usagesDigest": "BY9iaBuI51W+iyhY4Nmom6cjK/1zFFYXkN9SiDcmjzg=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_google_googleapis_imports": { + "repoRuleId": "@@grpc++grpc_repo_deps_ext+com_google_googleapis//:repository_rules.bzl%switched_rules", + "attributes": { + "rules": { + "proto_library_with_info": [ + "", + "" + ], + "moved_proto_library": [ + "", + "" + ], + "java_proto_library": [ + "", + "" + ], + "java_grpc_library": [ + "", + "" + ], + "java_gapic_library": [ + "", + "" + ], + "java_gapic_test": [ + "", + "" + ], + "java_gapic_assembly_gradle_pkg": [ + "", + "" + ], + "py_proto_library": [ + "@com_github_grpc_grpc//bazel:python_rules.bzl", + "" + ], + "py_grpc_library": [ + "@com_github_grpc_grpc//bazel:python_rules.bzl", + "" + ], + "py_gapic_library": [ + "", + "" + ], + "py_gapic_assembly_pkg": [ + "", + "" + ], + "go_proto_library": [ + "", + "" + ], + "go_library": [ + "", + "" + ], + "go_test": [ + "", + "" + ], + "go_gapic_library": [ + "", + "" + ], + "go_gapic_assembly_pkg": [ + "", + "" + ], + "cc_proto_library": [ + "native.cc_proto_library", + "" + ], + "cc_grpc_library": [ + "@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", + "" + ], + "cc_gapic_library": [ + "", + "" + ], + "php_proto_library": [ + "", + "php_proto_library" + ], + "php_grpc_library": [ + "", + "php_grpc_library" + ], + "php_gapic_library": [ + "", + "php_gapic_library" + ], + "php_gapic_assembly_pkg": [ + "", + "php_gapic_assembly_pkg" + ], + "nodejs_gapic_library": [ + "", + "typescript_gapic_library" + ], + "nodejs_gapic_assembly_pkg": [ + "", + "typescript_gapic_assembly_pkg" + ], + "ruby_proto_library": [ + "", + "" + ], + "ruby_grpc_library": [ + "", + "" + ], + "ruby_ads_gapic_library": [ + "", + "" + ], + "ruby_cloud_gapic_library": [ + "", + "" + ], + "ruby_gapic_assembly_pkg": [ + "", + "" + ], + "csharp_proto_library": [ + "", + "" + ], + "csharp_grpc_library": [ + "", + "" + ], + "csharp_gapic_library": [ + "", + "" + ], + "csharp_gapic_assembly_pkg": [ + "", + "" + ] + } + } + } + }, + "recordedRepoMappingEntries": [ + [ + "grpc+", + "com_envoyproxy_protoc_gen_validate", + "grpc++grpc_repo_deps_ext+com_envoyproxy_protoc_gen_validate" + ], + [ + "grpc+", + "com_google_googleapis", + "grpc++grpc_repo_deps_ext+com_google_googleapis" + ], + [ + "grpc+", + "com_google_protobuf", + "protobuf+" + ], + [ + "grpc+", + "envoy_api", + "grpc++grpc_repo_deps_ext+envoy_api" + ], + [ + "grpc+", + "io_bazel_rules_go", + "rules_go+" + ], + [ + "grpc+", + "upb", + "upb+" + ], + [ + "grpc++grpc_repo_deps_ext+bazel_gazelle", + "bazel_gazelle", + "grpc++grpc_repo_deps_ext+bazel_gazelle" + ], + [ + "grpc++grpc_repo_deps_ext+bazel_gazelle", + "bazel_tools", + "bazel_tools" + ], + [ + "grpc++grpc_repo_deps_ext+com_envoyproxy_protoc_gen_validate", + "bazel_gazelle", + "grpc++grpc_repo_deps_ext+bazel_gazelle" + ], + [ + "grpc++grpc_repo_deps_ext+envoy_api", + "bazel_tools", + "bazel_tools" + ], + [ + "grpc++grpc_repo_deps_ext+envoy_api", + "envoy_api", + "grpc++grpc_repo_deps_ext+envoy_api" + ], + [ + "protobuf+", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_go+", + "bazel_tools", + "bazel_tools" + ], + [ + "upb+", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@grpc+//bazel:grpc_python_deps.bzl%grpc_python_deps_ext": { + "general": { + "bzlTransitiveDigest": "zyerALv7EQtUAEtYpLO8j74Z4NT5zcDzwkMjTFUxM6M=", + "usagesDigest": "DFOlU21+OzU+IhRpTR0jJu6qlQs6nFR7xn7mnx2oxW8=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "cython": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file": "@@grpc+//third_party:cython.BUILD", + "sha256": "a2da56cc22be823acf49741b9aa3aa116d4f07fa8e8b35a3cb08b8447b37c607", + "strip_prefix": "cython-0.29.35", + "urls": [ + "https://github.com/cython/cython/archive/0.29.35.tar.gz" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "grpc+", + "bazel_tools", + "bazel_tools" + ], + [ + "grpc+", + "com_github_grpc_grpc", + "grpc+" + ] + ] + } + }, + "@@hedron_compile_commands+//:workspace_setup.bzl%hedron_compile_commands_extension": { + "general": { + "bzlTransitiveDigest": "7Ey+orEPG9KH85wB77is9jsTlAqjXehBmrGP1vKxaCk=", + "usagesDigest": "CbJ2MjubH36j9xaONhhASfhodhpi5fzvuyg/IW2f7Ds=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": {}, + "recordedRepoMappingEntries": [ + [ + "hedron_compile_commands+", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@hedron_compile_commands+//:workspace_setup_transitive.bzl%hedron_compile_commands_extension": { + "general": { + "bzlTransitiveDigest": "IfDf0vEa2jjQ11RNpUM0u4xftPXIs+pyM8IMVkRqVMk=", + "usagesDigest": "yxZQbFglJyjpn7JZ9mhIc3EhLzZivlbs6wiHWOKJ/UA=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": {}, + "recordedRepoMappingEntries": [] + } + }, + "@@hedron_compile_commands+//:workspace_setup_transitive_transitive.bzl%hedron_compile_commands_extension": { + "general": { + "bzlTransitiveDigest": "1p58k3o2Jgjt/pBE7cb8WmmkplrSguIKma/h32x7X10=", + "usagesDigest": "GkOuy/k8wz0dbKMeEJFKEJB3CWkMZt3DYcPgj4lALkI=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": {}, + "recordedRepoMappingEntries": [] + } + }, + "@@hedron_compile_commands+//:workspace_setup_transitive_transitive_transitive.bzl%hedron_compile_commands_extension": { + "general": { + "bzlTransitiveDigest": "arNWX4EleUjJxqkM5nCRTj+ce05Zz1gSdGH1DCKOoLs=", + "usagesDigest": "WZExKK/BI4lqpUZfPpv4YARDE1Y7igQB+wYGKvNoCKs=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": {}, + "recordedRepoMappingEntries": [] + } + }, "@@pybind11_bazel+//:internal_configure.bzl%internal_configure_extension": { "general": { - "bzlTransitiveDigest": "wXImnqOfGKOqkiPwQBuez+TGQdj1tuLQU6OYcfhB97I=", - "usagesDigest": "/N7/XiWypVB4Uub/CNx0gUv2k2oUf1KA5dvJdrmWqXQ=", + "bzlTransitiveDigest": "wXImnqOfGKOqkiPwQBuez+TGQdj1tuLQU6OYcfhB97I=", + "usagesDigest": "/N7/XiWypVB4Uub/CNx0gUv2k2oUf1KA5dvJdrmWqXQ=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "pybind11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file": "@@pybind11_bazel+//:pybind11-BUILD.bazel", + "strip_prefix": "pybind11-2.13.6", + "url": "https://github.com/pybind/pybind11/archive/refs/tags/v2.13.6.tar.gz", + "integrity": "sha256-4Iy4f0dz2pf6e18DXeh2OrxlbYfVdz5i9toFh9Hw7CA=" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "pybind11_bazel+", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_apple+//apple:apple.bzl%provisioning_profile_repository_extension": { + "general": { + "bzlTransitiveDigest": "0owyZzufrcndNC+tsd4gvFRHhsHMpOkROsveC5nuiXc=", + "usagesDigest": "vsJl8Rw5NL+5Ag2wdUDoTeRF/5klkXO8545Iy7U1Q08=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_provisioning_profiles": { + "repoRuleId": "@@rules_apple+//apple/internal:local_provisioning_profiles.bzl%provisioning_profile_repository", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [ + [ + "apple_support+", + "bazel_skylib", + "bazel_skylib+" + ], + [ + "bazel_tools", + "rules_cc", + "rules_cc+" + ], + [ + "rules_apple+", + "bazel_skylib", + "bazel_skylib+" + ], + [ + "rules_apple+", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_apple+", + "build_bazel_apple_support", + "apple_support+" + ], + [ + "rules_apple+", + "build_bazel_rules_swift", + "rules_swift+" + ], + [ + "rules_cc+", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_cc+", + "rules_cc", + "rules_cc+" + ], + [ + "rules_swift+", + "bazel_skylib", + "bazel_skylib+" + ], + [ + "rules_swift+", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_swift+", + "build_bazel_apple_support", + "apple_support+" + ], + [ + "rules_swift+", + "build_bazel_rules_swift", + "rules_swift+" + ], + [ + "rules_swift+", + "build_bazel_rules_swift_local_config", + "rules_swift++non_module_deps+build_bazel_rules_swift_local_config" + ] + ] + } + }, + "@@rules_apple+//apple:extensions.bzl%non_module_deps": { + "general": { + "bzlTransitiveDigest": "rdeowIB16n42a/MEy5gV/a/kpjt45s1nmLJCD/kXsPU=", + "usagesDigest": "M3VqFpeTCo4qmrNKGZw0dxBHvTYDrfV3cscGzlSAhQ4=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { - "pybind11": { + "xctestrunner": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "build_file": "@@pybind11_bazel+//:pybind11-BUILD.bazel", - "strip_prefix": "pybind11-2.13.6", - "url": "https://github.com/pybind/pybind11/archive/refs/tags/v2.13.6.tar.gz", - "integrity": "sha256-4Iy4f0dz2pf6e18DXeh2OrxlbYfVdz5i9toFh9Hw7CA=" + "urls": [ + "https://github.com/google/xctestrunner/archive/b7698df3d435b6491b4b4c0f9fc7a63fbed5e3a6.tar.gz" + ], + "strip_prefix": "xctestrunner-b7698df3d435b6491b4b4c0f9fc7a63fbed5e3a6", + "sha256": "ae3a063c985a8633cb7eb566db21656f8db8eb9a0edb8c182312c7f0db53730d" } } }, "recordedRepoMappingEntries": [ [ - "pybind11_bazel+", + "rules_apple+", "bazel_tools", "bazel_tools" ] @@ -935,6 +1903,213 @@ ] } }, + "@@rules_go+//go/private:extensions.bzl%non_module_dependencies": { + "general": { + "bzlTransitiveDigest": "OdOxz+N0k26IWdEfgMY0z7SVQgDOCKJ6DCRbvEX8ETk=", + "usagesDigest": "wXfEypf5dx8CldENG2iBAbD5BcTuPmxnw78NFUFciD8=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "bazel_skylib": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz" + ], + "sha256": "b8a1527901774180afc798aeb28c4634bdccf19c4d98e7bdd1ce79d1fe9aaad7", + "strip_prefix": "" + } + }, + "org_golang_x_tools": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/golang/tools/archive/refs/tags/v0.7.0.zip", + "https://github.com/golang/tools/archive/refs/tags/v0.7.0.zip" + ], + "sha256": "9f20a20f29f4008d797a8be882ef82b69cf8f7f2b96dbdfe3814c57d8280fa4b", + "strip_prefix": "tools-0.7.0", + "patches": [ + "@@rules_go+//third_party:org_golang_x_tools-deletegopls.patch", + "@@rules_go+//third_party:org_golang_x_tools-gazelle.patch" + ], + "patch_args": [ + "-p1" + ] + } + }, + "org_golang_x_sys": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/golang/sys/archive/refs/tags/v0.6.0.zip", + "https://github.com/golang/sys/archive/refs/tags/v0.6.0.zip" + ], + "sha256": "7f2399398b2eb4f1f495cc754d6353566e0ad934ee0eb46505e55162e0def56d", + "strip_prefix": "sys-0.6.0", + "patches": [ + "@@rules_go+//third_party:org_golang_x_sys-gazelle.patch" + ], + "patch_args": [ + "-p1" + ] + } + }, + "org_golang_x_xerrors": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/golang/xerrors/archive/04be3eba64a22a838cdb17b8dca15a52871c08b4.zip", + "https://github.com/golang/xerrors/archive/04be3eba64a22a838cdb17b8dca15a52871c08b4.zip" + ], + "sha256": "ffad2b06ef2e09d040da2ff08077865e99ab95d4d0451737fc8e33706bb01634", + "strip_prefix": "xerrors-04be3eba64a22a838cdb17b8dca15a52871c08b4", + "patches": [ + "@@rules_go+//third_party:org_golang_x_xerrors-gazelle.patch" + ], + "patch_args": [ + "-p1" + ] + } + }, + "org_golang_google_protobuf": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "cb1a05581c33b3705ede6c08edf9b9c1dbc579559ba30f532704c324e42bf801", + "urls": [ + "https://mirror.bazel.build/github.com/protocolbuffers/protobuf-go/archive/refs/tags/v1.30.0.zip", + "https://github.com/protocolbuffers/protobuf-go/archive/refs/tags/v1.30.0.zip" + ], + "strip_prefix": "protobuf-go-1.30.0", + "patches": [ + "@@rules_go+//third_party:org_golang_google_protobuf-gazelle.patch" + ], + "patch_args": [ + "-p1" + ] + } + }, + "com_github_golang_protobuf": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/golang/protobuf/archive/refs/tags/v1.5.3.zip", + "https://github.com/golang/protobuf/archive/refs/tags/v1.5.3.zip" + ], + "sha256": "2dced4544ae5372281e20f1e48ca76368355a01b31353724718c4d6e3dcbb430", + "strip_prefix": "protobuf-1.5.3", + "patches": [ + "@@rules_go+//third_party:com_github_golang_protobuf-gazelle.patch" + ], + "patch_args": [ + "-p1" + ] + } + }, + "com_github_mwitkow_go_proto_validators": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/mwitkow/go-proto-validators/archive/refs/tags/v0.3.2.zip", + "https://github.com/mwitkow/go-proto-validators/archive/refs/tags/v0.3.2.zip" + ], + "sha256": "d8697f05a2f0eaeb65261b480e1e6035301892d9fc07ed945622f41b12a68142", + "strip_prefix": "go-proto-validators-0.3.2" + } + }, + "com_github_gogo_protobuf": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/gogo/protobuf/archive/refs/tags/v1.3.2.zip", + "https://github.com/gogo/protobuf/archive/refs/tags/v1.3.2.zip" + ], + "sha256": "f89f8241af909ce3226562d135c25b28e656ae173337b3e58ede917aa26e1e3c", + "strip_prefix": "protobuf-1.3.2", + "patches": [ + "@@rules_go+//third_party:com_github_gogo_protobuf-gazelle.patch" + ], + "patch_args": [ + "-p1" + ] + } + }, + "gogo_special_proto": { + "repoRuleId": "@@rules_go+//proto:gogo.bzl%gogo_special_proto", + "attributes": {} + }, + "org_golang_google_genproto": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/googleapis/go-genproto/archive/6ac7f18bb9d5eeeb13a9f1ae4f21e4374a1952f8.zip", + "https://github.com/googleapis/go-genproto/archive/6ac7f18bb9d5eeeb13a9f1ae4f21e4374a1952f8.zip" + ], + "sha256": "3470e7a89b24971b20c4bb8900a668df25279e4b741f72bc09418c1f22543215", + "strip_prefix": "go-genproto-6ac7f18bb9d5eeeb13a9f1ae4f21e4374a1952f8", + "patches": [ + "@@rules_go+//third_party:org_golang_google_genproto-gazelle.patch" + ], + "patch_args": [ + "-p1" + ] + } + }, + "go_googleapis": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/googleapis/googleapis/archive/83c3605afb5a39952bf0a0809875d41cf2a558ca.zip", + "https://github.com/googleapis/googleapis/archive/83c3605afb5a39952bf0a0809875d41cf2a558ca.zip" + ], + "sha256": "ba694861340e792fd31cb77274eacaf6e4ca8bda97707898f41d8bebfd8a4984", + "strip_prefix": "googleapis-83c3605afb5a39952bf0a0809875d41cf2a558ca", + "patches": [ + "@@rules_go+//third_party:go_googleapis-deletebuild.patch", + "@@rules_go+//third_party:go_googleapis-directives.patch", + "@@rules_go+//third_party:go_googleapis-gazelle.patch" + ], + "patch_args": [ + "-E", + "-p1" + ] + } + }, + "com_github_golang_mock": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://mirror.bazel.build/github.com/golang/mock/archive/refs/tags/v1.7.0-rc.1.zip", + "https://github.com/golang/mock/archive/refs/tags/v1.7.0-rc.1.zip" + ], + "patches": [ + "@@rules_go+//third_party:com_github_golang_mock-gazelle.patch" + ], + "patch_args": [ + "-p1" + ], + "sha256": "5359c78b0c1649cf7beb3b48ff8b1d1aaf0243b22ea4789aba94805280075d8e", + "strip_prefix": "mock-1.7.0-rc.1" + } + }, + "io_bazel_rules_nogo": { + "repoRuleId": "@@rules_go+//go/private:nogo.bzl%go_register_nogo", + "attributes": { + "nogo": "@io_bazel_rules_go//:default_nogo" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_go+", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { "general": { "bzlTransitiveDigest": "sFhcgPbDQehmbD1EOXzX4H1q/CD5df8zwG4kp4jbvr8=", @@ -1034,6 +2209,193 @@ ] ] } + }, + "@@rules_swift+//swift:extensions.bzl%non_module_deps": { + "general": { + "bzlTransitiveDigest": "X3B53n1AmUggqagsfW3TwgDmiWEQnqWY1izDXQ3mZtY=", + "usagesDigest": "mhACFnrdMv9Wi0Mt67bxocJqviRkDSV+Ee5Mqdj5akA=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_apple_swift_protobuf": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-protobuf/archive/1.20.2.tar.gz" + ], + "sha256": "3fb50bd4d293337f202d917b6ada22f9548a0a0aed9d9a4d791e6fbd8a246ebb", + "strip_prefix": "swift-protobuf-1.20.2/", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_protobuf/BUILD.overlay" + } + }, + "com_github_grpc_grpc_swift": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/grpc/grpc-swift/archive/1.16.0.tar.gz" + ], + "sha256": "58b60431d0064969f9679411264b82e40a217ae6bd34e17096d92cc4e47556a5", + "strip_prefix": "grpc-swift-1.16.0/", + "build_file": "@@rules_swift+//third_party:com_github_grpc_grpc_swift/BUILD.overlay" + } + }, + "com_github_apple_swift_docc_symbolkit": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-docc-symbolkit/archive/refs/tags/swift-5.10-RELEASE.tar.gz" + ], + "sha256": "de1d4b6940468ddb53b89df7aa1a81323b9712775b0e33e8254fa0f6f7469a97", + "strip_prefix": "swift-docc-symbolkit-swift-5.10-RELEASE", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_docc_symbolkit/BUILD.overlay" + } + }, + "com_github_apple_swift_nio": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-nio/archive/2.42.0.tar.gz" + ], + "sha256": "e3304bc3fb53aea74a3e54bd005ede11f6dc357117d9b1db642d03aea87194a0", + "strip_prefix": "swift-nio-2.42.0/", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio/BUILD.overlay" + } + }, + "com_github_apple_swift_nio_http2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-nio-http2/archive/1.26.0.tar.gz" + ], + "sha256": "f0edfc9d6a7be1d587e5b403f2d04264bdfae59aac1d74f7d974a9022c6d2b25", + "strip_prefix": "swift-nio-http2-1.26.0/", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio_http2/BUILD.overlay" + } + }, + "com_github_apple_swift_nio_transport_services": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-nio-transport-services/archive/1.15.0.tar.gz" + ], + "sha256": "f3498dafa633751a52b9b7f741f7ac30c42bcbeb3b9edca6d447e0da8e693262", + "strip_prefix": "swift-nio-transport-services-1.15.0/", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio_transport_services/BUILD.overlay" + } + }, + "com_github_apple_swift_nio_extras": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-nio-extras/archive/1.4.0.tar.gz" + ], + "sha256": "4684b52951d9d9937bb3e8ccd6b5daedd777021ef2519ea2f18c4c922843b52b", + "strip_prefix": "swift-nio-extras-1.4.0/", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio_extras/BUILD.overlay" + } + }, + "com_github_apple_swift_log": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-log/archive/1.4.4.tar.gz" + ], + "sha256": "48fe66426c784c0c20031f15dc17faf9f4c9037c192bfac2f643f65cb2321ba0", + "strip_prefix": "swift-log-1.4.4/", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_log/BUILD.overlay" + } + }, + "com_github_apple_swift_nio_ssl": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-nio-ssl/archive/2.23.0.tar.gz" + ], + "sha256": "4787c63f61dd04d99e498adc3d1a628193387e41efddf8de19b8db04544d016d", + "strip_prefix": "swift-nio-ssl-2.23.0/", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio_ssl/BUILD.overlay" + } + }, + "com_github_apple_swift_collections": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-collections/archive/1.0.4.tar.gz" + ], + "sha256": "d9e4c8a91c60fb9c92a04caccbb10ded42f4cb47b26a212bc6b39cc390a4b096", + "strip_prefix": "swift-collections-1.0.4/", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_collections/BUILD.overlay" + } + }, + "com_github_apple_swift_atomics": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/apple/swift-atomics/archive/1.1.0.tar.gz" + ], + "sha256": "1bee7f469f7e8dc49f11cfa4da07182fbc79eab000ec2c17bfdce468c5d276fb", + "strip_prefix": "swift-atomics-1.1.0/", + "build_file": "@@rules_swift+//third_party:com_github_apple_swift_atomics/BUILD.overlay" + } + }, + "build_bazel_rules_swift_index_import": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file": "@@rules_swift+//third_party:build_bazel_rules_swift_index_import/BUILD.overlay", + "canonical_id": "index-import-5.8", + "urls": [ + "https://github.com/MobileNativeFoundation/index-import/releases/download/5.8.0.1/index-import.tar.gz" + ], + "sha256": "28c1ffa39d99e74ed70623899b207b41f79214c498c603915aef55972a851a15" + } + }, + "build_bazel_rules_swift_local_config": { + "repoRuleId": "@@rules_swift+//swift/internal:swift_autoconfiguration.bzl%swift_autoconfiguration", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_swift+", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_swift+", + "build_bazel_rules_swift", + "rules_swift+" + ] + ] + } + }, + "@@upb+//:non_module_deps.bzl%non_module_deps": { + "general": { + "bzlTransitiveDigest": "MoDKeLK+fZfOC/Kn2bejs500LmbsWGEP2rGmPqFJaxo=", + "usagesDigest": "pZOZBYc8Kee/Hi8/EIf3SfYt6ar0unb9MMI2Tczhi6g=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "utf8_range": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://github.com/protocolbuffers/utf8_range/archive/de0b4a8ff9b5d4c98108bdfe723291a33c52c54f.zip" + ], + "strip_prefix": "utf8_range-de0b4a8ff9b5d4c98108bdfe723291a33c52c54f", + "sha256": "5da960e5e5d92394c809629a03af3c7709d2d3d0ca731dacb3a9fb4bf28f7702" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "upb+", + "bazel_tools", + "bazel_tools" + ] + ] + } } } } diff --git a/src/extlibs/tomlplusplus.BUILD b/src/extlibs/tomlplusplus.BUILD new file mode 100644 index 0000000000..784ad9b64e --- /dev/null +++ b/src/extlibs/tomlplusplus.BUILD @@ -0,0 +1,10 @@ +cc_library( + name = "tomlplusplus", + hdrs = glob([ + "include/toml++/**/*.hpp", + "include/toml++/**/*.h", + "include/toml++/**/*.inl", + ]), + includes = ["include"], + visibility = ["//visibility:public"], +) diff --git a/src/shared/constants.h b/src/shared/constants.h index d5047d92b9..832e702c56 100644 --- a/src/shared/constants.h +++ b/src/shared/constants.h @@ -34,10 +34,8 @@ static const unsigned int REPLAY_FILE_VERSION = 2; #endif // PLATFORMIO_BUILD -// Redis default server connections properties -#define REDIS_HOST_LENGTH 10 -static const char REDIS_DEFAULT_HOST[REDIS_HOST_LENGTH] = "127.0.0.1"; -static const short unsigned int REDIS_DEFAULT_PORT = 6379; +// TOML config file path for robot configuration +static const char TOML_CONFIG_FILE_PATH[] = "/opt/tbotspython/robot_config.toml"; // the UDP port robots are listening to for primitives static const short unsigned int PRIMITIVE_PORT = 42070; diff --git a/src/software/constants.h b/src/software/constants.h index 0d7156f665..d1592e54b1 100644 --- a/src/software/constants.h +++ b/src/software/constants.h @@ -44,16 +44,13 @@ static const double BALL_TO_FRONT_OF_ROBOT_DISTANCE_WHEN_DRIBBLING = BALL_MAX_RADIUS_METERS - 2 * BALL_MAX_RADIUS_METERS * MAX_FRACTION_OF_BALL_COVERED_BY_ROBOT; -// Redis Keys -const std::string ROBOT_ID_REDIS_KEY = "/robot_id"; -const std::string ROBOT_MULTICAST_CHANNEL_REDIS_KEY = "/channel_id"; -const std::string ROBOT_NETWORK_INTERFACE_REDIS_KEY = "/network_interface"; -const std::string ROBOT_KICK_CONSTANT_REDIS_KEY = "/kick_constant"; -const std::string ROBOT_KICK_EXP_COEFF_REDIS_KEY = "/kick_coeff"; -const std::string ROBOT_CHIP_PULSE_WIDTH_REDIS_KEY = "/chip_pulse_width"; -const std::string ROBOT_CURRENT_DRAW_REDIS_KEY = "/current_draw"; -const std::string ROBOT_BATTERY_VOLTAGE_REDIS_KEY = "/battery_voltage"; -const std::string ROBOT_CAPACITOR_VOLTAGE_REDIS_KEY = "/cap_voltage"; +// TOML Config Keys +const std::string ROBOT_ID_CONFIG_KEY = "robot_id"; +const std::string ROBOT_MULTICAST_CHANNEL_CONFIG_KEY = "channel_id"; +const std::string ROBOT_NETWORK_INTERFACE_CONFIG_KEY = "network_interface"; +const std::string ROBOT_KICK_CONSTANT_CONFIG_KEY = "kick_constant"; +const std::string ROBOT_KICK_EXP_COEFF_CONFIG_KEY = "kick_coeff"; +const std::string ROBOT_CHIP_PULSE_WIDTH_CONFIG_KEY = "chip_pulse_width"; const std::string SSL_VISION_ADDRESS = "224.5.23.2"; static constexpr unsigned int SSL_VISION_PORT = 10020; diff --git a/src/software/embedded/BUILD b/src/software/embedded/BUILD index f3efd2e985..eb3620570b 100644 --- a/src/software/embedded/BUILD +++ b/src/software/embedded/BUILD @@ -63,10 +63,10 @@ cc_library( deps = [ ":primitive_executor", "//proto:tbots_cc_proto", - "//software/embedded/redis", "//software/embedded/services:motor", "//software/embedded/services:power", "//software/embedded/services/network", + "//software/embedded/toml_config", "//software/logger:network_logger", "//software/tracy:tracy_constants", "//software/util/scoped_timespec_timer", diff --git a/src/software/embedded/ansible/BUILD b/src/software/embedded/ansible/BUILD index f20fb92ee5..3a36abe960 100644 --- a/src/software/embedded/ansible/BUILD +++ b/src/software/embedded/ansible/BUILD @@ -23,7 +23,6 @@ py_binary( "//software/embedded/linux_configs/jetson_nano:jetson_nano_files", "//software/embedded/linux_configs/pi:pi_files", "//software/embedded/linux_configs/systemd:systemd_files", - "//software/embedded/redis", "//software/embedded/robot_diagnostics_cli:robot_diagnostics_cli_tar", "//software/embedded/services:robot_auto_test", "//software/power:powerloop_tar", diff --git a/src/software/embedded/ansible/tasks/setup_robot_software_deps.yml b/src/software/embedded/ansible/tasks/setup_robot_software_deps.yml index 1cd7d27416..8f859f9298 100644 --- a/src/software/embedded/ansible/tasks/setup_robot_software_deps.yml +++ b/src/software/embedded/ansible/tasks/setup_robot_software_deps.yml @@ -17,16 +17,6 @@ args: chdir: ~/ -- name: Configure Redis persistence setting - become: true - become_method: ansible.builtin.sudo - ansible.builtin.lineinfile: - path: /etc/redis/redis.conf - state: present - regexp: ^(appendonly) - line: "appendonly yes" - backrefs: true - - name: Disable WiFi power management block: - name: Delete WiFi power management rule diff --git a/src/software/embedded/redis/BUILD b/src/software/embedded/redis/BUILD deleted file mode 100644 index 4d0099a77f..0000000000 --- a/src/software/embedded/redis/BUILD +++ /dev/null @@ -1,24 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -cc_library( - name = "redis", - srcs = ["redis_client.cpp"], - hdrs = ["redis_client.h"], - deps = [ - "//software/logger", - "@cpp_redis", - ], -) - -cc_test( - name = "redis_test_cpp", - srcs = [ - "redis_client_test.cpp", - ], - deps = [ - ":redis", - "//shared/test_util:tbots_gtest_main", - "//software/test_util", - "@cpp_redis", - ], -) diff --git a/src/software/embedded/redis/redis_client.cpp b/src/software/embedded/redis/redis_client.cpp deleted file mode 100644 index 441a9a2f96..0000000000 --- a/src/software/embedded/redis/redis_client.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "software/embedded/redis/redis_client.h" - - -RedisClient::RedisClient(std::string host, size_t port) - : subscriber_(), client_(), host_(host), port_(port) -{ - auto connection_callback = - [](const std::string &host, std::size_t port, cpp_redis::connect_state status) - { - if (status == cpp_redis::connect_state::dropped) - { - LOG(WARNING) << "Redis subscriber_ connection dropped"; - } - else if (status == cpp_redis::connect_state::failed) - { - LOG(WARNING) << "Redis subscriber_ connection failed"; - } - else if (status == cpp_redis::connect_state::ok) - { - LOG(INFO) << "Redis subscriber_ connection successful"; - } - }; - - subscriber_.connect(host_, port_, connection_callback); - client_.connect(host_, port_, connection_callback); - - // ensure that keyspace events are configured properly - client_.config_set("notify-keyspace-events", "KEA"); - - // ensure that redis server is accepting connections from any host (potentially - // unsafe) - client_.config_set("bind", "0.0.0.0"); - - // ensure that redis server has AOF (append-only file) persistence - client_.config_set("appendonly", "yes"); - - // subscribe to key 'set' event within the keyspace - // adds key and its value to the key value set - subscriber_.subscribe("__keyevent@0__:set", - [this](const std::string &channel, const std::string &key) - { - client_.get(key, [this, key](cpp_redis::reply &value) - { key_value_set_[key] = value.as_string(); }); - client_.commit(); - }); - subscriber_.commit(); -} - -std::string RedisClient::getSync(const std::string &key) -{ - auto future = client_.get(key); - client_.commit(); - return future.get().as_string(); -} - -void RedisClient::getAsyncNoCommit(const std::string &key, - const cpp_redis::reply_callback_t &reply_callback) -{ - client_.get(key, reply_callback); -} - -void RedisClient::getAsync(const std::string &key, - const cpp_redis::reply_callback_t &reply_callback) -{ - client_.get(key, reply_callback); - asyncCommit(); -} - -void RedisClient::setAsync(const std::string &key, const std::string &value) -{ - client_.set(key, value); - asyncCommit(); -} - -void RedisClient::setSync(const std::string &key, const std::string &value) -{ - client_.set(key, value); - syncCommit(); -} - -void RedisClient::setNoCommit(const std::string &key, const std::string &value) -{ - client_.set(key, value); -} - -void RedisClient::asyncCommit() -{ - client_.commit(); -} - -void RedisClient::syncCommit() -{ - client_.sync_commit(); -} - -std::unordered_map RedisClient::getAllKeyValuePairs() -{ - return key_value_set_; -} - -RedisClient::~RedisClient() {} diff --git a/src/software/embedded/redis/redis_client.h b/src/software/embedded/redis/redis_client.h deleted file mode 100644 index 00763bb126..0000000000 --- a/src/software/embedded/redis/redis_client.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include "chrono" -#include "cpp_redis/cpp_redis" -#include "shared/constants.h" -#include "software/logger/logger.h" -#include "string" -#include "unordered_map" - - -class RedisClient -{ - public: - /** - * Client that communicates with the a redis server - * @param address The IP of the Redis server, default localhost - * @param port the key of the Redis server, default 6379 - */ - explicit RedisClient(std::string address, size_t port); - - virtual ~RedisClient(); - - - /** - * Gets the value corresponding to the key; blocking - * - * @param key - * @return the value - */ - std::string getSync(const std::string &key); - - /** - * Gets the value corresponding to the key, non blocking - executes the callback once - * a reply is received. - * - * @param key - * @param reply_callback callback function once the value is obtained - */ - void getAsync(const std::string &key, - const cpp_redis::reply_callback_t &reply_callback); - - /** - * Gets the value corresponding to the key, asynchronously but doesn't commit it. Must - * manually call asyncCommit() to commit it to the REDIS server. - * - * Allows us to batch call a number of GET/SET requests to the REDIS server with one - * network request. - * - * @param key - * @param reply_callback callback function once the value is obtained - */ - void getAsyncNoCommit(const std::string &key, - const cpp_redis::reply_callback_t &reply_callback); - - /** - * Sets a key value pair in the redis database asynchronously - * - * @param key - * @param value - */ - void setAsync(const std::string &key, const std::string &value); - - /** - * Gets the value corresponding to the key; blocking synchronously - * - * @param key - * @param the value - */ - void setSync(const std::string &key, const std::string &value); - - /** - * Sets a key value pair in the redis database but does not commit it. Waits for the - * next commit() to send it to the REDIS server. - * - * Allows us to batch call a number of GET/SET requests to the REDIS server with one - * network request. - * - * @param key key for key-value pair - * @param value value to set to key-value pair - */ - void setNoCommit(const std::string &key, const std::string &value); - - /** - * Asynchronously commit all pending requests since last commit. - */ - void asyncCommit(); - - /** - * Synchronously commit all pending requests since last commit. - */ - void syncCommit(); - - /** - * @return a map of all the key value pairs in redis server - */ - std::unordered_map getAllKeyValuePairs(); - - private: - cpp_redis::subscriber subscriber_; - cpp_redis::client client_; - std::unordered_map key_value_set_; - // Connection Parameters - std::string host_; - size_t port_; -}; diff --git a/src/software/embedded/redis/redis_client_test.cpp b/src/software/embedded/redis/redis_client_test.cpp deleted file mode 100644 index 9a51ea1947..0000000000 --- a/src/software/embedded/redis/redis_client_test.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "software/embedded/redis/redis_client.h" - -#include -#include -#include -#include - -#include "cpp_redis/core/client.hpp" -#include "cpp_redis/core/subscriber.hpp" -#include "software/test_util/test_util.h" - -// TODO #2805: Convert this into a test fixture so that we can start and run a REDIS -// server during the lifetime of the test fixture. Then re-enable all tests - -TEST(RedisKeyValueStoreTests, DISABLED_cpp_redis_get_test) -{ - cpp_redis::client client; - client.connect( - REDIS_DEFAULT_HOST, REDIS_DEFAULT_PORT, - [](const std::string &host, std::size_t port, cpp_redis::connect_state status) - { - if (status == cpp_redis::connect_state::dropped) - { - std::cout << "client disconnected from " << host << ":" << port - << std::endl; - } - }); - - client.set("A", "1", - [](cpp_redis::reply &reply) - { std::cout << "Setting A to 1: " << reply << std::endl; }); - - client.get("A", - [](cpp_redis::reply &reply) - { - std::cout << "Getting A: " << reply << std::endl; - ASSERT_EQ(atoi(reply.as_string().c_str()), 1); - }); - - client.set("A", "2", - [](cpp_redis::reply &reply) - { std::cout << "Setting A to 2: " << reply << std::endl; }); - - client.get("A", - [](cpp_redis::reply &reply) - { - std::cout << "Getting A: " << reply << std::endl; - ASSERT_EQ(atoi(reply.as_string().c_str()), 2); - }); - client.sync_commit(); -} - -TEST(RedisKeyValueStoreTests, DISABLED_cpp_redis_get_and_set_speed_test) -{ - cpp_redis::client client; - client.connect( - REDIS_DEFAULT_HOST, REDIS_DEFAULT_PORT, - [](const std::string &host, std::size_t port, cpp_redis::connect_state status) - { - if (status == cpp_redis::connect_state::dropped) - { - std::cout << "client disconnected from " << host << ":" << port - << std::endl; - } - }); - auto start = std::chrono::system_clock::now(); - std::time_t start_time = std::chrono::system_clock::to_time_t(start); - std::cout << "Started computation at " << std::ctime(&start_time); - for (int i = 0; i <= 200; i++) - { - client.set("A", "1", [](cpp_redis::reply &reply) {}); - - client.get("A", [](cpp_redis::reply &reply) - { ASSERT_EQ(atoi(reply.as_string().c_str()), 1); }); - - client.set("A", "2", [](cpp_redis::reply &reply) {}); - - client.get("A", [](cpp_redis::reply &reply) - { ASSERT_EQ(atoi(reply.as_string().c_str()), 2); }); - } - auto end = std::chrono::system_clock::now(); - std::chrono::duration elapsed_seconds = end - start; - std::time_t end_time = std::chrono::system_clock::to_time_t(end); - - std::cout << "Finished computation at " << std::ctime(&end_time) - << "Elapsed time: " << elapsed_seconds.count() << "s\n"; -} - - -TEST(RedisImplTests, DISABLED_redis_client_get_and_set_impl_test) -{ - auto redis = RedisClient("127.0.0.1", 6379); - - cpp_redis::client client; - client.connect( - REDIS_DEFAULT_HOST, REDIS_DEFAULT_PORT, - [](const std::string &host, std::size_t port, cpp_redis::connect_state status) - { - if (status == cpp_redis::connect_state::dropped) - { - std::cout << "client disconnected from " << host << ":" << port - << std::endl; - } - }); - - auto start = std::chrono::system_clock::now(); - std::time_t start_time = std::chrono::system_clock::to_time_t(start); - std::cout << "Started computation at " << std::ctime(&start_time); - - for (int i = 0; i <= 20; i++) - { - redis.setSync(std::to_string(i), "test_value_new"); - auto reply = redis.getSync(std::to_string(i)); - ASSERT_EQ(reply, "test_value_new"); - } - - auto end = std::chrono::system_clock::now(); - std::chrono::duration elapsed_seconds = end - start; - std::time_t end_time = std::chrono::system_clock::to_time_t(end); - - ASSERT_LE(elapsed_seconds.count() * 1000, 25); - ASSERT_EQ(redis.getAllKeyValuePairs().size(), 20); - - std::cout << "Finished computation at " << std::ctime(&end_time) - << "Elapsed time: " << elapsed_seconds.count() << "s\n"; -} diff --git a/src/software/embedded/robot_diagnostics_cli/BUILD b/src/software/embedded/robot_diagnostics_cli/BUILD index 98103c8401..588f9dea08 100644 --- a/src/software/embedded/robot_diagnostics_cli/BUILD +++ b/src/software/embedded/robot_diagnostics_cli/BUILD @@ -31,7 +31,6 @@ py_binary( requirement("typer_shell"), requirement("rich"), requirement("protobuf"), - requirement("redis"), requirement("inquirerpy"), ], ) @@ -55,14 +54,10 @@ py_library( srcs = [":embedded_communication.py"], deps = [ requirement("protobuf"), - requirement("redis"), ], ) py_library( name = "embedded_data", srcs = [":embedded_data.py"], - deps = [ - requirement("redis"), - ], ) diff --git a/src/software/embedded/robot_diagnostics_cli/embedded_data.py b/src/software/embedded/robot_diagnostics_cli/embedded_data.py index 0252163d58..1633c19036 100644 --- a/src/software/embedded/robot_diagnostics_cli/embedded_data.py +++ b/src/software/embedded/robot_diagnostics_cli/embedded_data.py @@ -1,5 +1,6 @@ import math -import redis +import os +import tomllib from software.py_constants import * from proto.import_all_protos import * from software.embedded.constants.py_constants import ( @@ -20,44 +21,57 @@ class EmbeddedData: """ def __init__(self) -> None: - # Initializes the redis cache connection - self.redis = redis.StrictRedis( - host=REDIS_DEFAULT_HOST, - port=REDIS_DEFAULT_PORT, - charset="utf-8", - decode_responses=True, - ) + self.config_file_path = "/opt/tbotspython/robot_config.toml" + self.config = self._load_config() self.epoch_timestamp_seconds = 0 self.battery_voltage = 0 self.primitive_packet_loss_percentage = 0 self.primitive_executor_step_time_ms = 0 + def _load_config(self) -> dict: + """Load TOML configuration file.""" + if not os.path.exists(self.config_file_path): + return {} + try: + with open(self.config_file_path, "rb") as f: + return tomllib.load(f) + except Exception as e: + print( + f"Warning: Failed to load TOML config from {self.config_file_path}: {e}" + ) + return {} + + def _get_value(self, key: str): + """Get a value from the TOML file; TOML keys do not start with '/'.""" + normalized_key = key.lstrip("/") + return self.config.get(normalized_key, "") + def get_robot_id(self) -> str: - return str(self.redis.get(ROBOT_ID_REDIS_KEY)) + return self._get_value(ROBOT_ID_CONFIG_KEY) def get_network_interface(self) -> str: - return str(self.redis.get(ROBOT_NETWORK_INTERFACE_REDIS_KEY)) + return self._get_value(ROBOT_NETWORK_INTERFACE_CONFIG_KEY) def get_channel_id(self) -> str: - return str(self.redis.get(ROBOT_MULTICAST_CHANNEL_REDIS_KEY)) + return self._get_value(ROBOT_MULTICAST_CHANNEL_CONFIG_KEY) def get_kick_constant(self) -> str: - return str(self.redis.get(ROBOT_KICK_CONSTANT_REDIS_KEY)) + return self._get_value(ROBOT_KICK_CONSTANT_CONFIG_KEY) def get_kick_coeff(self) -> str: - return str(self.redis.get(ROBOT_KICK_EXP_COEFF_REDIS_KEY)) + return self._get_value(ROBOT_KICK_EXP_COEFF_CONFIG_KEY) def get_chip_pulse_width(self) -> str: - return str(self.redis.get(ROBOT_CHIP_PULSE_WIDTH_REDIS_KEY)) + return self._get_value(ROBOT_CHIP_PULSE_WIDTH_CONFIG_KEY) def get_current_draw(self) -> str: - return str(self.redis.get(ROBOT_CURRENT_DRAW_REDIS_KEY)) + return self._get_value(ROBOT_CURRENT_DRAW_CONFIG_KEY) def get_battery_volt(self) -> str: - return str(self.redis.get(ROBOT_BATTERY_VOLTAGE_REDIS_KEY)) + return self._get_value(ROBOT_BATTERY_VOLTAGE_CONFIG_KEY) def get_cap_volt(self) -> str: - return str(self.redis.get(ROBOT_CAPACITOR_VOLTAGE_REDIS_KEY)) + return self._get_value(ROBOT_CAPACITOR_VOLTAGE_CONFIG_KEY) def __clamp(self, val: float, min_val: float, max_val: float) -> float: """Simple Math Clamp function (Faster than numpy & fewer dependencies) diff --git a/src/software/embedded/robot_diagnostics_cli/requirements.in b/src/software/embedded/robot_diagnostics_cli/requirements.in index f0fc563702..95ef1fb287 100644 --- a/src/software/embedded/robot_diagnostics_cli/requirements.in +++ b/src/software/embedded/robot_diagnostics_cli/requirements.in @@ -1,5 +1,4 @@ rich==13.9.2 typer-shell==0.1.12 protobuf==6.31.1 -redis==5.2.0 inquirerpy==0.3.4 diff --git a/src/software/embedded/robot_diagnostics_cli/requirements_lock.txt b/src/software/embedded/robot_diagnostics_cli/requirements_lock.txt index d35c009a6b..ac94619ecf 100644 --- a/src/software/embedded/robot_diagnostics_cli/requirements_lock.txt +++ b/src/software/embedded/robot_diagnostics_cli/requirements_lock.txt @@ -105,10 +105,6 @@ pyyaml==6.0.2 \ --hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \ --hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4 # via typer-shell -redis==5.2.0 \ - --hash=sha256:0b1087665a771b1ff2e003aa5bdd354f15a70c9e25d5a7dbf9c722c16528a7b0 \ - --hash=sha256:ae174f2bb3b1bf2b09d54bf3e51fbc1469cf6c10aa03e21141f51969801a7897 - # via -r software/embedded/robot_diagnostics_cli/requirements.in rich==13.9.2 \ --hash=sha256:51a2c62057461aaf7152b4d611168f93a9fc73068f8ded2790f29fe2b5366d0c \ --hash=sha256:8c82a3d3f8dcfe9e734771313e606b39d8247bb6b826e196f4914b333b743cf1 diff --git a/src/software/embedded/robot_diagnostics_cli/robot_diagnostics_cli.py b/src/software/embedded/robot_diagnostics_cli/robot_diagnostics_cli.py index 8761a8f280..3341780204 100644 --- a/src/software/embedded/robot_diagnostics_cli/robot_diagnostics_cli.py +++ b/src/software/embedded/robot_diagnostics_cli/robot_diagnostics_cli.py @@ -49,7 +49,7 @@ def __init__(self, embedded_communication: EmbeddedCommunication) -> None: self.app.command(short_help="Chips the chipper")(self.chip) self.app.command(short_help="Kicks the kicker")(self.kick) self.app.command(short_help="Show Robot Status Info")(self.stats) - self.app.command(short_help="Shows Redis Values")(self.redis) + self.app.command(short_help="Shows TOML Config Values")(self.config) self.app.command(short_help="Prints Thunderloop Logs")(self.log) self.app.command(short_help="Prints Thunderloop Status")(self.status) self.app.command(short_help="Restarts Thunderloop")(self.restart_thunderloop) @@ -126,54 +126,54 @@ def __generate_stats_table(self) -> Table: ) return table - def __generate_redis_table(self) -> Table: - """Make a new table with embedded_data.redis value information.""" + def __generate_config_table(self) -> Table: + """Make a new table with embedded_data TOML config value information.""" table = Table(show_header=True, header_style="bold blue") - table.add_column("Redis Value Name") + table.add_column("Config Value Name") table.add_column("Key", style="dim") table.add_column("Value") table.add_row( - "Robot ID", f"{ROBOT_ID_REDIS_KEY}", self.embedded_data.get_robot_id() + "Robot ID", f"{ROBOT_ID_CONFIG_KEY}", self.embedded_data.get_robot_id() ) table.add_row( "Channel ID", - f"{ROBOT_MULTICAST_CHANNEL_REDIS_KEY}", + f"{ROBOT_MULTICAST_CHANNEL_CONFIG_KEY}", self.embedded_data.get_channel_id(), ) table.add_row( "Network Interface", - f"{ROBOT_NETWORK_INTERFACE_REDIS_KEY}", + f"{ROBOT_NETWORK_INTERFACE_CONFIG_KEY}", self.embedded_data.get_network_interface(), ) table.add_row( "Kick Constant", - f"{ROBOT_KICK_CONSTANT_REDIS_KEY}", + f"{ROBOT_KICK_CONSTANT_CONFIG_KEY}", self.embedded_data.get_kick_constant(), ) table.add_row( "Kick Coefficient", - f"{ROBOT_KICK_EXP_COEFF_REDIS_KEY}", + f"{ROBOT_KICK_EXP_COEFF_CONFIG_KEY}", self.embedded_data.get_kick_coeff(), ) table.add_row( "Chip Pulse Width", - f"{ROBOT_CHIP_PULSE_WIDTH_REDIS_KEY}", + f"{ROBOT_CHIP_PULSE_WIDTH_CONFIG_KEY}", self.embedded_data.get_chip_pulse_width(), ) table.add_row( "Battery Voltage", - f"{ROBOT_BATTERY_VOLTAGE_REDIS_KEY}", + f"{ROBOT_BATTERY_VOLTAGE_CONFIG_KEY}", self.embedded_data.get_battery_volt(), ) table.add_row( "Battery Current Draw", - f"{ROBOT_CURRENT_DRAW_REDIS_KEY}", + f"{ROBOT_CURRENT_DRAW_CONFIG_KEY}", self.embedded_data.get_current_draw(), ) table.add_row( "Capacitor Voltage", - f"{ROBOT_CAPACITOR_VOLTAGE_REDIS_KEY}", + f"{ROBOT_CAPACITOR_VOLTAGE_CONFIG_KEY}", self.embedded_data.get_cap_volt(), ) return table @@ -184,9 +184,9 @@ def stats(self) -> None: while True: live.update(self.__generate_stats_table()) - def redis(self): - """CLI Command to generate Onboard Redis information""" - self.console.print(self.__generate_redis_table()) + def config(self): + """CLI Command to generate Onboard TOML config information""" + self.console.print(self.__generate_config_table()) def status(self): """CLI Command to print Thunderloop service status""" diff --git a/src/software/embedded/setup_robot_software_deps.sh b/src/software/embedded/setup_robot_software_deps.sh index f73e919bc1..5769d12f65 100755 --- a/src/software/embedded/setup_robot_software_deps.sh +++ b/src/software/embedded/setup_robot_software_deps.sh @@ -3,7 +3,6 @@ set -ex host_software_packages=( - redis device-tree-compiler curl ) diff --git a/src/software/embedded/thunderloop.cpp b/src/software/embedded/thunderloop.cpp index fa97196df9..a9edcd7ea6 100644 --- a/src/software/embedded/thunderloop.cpp +++ b/src/software/embedded/thunderloop.cpp @@ -71,18 +71,18 @@ extern "C" Thunderloop::Thunderloop(const RobotConstants_t& robot_constants, bool enable_log_merging, const int loop_hz) // TODO (#2495): Set the friendly team colour - : redis_client_( - std::make_unique(REDIS_DEFAULT_HOST, REDIS_DEFAULT_PORT)), + : toml_config_client_(std::make_unique(TOML_CONFIG_FILE_PATH)), motor_status_(std::nullopt), robot_constants_(robot_constants), - robot_id_(std::stoi(redis_client_->getSync(ROBOT_ID_REDIS_KEY))), - channel_id_(std::stoi(redis_client_->getSync(ROBOT_MULTICAST_CHANNEL_REDIS_KEY))), - network_interface_(redis_client_->getSync(ROBOT_NETWORK_INTERFACE_REDIS_KEY)), + robot_id_(std::stoi(toml_config_client_->get(ROBOT_ID_CONFIG_KEY))), + channel_id_( + std::stoi(toml_config_client_->get(ROBOT_MULTICAST_CHANNEL_CONFIG_KEY))), + network_interface_(toml_config_client_->get(ROBOT_NETWORK_INTERFACE_CONFIG_KEY)), loop_hz_(loop_hz), - kick_coeff_(std::stod(redis_client_->getSync(ROBOT_KICK_EXP_COEFF_REDIS_KEY))), - kick_constant_(std::stoi(redis_client_->getSync(ROBOT_KICK_CONSTANT_REDIS_KEY))), + kick_coeff_(std::stod(toml_config_client_->get(ROBOT_KICK_EXP_COEFF_CONFIG_KEY))), + kick_constant_(std::stoi(toml_config_client_->get(ROBOT_KICK_CONSTANT_CONFIG_KEY))), chip_pulse_width_( - std::stoi(redis_client_->getSync(ROBOT_CHIP_PULSE_WIDTH_REDIS_KEY))), + std::stoi(toml_config_client_->get(ROBOT_CHIP_PULSE_WIDTH_CONFIG_KEY))), primitive_executor_(Duration::fromSeconds(1.0 / loop_hz), robot_constants, TeamColour::YELLOW, robot_id_) { @@ -133,7 +133,7 @@ Thunderloop::Thunderloop(const RobotConstants_t& robot_constants, bool enable_lo << ", CHANNEL ID: " << channel_id_ << ", and NETWORK INTERFACE: " << network_interface_; LOG(INFO) - << "THUNDERLOOP: to update Thunderloop configuration, change REDIS store and restart Thunderloop"; + << "THUNDERLOOP: to update Thunderloop configuration, edit TOML config file and restart Thunderloop"; } Thunderloop::~Thunderloop() {} @@ -350,18 +350,6 @@ void Thunderloop::runLoop() *(robot_status_.mutable_primitive_executor_status()) = primitive_executor_status_; - // Update Redis - { - ZoneNamedN(_tracy_redis, "Thunderloop: Commit to REDIS", true); - - redis_client_->setNoCommit( - ROBOT_BATTERY_VOLTAGE_REDIS_KEY, - std::to_string(power_status_.battery_voltage())); - redis_client_->setNoCommit(ROBOT_CURRENT_DRAW_REDIS_KEY, - std::to_string(power_status_.current_draw())); - redis_client_->asyncCommit(); - } - updateErrorCodes(); } diff --git a/src/software/embedded/thunderloop.h b/src/software/embedded/thunderloop.h index 3657f21165..2192b40f01 100644 --- a/src/software/embedded/thunderloop.h +++ b/src/software/embedded/thunderloop.h @@ -10,10 +10,10 @@ #include "shared/2021_robot_constants.h" #include "shared/constants.h" #include "software/embedded/primitive_executor.h" -#include "software/embedded/redis/redis_client.h" #include "software/embedded/services/motor.h" #include "software/embedded/services/network/network.h" #include "software/embedded/services/power.h" +#include "software/embedded/toml_config/toml_config_client.h" #include "software/logger/logger.h" class Thunderloop @@ -61,8 +61,8 @@ class Thunderloop std::unique_ptr network_service_; std::unique_ptr power_service_; - // Clients - std::unique_ptr redis_client_; + // TOML config client + std::unique_ptr toml_config_client_; private: /* diff --git a/src/software/embedded/toml_config/BUILD b/src/software/embedded/toml_config/BUILD new file mode 100644 index 0000000000..758908dbbb --- /dev/null +++ b/src/software/embedded/toml_config/BUILD @@ -0,0 +1,20 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "toml_config", + srcs = ["toml_config_client.cpp"], + hdrs = ["toml_config_client.h"], + deps = [ + "//software/logger", + "@tomlplusplus", + ], +) + +cc_test( + name = "toml_config_client_test", + srcs = ["toml_config_client_test.cpp"], + deps = [ + ":toml_config", + "//shared/test_util:tbots_gtest_main", + ], +) diff --git a/src/software/embedded/toml_config/toml_config_client.cpp b/src/software/embedded/toml_config/toml_config_client.cpp new file mode 100644 index 0000000000..babaa2e2e5 --- /dev/null +++ b/src/software/embedded/toml_config/toml_config_client.cpp @@ -0,0 +1,143 @@ +#include "software/embedded/toml_config/toml_config_client.h" + +#include +#include + +TomlConfigClient::TomlConfigClient(const std::string& config_file_path) + : config_file_path_(config_file_path), has_pending_changes_(false) +{ + loadConfig(); +} + +TomlConfigClient::~TomlConfigClient() +{ + // Flush any pending changes on destruction + if (has_pending_changes_) + { + flush(); + } +} + +void TomlConfigClient::loadConfig() +{ + std::lock_guard lock(config_mutex_); + + // Create directory if it doesn't exist + std::filesystem::path config_path(config_file_path_); + std::filesystem::path config_dir = config_path.parent_path(); + if (!config_dir.empty() && !std::filesystem::exists(config_dir)) + { + std::filesystem::create_directories(config_dir); + LOG(INFO) << "Created TOML config directory: " << config_dir; + } + + // Check if file exists + if (!std::filesystem::exists(config_file_path_)) + { + LOG(INFO) << "TOML config file does not exist, creating default: " + << config_file_path_; + // Create table with default values + config_table_ = toml::table{ + {"robot_id", "1"}, + {"channel_id", "0"}, + {"network_interface", "tbotswifi5"}, + {"kick_constant", "0"}, + {"kick_coeff", "0.0"}, + {"chip_pulse_width", "0"}, + {"battery_voltage", "0.0"}, + {"current_draw", "0.0"}, + {"cap_voltage", "0.0"}, + }; + writeConfig(); + return; + } + + try + { + config_table_ = toml::parse_file(config_file_path_); + LOG(INFO) << "Successfully loaded TOML config from: " << config_file_path_; + } + catch (const toml::parse_error& err) + { + LOG(WARNING) << "Failed to parse TOML config file: " << config_file_path_ + << ". Error: " << err.description(); + // Create empty table on parse error + config_table_ = toml::table{}; + } +} + +void TomlConfigClient::writeConfig() +{ + std::ofstream file(config_file_path_); + if (!file.is_open()) + { + LOG(WARNING) << "Failed to open TOML config file for writing: " + << config_file_path_; + return; + } + + file << config_table_; + file.close(); + has_pending_changes_ = false; +} + +std::string TomlConfigClient::get(const std::string& key) +{ + std::lock_guard lock(config_mutex_); + + try + { + auto node = config_table_[key]; + if (node.is_string()) + { + return node.as_string()->get(); + } + else if (node.is_integer()) + { + return std::to_string(node.as_integer()->get()); + } + else if (node.is_floating_point()) + { + return std::to_string(node.as_floating_point()->get()); + } + else if (node.is_boolean()) + { + return node.as_boolean()->get() ? "1" : "0"; + } + else + { + LOG(WARNING) << "TOML key '" << key << "' exists but is not a supported type"; + return ""; + } + } + catch (const std::exception& e) + { + LOG(WARNING) << "TOML key '" << key << "' not found: " << e.what(); + return ""; + } +} + +void TomlConfigClient::set(const std::string& key, const std::string& value) +{ + std::lock_guard lock(config_mutex_); + config_table_.insert_or_assign(key, value); + has_pending_changes_ = true; + writeConfig(); +} + +void TomlConfigClient::setNoCommit(const std::string& key, const std::string& value) +{ + std::lock_guard lock(config_mutex_); + config_table_.insert_or_assign(key, value); + has_pending_changes_ = true; +} + +void TomlConfigClient::flush() +{ + std::lock_guard lock(config_mutex_); + + if (has_pending_changes_) + { + writeConfig(); + } +} diff --git a/src/software/embedded/toml_config/toml_config_client.h b/src/software/embedded/toml_config/toml_config_client.h new file mode 100644 index 0000000000..07b7a5c9a6 --- /dev/null +++ b/src/software/embedded/toml_config/toml_config_client.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include + +#include "software/logger/logger.h" + +/** + * Client for reading and writing TOML configuration files. + * Handles loading, reading, and writing robot configuration values. + */ +class TomlConfigClient +{ + public: + /** + * Creates a TOML config client that reads/writes to the specified file path. + * If the file doesn't exist, it will be created with default values. + * + * @param config_file_path Path to the TOML configuration file + */ + explicit TomlConfigClient(const std::string& config_file_path); + + virtual ~TomlConfigClient(); + + /** + * Gets the value corresponding to the key as a string. + * Returns empty string if key doesn't exist. + * + * @param key The configuration key (e.g., "/robot_id") + * @return The value as a string, or empty string if not found + */ + std::string get(const std::string& key); + + /** + * Sets a key-value pair in the TOML file. + * The file is written immediately (synchronously). + * + * @param key The configuration key (e.g., "/robot_id") + * @param value The value to set + */ + void set(const std::string& key, const std::string& value); + + /** + * Sets a key-value pair but doesn't write to disk immediately. + * Call flush() to write all pending changes. + * + * @param key The configuration key + * @param value The value to set + */ + void setNoCommit(const std::string& key, const std::string& value); + + /** + * Writes all pending changes to the TOML file. + */ + void flush(); + + private: + std::string config_file_path_; + toml::table config_table_; + std::mutex config_mutex_; + bool has_pending_changes_; + + /** + * Loads the TOML file from disk into memory. + * Creates a default file with default values if it doesn't exist. + */ + void loadConfig(); + + /** + * Writes the current config_table_ to the TOML file. + */ + void writeConfig(); +}; diff --git a/src/software/embedded/toml_config/toml_config_client_test.cpp b/src/software/embedded/toml_config/toml_config_client_test.cpp new file mode 100644 index 0000000000..8f561785d1 --- /dev/null +++ b/src/software/embedded/toml_config/toml_config_client_test.cpp @@ -0,0 +1,86 @@ +#include "software/embedded/toml_config/toml_config_client.h" + +#include + +#include +#include + +class TomlConfigClientTest : public ::testing::Test +{ + protected: + void TearDown() override + { + if (!config_path_.empty() && std::filesystem::exists(config_path_)) + { + std::remove(config_path_.c_str()); + } + } + + std::string config_path_; +}; + +TEST_F(TomlConfigClientTest, create_with_nonexistent_file_creates_default_config) +{ + config_path_ = "/tmp/toml_config_test_default.toml"; + std::remove(config_path_.c_str()); + + TomlConfigClient client(config_path_); + + EXPECT_EQ(client.get("robot_id"), "1"); + EXPECT_EQ(client.get("channel_id"), "0"); + EXPECT_EQ(client.get("network_interface"), "tbotswifi5"); +} + +TEST_F(TomlConfigClientTest, get_nonexistent_key_returns_empty_string) +{ + config_path_ = "/tmp/toml_config_test_nonexistent_key.toml"; + std::remove(config_path_.c_str()); + + TomlConfigClient client(config_path_); + + EXPECT_EQ(client.get("nonexistent_key"), ""); +} + +TEST_F(TomlConfigClientTest, set_then_get_round_trip) +{ + config_path_ = "/tmp/toml_config_test_round_trip.toml"; + std::remove(config_path_.c_str()); + + TomlConfigClient client(config_path_); + + client.set("robot_id", "42"); + EXPECT_EQ(client.get("robot_id"), "42"); + + client.set("custom_key", "custom_value"); + EXPECT_EQ(client.get("custom_key"), "custom_value"); +} + +TEST_F(TomlConfigClientTest, set_no_commit_then_flush_then_get) +{ + config_path_ = "/tmp/toml_config_test_no_commit.toml"; + std::remove(config_path_.c_str()); + + TomlConfigClient client(config_path_); + + client.setNoCommit("robot_id", "99"); + EXPECT_EQ(client.get("robot_id"), "99"); + + client.flush(); + + TomlConfigClient client2(config_path_); + EXPECT_EQ(client2.get("robot_id"), "99"); +} + +TEST_F(TomlConfigClientTest, load_existing_file_preserves_values) +{ + config_path_ = "/tmp/toml_config_test_existing.toml"; + std::remove(config_path_.c_str()); + + { + TomlConfigClient client(config_path_); + client.set("robot_id", "7"); + } + + TomlConfigClient client(config_path_); + EXPECT_EQ(client.get("robot_id"), "7"); +} diff --git a/src/software/py_constants.cpp b/src/software/py_constants.cpp index ab37d9af86..ce7b5f1f1a 100644 --- a/src/software/py_constants.cpp +++ b/src/software/py_constants.cpp @@ -143,18 +143,14 @@ PYBIND11_MODULE(py_constants, m) m.attr("DIV_A_NUM_ROBOTS") = DIV_A_NUM_ROBOTS; m.attr("DIV_B_NUM_ROBOTS") = DIV_B_NUM_ROBOTS; - // Redis Keys, Ports, & Host - m.attr("ROBOT_ID_REDIS_KEY") = ROBOT_ID_REDIS_KEY; - m.attr("ROBOT_MULTICAST_CHANNEL_REDIS_KEY") = ROBOT_MULTICAST_CHANNEL_REDIS_KEY; - m.attr("ROBOT_NETWORK_INTERFACE_REDIS_KEY") = ROBOT_NETWORK_INTERFACE_REDIS_KEY; - m.attr("ROBOT_KICK_CONSTANT_REDIS_KEY") = ROBOT_KICK_CONSTANT_REDIS_KEY; - m.attr("ROBOT_KICK_EXP_COEFF_REDIS_KEY") = ROBOT_KICK_EXP_COEFF_REDIS_KEY; - m.attr("ROBOT_CHIP_PULSE_WIDTH_REDIS_KEY") = ROBOT_CHIP_PULSE_WIDTH_REDIS_KEY; - m.attr("ROBOT_CURRENT_DRAW_REDIS_KEY") = ROBOT_CURRENT_DRAW_REDIS_KEY; - m.attr("ROBOT_BATTERY_VOLTAGE_REDIS_KEY") = ROBOT_BATTERY_VOLTAGE_REDIS_KEY; - m.attr("ROBOT_CAPACITOR_VOLTAGE_REDIS_KEY") = ROBOT_CAPACITOR_VOLTAGE_REDIS_KEY; - m.attr("REDIS_DEFAULT_HOST") = REDIS_DEFAULT_HOST; - m.attr("REDIS_DEFAULT_PORT") = REDIS_DEFAULT_PORT; + // TOML Config Keys and File Path + m.attr("ROBOT_ID_CONFIG_KEY") = ROBOT_ID_CONFIG_KEY; + m.attr("ROBOT_MULTICAST_CHANNEL_CONFIG_KEY") = ROBOT_MULTICAST_CHANNEL_CONFIG_KEY; + m.attr("ROBOT_NETWORK_INTERFACE_CONFIG_KEY") = ROBOT_NETWORK_INTERFACE_CONFIG_KEY; + m.attr("ROBOT_KICK_CONSTANT_CONFIG_KEY") = ROBOT_KICK_CONSTANT_CONFIG_KEY; + m.attr("ROBOT_KICK_EXP_COEFF_CONFIG_KEY") = ROBOT_KICK_EXP_COEFF_CONFIG_KEY; + m.attr("ROBOT_CHIP_PULSE_WIDTH_CONFIG_KEY") = ROBOT_CHIP_PULSE_WIDTH_CONFIG_KEY; + m.attr("TOML_CONFIG_FILE_PATH") = TOML_CONFIG_FILE_PATH; // Robot power constants m.attr("MIN_CAPACITOR_VOLTAGE") = MIN_CAPACITOR_VOLTAGE;