blob: 1b4197f05052ca0ef410fa0f238a0fc99cabdc4f [file] [edit]
// Copyright 2026 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include <chrono>
#include "hardware/gpio.h"
#include "hardware/uart.h"
#include "pw_system/config.h"
#include "pw_system/system.h"
#include "pw_thread/attrs.h"
#include "pw_thread/detached_thread.h"
#include "pw_thread/sleep.h"
namespace pw::hil {
namespace {
inline constexpr ThreadPriority kThreadPriorityUartBlaster = ThreadPriority();
inline constexpr pw::ThreadAttrs kUartBlasterThread =
pw::ThreadAttrs()
.set_stack_size_bytes(4096)
.set_name("UartBlasterThread")
.set_priority(kThreadPriorityUartBlaster);
static constexpr char ABC_LUT[26] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
} // namespace
} // namespace pw::hil
namespace pw {
template <typename T>
class Debouncer {
public:
Debouncer(const T& initial_state, size_t threshold)
: state_(initial_state),
last_state_(initial_state),
threshold_(threshold),
count_(0) {}
const T& state() const { return state_; }
const T& Update(const T& new_state) {
if (new_state == state_) {
count_ = 0;
} else if (new_state == last_state_) {
if (count_ >= threshold_) {
state_ = last_state_;
count_ = 0;
} else {
count_++;
}
} else {
last_state_ = new_state;
count_ = 1;
}
return state_;
}
private:
T state_;
T last_state_;
size_t threshold_;
size_t count_;
};
} // namespace pw
inline void pause(uint32_t delay_loops = 10) {
volatile uint32_t loop = 0;
for (loop = 0; loop < delay_loops;) {
loop = loop + 1;
}
}
namespace pw::system {
void UserAppInit() {
PW_CONSTINIT static ThreadContextFor<::pw::hil::kUartBlasterThread>
uart_blaster_thread;
pw::Thread(uart_blaster_thread, []() {
static constexpr uint32_t TRIGGER_GPIO = 17;
static constexpr uint32_t LED_GPIO = 24;
static constexpr uint32_t UART1_RX_PIN = 5;
static constexpr uint32_t UART1_TX_PIN = 4;
static constexpr uint32_t LOOP_TIME_MS = 10;
static constexpr uint32_t LED_PERIOD_MS = 500;
gpio_init(TRIGGER_GPIO);
gpio_set_dir(TRIGGER_GPIO, GPIO_IN);
gpio_init(LED_GPIO);
gpio_set_dir(LED_GPIO, GPIO_OUT);
uart_init(uart1, 115200);
uart_set_format(uart1, 8, 1, UART_PARITY_NONE);
gpio_set_function(UART1_RX_PIN,
UART_FUNCSEL_NUM(uart1, UART1_RX_PIN)); // TEST_UART_RX
gpio_set_function(UART1_TX_PIN,
UART_FUNCSEL_NUM(uart1, UART1_TX_PIN)); // TEST_UART_TX
pw::Debouncer<bool> debouncer(false, 10);
size_t loop_counts = 0;
while (true) {
loop_counts++;
debouncer.Update(gpio_get(TRIGGER_GPIO));
// While GPIO is high, blast UART
if (debouncer.state() == true) {
uart_putc(uart1, pw::hil::ABC_LUT[loop_counts % 26]);
}
if (loop_counts % (LED_PERIOD_MS / LOOP_TIME_MS) == 0) {
gpio_put(LED_GPIO, !gpio_get(LED_GPIO));
}
pw::this_thread::sleep_for(std::chrono::milliseconds(LOOP_TIME_MS));
}
}).detach();
}
} // namespace pw::system