151 lines
4.8 KiB
C++
151 lines
4.8 KiB
C++
#pragma once
|
|
|
|
#include "esphome/core/component.h"
|
|
#include "esphome/core/gpio.h"
|
|
#include "esphome/core/helpers.h"
|
|
#include "esphome/components/display/display_buffer.h"
|
|
#include "esphome/components/spi/spi.h"
|
|
#include "esphome/components/time/real_time_clock.h"
|
|
#include <cstdarg>
|
|
#include <string>
|
|
|
|
namespace esphome {
|
|
namespace nixie_display {
|
|
|
|
class NixieDisplay : public display::DisplayBuffer,
|
|
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST,
|
|
spi::CLOCK_POLARITY_HIGH,
|
|
spi::CLOCK_PHASE_TRAILING,
|
|
spi::DATA_RATE_200KHZ> {
|
|
public:
|
|
enum DisplayMode : uint8_t {
|
|
MODE_UNKNOWN = 0,
|
|
MODE_TIME = 1,
|
|
MODE_DATE = 2,
|
|
};
|
|
|
|
void set_anode_pins(InternalGPIOPin *anode0, InternalGPIOPin *anode1,
|
|
InternalGPIOPin *anode2, InternalGPIOPin *le_pin) {
|
|
this->anode0_pin_ = anode0;
|
|
this->anode1_pin_ = anode1;
|
|
this->anode2_pin_ = anode2;
|
|
this->le_pin_ = le_pin;
|
|
}
|
|
|
|
void setup() override;
|
|
void dump_config() override;
|
|
void update() override;
|
|
void loop() override;
|
|
display::DisplayType get_display_type() override {
|
|
return display::DISPLAY_TYPE_BINARY;
|
|
}
|
|
void printf(const char *format, ...);
|
|
void display_text(const char *text) {
|
|
this->last_external_text_ms_ = millis();
|
|
this->set_target_string_(text, MODE_UNKNOWN);
|
|
}
|
|
void display_time_text(const char *text) {
|
|
this->last_external_text_ms_ = millis();
|
|
this->set_target_string_(text, MODE_TIME);
|
|
}
|
|
void display_date_text(const char *text) {
|
|
this->last_external_text_ms_ = millis();
|
|
this->set_target_string_(text, MODE_DATE);
|
|
}
|
|
void set_time_source(time::RealTimeClock *rtc) { this->time_source_ = rtc; }
|
|
void set_debug_logging(bool enabled) { this->debug_logging_ = enabled; }
|
|
void set_anti_poisoning(bool enabled) { this->anti_poisoning_ = enabled; }
|
|
void set_lambda_hold_ms(uint32_t hold_ms) { this->lambda_hold_ms_ = hold_ms; }
|
|
void set_auto_time(bool enabled) { this->auto_time_ = enabled; }
|
|
void set_date_mode(bool enabled) {
|
|
this->date_mode_ = enabled;
|
|
if (enabled) {
|
|
this->auto_rotate_ = false;
|
|
}
|
|
}
|
|
bool is_date_mode() const { return this->date_mode_; }
|
|
void set_auto_rotate(bool enabled) {
|
|
this->auto_rotate_ = enabled;
|
|
if (enabled) {
|
|
this->date_mode_ = false;
|
|
}
|
|
}
|
|
bool is_auto_rotate() const { return this->auto_rotate_; }
|
|
void set_refresh_interval_us(uint32_t interval_us) {
|
|
this->refresh_interval_us_ = interval_us;
|
|
}
|
|
float get_setup_priority() const override { return setup_priority::PROCESSOR; }
|
|
|
|
protected:
|
|
void draw_absolute_pixel_internal(int x, int y, Color color) override;
|
|
int get_height_internal() override { return 1; }
|
|
int get_width_internal() override { return NUM_TUBES; }
|
|
|
|
private:
|
|
InternalGPIOPin *anode0_pin_{nullptr};
|
|
InternalGPIOPin *anode1_pin_{nullptr};
|
|
InternalGPIOPin *anode2_pin_{nullptr};
|
|
InternalGPIOPin *le_pin_{nullptr};
|
|
|
|
// Bitmap for digits 0-9, 10 bits per digit (cathode pins)
|
|
const uint16_t digit_bitmap_[10] = {
|
|
1022, // 0
|
|
1021, // 1
|
|
1019, // 2
|
|
1015, // 3
|
|
1007, // 4
|
|
991, // 5
|
|
959, // 6
|
|
895, // 7
|
|
767, // 8
|
|
511 // 9
|
|
};
|
|
|
|
static constexpr int NUM_TUBES = 6;
|
|
static constexpr uint32_t DEFAULT_REFRESH_INTERVAL_US = 1000;
|
|
|
|
uint32_t last_update_us_;
|
|
uint32_t last_logic_update_ms_{0};
|
|
uint32_t refresh_interval_us_{DEFAULT_REFRESH_INTERVAL_US};
|
|
uint32_t lambda_hold_ms_{1500};
|
|
uint8_t current_anode_;
|
|
std::string displayed_string_;
|
|
std::string target_string_;
|
|
DisplayMode current_mode_{MODE_UNKNOWN};
|
|
DisplayMode target_mode_{MODE_UNKNOWN};
|
|
bool anti_poison_active_;
|
|
unsigned long anti_poison_start_;
|
|
uint8_t anti_poison_counter_;
|
|
HighFrequencyLoopRequester high_freq_;
|
|
time::RealTimeClock *time_source_{nullptr};
|
|
bool debug_logging_{false};
|
|
bool anti_poisoning_{true};
|
|
bool auto_time_{true};
|
|
bool date_mode_{false};
|
|
bool auto_rotate_{false};
|
|
bool anti_poison_on_mode_change_{true};
|
|
bool anti_poison_pending_{false};
|
|
uint32_t last_debug_log_ms_{0};
|
|
uint32_t last_external_text_ms_{0};
|
|
int last_render_second_{-1};
|
|
bool last_effective_date_mode_{false};
|
|
|
|
// Anti-poisoning function: cycles through digits to prevent cathode buildup
|
|
std::string anti_poison_transition_(const std::string &from_str,
|
|
const std::string &to_str);
|
|
|
|
// Update the SPI display for current tube pair and anode
|
|
void update_tube_display_(const std::string &display_str);
|
|
|
|
// Set active anode
|
|
void set_anode_(uint8_t anode_index);
|
|
|
|
// Convert character to digit (0-9)
|
|
uint8_t char_to_digit_(char c);
|
|
|
|
void set_target_string_(const std::string &value, DisplayMode mode);
|
|
};
|
|
|
|
} // namespace nixie_display
|
|
} // namespace esphome
|