mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[Ion] Move to C++
Change-Id: Id75fca5e92a3fdf18258015bcda7cd70297b0fdb
This commit is contained in:
@@ -6,8 +6,8 @@ AppsContainer::AppsContainer() :
|
||||
{
|
||||
}
|
||||
|
||||
bool AppsContainer::handleEvent(ion_event_t event) {
|
||||
if (event == F1) {
|
||||
bool AppsContainer::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Event::F1) {
|
||||
m_activeAppIndex++;
|
||||
if (m_activeAppIndex >= (int)(AppId::Count)) {
|
||||
m_activeAppIndex = 0;
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
#endif
|
||||
};
|
||||
void switchTo(AppId appId);
|
||||
bool handleEvent(ion_event_t event) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
private:
|
||||
App * appWithId(AppId appId);
|
||||
int m_activeAppIndex;
|
||||
|
||||
@@ -22,9 +22,9 @@ void GraphController::setFocused(bool focused) {
|
||||
*/
|
||||
}
|
||||
|
||||
bool GraphController::handleEvent(ion_event_t event) {
|
||||
bool GraphController::handleEvent(Ion::Events::Event event) {
|
||||
switch (event) {
|
||||
case ENTER:
|
||||
case Ion::Events::Event::ENTER:
|
||||
m_view.moveCursorRight();
|
||||
return true;
|
||||
default:
|
||||
|
||||
@@ -11,7 +11,7 @@ public:
|
||||
View * view() override;
|
||||
const char * title() const override;
|
||||
void setFocused(bool focused) override;
|
||||
bool handleEvent(ion_event_t event) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
private:
|
||||
GraphView m_view;
|
||||
};
|
||||
|
||||
@@ -30,15 +30,15 @@ void ListController::setActiveCell(int index) {
|
||||
app()->focus(cell);
|
||||
}
|
||||
|
||||
bool ListController::handleEvent(ion_event_t event) {
|
||||
bool ListController::handleEvent(Ion::Events::Event event) {
|
||||
switch (event) {
|
||||
case DOWN_ARROW:
|
||||
case Ion::Events::Event::DOWN_ARROW:
|
||||
setActiveCell(m_activeCell+1);
|
||||
return true;
|
||||
case UP_ARROW:
|
||||
case Ion::Events::Event::UP_ARROW:
|
||||
setActiveCell(m_activeCell-1);
|
||||
return true;
|
||||
case ENTER:
|
||||
case Ion::Events::Event::ENTER:
|
||||
m_manualScrolling += 10;
|
||||
m_tableView.setContentOffset({0, m_manualScrolling});
|
||||
return true;
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
|
||||
View * view() override;
|
||||
const char * title() const override;
|
||||
bool handleEvent(ion_event_t event) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
|
||||
int numberOfCells() override;
|
||||
void willDisplayCellForIndex(View * cell, int index) override;
|
||||
|
||||
@@ -41,15 +41,15 @@ void Probability::LawController::setActiveCell(int index) {
|
||||
app()->focus(cell);
|
||||
}
|
||||
|
||||
bool Probability::LawController::handleEvent(ion_event_t event) {
|
||||
bool Probability::LawController::handleEvent(Ion::Events::Event event) {
|
||||
switch (event) {
|
||||
case DOWN_ARROW:
|
||||
case Ion::Events::Event::DOWN_ARROW:
|
||||
setActiveCell(m_activeCell+1);
|
||||
return true;
|
||||
case UP_ARROW:
|
||||
case Ion::Events::Event::UP_ARROW:
|
||||
setActiveCell(m_activeCell-1);
|
||||
return true;
|
||||
case ENTER:
|
||||
case Ion::Events::Event::ENTER:
|
||||
((Probability::App *)app())->setLaw(App::Law::Normal);
|
||||
return true;
|
||||
default:
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
|
||||
View * view() override;
|
||||
const char * title() const override;
|
||||
bool handleEvent(ion_event_t event) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
|
||||
int numberOfCells() override;
|
||||
void willDisplayCellForIndex(View * cell, int index) override;
|
||||
|
||||
@@ -14,6 +14,6 @@ const char * Probability::ParametersController::title() const {
|
||||
return "Parameters";
|
||||
}
|
||||
|
||||
bool Probability::ParametersController::handleEvent(ion_event_t event) {
|
||||
bool Probability::ParametersController::handleEvent(Ion::Events::Event event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public:
|
||||
|
||||
View * view() override;
|
||||
const char * title() const override;
|
||||
bool handleEvent(ion_event_t event) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
private:
|
||||
SolidColorView m_view;
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
App();
|
||||
void setWindow(Window * window);
|
||||
void focus(Responder * responder);
|
||||
void processEvent(ion_event_t event);
|
||||
void processEvent(Ion::Events::Event event);
|
||||
protected:
|
||||
virtual ViewController * rootViewController() = 0;
|
||||
private:
|
||||
|
||||
@@ -12,16 +12,14 @@
|
||||
|
||||
#include <escher/app.h>
|
||||
#include <escher/window.h>
|
||||
extern "C" {
|
||||
#include <ion.h>
|
||||
}
|
||||
#include <ion/events.h>
|
||||
|
||||
class Container {
|
||||
public:
|
||||
Container();
|
||||
void run();
|
||||
App * activeApp();
|
||||
virtual bool handleEvent(ion_event_t event);
|
||||
virtual bool handleEvent(Ion::Events::Event event);
|
||||
protected:
|
||||
void switchTo(App * app);
|
||||
private:
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#ifndef ESCHER_RESPONDER_H
|
||||
#define ESCHER_RESPONDER_H
|
||||
|
||||
extern "C" {
|
||||
#include <ion.h>
|
||||
}
|
||||
#include <ion/events.h>
|
||||
|
||||
class App;
|
||||
|
||||
class Responder {
|
||||
public:
|
||||
Responder(Responder * parentResponder);
|
||||
virtual bool handleEvent(ion_event_t event); // Default implementation does nothing
|
||||
virtual bool handleEvent(Ion::Events::Event event); // Default implementation does nothing
|
||||
virtual void setFocused(bool focused); // Default implementation does nothing. Used by subclasses to know when active or not
|
||||
Responder * parentResponder() const;
|
||||
void setParentResponder(Responder * responder);
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
View * view() override;
|
||||
void handleKeyEvent(int key) override;
|
||||
|
||||
bool handleEvent(ion_event_t event) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
private:
|
||||
class ControllerView : public View {
|
||||
public:
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
uint8_t numberOfTabs();
|
||||
|
||||
const char * tabName(uint8_t index);
|
||||
bool handleEvent(ion_event_t event) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
|
||||
@@ -11,7 +11,7 @@ public:
|
||||
// View
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
// Responder
|
||||
bool handleEvent(ion_event_t event) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
protected:
|
||||
#if ESCHER_VIEW_LOGGING
|
||||
const char * className() const override;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <escher/app.h>
|
||||
#include <escher/window.h>
|
||||
extern "C" {
|
||||
#include <ion.h>
|
||||
#include <assert.h>
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ void App::setWindow(Window * window) {
|
||||
window->redraw();
|
||||
}
|
||||
|
||||
void App::processEvent(ion_event_t event) {
|
||||
void App::processEvent(Ion::Events::Event event) {
|
||||
Responder * responder = m_focusedResponder;
|
||||
bool didHandleEvent = false;
|
||||
while (responder) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include <escher/container.h>
|
||||
extern "C" {
|
||||
#include <ion.h>
|
||||
}
|
||||
#include <ion/display.h>
|
||||
|
||||
Container::Container() :
|
||||
m_activeApp(nullptr)
|
||||
@@ -18,16 +16,16 @@ App * Container::activeApp() {
|
||||
return m_activeApp;
|
||||
}
|
||||
|
||||
bool Container::handleEvent(ion_event_t event) {
|
||||
bool Container::handleEvent(Ion::Events::Event event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Container::run() {
|
||||
m_window.setFrame(KDRect(0, 0, ION_SCREEN_WIDTH, ION_SCREEN_HEIGHT));
|
||||
m_window.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height));
|
||||
m_window.redraw();
|
||||
|
||||
while (true) {
|
||||
ion_event_t event = ion_get_event(); // This is a blocking call
|
||||
Ion::Events::Event event = Ion::Events::getEvent(); // This is a blocking call
|
||||
if (handleEvent(event)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ void Responder::setParentResponder(Responder * responder) {
|
||||
m_parentResponder = responder;
|
||||
}
|
||||
|
||||
bool Responder::handleEvent(ion_event_t event) {
|
||||
bool Responder::handleEvent(Ion::Events::Event event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,8 +91,8 @@ void StackViewController::handleKeyEvent(int key) {
|
||||
}
|
||||
|
||||
|
||||
bool StackViewController::handleEvent(ion_event_t event) {
|
||||
if (event == ESC && m_numberOfChildren > 1) {
|
||||
bool StackViewController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Event::ESC && m_numberOfChildren > 1) {
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -71,14 +71,14 @@ TabViewController::TabViewController(Responder * parentResponder, ViewController
|
||||
}
|
||||
}
|
||||
|
||||
bool TabViewController::handleEvent(ion_event_t event) {
|
||||
bool TabViewController::handleEvent(Ion::Events::Event event) {
|
||||
switch(event) {
|
||||
case LEFT_ARROW:
|
||||
case Ion::Events::Event::LEFT_ARROW:
|
||||
if (m_activeChildIndex > 0) {
|
||||
setActiveTab(m_activeChildIndex-1);
|
||||
}
|
||||
return true;
|
||||
case RIGHT_ARROW:
|
||||
case Ion::Events::Event::RIGHT_ARROW:
|
||||
if (m_activeChildIndex < m_numberOfChildren-1) {
|
||||
setActiveTab(m_activeChildIndex+1);
|
||||
}
|
||||
|
||||
@@ -24,16 +24,16 @@ const char * TextField::className() const {
|
||||
|
||||
/* Responder */
|
||||
|
||||
bool TextField::handleEvent(ion_event_t event) {
|
||||
if (event == DELETE && m_currentTextLength > 0) {
|
||||
bool TextField::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Event::DELETE && m_currentTextLength > 0) {
|
||||
m_currentTextLength--;
|
||||
return true;
|
||||
}
|
||||
if (event >= 0x100) {
|
||||
if ((int)event >= 0x100) {
|
||||
return false;
|
||||
}
|
||||
if (m_currentTextLength-1 < m_textBufferSize) {
|
||||
m_textBuffer[m_currentTextLength++] = event;
|
||||
m_textBuffer[m_currentTextLength++] = (int)event;
|
||||
markRectAsDirty(bounds()); // TODO: Could be optimized
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef ION_ION_H
|
||||
#define ION_ION_H
|
||||
|
||||
#include <ion/display.h>
|
||||
#include <ion/events.h>
|
||||
#include <ion/keyboard.h>
|
||||
#include <ion/screen.h>
|
||||
|
||||
|
||||
/* ION is not your regular library. It is a library you link against, but it
|
||||
* will take care of configuring the whole environment for you. In POSIX terms,
|
||||
@@ -13,12 +14,13 @@
|
||||
|
||||
void ion_app();
|
||||
|
||||
void ion_display_on();
|
||||
void ion_display_off();
|
||||
namespace Ion {
|
||||
|
||||
void ion_sleep(long ms);
|
||||
void msleep(long ms);
|
||||
|
||||
/* CAUTION: This is a complete reset! */
|
||||
void ion_reset();
|
||||
void reset();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
30
ion/include/ion/display.h
Normal file
30
ion/include/ion/display.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef ION_DISPLAY_H
|
||||
#define ION_DISPLAY_H
|
||||
|
||||
/* ION abstracts pushing pixels to the screen.
|
||||
*
|
||||
* There could be a single entry point, set_pixel, but setting pixels one by one
|
||||
* incurs quite a large overhead because you need to send the coordinate of each
|
||||
* pixel to the screen.
|
||||
*
|
||||
* Many displays support sending contiguous pixels without having to repeat the
|
||||
* pixel coordinates every time. We're therefore leveraging this capability
|
||||
* which results in a very consequent speedup (up to ~10x faster). */
|
||||
|
||||
#include <kandinsky/rect.h>
|
||||
#include <kandinsky/color.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Display {
|
||||
|
||||
void pushRect(KDRect r, const KDColor * pixels);
|
||||
void pushRectUniform(KDRect r, KDColor c);
|
||||
void pullRect(KDRect r, KDColor * pixels);
|
||||
|
||||
constexpr int Width = 320;
|
||||
constexpr int Height = 240;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,10 @@
|
||||
#ifndef ION_EVENTS_H
|
||||
#define ION_EVENTS_H
|
||||
|
||||
typedef enum {
|
||||
namespace Ion {
|
||||
namespace Events {
|
||||
|
||||
enum class Event {
|
||||
LEFT_PARENTHESIS = '(', // 0x28
|
||||
RIGHT_PARENTHESIS = ')', // 0x29
|
||||
COMMA = ',',
|
||||
@@ -97,9 +100,12 @@ typedef enum {
|
||||
MODE,
|
||||
CATALOG,
|
||||
CLEAR,
|
||||
ERROR = 0xffffffff,
|
||||
} ion_event_t;
|
||||
//ERROR = 0xffffffff,
|
||||
};
|
||||
|
||||
ion_event_t ion_get_event();
|
||||
Event getEvent();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,72 +1,27 @@
|
||||
#ifndef ION_KEYBOARD_H
|
||||
#define ION_KEYBOARD_H
|
||||
|
||||
#include <stdbool.h>
|
||||
namespace Ion {
|
||||
namespace Keyboard {
|
||||
|
||||
typedef enum {
|
||||
ION_KEY_A_1,
|
||||
ION_KEY_A_2,
|
||||
ION_KEY_A_3,
|
||||
ION_KEY_A_4,
|
||||
ION_KEY_A_5,
|
||||
enum class Key {
|
||||
A1 = 0, A2 = 1, A3 = 2, A4 = 3, A5 = 4,
|
||||
B1 = 5, B2 = 6, B3 = 7, B4 = 8, B5 = 9,
|
||||
C1 = 10, C2 = 11, C3 = 12, C4 = 13, C5 = 14,
|
||||
D1, D2, D3, D4, D5,
|
||||
E1, E2, E3, E4, E5,
|
||||
F1, F2, F3, F4, F5,
|
||||
G1, G2, G3, G4, G5,
|
||||
H1, H2, H3, H4, H5,
|
||||
I1, I2, I3, I4, I5,
|
||||
J1, J2, J3, J4, J5
|
||||
};
|
||||
|
||||
ION_KEY_B_1,
|
||||
ION_KEY_B_2,
|
||||
ION_KEY_B_3,
|
||||
ION_KEY_B_4,
|
||||
ION_KEY_B_5,
|
||||
constexpr int NumberOfKeys = 50;
|
||||
|
||||
ION_KEY_C_1,
|
||||
ION_KEY_C_2,
|
||||
ION_KEY_C_3,
|
||||
ION_KEY_C_4,
|
||||
ION_KEY_C_5,
|
||||
bool keyDown(Key k);
|
||||
|
||||
ION_KEY_D_1,
|
||||
ION_KEY_D_2,
|
||||
ION_KEY_D_3,
|
||||
ION_KEY_D_4,
|
||||
ION_KEY_D_5,
|
||||
|
||||
ION_KEY_E_1,
|
||||
ION_KEY_E_2,
|
||||
ION_KEY_E_3,
|
||||
ION_KEY_E_4,
|
||||
ION_KEY_E_5,
|
||||
|
||||
ION_KEY_F_1,
|
||||
ION_KEY_F_2,
|
||||
ION_KEY_F_3,
|
||||
ION_KEY_F_4,
|
||||
ION_KEY_F_5,
|
||||
|
||||
ION_KEY_G_1,
|
||||
ION_KEY_G_2,
|
||||
ION_KEY_G_3,
|
||||
ION_KEY_G_4,
|
||||
ION_KEY_G_5,
|
||||
|
||||
ION_KEY_H_1,
|
||||
ION_KEY_H_2,
|
||||
ION_KEY_H_3,
|
||||
ION_KEY_H_4,
|
||||
ION_KEY_H_5,
|
||||
|
||||
ION_KEY_I_1,
|
||||
ION_KEY_I_2,
|
||||
ION_KEY_I_3,
|
||||
ION_KEY_I_4,
|
||||
ION_KEY_I_5,
|
||||
|
||||
ION_KEY_J_1,
|
||||
ION_KEY_J_2,
|
||||
ION_KEY_J_3,
|
||||
ION_KEY_J_4,
|
||||
ION_KEY_J_5
|
||||
} ion_key_t;
|
||||
|
||||
#define ION_NUMBER_OF_KEYS 50
|
||||
|
||||
bool ion_key_down(ion_key_t key);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
#ifndef ION_LED_H
|
||||
#define ION_LED_H
|
||||
|
||||
/* ION abstracts pushing pixels to the screen.
|
||||
*
|
||||
* There could be a single entry point, set_pixel, but setting pixels one by one
|
||||
* incurs quite a large overhead because you need to send the coordinate of each
|
||||
* pixel to the screen.
|
||||
*
|
||||
* Many displays support sending contiguous pixels without having to repeat the
|
||||
* pixel coordinates every time. We're therefore leveraging this capability
|
||||
* which results in a very consequent speedup (up to ~10x faster). */
|
||||
#include <kandinsky/color.h>
|
||||
|
||||
#include <stdint.h>
|
||||
namespace Ion {
|
||||
namespace LED {
|
||||
|
||||
typedef uint16_t ion_color_t;
|
||||
void setColor(KDColor c);
|
||||
|
||||
void ion_led_set_color(ion_color_t color);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef ION_SCREEN_H
|
||||
#define ION_SCREEN_H
|
||||
|
||||
/* ION abstracts pushing pixels to the screen.
|
||||
*
|
||||
* There could be a single entry point, set_pixel, but setting pixels one by one
|
||||
* incurs quite a large overhead because you need to send the coordinate of each
|
||||
* pixel to the screen.
|
||||
*
|
||||
* Many displays support sending contiguous pixels without having to repeat the
|
||||
* pixel coordinates every time. We're therefore leveraging this capability
|
||||
* which results in a very consequent speedup (up to ~10x faster). */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint16_t ion_color_t;
|
||||
|
||||
void ion_screen_push_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const ion_color_t * pixels);
|
||||
void ion_screen_push_rect_uniform(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t color);
|
||||
void ion_screen_pull_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t * pixels);
|
||||
/*
|
||||
void ion_screen_set_working_area(KDRect area);
|
||||
void ion_screen_push_pixels(const KDColor * pixels, size_t count);
|
||||
void ion_screen_pull_pixels(KDColor * pixels, size_t count);
|
||||
*/
|
||||
|
||||
#define ION_SCREEN_WIDTH 320
|
||||
#define ION_SCREEN_HEIGHT 240
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,11 @@
|
||||
include ion/src/device/boot/Makefile
|
||||
objs += $(addprefix ion/src/device/, init.o heap.o led.o display.o)
|
||||
objs += $(addprefix ion/src/device/, \
|
||||
device.o\
|
||||
display.o\
|
||||
heap.o\
|
||||
keyboard.o\
|
||||
led.o\
|
||||
)
|
||||
|
||||
# When using the register.h C++ file in production mode, we expect the compiler
|
||||
# to completely inline all bit manipulations. For some reason, if we build using
|
||||
@@ -14,4 +20,4 @@ ion/src/device/display.o: SFLAGS+=-O3
|
||||
endif
|
||||
endif
|
||||
|
||||
objs += $(addprefix ion/src/device/keyboard/, keyboard.o)
|
||||
#objs += $(addprefix ion/src/device/keyboard/, keyboard.o)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
objs += $(addprefix ion/src/device/boot/, isr.o crt0.o)
|
||||
objs += $(addprefix ion/src/device/boot/, isr.o rt0.o)
|
||||
LDFLAGS += -T ion/src/device/boot/flash.ld
|
||||
|
||||
LDFLAGS += -M -Map output.map
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ion.h>
|
||||
#include "../init.h"
|
||||
#include "../device.h"
|
||||
|
||||
extern char _data_section_start_flash;
|
||||
extern char _data_section_start_ram;
|
||||
@@ -9,16 +9,21 @@ extern char _data_section_end_ram;
|
||||
extern char _bss_section_start_ram;
|
||||
extern char _bss_section_end_ram;
|
||||
|
||||
extern "C" {
|
||||
void _start();
|
||||
void abort();
|
||||
}
|
||||
|
||||
void abort() {
|
||||
#ifdef DEBUG
|
||||
while (1) {
|
||||
}
|
||||
#else
|
||||
ion_reset();
|
||||
Ion::reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
void _start(void) {
|
||||
void _start() {
|
||||
// This is where execution starts after reset.
|
||||
// Many things are not initialized yet so the code here has to pay attention.
|
||||
|
||||
@@ -35,7 +40,7 @@ void _start(void) {
|
||||
size_t bssSectionLength = (&_bss_section_end_ram - &_bss_section_start_ram);
|
||||
memset(&_bss_section_start_ram, 0, bssSectionLength);
|
||||
|
||||
init_platform();
|
||||
Ion::Device::init();
|
||||
|
||||
ion_app();
|
||||
|
||||
54
ion/src/device/device.cpp
Normal file
54
ion/src/device/device.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "device.h"
|
||||
#include "regs/regs.h"
|
||||
extern "C" {
|
||||
#include <assert.h>
|
||||
#include "registers/registers.h"
|
||||
}
|
||||
#include <ion.h>
|
||||
#include "led.h"
|
||||
#include "display.h"
|
||||
#include "keyboard.h"
|
||||
|
||||
// Public Ion methods
|
||||
|
||||
void Ion::msleep(long ms) {
|
||||
for (volatile long i=0; i<1040*ms; i++) {
|
||||
__asm volatile("nop");
|
||||
}
|
||||
}
|
||||
|
||||
void Ion::reset() {
|
||||
AIRCR = AIRCR_VECTKEY_MASK | AIRCR_SYSRESETREQ;
|
||||
}
|
||||
|
||||
// Private Ion::Device methods
|
||||
|
||||
void Ion::Device::init() {
|
||||
initFPU();
|
||||
initClocks();
|
||||
LED::Device::init();
|
||||
Display::Device::init();
|
||||
Keyboard::Device::init();
|
||||
}
|
||||
|
||||
void Ion::Device::initClocks() {
|
||||
// Our peripherals are using GPIO A, B, C and D.
|
||||
// We're not using the CRC nor DMA engines.
|
||||
class RCC::AHB1ENR ahb1enr(0); // Reset value
|
||||
ahb1enr.setGPIOAEN(true);
|
||||
ahb1enr.setGPIOBEN(true);
|
||||
ahb1enr.setGPIOCEN(true);
|
||||
ahb1enr.setGPIODEN(true);
|
||||
RCC.AHB1ENR()->set(ahb1enr);
|
||||
}
|
||||
|
||||
void Ion::Device::initFPU() {
|
||||
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/BABDBFBJ.html
|
||||
//CPACR |= (0xF << 20); // Set the bits 20-23 to enable CP10 and CP11 coprocessors
|
||||
CPACR |= (
|
||||
REGISTER_FIELD_VALUE(CPACR_CP(10), CPACR_ACCESS_FULL)
|
||||
|
|
||||
REGISTER_FIELD_VALUE(CPACR_CP(11), CPACR_ACCESS_FULL)
|
||||
);
|
||||
// FIXME: The pipeline should be flushed at this point
|
||||
}
|
||||
50
ion/src/device/device.h
Normal file
50
ion/src/device/device.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef ION_DEVICE_H
|
||||
#define ION_DEVICE_H
|
||||
|
||||
namespace Ion {
|
||||
namespace Device {
|
||||
|
||||
void init();
|
||||
void initFPU();
|
||||
void initClocks();
|
||||
|
||||
/* Pin | Role | Mode | Function
|
||||
* -----+-------------------+-----------------------+----------
|
||||
* PA0 | Battery sensing | |
|
||||
* PA2 | LCD D4 | Alternate Function 12 | FMSC_D4
|
||||
* PA3 | LCD D5 | Alternate Function 12 | FSMC_D5
|
||||
* PA4 | LCD D6 | Alternate Function 12 | FSMC_D6
|
||||
* PA5 | LCD D7 | Alternate Function 12 | FSMC_D7
|
||||
* PA6 | LED red | Alternate Function XX | TIM3_CH1
|
||||
* PA7 | LED green | Alternate Function XX | TIM3_CH2
|
||||
* PB0 | LED blue | Alternate Function XX | TIM3_CH3
|
||||
* PB1 | Keyboard row A | Output, open-drain |
|
||||
* PB2 | Keyboard row B | Output, open-drain |
|
||||
* PB3 | Keyboard row C | Output, open-drain |
|
||||
* PB4 | Keyboard row D | Output, open-drain |
|
||||
* PB5 | Keyboard row E | Output, open-drain |
|
||||
* PB6 | Keyboard row F | Output, open-drain |
|
||||
* PB7 | Keyboard row G | Output, open-drain |
|
||||
* PB8 | Keyboard row H | Output, open-drain |
|
||||
* PB9 | Keyboard row I | Output, open-drain |
|
||||
* PB10 | Keyboard row J | Output, open-drain |
|
||||
* PB14 | LCD D0 | Alternate Function 12 | FSMC_D0
|
||||
* PC0 | Keyboard column 1 | Input, pulled-up |
|
||||
* PC1 | Keyboard column 2 | Input, pulled-up |
|
||||
* PC3 | LCD data/command | Alternate Function 12 | FSMC_A0
|
||||
* PC4 | LCD chip select | Alternate Function 12 | FSMC_NE4
|
||||
* PC5 | LCD read signal | Alternate Function 12 | FSMC_NOE
|
||||
* PC6 | LCD D1 | Alternate Function 12 | FSMC_D7
|
||||
* PC9 | LCD backlight | Alternate Function 12 | TIM3_CH4
|
||||
* PC11 | LCD D2 | Alternate Function 12 | FSMC_D2
|
||||
* PC12 | LCD D3 | Alternate Function 12 | FSMC_D3
|
||||
* PC13 | Keyboard column 3 | Input, pulled-up |
|
||||
* PC14 | Keyboard column 4 | Input, pulled-up |
|
||||
* PC15 | Keyboard column 5 | Input, pulled-up |
|
||||
* PD2 | LCD write signal | Alternate Function 12 | FSMC_NWE
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,54 +1,78 @@
|
||||
#include <ion.h>
|
||||
#include "display.h"
|
||||
#include "regs/regs.h"
|
||||
extern "C" {
|
||||
#include <assert.h>
|
||||
#include <ion.h>
|
||||
}
|
||||
|
||||
// Public Ion::Display methods
|
||||
|
||||
namespace Ion {
|
||||
namespace Display {
|
||||
|
||||
void pushRect(KDRect r, const KDColor * pixels) {
|
||||
Device::setDrawingArea(r);
|
||||
Device::pushPixels(pixels, r.width()*r.height());
|
||||
}
|
||||
|
||||
void pushRectUniform(KDRect r, KDColor c) {
|
||||
Device::setDrawingArea(r);
|
||||
for (size_t i=0; i<r.width()*r.height(); i++) {
|
||||
Device::pushPixels(&c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void pullRect(KDRect r, KDColor * pixels) {
|
||||
//assert(0); // Unimplemented
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Private Ion::Display::Device methods
|
||||
|
||||
namespace Ion {
|
||||
namespace Display {
|
||||
namespace Device {
|
||||
|
||||
#define SEND_COMMAND(c, ...) {*CommandAddress = Command::c; uint8_t data[] = {__VA_ARGS__}; for (unsigned int i=0;i<sizeof(data);i++) { *DataAddress = data[i];};}
|
||||
|
||||
void Ion::Screen::init() {
|
||||
void init() {
|
||||
// Turn on the backlight
|
||||
RCC.AHB1ENR()->setGPIOCEN(true);
|
||||
GPIOC.MODER()->setMODER(9, GPIO::MODER::MODE::Output);
|
||||
GPIOC.ODR()->setODR(9, true);
|
||||
GPIOC.MODER()->setMode(9, GPIO::MODER::Mode::Output);
|
||||
GPIOC.ODR()->set(9, true);
|
||||
|
||||
// Turn on the reset pin
|
||||
RCC.AHB1ENR()->setGPIOBEN(true);
|
||||
GPIOB.MODER()->setMODER(13, GPIO::MODER::MODE::Output);
|
||||
GPIOB.ODR()->setODR(13, true);
|
||||
GPIOB.MODER()->setMode(13, GPIO::MODER::Mode::Output);
|
||||
GPIOB.ODR()->set(13, true);
|
||||
|
||||
ion_sleep(120);
|
||||
msleep(120);
|
||||
|
||||
Ion::Screen::initGPIO();
|
||||
Ion::Screen::initFSMC();
|
||||
Ion::Screen::initPanel();
|
||||
initGPIO();
|
||||
initFSMC();
|
||||
initPanel();
|
||||
}
|
||||
|
||||
void Ion::Screen::initGPIO() {
|
||||
// We use GPIOA to GPIOD
|
||||
RCC.AHB1ENR()->setGPIOAEN(true);
|
||||
RCC.AHB1ENR()->setGPIOBEN(true);
|
||||
RCC.AHB1ENR()->setGPIOCEN(true);
|
||||
RCC.AHB1ENR()->setGPIODEN(true);
|
||||
|
||||
void initGPIO() {
|
||||
// Configure GPIOs to use AF
|
||||
|
||||
GPIOA.MODER()->setMODER(2, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOA.MODER()->setMODER(3, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOA.MODER()->setMODER(4, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOA.MODER()->setMODER(5, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOA.MODER()->setMode(2, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOA.MODER()->setMode(3, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOA.MODER()->setMode(4, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOA.MODER()->setMode(5, GPIO::MODER::Mode::AlternateFunction);
|
||||
|
||||
GPIOB.MODER()->setMODER(14, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOB.MODER()->setMode(14, GPIO::MODER::Mode::AlternateFunction);
|
||||
|
||||
GPIOC.MODER()->setMODER(3, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOC.MODER()->setMODER(4, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOC.MODER()->setMODER(5, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOC.MODER()->setMODER(6, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOC.MODER()->setMODER(11, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOC.MODER()->setMODER(12, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOC.MODER()->setMode(3, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOC.MODER()->setMode(4, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOC.MODER()->setMode(5, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOC.MODER()->setMode(6, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOC.MODER()->setMode(11, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOC.MODER()->setMode(12, GPIO::MODER::Mode::AlternateFunction);
|
||||
|
||||
GPIOD.MODER()->setMODER(2, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOD.MODER()->setMode(2, GPIO::MODER::Mode::AlternateFunction);
|
||||
|
||||
/* More precisely, we want to use the FSMC alternate function.
|
||||
* Oddly enough, this isn't always the same AF number. That equals to:
|
||||
@@ -57,24 +81,24 @@ void Ion::Screen::initGPIO() {
|
||||
* AF12 for PC3,4,5
|
||||
* AF10 for PC6,11,12
|
||||
* AF10 for PD2 */
|
||||
GPIOA.AFR()->setAFR(2, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOA.AFR()->setAFR(3, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOA.AFR()->setAFR(4, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOA.AFR()->setAFR(5, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOA.AFR()->setAlternateFunction(2, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOA.AFR()->setAlternateFunction(3, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOA.AFR()->setAlternateFunction(4, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOA.AFR()->setAlternateFunction(5, GPIO::AFR::AlternateFunction::AF12);
|
||||
|
||||
GPIOB.AFR()->setAFR(14, GPIO::AFR::AlternateFunction::AF10);
|
||||
GPIOB.AFR()->setAlternateFunction(14, GPIO::AFR::AlternateFunction::AF10);
|
||||
|
||||
GPIOC.AFR()->setAFR(3, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOC.AFR()->setAFR(4, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOC.AFR()->setAFR(5, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOC.AFR()->setAFR(6, GPIO::AFR::AlternateFunction::AF10);
|
||||
GPIOC.AFR()->setAFR(11, GPIO::AFR::AlternateFunction::AF10);
|
||||
GPIOC.AFR()->setAFR(12, GPIO::AFR::AlternateFunction::AF10);
|
||||
GPIOC.AFR()->setAlternateFunction(3, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOC.AFR()->setAlternateFunction(4, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOC.AFR()->setAlternateFunction(5, GPIO::AFR::AlternateFunction::AF12);
|
||||
GPIOC.AFR()->setAlternateFunction(6, GPIO::AFR::AlternateFunction::AF10);
|
||||
GPIOC.AFR()->setAlternateFunction(11, GPIO::AFR::AlternateFunction::AF10);
|
||||
GPIOC.AFR()->setAlternateFunction(12, GPIO::AFR::AlternateFunction::AF10);
|
||||
|
||||
GPIOD.AFR()->setAFR(2, GPIO::AFR::AlternateFunction::AF10);
|
||||
GPIOD.AFR()->setAlternateFunction(2, GPIO::AFR::AlternateFunction::AF10);
|
||||
}
|
||||
|
||||
void Ion::Screen::initFSMC() {
|
||||
void initFSMC() {
|
||||
// FSMC lives on the AHB3 bus. Let's enable its clock. */
|
||||
RCC.AHB3ENR()->setFSMCEN(true);
|
||||
|
||||
@@ -98,13 +122,13 @@ void Ion::Screen::initFSMC() {
|
||||
FSMC.BTR(4)->setBUSTURN(0);
|
||||
}
|
||||
|
||||
void Ion::Screen::initPanel() {
|
||||
void initPanel() {
|
||||
|
||||
//*CommandAddress = 0x01; //software reset
|
||||
//ion_sleep(5);
|
||||
// msleep(5);
|
||||
|
||||
*CommandAddress = Command::SleepOut;
|
||||
ion_sleep(120);
|
||||
msleep(120);
|
||||
|
||||
SEND_COMMAND(PowerControlB, 0x00, 0x83, 0x30);
|
||||
SEND_COMMAND(PowerOnSequenceControl, 0x64, 0x03, 0x12, 0x81);
|
||||
@@ -126,17 +150,17 @@ void Ion::Screen::initPanel() {
|
||||
SEND_COMMAND(NegativeGammaCorrection, 0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3a, 0x78, 0x4d, 0x05, 0x18, 0x0d, 0x38, 0x3a, 0x1f);
|
||||
|
||||
*CommandAddress = Command::SleepOut; //Exit Sleep
|
||||
ion_sleep(120);
|
||||
msleep(120);
|
||||
*CommandAddress = Command::DisplayOn; //Display on
|
||||
ion_sleep(50);
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
|
||||
void Ion::Screen::setDrawingArea(uint16_t x, uint16_t y, uint16_t width, uint16_t height) {
|
||||
uint16_t x_start = x;
|
||||
uint16_t x_end = x + width - 1;
|
||||
uint16_t y_start = y;
|
||||
uint16_t y_end = y + height - 1;
|
||||
void setDrawingArea(KDRect r) {
|
||||
uint16_t x_start = r.x();
|
||||
uint16_t x_end = r.x() + r.width() - 1;
|
||||
uint16_t y_start = r.y();
|
||||
uint16_t y_end = r.y() + r.height() - 1;
|
||||
|
||||
*CommandAddress = Command::ColumnAddressSet;
|
||||
*DataAddress = (x_start >> 8);
|
||||
@@ -153,26 +177,15 @@ void Ion::Screen::setDrawingArea(uint16_t x, uint16_t y, uint16_t width, uint16_
|
||||
*CommandAddress = Command::MemoryWrite;
|
||||
}
|
||||
|
||||
void Ion::Screen::pushPixels(const ion_color_t * pixels, size_t numberOfPixels) {
|
||||
assert(sizeof(ion_color_t) == 2); // We expect KDColor to be RGB565
|
||||
void pushPixels(const KDColor * pixels, size_t numberOfPixels) {
|
||||
assert(sizeof(KDColor) == 2); // We expect KDColor to be RGB565
|
||||
for (size_t i=0; i<numberOfPixels; i++) {
|
||||
*DataAddress = (pixels[i] >> 8);
|
||||
*DataAddress = (pixels[i] & 0xFF);
|
||||
uint16_t pixel = pixels[i];
|
||||
*DataAddress = (pixel >> 8);
|
||||
*DataAddress = (pixel & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void ion_screen_push_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const ion_color_t * pixels) {
|
||||
Ion::Screen::setDrawingArea(x, y, width, height);
|
||||
Ion::Screen::pushPixels(pixels, width*height);
|
||||
}
|
||||
|
||||
void ion_screen_push_rect_uniform(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t color) {
|
||||
Ion::Screen::setDrawingArea(x, y, width, height);
|
||||
for (size_t i=0; i<width*height; i++) {
|
||||
Ion::Screen::pushPixels(&color, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ion_screen_pull_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t * pixels) {
|
||||
assert(0); // Unimplemented
|
||||
}
|
||||
|
||||
@@ -1,61 +1,73 @@
|
||||
extern "C" {
|
||||
#include <ion/screen.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
}
|
||||
#ifndef ION_DEVICE_DISPLAY_H
|
||||
#define ION_DEVICE_DISPLAY_H
|
||||
|
||||
/* Pinout:
|
||||
* PA2 - D4
|
||||
* PA3 - D5
|
||||
* PA4 - D6
|
||||
* PA5 - D7
|
||||
* PB14 - D0
|
||||
* PC3 - A0
|
||||
* PC4 - NE4
|
||||
* PC5 - NOE
|
||||
* PC6 - D1
|
||||
* PC11 - D2
|
||||
* PC12 - D3
|
||||
* PD2 - NWE
|
||||
*/
|
||||
#include <kandinsky/rect.h>
|
||||
#include <kandinsky/color.h>
|
||||
extern "C" {
|
||||
#include <stddef.h>
|
||||
}
|
||||
|
||||
namespace Ion {
|
||||
namespace Screen {
|
||||
void init();
|
||||
void initGPIO();
|
||||
void initFSMC();
|
||||
void initPanel();
|
||||
namespace Display {
|
||||
namespace Device {
|
||||
|
||||
void setDrawingArea(uint16_t x, uint16_t y, uint16_t width, uint16_t height);
|
||||
void pushPixels(const ion_color_t * pixels, size_t numberOfPixels);
|
||||
/* Pin | Role | Mode | Function
|
||||
* -----+-------------------+-----------------------+----------
|
||||
* PA2 | LCD D4 | Alternate Function 12 | FMSC_D4
|
||||
* PA3 | LCD D5 | Alternate Function 12 | FSMC_D5
|
||||
* PA4 | LCD D6 | Alternate Function 12 | FSMC_D6
|
||||
* PA5 | LCD D7 | Alternate Function 12 | FSMC_D7
|
||||
* PB13 | LCD reset | Output |
|
||||
* PB14 | LCD D0 | Alternate Function 12 | FSMC_D0
|
||||
* PC3 | LCD data/command | Alternate Function 12 | FSMC_A0
|
||||
* PC4 | LCD chip select | Alternate Function 12 | FSMC_NE4
|
||||
* PC5 | LCD read signal | Alternate Function 12 | FSMC_NOE
|
||||
* PC6 | LCD D1 | Alternate Function 12 | FSMC_D7
|
||||
* PC9 | LCD backlight | Alternate Function 12 | TIM3_CH4
|
||||
* PC11 | LCD D2 | Alternate Function 12 | FSMC_D2
|
||||
* PC12 | LCD D3 | Alternate Function 12 | FSMC_D3
|
||||
* PD2 | LCD write signal | Alternate Function 12 | FSMC_NWE
|
||||
*/
|
||||
|
||||
enum class Command : uint8_t {
|
||||
SleepOut = 0x11,
|
||||
DisplayOn = 0x29,
|
||||
ColumnAddressSet = 0x2A,
|
||||
GammaSet = 0x26,
|
||||
PageAddressSet = 0x2B,
|
||||
MemoryWrite = 0x2C,
|
||||
MemoryAccessControl = 0x36,
|
||||
PixelFormatSet = 0x3A,
|
||||
FrameRateControl = 0xB1,
|
||||
DisplayFunctionControl = 0xB6,
|
||||
EntryMode = 0xB7,
|
||||
PowerControl2 = 0xC1,
|
||||
VCOMControl1 = 0xC5,
|
||||
VCOMControl2 = 0xC7,
|
||||
PowerControlA = 0xCB,
|
||||
PowerControlB = 0xCF,
|
||||
PositiveGammaCorrection = 0xE0,
|
||||
NegativeGammaCorrection = 0xE1,
|
||||
DriverTimingControlA = 0xE8,
|
||||
DriverTimingControlB = 0xEA,
|
||||
PowerOnSequenceControl = 0xED,
|
||||
Enable3G = 0xF2,
|
||||
PumpRatioControl = 0xF7,
|
||||
};
|
||||
void init();
|
||||
void initGPIO();
|
||||
void initFSMC();
|
||||
void initPanel();
|
||||
|
||||
void setDrawingArea(KDRect r);
|
||||
void pushPixels(const KDColor * pixels, size_t numberOfPixels);
|
||||
|
||||
enum class Command : uint8_t {
|
||||
SleepOut = 0x11,
|
||||
DisplayOn = 0x29,
|
||||
ColumnAddressSet = 0x2A,
|
||||
GammaSet = 0x26,
|
||||
PageAddressSet = 0x2B,
|
||||
MemoryWrite = 0x2C,
|
||||
MemoryAccessControl = 0x36,
|
||||
PixelFormatSet = 0x3A,
|
||||
FrameRateControl = 0xB1,
|
||||
DisplayFunctionControl = 0xB6,
|
||||
EntryMode = 0xB7,
|
||||
PowerControl2 = 0xC1,
|
||||
VCOMControl1 = 0xC5,
|
||||
VCOMControl2 = 0xC7,
|
||||
PowerControlA = 0xCB,
|
||||
PowerControlB = 0xCF,
|
||||
PositiveGammaCorrection = 0xE0,
|
||||
NegativeGammaCorrection = 0xE1,
|
||||
DriverTimingControlA = 0xE8,
|
||||
DriverTimingControlB = 0xEA,
|
||||
PowerOnSequenceControl = 0xED,
|
||||
Enable3G = 0xF2,
|
||||
PumpRatioControl = 0xF7,
|
||||
};
|
||||
|
||||
static volatile Command * const CommandAddress = (Command *)0x6C000000;
|
||||
static volatile uint8_t * const DataAddress = (uint8_t *)0x6C000001;
|
||||
|
||||
static volatile Command * const CommandAddress = (Command *)0x6C000000;
|
||||
static volatile uint8_t * const DataAddress = (uint8_t *)0x6C000001;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
extern "C" {
|
||||
#include "init.h"
|
||||
#include <ion.h>
|
||||
#include <assert.h>
|
||||
#include "keyboard/keyboard.h"
|
||||
#include "registers/registers.h"
|
||||
}
|
||||
#include "display.h"
|
||||
|
||||
void enable_fpu() {
|
||||
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/BABDBFBJ.html
|
||||
//CPACR |= (0xF << 20); // Set the bits 20-23 to enable CP10 and CP11 coprocessors
|
||||
CPACR |= (
|
||||
REGISTER_FIELD_VALUE(CPACR_CP(10), CPACR_ACCESS_FULL)
|
||||
|
|
||||
REGISTER_FIELD_VALUE(CPACR_CP(11), CPACR_ACCESS_FULL)
|
||||
);
|
||||
// FIXME: The pipeline should be flushed at this point
|
||||
}
|
||||
|
||||
void init_platform() {
|
||||
enable_fpu();
|
||||
init_keyboard();
|
||||
//ion_led_init();
|
||||
Ion::Screen::init();
|
||||
}
|
||||
|
||||
void ion_sleep(long ms) {
|
||||
for (volatile long i=0; i<1040*ms; i++) {
|
||||
__asm volatile("nop");
|
||||
}
|
||||
}
|
||||
|
||||
void ion_reset() {
|
||||
AIRCR = AIRCR_VECTKEY_MASK | AIRCR_SYSRESETREQ;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef ION_DEVICE_PLATFORM_INIT_H
|
||||
#define ION_DEVICE_PLATFORM_INIT_H
|
||||
|
||||
void init_platform();
|
||||
|
||||
#endif
|
||||
94
ion/src/device/keyboard.cpp
Normal file
94
ion/src/device/keyboard.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/* Keyboard initialization code
|
||||
*
|
||||
* The job of this code is to implement the "ion_key_state" function.
|
||||
*
|
||||
* The keyboard is a matrix that is laid out as follow:
|
||||
*
|
||||
* | PC0 | PC1 | PC13 | PC14 | PC15 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB1 | K_A1 | K_A2 | K_A3 | K_A4 | K_A5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB2 | K_B1 | K_B2 | K_B3 | K_B4 | K_B5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB3 | K_C1 | K_C2 | K_C3 | K_C4 | K_C5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB4 | K_D1 | K_D2 | K_D3 | K_D4 | K_D5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB5 | K_E1 | K_E2 | K_E3 | K_E4 | K_E5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB6 | K_F1 | K_F2 | K_F3 | K_F4 | K_F5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB7 | K_G1 | K_G2 | K_G3 | K_G4 | K_G5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB8 | K_H1 | K_H2 | K_H3 | K_H4 | K_H5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB9 | K_I1 | K_I2 | K_I3 | K_I4 | K_I5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB10 | K_J1 | K_J2 | K_J3 | K_J4 | K_J5 |
|
||||
* -----+------+------+------+------+------+
|
||||
*
|
||||
* We decide to drive the rows (PB1-10) and read the columns (PC0,1,13,14,15).
|
||||
*
|
||||
* To avoid short-circuits, the pins B1-B10 will not be standard outputs but
|
||||
* only open-drain. Open drain means the pin is either driven low or left
|
||||
* floating.
|
||||
* When a user presses multiple keys, a connection between two rows can happen.
|
||||
* If we dont' use open drain outputs, this situation could trigger a short
|
||||
* circuit between an output driving high and another driving low.
|
||||
*
|
||||
* If the outputs are open-drain, this means that the input must be pulled up.
|
||||
* So if the input reads "1", this means the key is in fact *not* pressed, and
|
||||
* if it reads "0" it means that there's a short to an open-drain output. Which
|
||||
* means the corresponding key is pressed.
|
||||
*/
|
||||
|
||||
#include <ion.h>
|
||||
#include "keyboard.h"
|
||||
|
||||
// Public Ion::Keyboard methods
|
||||
|
||||
namespace Ion {
|
||||
namespace Keyboard {
|
||||
|
||||
bool keyDown(Key k) {
|
||||
// Drive the corresponding row low, and let all the others float.
|
||||
int row = Device::rowForKey(k);
|
||||
for (uint8_t i=0; i<Device::numberOfRows; i++) {
|
||||
/* In open-drain mode, a 0 in the register drives the pin low, and a 1 lets
|
||||
* the pin floating (Hi-Z). So we want to set the current row to zero and
|
||||
* all the others to 1. */
|
||||
bool state = (i == row ? 0 : 1);
|
||||
uint8_t pin = Device::RowPins[i];
|
||||
Device::RowGPIO.ODR()->set(pin, state);
|
||||
}
|
||||
|
||||
msleep(1);
|
||||
|
||||
// Read the input of the proper column
|
||||
uint8_t column = Device::columnForKey(k);
|
||||
uint8_t pin = Device::ColumnPins[column];
|
||||
bool input = Device::ColumnGPIO.IDR()->get(pin);
|
||||
|
||||
/* The key is down if the input is brought low by the output. In other words,
|
||||
* we want to return true if the input is low (false). */
|
||||
return (input == false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Private Ion::Keyboard::Device methods
|
||||
|
||||
void Ion::Keyboard::Device::init() {
|
||||
for (uint8_t i=0; i<numberOfRows; i++) {
|
||||
uint8_t pin = RowPins[i];
|
||||
RowGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Output);
|
||||
RowGPIO.OTYPER()->setType(pin, GPIO::OTYPER::Type::OpenDrain);
|
||||
}
|
||||
|
||||
for (uint8_t i=0; i<numberOfColumns; i++) {
|
||||
uint8_t pin = ColumnPins[i];
|
||||
ColumnGPIO.MODER()->setMode(pin, GPIO::MODER::Mode::Input);
|
||||
ColumnGPIO.PUPDR()->setPull(pin, GPIO::PUPDR::Pull::Up);
|
||||
}
|
||||
}
|
||||
50
ion/src/device/keyboard.h
Normal file
50
ion/src/device/keyboard.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef ION_DEVICE_KEYBOARD_H
|
||||
#define ION_DEVICE_KEYBOARD_H
|
||||
|
||||
#include "regs/regs.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Keyboard {
|
||||
namespace Device {
|
||||
|
||||
/* Pin | Role | Mode
|
||||
* -----+-------------------+--------------------
|
||||
* PB1 | Keyboard row A | Output, open drain
|
||||
* PB2 | Keyboard row B | Output, open drain
|
||||
* PB3 | Keyboard row C | Output, open drain
|
||||
* PB4 | Keyboard row D | Output, open drain
|
||||
* PB5 | Keyboard row E | Output, open drain
|
||||
* PB6 | Keyboard row F | Output, open drain
|
||||
* PB7 | Keyboard row G | Output, open drain
|
||||
* PB8 | Keyboard row H | Output, open drain
|
||||
* PB9 | Keyboard row I | Output, open drain
|
||||
* PB10 | Keyboard row J | Output, open drain
|
||||
* PC0 | Keyboard column 1 | Input, pulled up
|
||||
* PC1 | Keyboard column 2 | Input, pulled up
|
||||
* PC13 | Keyboard column 3 | Input, pulled up
|
||||
* PC14 | Keyboard column 4 | Input, pulled up
|
||||
* PC15 | Keyboard column 5 | Input, pulled up
|
||||
*/
|
||||
|
||||
void init();
|
||||
|
||||
constexpr GPIO RowGPIO = GPIOB;
|
||||
constexpr uint8_t numberOfRows = 10;
|
||||
constexpr uint8_t RowPins[numberOfRows] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
|
||||
constexpr GPIO ColumnGPIO = GPIOC;
|
||||
constexpr uint8_t numberOfColumns = 5;
|
||||
constexpr uint8_t ColumnPins[numberOfColumns] = {0, 1, 13, 14, 15};
|
||||
|
||||
inline uint8_t rowForKey(Ion::Keyboard::Key key) {
|
||||
return (int)key/numberOfColumns;
|
||||
}
|
||||
inline uint8_t columnForKey(Ion::Keyboard::Key key) {
|
||||
return (int)key%numberOfColumns;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
/* Keyboard initialization code
|
||||
*
|
||||
* The job of this code is to implement the "ion_key_state" function.
|
||||
*
|
||||
* The keyboard is a matrix that is laid out as follow:
|
||||
*
|
||||
* | PC0 | PC1 | PC13 | PC14 | PC15 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB1 | K_A1 | K_A2 | K_A3 | K_A4 | K_A5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB2 | K_B1 | K_B2 | K_B3 | K_B4 | K_B5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB3 | K_C1 | K_C2 | K_C3 | K_C4 | K_C5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB4 | K_D1 | K_D2 | K_D3 | K_D4 | K_D5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB5 | K_E1 | K_E2 | K_E3 | K_E4 | K_E5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB6 | K_F1 | K_F2 | K_F3 | K_F4 | K_F5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB7 | K_G1 | K_G2 | K_G3 | K_G4 | K_G5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB8 | K_H1 | K_H2 | K_H3 | K_H4 | K_H5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB9 | K_I1 | K_I2 | K_I3 | K_I4 | K_I5 |
|
||||
* -----+------+------+------+------+------+
|
||||
* PB10 | K_J1 | K_J2 | K_J3 | K_J4 | K_J5 |
|
||||
* -----+------+------+------+------+------+
|
||||
*
|
||||
* We decide to drive the rows (PB1-10) and read the columns (PC0,1,13,14,15).
|
||||
*
|
||||
* To avoid short-circuits, the pins B1-B10 will not be standard outputs but
|
||||
* only open-drain. Open drain means the pin is either driven low or left
|
||||
* floating.
|
||||
* When a user presses multiple keys, a connection between two rows can happen.
|
||||
* If we dont' use open drain outputs, this situation could trigger a short
|
||||
* circuit between an output driving high and another driving low.
|
||||
*
|
||||
* If the outputs are open-drain, this means that the input must be pulled up.
|
||||
* So if the input reads "1", this means the key is in fact *not* pressed, and
|
||||
* if it reads "0" it means that there's a short to an open-drain output. Which
|
||||
* means the corresponding key is pressed.
|
||||
*/
|
||||
|
||||
#include <ion.h>
|
||||
#include "../registers/registers.h"
|
||||
|
||||
/* This driver expects that row pins are contiguous. It also expects that
|
||||
* column pins are contiguous too. This is not mandatory but it makes the code
|
||||
* a lot simpler. */
|
||||
|
||||
#define ROW_GPIO GPIOB
|
||||
#define LOW_BIT_ROW 1
|
||||
#define HIGH_BIT_ROW 10
|
||||
|
||||
#define COLUMN_GPIO GPIOC
|
||||
|
||||
static inline uint8_t row_for_key(ion_key_t key) {
|
||||
return key/5;
|
||||
}
|
||||
static inline uint8_t column_for_key(ion_key_t key) {
|
||||
return key%5;
|
||||
}
|
||||
|
||||
bool ion_key_down(ion_key_t key) {
|
||||
/* Drive the corresponding row low, and let all the others float.
|
||||
* Note: In open-drain mode, a 0 in the register drives low, and a 1 lets the
|
||||
* pin floating (Hi-Z). */
|
||||
uint32_t new_row_value = ~((uint32_t)1 << row_for_key(key));
|
||||
uint32_t previous_row_value = REGISTER_GET_VALUE(GPIO_ODR(ROW_GPIO), ROW);
|
||||
|
||||
if (new_row_value != previous_row_value) {
|
||||
REGISTER_SET_VALUE(GPIO_ODR(ROW_GPIO), ROW, new_row_value);
|
||||
// We changed the outputs, give the hardware some time to react to this change
|
||||
// FIXME: Real delay!
|
||||
for (volatile int i=0;i<1000; i++) {
|
||||
}
|
||||
}
|
||||
|
||||
// Read the input of the proper column
|
||||
uint8_t column = column_for_key(key);
|
||||
uint8_t bit_for_column = (column <= 1 ? column : column+11);
|
||||
uint32_t input = (GPIO_IDR(COLUMN_GPIO) & (1 << bit_for_column));
|
||||
|
||||
/* The key is down if the input is brought low by the output. In other words,
|
||||
* we want to return "true" (1) if the input is low (0). */
|
||||
return (input == 0);
|
||||
}
|
||||
|
||||
void init_keyboard() {
|
||||
/* We are using GPIOs, let's start by enabling their clock. */
|
||||
/* Note: All GPIOs live on the AHB1 bus */
|
||||
RCC_AHB1ENR |= GPIO_EN(ROW_GPIO) | GPIO_EN(COLUMN_GPIO);
|
||||
|
||||
// Configure the row pins as open-drain outputs
|
||||
for (int pin=LOW_BIT_ROW; pin<=HIGH_BIT_ROW; pin++) {
|
||||
REGISTER_SET_VALUE(GPIO_MODER(ROW_GPIO), MODER(pin), GPIO_MODE_OUTPUT);
|
||||
REGISTER_SET_VALUE(GPIO_OTYPER(ROW_GPIO), OTYPER(pin), GPIO_OTYPE_OPEN_DRAIN);
|
||||
}
|
||||
|
||||
// Configure the column as are pulled-up inputs
|
||||
REGISTER_SET_VALUE(GPIO_MODER(COLUMN_GPIO), MODER(0), GPIO_MODE_INPUT);
|
||||
REGISTER_SET_VALUE(GPIO_PUPDR(COLUMN_GPIO), PUPDR(0), GPIO_PUPD_PULL_UP);
|
||||
REGISTER_SET_VALUE(GPIO_MODER(COLUMN_GPIO), MODER(1), GPIO_MODE_INPUT);
|
||||
REGISTER_SET_VALUE(GPIO_PUPDR(COLUMN_GPIO), PUPDR(1), GPIO_PUPD_PULL_UP);
|
||||
REGISTER_SET_VALUE(GPIO_MODER(COLUMN_GPIO), MODER(13), GPIO_MODE_INPUT);
|
||||
REGISTER_SET_VALUE(GPIO_PUPDR(COLUMN_GPIO), PUPDR(13), GPIO_PUPD_PULL_UP);
|
||||
REGISTER_SET_VALUE(GPIO_MODER(COLUMN_GPIO), MODER(14), GPIO_MODE_INPUT);
|
||||
REGISTER_SET_VALUE(GPIO_PUPDR(COLUMN_GPIO), PUPDR(14), GPIO_PUPD_PULL_UP);
|
||||
REGISTER_SET_VALUE(GPIO_MODER(COLUMN_GPIO), MODER(15), GPIO_MODE_INPUT);
|
||||
REGISTER_SET_VALUE(GPIO_PUPDR(COLUMN_GPIO), PUPDR(15), GPIO_PUPD_PULL_UP);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef ION_DEVICE_KEYBOARD_H
|
||||
#define ION_DEVICE_KEYBOARD_H
|
||||
|
||||
void init_keyboard();
|
||||
|
||||
#endif
|
||||
@@ -1,40 +1,39 @@
|
||||
extern "C" {
|
||||
#include <ion/led.h>
|
||||
}
|
||||
#include "led.h"
|
||||
#include "regs/regs.h"
|
||||
|
||||
extern "C" {
|
||||
void ion_led_init();
|
||||
// Public Ion::LED methods
|
||||
|
||||
void Ion::LED::setColor(KDColor c) {
|
||||
TIM1.CCR1()->set(15000);
|
||||
}
|
||||
|
||||
/* Pin used :
|
||||
* PA8 - Red LED - TIM1_CH1
|
||||
* PA9 - Green LED - TIM1_CH2
|
||||
* PA10 - Blue LED -TIM1_CH3
|
||||
*/
|
||||
// Private Ion::Device::LED methods
|
||||
|
||||
void sleep() {
|
||||
for (volatile int i=0;i<100000; i++) {
|
||||
}
|
||||
namespace Ion {
|
||||
namespace LED {
|
||||
namespace Device {
|
||||
|
||||
void init() {
|
||||
initGPIO();
|
||||
initTimer();
|
||||
}
|
||||
|
||||
void ion_led_gpio_init() {
|
||||
RCC.AHB1ENR()->setGPIOAEN(true);
|
||||
|
||||
void initGPIO() {
|
||||
/* RED_LED(PA8), GREEN_LED(PA9), BLUE_LED(PA10) are driven using a timer,
|
||||
* which is an alternate function. */
|
||||
GPIOA.MODER()->setMODER(8, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOA.MODER()->setMODER(9, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOA.MODER()->setMODER(10, GPIO::MODER::MODE::AlternateFunction);
|
||||
GPIOA.MODER()->setMode(8, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOA.MODER()->setMode(9, GPIO::MODER::Mode::AlternateFunction);
|
||||
GPIOA.MODER()->setMode(10, GPIO::MODER::Mode::AlternateFunction);
|
||||
|
||||
/* More precisely, we will use AF01, which maps PA8 to TIM1_CH1, PA9 to
|
||||
* TIM1_CH2 and PA10 to TIM1_CH3. */
|
||||
GPIOA.AFR()->setAFR(8, GPIO::AFR::AlternateFunction::AF1);
|
||||
GPIOA.AFR()->setAFR(9, GPIO::AFR::AlternateFunction::AF1);
|
||||
GPIOA.AFR()->setAFR(10, GPIO::AFR::AlternateFunction::AF1);
|
||||
GPIOA.AFR()->setAlternateFunction(8, GPIO::AFR::AlternateFunction::AF1);
|
||||
GPIOA.AFR()->setAlternateFunction(9, GPIO::AFR::AlternateFunction::AF1);
|
||||
GPIOA.AFR()->setAlternateFunction(10, GPIO::AFR::AlternateFunction::AF1);
|
||||
}
|
||||
|
||||
void ion_led_timer_init() {
|
||||
void initTimer() {
|
||||
/* TIM1 lives on the APB2 bus. Let's enable its clock. */
|
||||
RCC.APB2ENR()->setTIM1EN(true);
|
||||
TIM1.PSC()->set(1000);
|
||||
@@ -75,11 +74,6 @@ void ion_led_timer_init() {
|
||||
TIM1.CR1()->setCEN(true);
|
||||
}
|
||||
|
||||
void ion_led_init() {
|
||||
ion_led_gpio_init();
|
||||
ion_led_timer_init();
|
||||
}
|
||||
|
||||
|
||||
void ion_led_set_color(ion_color_t color) {
|
||||
}
|
||||
}
|
||||
|
||||
24
ion/src/device/led.h
Normal file
24
ion/src/device/led.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef ION_DEVICE_LED_H
|
||||
#define ION_DEVICE_LED_H
|
||||
|
||||
namespace Ion {
|
||||
namespace LED {
|
||||
namespace Device {
|
||||
|
||||
/* Pin | Role | Mode | Function
|
||||
* -----+-------------------+-----------------------+----------
|
||||
* PA6 | LED red | Alternate Function 12 | TIM3_CH1
|
||||
* PA7 | LED green | Alternate Function 12 | TIM3_CH2
|
||||
* PB0 | LED blue | Alternate Function 12 | TIM3_CH3
|
||||
* PC9 | LCD backlight | Alternate Function 12 | TIM3_CH4
|
||||
*/
|
||||
|
||||
void init();
|
||||
void initGPIO();
|
||||
void initTimer();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -7,20 +7,47 @@ class GPIO {
|
||||
public:
|
||||
class MODER : Register32 {
|
||||
public:
|
||||
enum class MODE {
|
||||
enum class Mode {
|
||||
Input = 0,
|
||||
Output = 1,
|
||||
AlternateFunction = 2,
|
||||
Analog = 3
|
||||
};
|
||||
MODE getMODER(int index) { return (MODE)get(2*index+1, 2*index); };
|
||||
void setMODER(int index, MODE mode) volatile { set(2*index+1, 2*index, (uint32_t)mode); };
|
||||
Mode getMode(int index) { return (Mode)getBitRange(2*index+1, 2*index); }
|
||||
void setMode(int index, Mode mode) volatile { setBitRange(2*index+1, 2*index, (uint32_t)mode); }
|
||||
};
|
||||
|
||||
class OTYPER : Register32 {
|
||||
public:
|
||||
enum class Type {
|
||||
PushPull = 0,
|
||||
OpenDrain = 1
|
||||
};
|
||||
Type getType(int index) { return (Type)getBitRange(index, index); }
|
||||
void setType(int index, Type type) volatile { setBitRange(index, index, (uint32_t)type); }
|
||||
};
|
||||
|
||||
class PUPDR : Register32 {
|
||||
public:
|
||||
enum class Pull {
|
||||
None = 0,
|
||||
Up = 1,
|
||||
Down = 2,
|
||||
Reserved = 3
|
||||
};
|
||||
Pull getPull(int index) { return (Pull)getBitRange(2*index+1, 2*index); }
|
||||
void setPull(int index, Pull pull) volatile { setBitRange(2*index+1, 2*index, (uint32_t)pull); }
|
||||
};
|
||||
|
||||
class IDR : Register32 {
|
||||
public:
|
||||
bool get(int index) volatile { return (bool)getBitRange(index, index); }
|
||||
};
|
||||
|
||||
class ODR : Register32 {
|
||||
public:
|
||||
bool getODR(int index) { return (bool)get(index, index); }
|
||||
void setODR(int index, bool state) volatile { set(index, index, state); }
|
||||
bool get(int index) { return (bool)getBitRange(index, index); }
|
||||
void set(int index, bool state) volatile { setBitRange(index, index, state); }
|
||||
};
|
||||
|
||||
class AFR : Register64 {
|
||||
@@ -33,16 +60,19 @@ public:
|
||||
AF8 = 8, AF9 = 9, AF10 = 10, AF11 = 11,
|
||||
AF12 = 12, AF13 = 13, AF14 = 14, AF15 = 15
|
||||
};
|
||||
AlternateFunction getAFR(int index) {
|
||||
return (AlternateFunction)get(4*index+3, 4*index);
|
||||
AlternateFunction getAlternateFunction(int index) {
|
||||
return (AlternateFunction)getBitRange(4*index+3, 4*index);
|
||||
};
|
||||
void setAFR(int index, AlternateFunction af) volatile {
|
||||
set(4*index+3, 4*index, (uint64_t)af);
|
||||
void setAlternateFunction(int index, AlternateFunction af) volatile {
|
||||
setBitRange(4*index+3, 4*index, (uint64_t)af);
|
||||
};
|
||||
};
|
||||
|
||||
constexpr GPIO(int i) : m_index(i) {}
|
||||
REGS_REGISTER_AT(MODER, 0x00);
|
||||
REGS_REGISTER_AT(OTYPER, 0x04);
|
||||
REGS_REGISTER_AT(PUPDR, 0x0C);
|
||||
REGS_REGISTER_AT(IDR, 0x10);
|
||||
REGS_REGISTER_AT(ODR, 0x14);
|
||||
REGS_REGISTER_AT(AFR, 0x20);
|
||||
private:
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
|
||||
class RCC {
|
||||
public:
|
||||
class AHB1ENR : Register32 {
|
||||
class AHB1ENR : public Register32 {
|
||||
public:
|
||||
AHB1ENR(uint32_t v) : Register32(v) {}
|
||||
REGS_BOOL_FIELD(GPIOAEN, 0);
|
||||
REGS_BOOL_FIELD(GPIOBEN, 1);
|
||||
REGS_BOOL_FIELD(GPIOCEN, 2);
|
||||
|
||||
@@ -7,10 +7,14 @@ template <typename T>
|
||||
class Register {
|
||||
public:
|
||||
Register() = delete;
|
||||
Register(T v) : m_value(v) {}
|
||||
void set(Register<T> value) volatile {
|
||||
m_value = value.m_value;
|
||||
}
|
||||
void set(T value) volatile {
|
||||
m_value = value;
|
||||
}
|
||||
T get() volatile {
|
||||
T get() {
|
||||
return m_value;
|
||||
}
|
||||
protected:
|
||||
@@ -23,10 +27,10 @@ protected:
|
||||
static constexpr T bit_range_set_value(uint8_t high, uint8_t low, T originalValue, T targetValue) {
|
||||
return (originalValue & ~bit_range_mask(high,low))|bit_range_value(targetValue, high, low);
|
||||
}
|
||||
void set(uint8_t high, uint8_t low, T value) volatile {
|
||||
void setBitRange(uint8_t high, uint8_t low, T value) volatile {
|
||||
m_value = bit_range_set_value(high, low, m_value, value);
|
||||
}
|
||||
T get(uint8_t high, uint8_t low) volatile {
|
||||
T getBitRange(uint8_t high, uint8_t low) volatile {
|
||||
return (m_value & bit_range_mask(high,low)) >> low;
|
||||
}
|
||||
private:
|
||||
@@ -37,7 +41,7 @@ typedef Register<uint16_t> Register16;
|
||||
typedef Register<uint32_t> Register32;
|
||||
typedef Register<uint64_t> Register64;
|
||||
|
||||
#define REGS_FIELD(name,type,high,low) type get##name() volatile { return (type)get(high,low); }; void set##name(type v) volatile { set(high, low, (uint8_t)v); };
|
||||
#define REGS_FIELD(name,type,high,low) type get##name() volatile { return (type)getBitRange(high,low); }; void set##name(type v) volatile { setBitRange(high, low, (uint8_t)v); };
|
||||
#define REGS_TYPE_FIELD(name,high,low) REGS_FIELD(name,name,high,low)
|
||||
#define REGS_BOOL_FIELD(name,bit) REGS_FIELD(name,bool,bit,bit)
|
||||
#define REGS_REGISTER_AT(name, offset) volatile name * name() const { return (class name *)(Base() + offset); };
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
objs += $(addprefix ion/src/shared/,\
|
||||
events.o)
|
||||
events.o\
|
||||
)
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
#include <ion.h>
|
||||
|
||||
// More event type will be added later.
|
||||
typedef enum {
|
||||
KEY_DOWN,
|
||||
} ion_key_event_type_t;
|
||||
|
||||
typedef struct {
|
||||
ion_key_t key;
|
||||
ion_key_event_type_t event;
|
||||
} ion_key_event_t;
|
||||
|
||||
// Debouncing, qnd change to get_key event.
|
||||
static ion_key_event_t ion_get_key_event() {
|
||||
// Let's start by saving which keys we've seen up
|
||||
bool key_seen_up[ION_NUMBER_OF_KEYS];
|
||||
for (ion_key_t k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
key_seen_up[k] = !ion_key_down(k);
|
||||
}
|
||||
|
||||
// Wait a little to debounce the button.
|
||||
ion_sleep(10);
|
||||
|
||||
/* Let's discard the keys we previously saw up but which aren't anymore: those
|
||||
* were probably bouncing! */
|
||||
for (ion_key_t k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
key_seen_up[k] &= !ion_key_down(k);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
for (ion_key_t k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
if (ion_key_down(k)) {
|
||||
if (key_seen_up[k]) {
|
||||
return (ion_key_event_t) {.key = k, .event = KEY_DOWN};
|
||||
}
|
||||
} else {
|
||||
key_seen_up[k] = 1;
|
||||
}
|
||||
}
|
||||
ion_sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
// For now this is a bit silly but needed for instreface purpose.
|
||||
static const ion_event_t kEventForKeyDown[ION_NUMBER_OF_KEYS] = {
|
||||
F1, F2, F3, F4, F5,
|
||||
SECOND, SHIFT, ESC, LEFT_ARROW, UP_ARROW,
|
||||
DIAMOND, ALPHA, APPS, DOWN_ARROW, RIGHT_ARROW,
|
||||
HOME, MODE, CATALOG, DELETE, CLEAR,
|
||||
LOWER_CASE_X, LOWER_CASE_Y, LOWER_CASE_Z, LOWER_CASE_T, POWER,
|
||||
EQUAL, LEFT_PARENTHESIS, RIGHT_PARENTHESIS, COMMA, DIVISION,
|
||||
DOT, SEVEN, EIGHT, NINE, PRODUCT,
|
||||
UPPER_CASE_E, FOUR, FIVE, SIX, MINUS,
|
||||
DOT, ONE, TWO, THREE, PLUS,
|
||||
DOT, ZERO, DOT, MINUS, ENTER
|
||||
};
|
||||
|
||||
ion_event_t ion_get_event() {
|
||||
// First we get a key event.
|
||||
const ion_key_event_t key_event = ion_get_key_event();
|
||||
// We then generate the event associated to this key event.
|
||||
if (key_event.event == KEY_DOWN) {
|
||||
return kEventForKeyDown[key_event.key];
|
||||
} else {
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
36
ion/src/shared/events.cpp
Normal file
36
ion/src/shared/events.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <ion.h>
|
||||
|
||||
const Ion::Events::Event kEventForKeyDown[] = {
|
||||
Ion::Events::Event::F1, Ion::Events::Event::F2, Ion::Events::Event::F3, Ion::Events::Event::F4, Ion::Events::Event::F5, Ion::Events::Event::SECOND, Ion::Events::Event::SHIFT, Ion::Events::Event::ESC, Ion::Events::Event::LEFT_ARROW, Ion::Events::Event::UP_ARROW, Ion::Events::Event::DIAMOND, Ion::Events::Event::ALPHA, Ion::Events::Event::APPS, Ion::Events::Event::DOWN_ARROW, Ion::Events::Event::RIGHT_ARROW, Ion::Events::Event::HOME, Ion::Events::Event::MODE, Ion::Events::Event::CATALOG, Ion::Events::Event::DELETE, Ion::Events::Event::CLEAR, Ion::Events::Event::LOWER_CASE_X, Ion::Events::Event::LOWER_CASE_Y, Ion::Events::Event::LOWER_CASE_Z, Ion::Events::Event::LOWER_CASE_T, Ion::Events::Event::POWER, Ion::Events::Event::EQUAL, Ion::Events::Event::LEFT_PARENTHESIS, Ion::Events::Event::RIGHT_PARENTHESIS, Ion::Events::Event::COMMA, Ion::Events::Event::DIVISION, Ion::Events::Event::DOT, Ion::Events::Event::SEVEN, Ion::Events::Event::EIGHT, Ion::Events::Event::NINE, Ion::Events::Event::PRODUCT, Ion::Events::Event::UPPER_CASE_E, Ion::Events::Event::FOUR, Ion::Events::Event::FIVE, Ion::Events::Event::SIX, Ion::Events::Event::MINUS, Ion::Events::Event::DOT, Ion::Events::Event::ONE, Ion::Events::Event::TWO, Ion::Events::Event::THREE, Ion::Events::Event::PLUS, Ion::Events::Event::DOT, Ion::Events::Event::ZERO, Ion::Events::Event::DOT, Ion::Events::Event::MINUS, Ion::Events::Event::ENTER
|
||||
};
|
||||
|
||||
// Debouncing, qnd change to get_key event.
|
||||
Ion::Events::Event Ion::Events::getEvent() {
|
||||
// Let's start by saving which keys we've seen up
|
||||
bool key_seen_up[Ion::Keyboard::NumberOfKeys];
|
||||
for (int k=0; k<Ion::Keyboard::NumberOfKeys; k++) {
|
||||
key_seen_up[k] = !Ion::Keyboard::keyDown((Ion::Keyboard::Key)k);
|
||||
}
|
||||
|
||||
// Wait a little to debounce the button.
|
||||
msleep(10);
|
||||
|
||||
/* Let's discard the keys we previously saw up but which aren't anymore: those
|
||||
* were probably bouncing! */
|
||||
for (int k=0; k<Ion::Keyboard::NumberOfKeys; k++) {
|
||||
key_seen_up[k] &= !Ion::Keyboard::keyDown((Ion::Keyboard::Key)k);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
for (int k=0; k<Ion::Keyboard::NumberOfKeys; k++) {
|
||||
if (Ion::Keyboard::keyDown((Ion::Keyboard::Key)k)) {
|
||||
if (key_seen_up[k]) {
|
||||
return kEventForKeyDown[k];
|
||||
}
|
||||
} else {
|
||||
key_seen_up[k] = true;
|
||||
}
|
||||
}
|
||||
msleep(10);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
extern "C" {
|
||||
#include <ion.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <kandinsky.h>
|
||||
#include "init.h"
|
||||
}
|
||||
#include "init.h"
|
||||
#include <ion.h>
|
||||
#include <kandinsky.h>
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Window.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
@@ -23,14 +23,14 @@ void init_platform() {
|
||||
Fl::visual(FL_RGB);
|
||||
|
||||
int margin = 10;
|
||||
int screen_width = ION_SCREEN_WIDTH;
|
||||
int screen_height = ION_SCREEN_HEIGHT;
|
||||
int screen_width = Ion::Display::Width;
|
||||
int screen_height = Ion::Display::Height;
|
||||
int keyboard_height = screen_width;
|
||||
|
||||
Fl_Window * window = new Fl_Window(screen_width+2*margin, margin+screen_height+margin+keyboard_height+margin);
|
||||
|
||||
KDColor * pixels = (KDColor *)malloc(ION_SCREEN_WIDTH*ION_SCREEN_HEIGHT*sizeof(KDColor));
|
||||
sFrameBuffer = new KDFrameBuffer(pixels, KDSize(ION_SCREEN_WIDTH, ION_SCREEN_HEIGHT));
|
||||
KDColor * pixels = (KDColor *)malloc(Ion::Display::Width*Ion::Display::Height*sizeof(KDColor));
|
||||
sFrameBuffer = new KDFrameBuffer(pixels, KDSize(Ion::Display::Width, Ion::Display::Height));
|
||||
/*
|
||||
sFrameBuffer.drawingArea.origin = KDPointZero;
|
||||
sFrameBuffer.drawingArea.size = sFrameBuffer.size;
|
||||
@@ -46,40 +46,23 @@ void init_platform() {
|
||||
//KDCurrentContext->fillRect = NULL;
|
||||
}
|
||||
|
||||
void ion_screen_push_rect(uint16_t x, uint16_t y,
|
||||
uint16_t width, uint16_t height,
|
||||
const ion_color_t * pixels)
|
||||
{
|
||||
// FIXME: Boy those casts are fugly
|
||||
const void * foo = static_cast<const void *>(pixels);
|
||||
const KDColor * pouet = static_cast<const KDColor *>(foo);
|
||||
sFrameBuffer->pushRect(KDRect(x,y,width,height), pouet);
|
||||
void Ion::Display::pushRect(KDRect r, const KDColor * pixels) {
|
||||
sFrameBuffer->pushRect(r, pixels);
|
||||
}
|
||||
|
||||
void ion_screen_push_rect_uniform(uint16_t x, uint16_t y,
|
||||
uint16_t width, uint16_t height,
|
||||
ion_color_t color)
|
||||
{
|
||||
ion_color_t * foo = &color;
|
||||
const void * bar = static_cast<const void *>(foo);
|
||||
const KDColor * baz = static_cast<const KDColor *>(bar);
|
||||
sFrameBuffer->pushRectUniform(KDRect(x,y,width,height), *baz);
|
||||
void Ion::Display::pushRectUniform(KDRect r, KDColor c) {
|
||||
sFrameBuffer->pushRectUniform(r, c);
|
||||
}
|
||||
|
||||
void ion_screen_pull_rect(uint16_t x, uint16_t y,
|
||||
uint16_t width, uint16_t height,
|
||||
ion_color_t * pixels)
|
||||
{
|
||||
void * foo = static_cast<void *>(pixels);
|
||||
KDColor * pouet = static_cast<KDColor *>(foo);
|
||||
sFrameBuffer->pullRect(KDRect(x,y,width,height), pouet);
|
||||
void Ion::Display::pullRect(KDRect r, KDColor * pixels) {
|
||||
sFrameBuffer->pullRect(r, pixels);
|
||||
}
|
||||
|
||||
bool ion_key_down(ion_key_t key) {
|
||||
bool Ion::Keyboard::keyDown(Ion::Keyboard::Key key) {
|
||||
return sKeyboard->key_down(key);
|
||||
}
|
||||
|
||||
void ion_sleep(long ms) {
|
||||
void Ion::msleep(long ms) {
|
||||
usleep(1000*ms);
|
||||
sDisplay->redraw();
|
||||
Fl::wait();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <assert.h>
|
||||
#include "fltkkbd.h"
|
||||
|
||||
#define KEYBOARD_ROWS 10
|
||||
#define KEYBOARD_COLUMNS 5
|
||||
constexpr int KeyboardRows = 10;
|
||||
constexpr int KeyboardColumns = 5;
|
||||
|
||||
static const char* kCharForKey[ION_NUMBER_OF_KEYS] = {
|
||||
static const char* kCharForKey[Ion::Keyboard::NumberOfKeys] = {
|
||||
"F1", "F2", "F3", "F4", "F5",
|
||||
"2nd", "Shift", "ESC", "LEFT", "UP",
|
||||
"Diamond", "alpha", "APPS", "DOWN", "RIGHT",
|
||||
@@ -18,12 +18,12 @@ static const char* kCharForKey[ION_NUMBER_OF_KEYS] = {
|
||||
};
|
||||
|
||||
FltkKbd::FltkKbd(int x, int y, int w, int h) : Fl_Group(x, y, w, h) {
|
||||
assert(KEYBOARD_ROWS*KEYBOARD_COLUMNS == ION_NUMBER_OF_KEYS);
|
||||
int key_width = w/KEYBOARD_COLUMNS;
|
||||
int key_height = h/KEYBOARD_ROWS;
|
||||
for (int k=0; k<ION_NUMBER_OF_KEYS; k++) {
|
||||
m_buttons[k] = new Fl_Button(x + (k%KEYBOARD_COLUMNS)*key_width,
|
||||
y + (k/KEYBOARD_COLUMNS)*key_height,
|
||||
assert(KeyboardRows*KeyboardColumns == Ion::Keyboard::NumberOfKeys);
|
||||
int key_width = w/KeyboardColumns;
|
||||
int key_height = h/KeyboardRows;
|
||||
for (int k=0; k<Ion::Keyboard::NumberOfKeys; k++) {
|
||||
m_buttons[k] = new Fl_Button(x + (k%KeyboardColumns)*key_width,
|
||||
y + (k/KeyboardColumns)*key_height,
|
||||
key_width,
|
||||
key_height,
|
||||
kCharForKey[k]);
|
||||
@@ -31,6 +31,6 @@ FltkKbd::FltkKbd(int x, int y, int w, int h) : Fl_Group(x, y, w, h) {
|
||||
end();
|
||||
}
|
||||
|
||||
bool FltkKbd::key_down(ion_key_t key) {
|
||||
return m_buttons[key]->value();
|
||||
bool FltkKbd::key_down(Ion::Keyboard::Key key) {
|
||||
return m_buttons[(int)key]->value();
|
||||
}
|
||||
|
||||
@@ -3,16 +3,14 @@
|
||||
|
||||
#include <FL/Fl_Group.H>
|
||||
#include <FL/Fl_Button.H>
|
||||
extern "C" {
|
||||
#include <ion/keyboard.h>
|
||||
}
|
||||
|
||||
class FltkKbd : public Fl_Group {
|
||||
public:
|
||||
FltkKbd(int x, int y, int w, int h);
|
||||
bool key_down(ion_key_t key);
|
||||
bool key_down(Ion::Keyboard::Key key);
|
||||
private:
|
||||
Fl_Button * m_buttons[ION_NUMBER_OF_KEYS];
|
||||
Fl_Button * m_buttons[Ion::Keyboard::NumberOfKeys];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
uint8_t green();
|
||||
uint8_t blue();
|
||||
KDColor blend(KDColor other, uint8_t alpha);
|
||||
operator uint16_t() { return m_value; }
|
||||
operator uint16_t() const { return m_value; }
|
||||
private:
|
||||
uint16_t m_value;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include <kandinsky/ion_context.h>
|
||||
extern "C" {
|
||||
#include <ion.h>
|
||||
}
|
||||
|
||||
KDIonContext * KDIonContext::sharedContext() {
|
||||
static KDIonContext context;
|
||||
@@ -10,18 +8,18 @@ KDIonContext * KDIonContext::sharedContext() {
|
||||
|
||||
KDIonContext::KDIonContext() :
|
||||
KDContext(KDPointZero,
|
||||
KDRect(0, 0, ION_SCREEN_WIDTH, ION_SCREEN_HEIGHT))
|
||||
KDRect(0, 0, Ion::Display::Width, Ion::Display::Height))
|
||||
{
|
||||
}
|
||||
|
||||
void KDIonContext::pushRect(KDRect rect, const KDColor * pixels) {
|
||||
ion_screen_push_rect(rect.x(), rect.y(), rect.width(), rect.height(), (const ion_color_t *)pixels);
|
||||
Ion::Display::pushRect(rect, pixels);
|
||||
}
|
||||
|
||||
void KDIonContext::pushRectUniform(KDRect rect, KDColor color) {
|
||||
ion_screen_push_rect_uniform(rect.x(), rect.y(), rect.width(), rect.height(), color);
|
||||
Ion::Display::pushRectUniform(rect, color);
|
||||
}
|
||||
|
||||
void KDIonContext::pullRect(KDRect rect, KDColor * pixels) {
|
||||
ion_screen_pull_rect(rect.x(), rect.y(), rect.width(), rect.height(), (ion_color_t *)pixels);
|
||||
Ion::Display::pullRect(rect, pixels);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#include "symbols.h"
|
||||
#include <string.h>
|
||||
#include <kandinsky.h>
|
||||
extern "C" {
|
||||
#include <ion.h>
|
||||
}
|
||||
|
||||
void print(const char * message) {
|
||||
static int line_y = 0;
|
||||
@@ -11,7 +9,7 @@ void print(const char * message) {
|
||||
int line_height = KDText::stringSize("M").height();
|
||||
ctx->drawString(message, KDPoint(0, line_y), 0);
|
||||
line_y += line_height;
|
||||
if (line_y > ION_SCREEN_HEIGHT) {
|
||||
if (line_y > Ion::Display::Height) {
|
||||
line_y = 0;
|
||||
// Clear screen maybe?
|
||||
}
|
||||
@@ -27,6 +25,6 @@ void ion_app() {
|
||||
}
|
||||
print("ALL TESTS FINISHED");
|
||||
while (1) {
|
||||
ion_sleep(1000);
|
||||
Ion::msleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user