diff --git a/watchos2/EventListener.cpp b/watchos2/EventListener.cpp new file mode 100644 index 0000000..20544b2 --- /dev/null +++ b/watchos2/EventListener.cpp @@ -0,0 +1,26 @@ +#include "EventListener.h" + +bool EventListener::hasEvent() +{ +} + +Event* EventListener::popEvent() +{ +} + +void EventListener::pushEvent(kernel_handle_t handle) +{ +} + +class IEventListener +{ +private: + Queue m_events; +protected: + bool hasEvent(); + Event* popEvent(); +public: + void pushEvent(kernel_handle_t handle); + uint32_t getEventSourceMask(); + uint16_t getEventTypeMask(); +}; \ No newline at end of file diff --git a/watchos2/EventListener.h b/watchos2/EventListener.h new file mode 100644 index 0000000..dee6946 --- /dev/null +++ b/watchos2/EventListener.h @@ -0,0 +1,22 @@ +#ifndef _EVENTLISTENER_h +#define _EVENTLISTENER_h + +#include "watchos.h" +#include "Queue.h" +#include "Events.h" + +class EventListener +{ +private: + Queue m_event_queue; +protected: + bool hasEvent(); + Event* popEvent(); + void releaseEvent(kernel_handle_t handle); +public: + void pushEvent(kernel_handle_t handle); + uint32_t getEventSourceMask(); + uint16_t getEventTypeMask(); +}; + +#endif \ No newline at end of file diff --git a/watchos2/Events.h b/watchos2/Events.h new file mode 100644 index 0000000..adefa6a --- /dev/null +++ b/watchos2/Events.h @@ -0,0 +1,12 @@ +#ifndef _EVENTS_h +#define _EVENTS_h + +struct Event +{ + uint32_t source; + uint16_t event; + byte param1; + byte param2; +}; + +#endif \ No newline at end of file diff --git a/watchos2/IDrawable.h b/watchos2/IDrawable.h new file mode 100644 index 0000000..ef5580d --- /dev/null +++ b/watchos2/IDrawable.h @@ -0,0 +1,10 @@ +#ifndef _IDRAWABLE_h +#define _IDRAWABLE_h + +class IDrawable +{ +public: + virtual void draw(int hwnd, int x, int y, int width, int height) = 0; +}; + +#endif \ No newline at end of file diff --git a/watchos2/IRunnable.h b/watchos2/IRunnable.h new file mode 100644 index 0000000..e2d9c91 --- /dev/null +++ b/watchos2/IRunnable.h @@ -0,0 +1,10 @@ +#ifndef _IRUNNABLE_h +#define _IRUNNABLE_h + +class IRunnable +{ +public: + virtual void tick() = 0; +}; + +#endif diff --git a/watchos2/Kernel.cpp b/watchos2/Kernel.cpp new file mode 100644 index 0000000..fdf75fa --- /dev/null +++ b/watchos2/Kernel.cpp @@ -0,0 +1,160 @@ +#include "watchos.h" +#include "IRunnable.h" + +struct KernelHandle +{ + kernel_handle_t handle; + kernel_handle_destructor_t destructor; + void* object; + uint references; + uint32_t well_known = 0; +}; + +struct KernelTask +{ + kernel_handle_t handle; + Task* task; +}; + +void destruct_task(kernel_handle_t handle, void* object) +{ + delete object; +} + +Kernel::Kernel() +{ + for (int i = 0; i < KERNEL_MAX_HANDLES; i++) + { + m_handle[i] = nullptr; + } + + for (int i = 0; i < KERNEL_MAX_TASKS; i++) + { + m_task[i] = nullptr; + } +} + +kernel_handle_t Kernel::allocHandle(byte type, void* object, kernel_handle_destructor_t destructor, uint32_t well_known) +{ + for (int i = 0; i < KERNEL_MAX_HANDLES; i++) + { + if (m_handle[i] == nullptr) + { + m_handle[i] = new KernelHandle(); + m_handle[i]->handle = type | m_next_handle++; + m_handle[i]->destructor = destructor; + m_handle[i]->object = object; + m_handle[i]->references = 1; + m_handle[i]->well_known = well_known; + return m_handle[i]->handle; + } + } + watchos::panic("Exceeded KERNEL_MAX_HANDLES"); +} + +void Kernel::freeHandle(kernel_handle_t handle) +{ + for (int i = 0; i < KERNEL_MAX_HANDLES; i++) + { + if (m_handle[i] != nullptr && m_handle[i]->handle == handle) + { + if (m_handle[i]->destructor != nullptr) + { + (m_handle[i]->destructor)(handle, m_handle[i]->object); + } + delete m_handle[i]; + m_handle[i] = nullptr; + } + } +} + +void* Kernel::getHandle(kernel_handle_t handle) +{ + for (int i = 0; i < KERNEL_MAX_HANDLES; i++) + { + if (m_handle[i] != nullptr && m_handle[i]->handle == handle) + { + m_handle[i]->references++; + return m_handle[i]->object; + } + } + watchos::panic("Attempt to access invalid Kernel handle"); +} + +void* Kernel::getHandle(uint32_t well_known) +{ + for (int i = 0; i < KERNEL_MAX_HANDLES; i++) + { + if (m_handle[i] != nullptr && m_handle[i]->well_known == well_known) + { + m_handle[i]->references++; + return m_handle[i]->object; + } + } + watchos::panic("Attempt to access invalid Kernel handle by well-known id: %#10x", well_known); +} + +void Kernel::releaseHandle(kernel_handle_t handle) +{ + for (int i = 0; i < KERNEL_MAX_HANDLES; i++) + { + if (m_handle[i] != nullptr && m_handle[i]->handle == handle) + { + m_handle[i]->references--; + + if (m_handle[i]->references == 0) + { + freeHandle(handle); + } + + return; + } + } + + watchos::panic("Attempt to release invalid Kernel handle"); +} + +kernel_handle_t Kernel::registerTask(Task* task) +{ + for (int i = 0; i < KERNEL_MAX_TASKS; i++) + { + if (m_task[i] == nullptr) + { + m_task[i] = new KernelTask(); + m_task[i]->handle = allocHandle(WATCHOS_HANDLE_TYPE_TASK, (void*)destruct_task); + m_task[i]->task = task; + return m_task[i]->handle; + } + } + + watchos::panic("Exceeded KERNEL_MAX_TASKS"); +} + +void Kernel::unregisterTask(Task* task) +{ + for (int i = 0; i < KERNEL_MAX_TASKS; i++) + { + if (m_task[i] != nullptr && m_task[i]->task == task) + { + releaseHandle(m_task[i]->handle); + delete m_task[i]; + m_task[i] = nullptr; + return; + } + } +} + +void Kernel::tick() +{ + for (int i = 0; i < KERNEL_MAX_TASKS; i++) + { + if (m_task[i] != nullptr) + { + IRunnable* runnable = dynamic_cast(m_task[i]->task); + if (runnable != nullptr) + { + runnable->tick(); + } + } + } +} \ No newline at end of file diff --git a/watchos2/Kernel.h b/watchos2/Kernel.h new file mode 100644 index 0000000..9cf9531 --- /dev/null +++ b/watchos2/Kernel.h @@ -0,0 +1,63 @@ +#ifndef _KERNEL_h +#define _KERNEL_h + +#include "Task.h" + +#define KERNEL_MAX_HANDLES 256 +#define KERNEL_MAX_TASKS 32 + +typedef void (*kernel_handle_destructor_t)(kernel_handle_t, void*); + +struct KernelHandle; +struct KernelTask; + +class Kernel +{ +private: + KernelHandle* m_handle[KERNEL_MAX_HANDLES]; + int m_next_handle = 1; + KernelTask* m_task[KERNEL_MAX_TASKS]; + + void freeHandle(kernel_handle_t handle); + +public: + Kernel(); + + /// + /// Create a new kernel handle pointing to an object + /// + /// Type of the handle, one of WATCHOS_HANDLE_TYPE_ consts + /// Pointer to the object this handle references + /// Function to call when this handle has released all references + /// Specify a 'well_known' value this pointer can be fetched by + /// A handle which can be used to fetch or release this object + kernel_handle_t allocHandle(byte type, void* object, kernel_handle_destructor_t destructor = nullptr, byte well_known = 0); + + /// + /// Fetch the object referenced by this handle, increasing the reference count + /// + /// Handle to fetch + /// A pointer to the object the handle references + void* getHandle(kernel_handle_t handle); + + /// + /// Fetch an object by its well-known value, increasing the reference count + /// + /// Well-known id of handle + /// A pointer to the object the handle references + void* getHandle(byte well_known); + + /// + /// Release a fetched reference to this object + /// + /// Handle to release + void releaseHandle(kernel_handle_t handle); + + kernel_handle_t registerTask(Task* task); + void unregisterTask(Task* task); + + void tick(); +}; + +#endif + diff --git a/watchos2/Queue.cpp b/watchos2/Queue.cpp new file mode 100644 index 0000000..d8499e2 --- /dev/null +++ b/watchos2/Queue.cpp @@ -0,0 +1,80 @@ +#include "Queue.h" + +template +Queue::Queue() +{ + for (int i = 0; i < QUEUE_RING_SIZE; i++) + { + m_item[i] = nullptr; + } +} + +template +void Queue::push(T* item) +{ + if (m_full) + { + watchos::panic("Cannot enqueue item: ring buffer full"); + } + + // Write at m_next + m_item[m_write] = item; + + // Move the write position up + m_write = next(m_write); + + // If the next position to write has looped back around to the next position + // to read, then the buffer is full + if (m_read == m_write) + { + m_full = true; + } +} + +template +T* Queue::peek() +{ + // If the next position to read and write match but the buffer isn't full, + // then the buffer is empty + if (m_read == m_write && !m_full) + { + watchos::panic("Cannot dequeue event: ring buffer empty"); + } + + return m_item[m_read]; +} + +template +T* Queue::pop() +{ + // If the next position to read and write match but the buffer isn't full, + // then the buffer is empty + if (m_read == m_write && !m_full) + { + watchos::panic("Cannot dequeue event: ring buffer empty"); + } + + T* nextItem = m_item[m_read]; + // Move to the next read position + m_read = next(m_read); + // We can never be full if we just removed an item + m_full = false; + + return nextItem; +} + +template +bool Queue::isEmpty() +{ + return m_read == m_write && !m_full; +} + +template +int Queue::next(int n) +{ + if (n + 1 == QUEUE_RING_SIZE) + return 0; + else + return n + 1; +} + diff --git a/watchos2/Queue.h b/watchos2/Queue.h new file mode 100644 index 0000000..3e0c0c4 --- /dev/null +++ b/watchos2/Queue.h @@ -0,0 +1,22 @@ +#ifndef _QUEUE_h +#define _QUEUE_h + +#define QUEUE_RING_SIZE 8 + +template +class Queue +{ +private: + T* m_item[QUEUE_RING_SIZE]; + int m_read = 0, m_write = 0; + bool m_full = false; + int next(int n); +public: + Queue(); + void push(T* item); + T* pop(); + T* peek(); + bool isEmpty(); +}; + +#endif \ No newline at end of file diff --git a/watchos2/Queues.cpp b/watchos2/Queues.cpp new file mode 100644 index 0000000..e315d34 --- /dev/null +++ b/watchos2/Queues.cpp @@ -0,0 +1,4 @@ +#include "Queue.h" +#include "Queue.cpp" + +template class Queue; \ No newline at end of file diff --git a/watchos2/Task.cpp b/watchos2/Task.cpp new file mode 100644 index 0000000..966c10f --- /dev/null +++ b/watchos2/Task.cpp @@ -0,0 +1,5 @@ +#include "Task.h" + +void Task::initialize() {}; +void Task::start() {}; +void Task::suspend() {}; \ No newline at end of file diff --git a/watchos2/Task.h b/watchos2/Task.h new file mode 100644 index 0000000..303947f --- /dev/null +++ b/watchos2/Task.h @@ -0,0 +1,13 @@ +#ifndef _TASK_h +#define _TASK_h + +class Task +{ +public: + virtual void initialize(); + virtual void start(); + virtual void suspend(); +}; + +#endif + diff --git a/watchos2/Task_Test.cpp b/watchos2/Task_Test.cpp new file mode 100644 index 0000000..8fface7 --- /dev/null +++ b/watchos2/Task_Test.cpp @@ -0,0 +1,12 @@ +#include "watchos.h" +#include "Task.h" +#include "IRunnable.h" + +class Task_Test : public IRunnable, public Task +{ +public: + void tick() + { + watchos::debug("Tick!"); + } +}; \ No newline at end of file diff --git a/watchos2/__vm/Compile.vmps.xml b/watchos2/__vm/Compile.vmps.xml index 72044c2..a8054e2 100644 --- a/watchos2/__vm/Compile.vmps.xml +++ b/watchos2/__vm/Compile.vmps.xml @@ -1,8 +1,8 @@ - + - + diff --git a/watchos2/__vm/Upload.vmps.xml b/watchos2/__vm/Upload.vmps.xml new file mode 100644 index 0000000..502d680 --- /dev/null +++ b/watchos2/__vm/Upload.vmps.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/watchos2/watchos.cpp b/watchos2/watchos.cpp new file mode 100644 index 0000000..1b8b620 --- /dev/null +++ b/watchos2/watchos.cpp @@ -0,0 +1,45 @@ +#include + +#include "watchos.h" + +Kernel* watchos::s_kernel = nullptr; + +void watchos::initialize() +{ + Serial.begin(115200); +} + +Kernel* watchos::kernel() +{ + if (s_kernel == nullptr) + { + s_kernel = new Kernel(); + } + return s_kernel; +} + +void watchos::panic(char* fmt...) +{ + Serial.println("PANIC PANIC PANIC"); + va_list args; + char msg[512]; + va_start(args, fmt); + vsprintf(msg, fmt, args); + va_end(args); + Serial.println(msg); + delay(3000); + Serial.println("Resetting..."); + ESP.restart(); +} + +void watchos::debug(char* fmt...) +{ +#ifdef WATCHOS_DEBUG + va_list args; + char msg[512]; + va_start(args, fmt); + vsprintf(msg, fmt, args); + va_end(args); + Serial.println(msg); +#endif +} \ No newline at end of file diff --git a/watchos2/watchos.h b/watchos2/watchos.h new file mode 100644 index 0000000..d2bd21f --- /dev/null +++ b/watchos2/watchos.h @@ -0,0 +1,25 @@ +#ifndef _WATCHOS2_h +#define _WATCHOS2_h + +#include +#include "watchos_config.h" +#include "watchos_consts.h" +#include "watchos_hw.h" +#include "watchos_types.h" + +#include "Kernel.h" + +class watchos +{ +private: + static Kernel* s_kernel; + +public: + static void initialize(); + static Kernel* kernel(); + static void panic(char* fmt...); + static void debug(char* fmt...); + +}; + +#endif diff --git a/watchos2/watchos2.ino b/watchos2/watchos2.ino index 1a02777..62f1f8c 100644 --- a/watchos2/watchos2.ino +++ b/watchos2/watchos2.ino @@ -3,13 +3,22 @@ Created: 6/30/2021 9:38:10 PM Author: Adam */ + +#include "watchos.h" +#include "Task_Test.cpp" +#include // the setup function runs once when you press reset or power the board void setup() { - + delay(500); + watchos::initialize(); + Kernel* kernel = watchos::kernel(); + kernel->registerTask(new Task_Test()); + watchos::debug("Setup done!"); + } // the loop function runs over and over again until power down or reset void loop() { - + watchos::kernel()->tick(); } diff --git a/watchos2/watchos_config.h b/watchos2/watchos_config.h new file mode 100644 index 0000000..e69de29 diff --git a/watchos2/watchos_consts.h b/watchos2/watchos_consts.h new file mode 100644 index 0000000..1ff4a8d --- /dev/null +++ b/watchos2/watchos_consts.h @@ -0,0 +1,12 @@ +#ifndef _WATCHOS_CONSTS_h +#define _WATCHOS_CONSTS_h + +// If defined, enable debugging output. +#define WATCHOS_DEBUG + +#define WATCHOS_WK_TEST 0x00000001 + +#define WATCHOS_HANDLE_NULL 0x00000000 +#define WATCHOS_HANDLE_TYPE_TASK 0x01 + +#endif \ No newline at end of file diff --git a/watchos2/watchos_hw.h b/watchos2/watchos_hw.h new file mode 100644 index 0000000..d86ad6d --- /dev/null +++ b/watchos2/watchos_hw.h @@ -0,0 +1,63 @@ +#ifndef _WATCHOS_HW_h +#define _WATCHOS_HW_h + +////////// +// I2C +#define HW_I2C_SDA 21 +#define HW_I2C_SCL 22 + + +////////// +// RTC + +// Pin +// #define HW_RTC 27 +#define HW_RTC GPIO_NUM_27 + +////////// +// Display + +// Controller pins +// Chip select? +#define HW_DISPLAY_CS 5 +// Data/Command selector? +#define HW_DISPLAY_DC 10 +#define HW_DISPLAY_RESET 9 +#define HW_DISPLAY_BUSY 19 + +#define DISPLAY_WIDTH 200 +#define DISPLAY_HEIGHT 200 + +// Enable GFX library in display driver +#define ENABLE_GxEPD2_GFX 1 + + +////////// +// ADC / Battery +#define HW_BATTERY_ADC_PIN 33 + + +////////// +// Vibration Motor + +// Pin +#define HW_VIBRATION_MOTOR 13 + +////////// +// Buttons + +// Pin assignments for buttons +#define HW_BUTTON_TL 25 +#define HW_BUTTON_TR 32 +#define HW_BUTTON_BL 26 +#define HW_BUTTON_BR 4 + +// Masks for wakeups +#define HW_BUTTON_TL_MASK GPIO_SEL_25 +#define HW_BUTTON_TR_MASK GPIO_SEL_32 +#define HW_BUTTON_BL_MASK GPIO_SEL_26 +#define HW_BUTTON_BR_MASK GPIO_SEL_4 +// Combined mask for any button +#define HW_BUTTON_MASK HW_BUTTON_TL_MASK|HW_BUTTON_TR_MASK|HW_BUTTON_BL_MASK|HW_BUTTON_BR_MASK + +#endif \ No newline at end of file diff --git a/watchos2/watchos_types.h b/watchos2/watchos_types.h new file mode 100644 index 0000000..ee69ec5 --- /dev/null +++ b/watchos2/watchos_types.h @@ -0,0 +1,9 @@ +#ifndef _WATCHOS_TYPES_h +#define _WATCHOS_TYPES_h + +/// +/// A handle to any kernel object +/// +typedef uint32_t kernel_handle_t; + +#endif