Native test suite (61 tests, 5 suites) with thin mock layer for Arduino/FreeRTOS/esp_timer enabling host-side testing without hardware. ASCOM Alpaca REST API on port 32323 with UDP discovery, implementing Telescope v3 interface for N.I.N.A., PHD2, and compatible software. Follows existing ST4WiFi conditional compilation pattern. README documents wiring, all three protocols (serial, WebSocket, Alpaca), pin/rate configuration, and build instructions.
231 lines
5.9 KiB
C++
231 lines
5.9 KiB
C++
// Arduino.h mock for native testing
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <cctype>
|
|
#include <string>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cmath>
|
|
#include "mock_state.h"
|
|
|
|
#define HIGH 1
|
|
#define LOW 0
|
|
#define OUTPUT 1
|
|
#define INPUT 0
|
|
#define SERIAL_8N1 0x800001c
|
|
|
|
#define log_w(...)
|
|
|
|
inline void pinMode(int pin, int mode) {
|
|
MockState::gpioModes[pin] = mode;
|
|
}
|
|
|
|
inline void digitalWrite(int pin, int val) {
|
|
MockState::gpioStates[pin] = val;
|
|
}
|
|
|
|
inline int digitalRead(int pin) {
|
|
auto it = MockState::gpioStates.find(pin);
|
|
if (it != MockState::gpioStates.end()) return it->second;
|
|
return LOW;
|
|
}
|
|
|
|
inline unsigned long millis() {
|
|
return static_cast<unsigned long>(MockState::mockTimeMicros / 1000);
|
|
}
|
|
|
|
inline void delay(unsigned long ms) {
|
|
MockState::advanceTime(static_cast<int64_t>(ms) * 1000);
|
|
}
|
|
|
|
inline bool isDigit(char c) {
|
|
return std::isdigit(static_cast<unsigned char>(c));
|
|
}
|
|
|
|
// Arduino String class mock
|
|
class String {
|
|
std::string s_;
|
|
public:
|
|
String() : s_() {}
|
|
String(const char* cstr) : s_(cstr ? cstr : "") {}
|
|
String(const String& other) : s_(other.s_) {}
|
|
String(const std::string& str) : s_(str) {}
|
|
|
|
String(double val, int precision) {
|
|
char buf[64];
|
|
std::snprintf(buf, sizeof(buf), "%.*f", precision, val);
|
|
s_ = buf;
|
|
}
|
|
|
|
String(int val) {
|
|
s_ = std::to_string(val);
|
|
}
|
|
|
|
String& operator=(const String& rhs) {
|
|
if (this != &rhs) s_ = rhs.s_;
|
|
return *this;
|
|
}
|
|
|
|
String& operator=(const char* cstr) {
|
|
s_ = cstr ? cstr : "";
|
|
return *this;
|
|
}
|
|
|
|
unsigned int length() const { return static_cast<unsigned int>(s_.length()); }
|
|
|
|
void reserve(unsigned int size) { s_.reserve(size); }
|
|
|
|
const char* c_str() const { return s_.c_str(); }
|
|
|
|
void trim() {
|
|
size_t start = s_.find_first_not_of(" \t\r\n");
|
|
size_t end = s_.find_last_not_of(" \t\r\n");
|
|
if (start == std::string::npos) {
|
|
s_.clear();
|
|
} else {
|
|
s_ = s_.substr(start, end - start + 1);
|
|
}
|
|
}
|
|
|
|
bool startsWith(const char* prefix) const {
|
|
size_t plen = std::strlen(prefix);
|
|
if (s_.length() < plen) return false;
|
|
return s_.compare(0, plen, prefix) == 0;
|
|
}
|
|
|
|
int indexOf(char ch) const {
|
|
auto pos = s_.find(ch);
|
|
return (pos == std::string::npos) ? -1 : static_cast<int>(pos);
|
|
}
|
|
|
|
int indexOf(char ch, int from) const {
|
|
if (from < 0) from = 0;
|
|
auto pos = s_.find(ch, static_cast<size_t>(from));
|
|
return (pos == std::string::npos) ? -1 : static_cast<int>(pos);
|
|
}
|
|
|
|
String substring(int from) const {
|
|
if (from < 0) from = 0;
|
|
if (static_cast<size_t>(from) >= s_.length()) return String("");
|
|
return String(s_.substr(static_cast<size_t>(from)));
|
|
}
|
|
|
|
String substring(int from, int to) const {
|
|
if (from < 0) from = 0;
|
|
if (to < from) return String("");
|
|
if (static_cast<size_t>(from) >= s_.length()) return String("");
|
|
size_t len = static_cast<size_t>(to - from);
|
|
return String(s_.substr(static_cast<size_t>(from), len));
|
|
}
|
|
|
|
long toInt() const { return std::atol(s_.c_str()); }
|
|
|
|
double toDouble() const { return std::atof(s_.c_str()); }
|
|
|
|
String& operator+=(char c) {
|
|
s_ += c;
|
|
return *this;
|
|
}
|
|
|
|
String& operator+=(const char* cstr) {
|
|
if (cstr) s_ += cstr;
|
|
return *this;
|
|
}
|
|
|
|
String& operator+=(const String& rhs) {
|
|
s_ += rhs.s_;
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(const String& rhs) const { return s_ == rhs.s_; }
|
|
bool operator==(const char* rhs) const { return s_ == (rhs ? rhs : ""); }
|
|
bool operator!=(const String& rhs) const { return s_ != rhs.s_; }
|
|
bool operator!=(const char* rhs) const { return s_ != (rhs ? rhs : ""); }
|
|
|
|
char operator[](unsigned int index) const {
|
|
if (index < s_.length()) return s_[index];
|
|
return '\0';
|
|
}
|
|
|
|
friend String operator+(const String& lhs, const String& rhs) {
|
|
return String(lhs.s_ + rhs.s_);
|
|
}
|
|
};
|
|
|
|
// HardwareSerial mock
|
|
class HardwareSerial {
|
|
size_t readPos_;
|
|
public:
|
|
HardwareSerial() : readPos_(0) {}
|
|
|
|
void begin(uint32_t baud, int config = 0) {
|
|
(void)baud;
|
|
(void)config;
|
|
readPos_ = 0;
|
|
}
|
|
|
|
int available() {
|
|
return static_cast<int>(MockState::serialInput.length() - readPos_);
|
|
}
|
|
|
|
char read() {
|
|
if (readPos_ < MockState::serialInput.length()) {
|
|
return MockState::serialInput[readPos_++];
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void resetReadPos() { readPos_ = 0; }
|
|
|
|
// print overloads
|
|
void print(const char* str) {
|
|
if (str) MockState::serialOutput += str;
|
|
}
|
|
|
|
void print(const String& str) {
|
|
MockState::serialOutput += str.c_str();
|
|
}
|
|
|
|
void print(double val, int decimals) {
|
|
char buf[64];
|
|
std::snprintf(buf, sizeof(buf), "%.*f", decimals, val);
|
|
MockState::serialOutput += buf;
|
|
}
|
|
|
|
void print(int val) {
|
|
MockState::serialOutput += std::to_string(val);
|
|
}
|
|
|
|
// println overloads
|
|
void println(const char* str) {
|
|
if (str) MockState::serialOutput += str;
|
|
MockState::serialOutput += "\n";
|
|
}
|
|
|
|
void println(const String& str) {
|
|
MockState::serialOutput += str.c_str();
|
|
MockState::serialOutput += "\n";
|
|
}
|
|
|
|
void println() {
|
|
MockState::serialOutput += "\n";
|
|
}
|
|
|
|
// write
|
|
size_t write(uint8_t c) {
|
|
MockState::serialOutput += static_cast<char>(c);
|
|
return 1;
|
|
}
|
|
|
|
size_t write(const uint8_t* buf, size_t size) {
|
|
for (size_t i = 0; i < size; i++) {
|
|
MockState::serialOutput += static_cast<char>(buf[i]);
|
|
}
|
|
return size;
|
|
}
|
|
};
|
|
|
|
extern HardwareSerial Serial;
|