| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- #include <furi.h>
- #include <cli/cli.h>
- #include <cli/cli_vcp.h>
- #include <dialogs/dialogs.h>
- #include <gui/gui.h>
- #include <gui/elements.h>
- #include <storage/storage.h>
- #include <furi_hal_resources.h>
- #include <furi_hal_light.h>
- #include <furi_hal_console.h>
- #include <math.h>
- /* generated by fbt from .png files in images folder */
- #include <tas_playback_icons.h>
- #include "WString.h"
- typedef enum {
- O_READ = FSAM_READ,
- O_WRITE = FSAM_WRITE,
- O_CREAT = ((uint16_t)FSOM_OPEN_ALWAYS << 8),
- O_APPEND = ((uint16_t)FSOM_OPEN_APPEND << 8),
- O_EXCL = ((uint16_t)FSOM_CREATE_NEW << 8),
- O_TRUNC = ((uint16_t)FSOM_CREATE_ALWAYS << 8),
- } FileOpenMode;
- #define SD_CARD_ERROR_ACMD41 0x16
- class SdFs {
- public:
- bool begin(int) {
- m_storage = (Storage*)furi_record_open(RECORD_STORAGE);
- return m_storage != nullptr;
- }
- bool mkdir(const char* path) {
- return storage_simply_mkdir(m_storage, path);
- }
- ~SdFs() {
- if(m_storage) furi_record_close(RECORD_STORAGE);
- }
- uint8_t sdErrorCode() const {
- return 0;
- }
- uint8_t sdErrorData() const {
- return 0;
- }
- private:
- Storage* m_storage = nullptr;
- friend class SdFile;
- };
- template <class T>
- static inline void printSdErrorSymbol(T*, uint8_t) {
- }
- class SdFile {
- public:
- ~SdFile() {
- if(m_file) storage_file_free(m_file);
- }
- void close() {
- if(m_file) storage_file_close(m_file);
- }
- bool open(SdFs* from, const char* path, uint16_t mode) {
- m_fs = from;
- initFile();
- m_path = path;
- return storage_file_open(
- m_file, path, FS_AccessMode((uint16_t)mode & 0xFF), FS_OpenMode((uint16_t)mode >> 8));
- }
- bool open(SdFs* from, const char* path, FileOpenMode mode) {
- return open(from, path, (uint16_t)mode);
- }
- void getName(char* dest, uint16_t size) {
- m_path.toCharArray(dest, size);
- }
- unsigned read(void* buff, int bytes_to_read) {
- return storage_file_read(m_file, buff, bytes_to_read);
- }
- unsigned write(const void* buff, int bytes_to_read) {
- return storage_file_write(m_file, buff, bytes_to_read);
- }
- bool available() {
- return !storage_file_eof(m_file);
- }
- uint64_t fileSize() {
- return storage_file_size(m_file);
- }
- uint64_t curPosition() {
- return storage_file_tell(m_file);
- }
- bool seekSet(uint32_t pos) {
- return storage_file_seek(m_file, pos, true);
- }
- bool isOpen() {
- return m_file && storage_file_is_open(m_file);
- }
- bool openNext(SdFile* from) {
- char name[64];
- bool ret = storage_dir_read(from->m_file, NULL, name, sizeof(name));
- if(!ret) return false;
- String path = from->m_path;
- path += "/";
- path += name;
- return open(from->m_fs, path.c_str(), O_READ);
- }
- bool rewind() {
- return false;
- // return storage_dir_rewind(m_file);
- }
- private:
- void initFile() {
- close();
- if(!m_file) m_file = storage_file_alloc(m_fs->m_storage);
- }
- File* m_file = nullptr;
- SdFs* m_fs = nullptr;
- String m_path;
- };
- #define F(x) x
- #define noInterrupts() uint32_t intLevel = ulPortRaiseBASEPRI()
- #define interrupts() vPortSetBASEPRI(intLevel)
- #define F_CPU /*SystemCoreClock*/ 64000000
- typedef enum { HEX = 16 } BaseType;
- class SerialObj {
- public:
- template <class... T>
- void print(const T&... v) {
- String out(v...);
- furi_hal_console_tx((uint8_t*)out.c_str(), out.length());
- }
- void println() {
- furi_hal_console_tx((uint8_t*)"\r\n", 2);
- }
- template <class... T>
- void println(const T&... v) {
- String out(v...);
- furi_hal_console_tx((uint8_t*)out.c_str(), out.length());
- println();
- }
- template <class... T>
- void write(const T&... v) {
- print(v...);
- }
- int read() {
- return -1;
- /*
- uint8_t buf;
- if (!cli_read_timeout(m_cli, &buf, 1, 0))
- return -1;
- return buf;*/
- }
- bool begin() {
- /*
- m_cli = (Cli*)furi_record_open(RECORD_CLI);
- // if (m_cli)
- // cli_session_open(m_cli, &cli_vcp);
- */
- return (bool)*this;
- }
- ~SerialObj() {
- if(m_cli) furi_record_close(RECORD_CLI);
- }
- explicit operator bool() {
- return true; // m_cli && cli_is_connected(m_cli);
- }
- void flush() {
- }
- private:
- Cli* m_cli = nullptr;
- };
- #define SERIAL_BAUD_RATE
- #define BUILTIN_SDCARD 0
- #define NO_CONSOLE_GPIO
- #define ARM_DWT_CYCCNT DWT->CYCCNT
- SerialObj Serial;
- typedef void (*ArduinoISR)();
- void gpioCallback(void* ctx) {
- ArduinoISR cb = (ArduinoISR)ctx;
- cb();
- }
- #define LOW false
- #define HIGH true
- typedef enum {
- INPUT = GpioModeInput,
- OUTPUT = GpioModeOutputOpenDrain,
- INPUT_PULLUP = (uint16_t)GpioModeInput | ((uint16_t)GpioPullUp << 8),
- INPUT_PULLDOWN = (uint16_t)GpioModeInput | ((uint16_t)GpioPullDown << 8),
- FALLING = (uint16_t)GpioModeInterruptFall | ((uint16_t)GpioPullUp << 8),
- } PinMode;
- void pinMode(const GpioPin* pin, PinMode mode) {
- furi_hal_gpio_init(
- pin, GpioMode((uint16_t)mode & 0xFF), GpioPull((uint16_t)mode >> 8), GpioSpeedVeryHigh);
- }
- void attachInterrupt(const GpioPin* pin, ArduinoISR cb, PinMode mode) {
- pinMode(pin, mode);
- furi_hal_gpio_remove_int_callback(pin);
- furi_hal_gpio_add_int_callback(pin, gpioCallback, (void*)cb);
- }
- static inline void digitalWrite(const GpioPin* pin, bool state) {
- furi_hal_gpio_write(pin, state);
- }
- static inline bool digitalRead(const GpioPin* pin) {
- return furi_hal_gpio_read(pin);
- }
- #define N64_PIN &gpio_ext_pc0
- #define N64_PIN_PREFIX PC0
- #define CONCAT1(a, b) a##b
- #define CONCAT(a, b) CONCAT1(a, b)
- #define N64_PORT CONCAT(N64_PIN_PREFIX, _GPIO_Port)
- #define N64_Pin CONCAT(N64_PIN_PREFIX, _Pin)
- #define N64_IRQ EXTI0_IRQn
- #define N64_PIN_LINE LL_SYSCFG_EXTI_LINE0
- #define DISABLE_N64_INTERRUPT() LL_EXTI_DisableFallingTrig_0_31(N64_PIN_LINE)
- #define ENABLE_N64_INTERRUPT() LL_EXTI_EnableFallingTrig_0_31(N64_PIN_LINE)
- #define N64_HIGH LL_GPIO_SetPinMode((N64_PIN)->port, (N64_PIN)->pin, LL_GPIO_MODE_INPUT)
- #define N64_LOW LL_GPIO_SetPinMode((N64_PIN)->port, (N64_PIN)->pin, LL_GPIO_MODE_OUTPUT)
- #define N64_QUERY (N64_PORT->IDR & N64_Pin)
- #define LED_HIGH (void)0; //furi_hal_light_set(LightGreen, 0xFF)
- #define LED_LOW (void)0; //furi_hal_light_set(LightGreen, 0x00)
- template <class T1, class T2>
- auto min(T1 x, T2 y) {
- return x < y ? x : y;
- }
- //#define USE_COMPARE_ABSOLUTE
- FuriMessageQueue* msg_queue;
- Gui* gui = nullptr;
- ViewPort* view_port = nullptr;
- typedef struct {
- enum {
- Input,
- ISRLog,
- } msg_type;
- union {
- InputEvent input;
- };
- } QueueMessage;
- void isrLogCb() {
- QueueMessage msg = {QueueMessage::ISRLog, {}};
- furi_message_queue_put(msg_queue, &msg, 0);
- }
- #define ISR_LOG_CB isrLogCb
- unsigned char frameDat[4] = {0};
- void frameCb(const unsigned char* dat, size_t count) {
- memcpy(frameDat, dat, count);
- }
- #define FRAME_CB frameCb
- #include "teensy/teensy.ino"
- static void input_callback(InputEvent* input_event, void* ctx) {
- (void)ctx;
- QueueMessage msg = {QueueMessage::Input, {.input = *input_event}};
- furi_message_queue_put(msg_queue, &msg, 0);
- }
- static void render_callback(Canvas* canvas, void* ctx) {
- (void)ctx;
- elements_text_box(canvas, 0, 0, 128, 10, AlignCenter, AlignTop, filename.c_str(), true);
- #define INVERT "\e!"
- static char inputStr[128] = "";
- #define GET_BIT(byte, bit) (frameDat[byte] & (1 << bit))
- #define INV_IF(x) ((x) ? INVERT : "")
- #define FMT_BTN(byte, bit) INV_IF(GET_BIT(byte, bit)), INV_IF(GET_BIT(byte, bit))
- #define PLUS_MIN_ZERO(x) (((x) == 0) ? '0' : (((x) > 127) ? '-' : '+'))
- #define UN_SIGN(x) (((x) <= 127) ? x : (-((int)(x)-256)))
- #define FMT_JOY(byte) \
- INV_IF(frameDat[byte] != 0), PLUS_MIN_ZERO(frameDat[byte]), UN_SIGN(frameDat[byte]), \
- INV_IF(frameDat[byte] != 0)
- if(console == N64)
- snprintf(
- inputStr,
- sizeof(inputStr),
- "\e*\e!X\e!:%s%c%02x%s \e!Y\e!:%s%c%02x%s %s<%s%s>%s%s^%s%sv%s\n%sA%s%sB%s%sZ%s%sS%s%sL%s%sR%s C(%s<%s%s>%s%s^%s%sv%s)",
- FMT_JOY(2),
- FMT_JOY(3),
- FMT_BTN(0, 1),
- FMT_BTN(0, 0),
- FMT_BTN(0, 3),
- FMT_BTN(0, 2),
- FMT_BTN(0, 7),
- FMT_BTN(0, 6),
- FMT_BTN(0, 5),
- FMT_BTN(0, 4),
- FMT_BTN(1, 5),
- FMT_BTN(1, 4),
- FMT_BTN(1, 1),
- FMT_BTN(1, 0),
- FMT_BTN(1, 3),
- FMT_BTN(1, 2));
- elements_text_box(canvas, 0, 15, 128, 32, AlignCenter, AlignTop, inputStr, false);
- int denom = numFrames ? numFrames : 1;
- float progress = (float)curFrame / denom;
- char progStr[32];
- snprintf(
- progStr, sizeof(progStr), "%07lu/%07lu:%03i%%", curFrame, numFrames, (int)(progress * 100));
- uint8_t progress_y = 41;
- uint8_t progress_h = 12;
- uint8_t progress_length = roundf(progress * (126));
- canvas_set_color(canvas, ColorWhite);
- canvas_draw_box(canvas, 1, progress_y + 1, 126, progress_h - 2);
- canvas_set_color(canvas, ColorBlack);
- canvas_draw_rframe(canvas, 0, progress_y, 128, progress_h, 3);
- canvas_draw_box(canvas, 1, progress_y + 1, progress_length, progress_h - 2);
- canvas_set_color(canvas, ColorXOR);
- canvas_set_font(canvas, FontKeyboard);
- canvas_draw_str_aligned(canvas, 64, progress_y + 2, AlignCenter, AlignTop, progStr);
- canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
- canvas_set_font(canvas, FontSecondary);
- elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
- }
- extern "C" int32_t tas_playback_app(const char* p) {
- FURI_LOG_I("TAS", "Hello world");
- FURI_LOG_I("TAS", "I'm tas_playback!");
- uint32_t oldPrio = NVIC_GetPriority(N64_IRQ);
- NVIC_SetPriority(N64_IRQ, 0);
- LL_GPIO_SetPinOutputType((N64_PIN)->port, (N64_PIN)->pin, LL_GPIO_OUTPUT_PUSHPULL);
- setup();
- FURI_LOG_I("TAS", "SETUP DONE");
- msg_queue = furi_message_queue_alloc(8, sizeof(QueueMessage));
- gui = (Gui*)furi_record_open(RECORD_GUI);
- view_port = view_port_alloc();
- gui_add_view_port(gui, view_port, GuiLayerFullscreen);
- view_port_draw_callback_set(view_port, render_callback, NULL);
- view_port_input_callback_set(view_port, input_callback, NULL);
- FuriString* file_path = furi_string_alloc();
- FURI_LOG_I("TAS", "STARTING LOOP");
- do {
- if(p && strlen(p)) {
- FURI_LOG_I("TAS", "GOT ARG");
- furi_string_set_str(file_path, (const char*)p);
- } else {
- FURI_LOG_I("TAS", "NO ARG");
- Storage* storage = (Storage*)furi_record_open(RECORD_STORAGE);
- storage_common_migrate(storage, EXT_PATH("tas"), STORAGE_APP_DATA_PATH_PREFIX);
- furi_record_close(RECORD_STORAGE);
- FURI_LOG_I("TAS", "MIGRATED");
- furi_string_set_str(file_path, STORAGE_APP_DATA_PATH_PREFIX);
- DialogsFileBrowserOptions browser_options;
- dialog_file_browser_set_basic_options(&browser_options, "m64", &I_tas_playback);
- browser_options.hide_ext = false;
- browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
- FURI_LOG_I("TAS", "SETUP OPTIONS");
- DialogsApp* dialogs = (DialogsApp*)furi_record_open(RECORD_DIALOGS);
- bool res = dialog_file_browser_show(dialogs, file_path, file_path, &browser_options);
- furi_record_close(RECORD_DIALOGS);
- if(!res) {
- FURI_LOG_E("TAS", "No file selected");
- break;
- }
- }
- if(!openTAS(furi_string_get_cstr(file_path))) continue;
- FURI_LOG_E("TAS", "Got file");
- QueueMessage msg;
- while(furi_message_queue_get(msg_queue, &msg, FuriWaitForever) == FuriStatusOk) {
- if(msg.msg_type == QueueMessage::Input) {
- if(msg.input.type == InputTypeLong) {
- if(msg.input.key == InputKeyBack) break;
- } else if(msg.input.type == InputTypeShort) {
- if(msg.input.key == InputKeyUp) {
- } else if(msg.input.key == InputKeyDown) {
- }
- }
- }
- view_port_update(view_port);
- loop();
- }
- view_port_update(view_port);
- if(p && strlen(p)) break; // Exit instead of going to browser if launched with arg
- } while(1);
- furi_string_free(file_path);
- gui_remove_view_port(gui, view_port);
- furi_record_close(RECORD_GUI);
- view_port_free(view_port);
- furi_message_queue_free(msg_queue);
- furi_hal_gpio_init(N64_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
- furi_hal_gpio_remove_int_callback(N64_PIN);
- NVIC_SetPriority(N64_IRQ, oldPrio);
- return 0;
- }
|