mirror of
https://github.com/LNH-team/pico-launcher.git
synced 2026-06-02 00:56:55 +02:00
Initial commit
This commit is contained in:
40
common/core/TickCounter.cpp
Normal file
40
common/core/TickCounter.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "common.h"
|
||||
#include <libtwl/timer/timer.h>
|
||||
#include <libtwl/rtos/rtosIrq.h>
|
||||
#include "TickCounter.h"
|
||||
|
||||
TickCounter gTickCounter;
|
||||
|
||||
void TickCounter::TimerOverflowIrq()
|
||||
{
|
||||
_msb += 1 << 16;
|
||||
}
|
||||
|
||||
void TickCounter::Start()
|
||||
{
|
||||
_msb = 0;
|
||||
tmr_configure(0, TMCNT_H_CLK_SYS_DIV_64, 0, true);
|
||||
rtos_ackIrqMask(RTOS_IRQ_TIMER0);
|
||||
rtos_setIrqFunc(RTOS_IRQ_TIMER0, [] (u32 mask) { gTickCounter.TimerOverflowIrq(); });
|
||||
rtos_enableIrqMask(RTOS_IRQ_TIMER0);
|
||||
tmr_start(0);
|
||||
}
|
||||
|
||||
void TickCounter::Stop()
|
||||
{
|
||||
rtos_disableIrqMask(RTOS_IRQ_TIMER0);
|
||||
rtos_setIrqFunc(RTOS_IRQ_TIMER0, nullptr);
|
||||
tmr_stop(0);
|
||||
}
|
||||
|
||||
u64 TickCounter::GetValue()
|
||||
{
|
||||
u32 irqs = rtos_disableIrqs();
|
||||
u32 value0 = tmr_getCounter(0);
|
||||
u64 msb = _msb;
|
||||
u32 value1 = tmr_getCounter(0);
|
||||
rtos_restoreIrqs(irqs);
|
||||
if (value1 < value0)
|
||||
value1 += 1 << 16;
|
||||
return msb + value1;
|
||||
}
|
||||
26
common/core/TickCounter.h
Normal file
26
common/core/TickCounter.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
class TickCounter
|
||||
{
|
||||
public:
|
||||
void Start();
|
||||
void Stop();
|
||||
u64 GetValue();
|
||||
|
||||
static u32 TicksToMilliSeconds(u32 ticks)
|
||||
{
|
||||
return ((ticks * 8201887ULL) + (1ULL << 31)) >> 32;
|
||||
}
|
||||
|
||||
static u32 TicksToMicroSeconds(u32 ticks)
|
||||
{
|
||||
return (ticks * 4100943703ULL + (1 << 30)) >> 31;
|
||||
}
|
||||
|
||||
private:
|
||||
u64 _msb = 0;
|
||||
|
||||
void TimerOverflowIrq();
|
||||
};
|
||||
|
||||
extern TickCounter gTickCounter;
|
||||
312
common/core/mini-printf.c
Normal file
312
common/core/mini-printf.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* The Minimal snprintf() implementation
|
||||
*
|
||||
* Copyright (c) 2013,2014 Michal Ludvig <michal@logix.cz>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the auhor nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* This is a minimal snprintf() implementation optimised
|
||||
* for embedded systems with a very limited program memory.
|
||||
* mini_snprintf() doesn't support _all_ the formatting
|
||||
* the glibc does but on the other hand is a lot smaller.
|
||||
* Here are some numbers from my STM32 project (.bin file size):
|
||||
* no snprintf(): 10768 bytes
|
||||
* mini snprintf(): 11420 bytes (+ 652 bytes)
|
||||
* glibc snprintf(): 34860 bytes (+24092 bytes)
|
||||
* Wasting nearly 24kB of memory just for snprintf() on
|
||||
* a chip with 32kB flash is crazy. Use mini_snprintf() instead.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mini-printf.h"
|
||||
|
||||
static int
|
||||
mini_strlen(const char *s)
|
||||
{
|
||||
int len = 0;
|
||||
while (s[len] != '\0') len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
mini_itoa(long value, unsigned int radix, int uppercase, int unsig,
|
||||
char *buffer)
|
||||
{
|
||||
char *pbuffer = buffer;
|
||||
int negative = 0;
|
||||
int i, len;
|
||||
|
||||
/* No support for unusual radixes. */
|
||||
if (radix > 16)
|
||||
return 0;
|
||||
|
||||
if (value < 0 && !unsig) {
|
||||
negative = 1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
/* This builds the string back to front ... */
|
||||
do {
|
||||
int digit = value % radix;
|
||||
*(pbuffer++) = (digit < 10 ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10);
|
||||
value /= radix;
|
||||
} while (value > 0);
|
||||
|
||||
if (negative)
|
||||
*(pbuffer++) = '-';
|
||||
|
||||
*(pbuffer) = '\0';
|
||||
|
||||
/* ... now we reverse it (could do it recursively but will
|
||||
* conserve the stack space) */
|
||||
len = (pbuffer - buffer);
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
char j = buffer[i];
|
||||
buffer[i] = buffer[len-i-1];
|
||||
buffer[len-i-1] = j;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
mini_pad(char* ptr, int len, char pad_char, int pad_to, char *buffer)
|
||||
{
|
||||
int i;
|
||||
int overflow = 0;
|
||||
char * pbuffer = buffer;
|
||||
if(pad_to == 0) pad_to = len;
|
||||
if(len > pad_to) {
|
||||
len = pad_to;
|
||||
overflow = 1;
|
||||
}
|
||||
for(i = pad_to - len; i > 0; i --) {
|
||||
*(pbuffer++) = pad_char;
|
||||
}
|
||||
for(i = len; i > 0; i --) {
|
||||
*(pbuffer++) = *(ptr++);
|
||||
}
|
||||
len = pbuffer - buffer;
|
||||
if(overflow) {
|
||||
for (i = 0; i < 3 && pbuffer > buffer; i ++) {
|
||||
*(pbuffer-- - 1) = '*';
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
struct mini_buff {
|
||||
char *buffer, *pbuffer;
|
||||
unsigned int buffer_len;
|
||||
};
|
||||
|
||||
static int
|
||||
_puts(char *s, int len, void *buf)
|
||||
{
|
||||
if(!buf) return len;
|
||||
struct mini_buff *b = buf;
|
||||
char * p0 = b->buffer;
|
||||
int i;
|
||||
/* Copy to buffer */
|
||||
for (i = 0; i < len; i++) {
|
||||
if(b->pbuffer == b->buffer + b->buffer_len - 1) {
|
||||
break;
|
||||
}
|
||||
*(b->pbuffer ++) = s[i];
|
||||
}
|
||||
*(b->pbuffer) = 0;
|
||||
return b->pbuffer - p0;
|
||||
}
|
||||
|
||||
#ifdef MINI_PRINTF_ENABLE_OBJECTS
|
||||
static int (*mini_handler) (void* data, void* obj, int ch, int lhint, char** bf) = 0;
|
||||
static void (*mini_handler_freeor)(void* data, void*) = 0;
|
||||
static void * mini_handler_data = 0;
|
||||
|
||||
void mini_printf_set_handler(
|
||||
void* data,
|
||||
int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
|
||||
void (*freeor)(void* data, void* buf))
|
||||
{
|
||||
mini_handler = handler;
|
||||
mini_handler_freeor = freeor;
|
||||
mini_handler_data = data;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va)
|
||||
{
|
||||
struct mini_buff b;
|
||||
b.buffer = buffer;
|
||||
b.pbuffer = buffer;
|
||||
b.buffer_len = buffer_len;
|
||||
if(buffer_len == 0) buffer = (void*) 0;
|
||||
int n = mini_vpprintf(_puts, (buffer != (void*)0)?&b:(void*)0, fmt, va);
|
||||
if(buffer == (void*) 0) {
|
||||
return n;
|
||||
}
|
||||
return b.pbuffer - b.buffer;
|
||||
}
|
||||
|
||||
int
|
||||
mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va)
|
||||
{
|
||||
char bf[24];
|
||||
char bf2[24];
|
||||
char ch;
|
||||
#ifdef MINI_PRINTF_ENABLE_OBJECTS
|
||||
void* obj;
|
||||
#endif
|
||||
if(puts == (void*)0) {
|
||||
/* run puts in counting mode. */
|
||||
puts = _puts; buf = (void*)0;
|
||||
}
|
||||
int n = 0;
|
||||
while ((ch=*(fmt++))) {
|
||||
int len;
|
||||
if (ch!='%') {
|
||||
len = 1;
|
||||
len = puts(&ch, len, buf);
|
||||
} else {
|
||||
char pad_char = ' ';
|
||||
int pad_to = 0;
|
||||
char l = 0;
|
||||
char *ptr;
|
||||
|
||||
ch=*(fmt++);
|
||||
|
||||
/* Zero padding requested */
|
||||
if (ch == '0') pad_char = '0';
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
pad_to = pad_to * 10 + (ch - '0');
|
||||
ch=*(fmt++);
|
||||
}
|
||||
if(pad_to > (signed int) sizeof(bf)) {
|
||||
pad_to = sizeof(bf);
|
||||
}
|
||||
if (ch == 'l') {
|
||||
l = 1;
|
||||
ch=*(fmt++);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case 0:
|
||||
goto end;
|
||||
case 'u':
|
||||
case 'd':
|
||||
if(l) {
|
||||
len = mini_itoa(va_arg(va, unsigned long), 10, 0, (ch=='u'), bf2);
|
||||
} else {
|
||||
if(ch == 'u') {
|
||||
len = mini_itoa((unsigned long) va_arg(va, unsigned int), 10, 0, 1, bf2);
|
||||
} else {
|
||||
len = mini_itoa((long) va_arg(va, int), 10, 0, 0, bf2);
|
||||
}
|
||||
}
|
||||
len = mini_pad(bf2, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'x':
|
||||
case 'X':
|
||||
if(l) {
|
||||
len = mini_itoa(va_arg(va, unsigned long), 16, (ch=='X'), 1, bf2);
|
||||
} else {
|
||||
len = mini_itoa((unsigned long) va_arg(va, unsigned int), 16, (ch=='X'), 1, bf2);
|
||||
}
|
||||
len = mini_pad(bf2, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
break;
|
||||
|
||||
case 'c' :
|
||||
ch = (char)(va_arg(va, int));
|
||||
len = mini_pad(&ch, 1, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
break;
|
||||
|
||||
case 's' :
|
||||
ptr = va_arg(va, char*);
|
||||
len = mini_strlen(ptr);
|
||||
if (pad_to > 0) {
|
||||
len = mini_pad(ptr, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
} else {
|
||||
len = puts(ptr, len, buf);
|
||||
}
|
||||
break;
|
||||
#ifdef MINI_PRINTF_ENABLE_OBJECTS
|
||||
case 'O' : /* Object by content (e.g. str) */
|
||||
case 'R' : /* Object by representation (e.g. repr)*/
|
||||
obj = va_arg(va, void*);
|
||||
len = mini_handler(mini_handler_data, obj, ch, pad_to, &ptr);
|
||||
if (pad_to > 0) {
|
||||
len = mini_pad(ptr, len, pad_char, pad_to, bf);
|
||||
len = puts(bf, len, buf);
|
||||
} else {
|
||||
len = puts(ptr, len, buf);
|
||||
}
|
||||
mini_handler_freeor(mini_handler_data, ptr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
len = 1;
|
||||
len = puts(&ch, len, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
n = n + len;
|
||||
}
|
||||
end:
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ret = mini_vsnprintf(buffer, buffer_len, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ret = mini_vpprintf(puts, buf, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
73
common/core/mini-printf.h
Normal file
73
common/core/mini-printf.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* The Minimal snprintf() implementation
|
||||
*
|
||||
* Copyright (c) 2013 Michal Ludvig <michal@logix.cz>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the auhor nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __MINI_PRINTF__
|
||||
#define __MINI_PRINTF__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef MINI_PRINTF_ENABLE_OBJECTS
|
||||
/* If enabled, callback for object types (O and R).
|
||||
* void* arguments matching %O and %R are sent to handler as obj.
|
||||
* the result string created by handler at *buf is freed by freeor.
|
||||
* */
|
||||
void mini_printf_set_handler(
|
||||
void * data,
|
||||
/* handler returns number of chars in *buf; *buf is not NUL-terminated. */
|
||||
int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
|
||||
void (*freeor)(void* data, void* buf));
|
||||
#endif
|
||||
|
||||
/* String IO interface; returns number of bytes written, not including the ending NUL.
|
||||
* Always appends a NUL at the end, therefore buffer_len shall be at least 1 in normal operation.
|
||||
* If buffer is NULL or buffer_len is 0, returns number of bytes to be written, not including the ending NUL.
|
||||
*/
|
||||
int mini_vsnprintf(char* buffer, unsigned int buffer_len, const char *fmt, va_list va);
|
||||
int mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...);
|
||||
|
||||
/* Stream IO interface; returns number of bytes written.
|
||||
* If puts is NULL, number of bytes to be written.
|
||||
* puts shall return number of bytes written.
|
||||
*/
|
||||
int mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va);
|
||||
int mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define vsnprintf mini_vsnprintf
|
||||
#define snprintf mini_snprintf
|
||||
|
||||
#endif
|
||||
17
common/dldiIpcCommand.h
Normal file
17
common/dldiIpcCommand.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DLDI_IPC_CMD_SETUP,
|
||||
DLDI_IPC_CMD_READ_SECTORS,
|
||||
DLDI_IPC_CMD_WRITE_SECTORS
|
||||
} DldiIpcCommand;
|
||||
|
||||
typedef struct alignas(32)
|
||||
{
|
||||
u32 cmd;
|
||||
void* buffer;
|
||||
u32 sector;
|
||||
u32 count;
|
||||
u8 sizeAlign[16]; // ensure the size is also cache aligned
|
||||
} dldi_ipc_cmd_t;
|
||||
16
common/dsiSdIpcCommand.h
Normal file
16
common/dsiSdIpcCommand.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DSI_SD_IPC_CMD_READ_SECTORS,
|
||||
DSI_SD_IPC_CMD_WRITE_SECTORS
|
||||
} DsiSdIpcCommand;
|
||||
|
||||
typedef struct alignas(32)
|
||||
{
|
||||
u32 cmd;
|
||||
void* buffer;
|
||||
u32 sector;
|
||||
u32 count;
|
||||
u8 sizeAlign[16]; // ensure the size is also cache aligned
|
||||
} dsisd_ipc_cmd_t;
|
||||
11
common/ipc/IpcService.cpp
Normal file
11
common/ipc/IpcService.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "common.h"
|
||||
#include <libtwl/ipc/ipcFifoSystem.h>
|
||||
#include "IpcService.h"
|
||||
|
||||
void IpcService::Start()
|
||||
{
|
||||
ipc_setChannelHandler(_ipcChannel, [] (u32 channel, u32 data, void* arg)
|
||||
{
|
||||
static_cast<IpcService*>(arg)->OnMessageReceived(data);
|
||||
}, this);
|
||||
}
|
||||
19
common/ipc/IpcService.h
Normal file
19
common/ipc/IpcService.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <libtwl/ipc/ipcFifoSystem.h>
|
||||
|
||||
class IpcService
|
||||
{
|
||||
const u32 _ipcChannel;
|
||||
protected:
|
||||
explicit IpcService(u32 ipcChannel)
|
||||
: _ipcChannel(ipcChannel) { }
|
||||
|
||||
void SendResponseMessage(u32 data) const
|
||||
{
|
||||
ipc_sendFifoMessage(_ipcChannel, data);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void Start();
|
||||
virtual void OnMessageReceived(u32 data) = 0;
|
||||
};
|
||||
33
common/ipc/ThreadIpcService.cpp
Normal file
33
common/ipc/ThreadIpcService.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "common.h"
|
||||
#include "ThreadIpcService.h"
|
||||
|
||||
void ThreadIpcService::ThreadMain()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
rtos_waitEvent(&_event, false, true);
|
||||
if (_messageValid)
|
||||
{
|
||||
_messageValid = false;
|
||||
HandleMessage(_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadIpcService::Start()
|
||||
{
|
||||
rtos_createEvent(&_event);
|
||||
rtos_createThread(&_thread, 5, [] (void* arg)
|
||||
{
|
||||
static_cast<ThreadIpcService*>(arg)->ThreadMain();
|
||||
}, this, _stack, _stackSize);
|
||||
rtos_wakeupThread(&_thread);
|
||||
IpcService::Start();
|
||||
}
|
||||
|
||||
void ThreadIpcService::OnMessageReceived(u32 data)
|
||||
{
|
||||
_message = data;
|
||||
_messageValid = true;
|
||||
rtos_signalEvent(&_event);
|
||||
}
|
||||
26
common/ipc/ThreadIpcService.h
Normal file
26
common/ipc/ThreadIpcService.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <libtwl/rtos/rtosThread.h>
|
||||
#include <libtwl/rtos/rtosEvent.h>
|
||||
#include "IpcService.h"
|
||||
|
||||
class ThreadIpcService : public IpcService
|
||||
{
|
||||
rtos_thread_t _thread;
|
||||
rtos_event_t _event;
|
||||
u32* _stack;
|
||||
u32 _stackSize;
|
||||
u8 _priority;
|
||||
bool _messageValid = false;
|
||||
u32 _message;
|
||||
|
||||
void ThreadMain();
|
||||
|
||||
public:
|
||||
ThreadIpcService(u32 ipcChannel, u8 priority, u32* stack, u32 stackSize)
|
||||
: IpcService(ipcChannel), _stack(stack), _stackSize(stackSize), _priority(priority) { }
|
||||
|
||||
void Start() override;
|
||||
void OnMessageReceived(u32 data) override;
|
||||
|
||||
virtual void HandleMessage(u32 data);
|
||||
};
|
||||
7
common/ipcChannels.h
Normal file
7
common/ipcChannels.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define IPC_CHANNEL_DSI_SD 16
|
||||
#define IPC_CHANNEL_DLDI 17
|
||||
#define IPC_CHANNEL_LOADER 18
|
||||
#define IPC_CHANNEL_SOUND 19
|
||||
#define IPC_CHANNEL_RTC 20
|
||||
32
common/logger/ILogger.h
Normal file
32
common/logger/ILogger.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <stdarg.h>
|
||||
|
||||
enum class LogLevel
|
||||
{
|
||||
Off,
|
||||
|
||||
Fatal,
|
||||
Error,
|
||||
Warning,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
|
||||
All
|
||||
};
|
||||
|
||||
class ILogger
|
||||
{
|
||||
public:
|
||||
virtual ~ILogger() { }
|
||||
|
||||
void Log(LogLevel level, const char* fmt, ...)
|
||||
{
|
||||
va_list vlist;
|
||||
va_start(vlist, fmt);
|
||||
LogV(level, fmt, vlist);
|
||||
va_end(vlist);
|
||||
}
|
||||
|
||||
virtual void LogV(LogLevel level, const char* fmt, va_list vlist) = 0;
|
||||
};
|
||||
10
common/logger/IOutputStream.h
Normal file
10
common/logger/IOutputStream.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
class IOutputStream
|
||||
{
|
||||
public:
|
||||
virtual ~IOutputStream() { }
|
||||
|
||||
virtual void Write(const char* str) = 0;
|
||||
virtual void Flush() = 0;
|
||||
};
|
||||
47
common/logger/NitroEmulatorOutputStream.cpp
Normal file
47
common/logger/NitroEmulatorOutputStream.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "common.h"
|
||||
#include "NitroEmulatorOutputStream.h"
|
||||
|
||||
#define ISND_DBGINFO_ADDRESS 0x027FFF60
|
||||
#define ISND_DBGINFO_AGB_ADDR_OFFSET 0x1C
|
||||
#define ISND_DBGINFO_AGB_ADDR (*(u32*)(ISND_DBGINFO_ADDRESS + ISND_DBGINFO_AGB_ADDR_OFFSET))
|
||||
|
||||
#define ISND_AGB_PRINT_ARM9_WRITE_PTR_OFFSET 0x90
|
||||
#define ISND_AGB_PRINT_ARM7_WRITE_PTR_OFFSET 0x92
|
||||
#define ISND_AGB_PRINT_ARM9_READ_PTR_OFFSET 0x94
|
||||
#define ISND_AGB_PRINT_ARM7_READ_PTR_OFFSET 0x96
|
||||
#define ISND_AGB_SOMETHING_OFFSET 0xFE
|
||||
#define ISND_AGB_PRINT_ARM9_RING_OFFSET 0x8000
|
||||
#define ISND_AGB_PRINT_ARM7_RING_OFFSET 0xC000
|
||||
#define ISND_AGB_PRINT_RING_LENGTH 0x4000
|
||||
|
||||
NitroEmulatorOutputStream::NitroEmulatorOutputStream()
|
||||
{
|
||||
#ifdef LIBTWL_ARM9
|
||||
*(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_SOMETHING_OFFSET) = 0x202;
|
||||
#endif
|
||||
}
|
||||
|
||||
void NitroEmulatorOutputStream::Write(const char* str)
|
||||
{
|
||||
#ifdef LIBTWL_ARM9
|
||||
char c;
|
||||
vu16* ring = (vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_RING_OFFSET);
|
||||
u32 writePtr = *(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_WRITE_PTR_OFFSET);
|
||||
u32 readPtr = *(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_READ_PTR_OFFSET);
|
||||
while ((c = *str++) != 0)
|
||||
{
|
||||
u32 newWritePtr = (writePtr + 1) & (ISND_AGB_PRINT_RING_LENGTH - 1);
|
||||
while (newWritePtr == readPtr)
|
||||
{
|
||||
*(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_WRITE_PTR_OFFSET) = writePtr;
|
||||
readPtr = *(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_READ_PTR_OFFSET);
|
||||
}
|
||||
if (writePtr & 1)
|
||||
ring[writePtr >> 1] = (ring[writePtr >> 1] & 0xFF) | (c << 8);
|
||||
else
|
||||
ring[writePtr >> 1] = (ring[writePtr >> 1] & 0xFF00) | c;
|
||||
writePtr = newWritePtr;
|
||||
}
|
||||
*(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_WRITE_PTR_OFFSET) = writePtr;
|
||||
#endif
|
||||
}
|
||||
11
common/logger/NitroEmulatorOutputStream.h
Normal file
11
common/logger/NitroEmulatorOutputStream.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "IOutputStream.h"
|
||||
|
||||
class NitroEmulatorOutputStream : public IOutputStream
|
||||
{
|
||||
public:
|
||||
NitroEmulatorOutputStream();
|
||||
|
||||
void Write(const char* str) override;
|
||||
void Flush() override { }
|
||||
};
|
||||
16
common/logger/NocashOutputStream.h
Normal file
16
common/logger/NocashOutputStream.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "IOutputStream.h"
|
||||
|
||||
#define REG_NOCASH_STRING_OUT (*(vu32*)0x04FFFA10)
|
||||
#define REG_NOCASH_CHAR_OUT (*(vu32*)0x04FFFA1C)
|
||||
|
||||
class NocashOutputStream : public IOutputStream
|
||||
{
|
||||
public:
|
||||
void Write(const char* str) override
|
||||
{
|
||||
REG_NOCASH_STRING_OUT = (u32)str;
|
||||
}
|
||||
|
||||
void Flush() override { }
|
||||
};
|
||||
8
common/logger/NullLogger.h
Normal file
8
common/logger/NullLogger.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "ILogger.h"
|
||||
|
||||
class NullLogger : public ILogger
|
||||
{
|
||||
public:
|
||||
void LogV(LogLevel level, const char* fmt, va_list vlist) override { }
|
||||
};
|
||||
9
common/logger/NullOutputStream.h
Normal file
9
common/logger/NullOutputStream.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "IOutputStream.h"
|
||||
|
||||
class NullOutputStream : public IOutputStream
|
||||
{
|
||||
public:
|
||||
void Write(const char* str) { }
|
||||
void Flush() { }
|
||||
};
|
||||
28
common/logger/PicoAgbAdapterOutputStream.cpp
Normal file
28
common/logger/PicoAgbAdapterOutputStream.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "common.h"
|
||||
#include "picoAgbAdapter.h"
|
||||
#include "PicoAgbAdapterOutputStream.h"
|
||||
|
||||
void PicoAgbAdapterOutputStream::Write(const char* str)
|
||||
{
|
||||
#ifdef LIBTWL_ARM9
|
||||
char c;
|
||||
vu16* ring = PICO_AGB_PRINT_ARM9_RING;
|
||||
u32 writePtr = PICO_AGB_PRINT_ARM9_WRITE_PTR;
|
||||
u32 readPtr = PICO_AGB_PRINT_ARM9_READ_PTR;
|
||||
while ((c = *str++) != 0)
|
||||
{
|
||||
u32 newWritePtr = (writePtr + 1) & (PICO_AGB_PRINT_RING_LENGTH - 1);
|
||||
while (newWritePtr == readPtr)
|
||||
{
|
||||
PICO_AGB_PRINT_ARM9_WRITE_PTR = writePtr;
|
||||
readPtr = PICO_AGB_PRINT_ARM9_READ_PTR;
|
||||
}
|
||||
if (writePtr & 1)
|
||||
ring[writePtr >> 1] = (ring[writePtr >> 1] & 0xFF) | (c << 8);
|
||||
else
|
||||
ring[writePtr >> 1] = (ring[writePtr >> 1] & 0xFF00) | c;
|
||||
writePtr = newWritePtr;
|
||||
}
|
||||
PICO_AGB_PRINT_ARM9_WRITE_PTR = writePtr;
|
||||
#endif
|
||||
}
|
||||
11
common/logger/PicoAgbAdapterOutputStream.h
Normal file
11
common/logger/PicoAgbAdapterOutputStream.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "IOutputStream.h"
|
||||
|
||||
class PicoAgbAdapterOutputStream : public IOutputStream
|
||||
{
|
||||
public:
|
||||
PicoAgbAdapterOutputStream() { }
|
||||
|
||||
void Write(const char* str) override;
|
||||
void Flush() override { }
|
||||
};
|
||||
26
common/logger/PlainLogger.h
Normal file
26
common/logger/PlainLogger.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "core/mini-printf.h"
|
||||
#include "ILogger.h"
|
||||
#include "IOutputStream.h"
|
||||
|
||||
class PlainLogger : public ILogger
|
||||
{
|
||||
LogLevel _maxLogLevel;
|
||||
std::unique_ptr<IOutputStream> _outputStream;
|
||||
|
||||
char _logBuffer[512];
|
||||
|
||||
public:
|
||||
PlainLogger(LogLevel maxLogLevel, std::unique_ptr<IOutputStream> outputStream)
|
||||
: _maxLogLevel(maxLogLevel), _outputStream(std::move(outputStream))
|
||||
{ }
|
||||
|
||||
void LogV(LogLevel level, const char* fmt, va_list vlist) override
|
||||
{
|
||||
if (level > _maxLogLevel)
|
||||
return;
|
||||
mini_vsnprintf(_logBuffer, sizeof(_logBuffer), fmt, vlist);
|
||||
_outputStream->Write(_logBuffer);
|
||||
}
|
||||
};
|
||||
26
common/logger/ThreadSafeLogger.h
Normal file
26
common/logger/ThreadSafeLogger.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <libtwl/rtos/rtosMutex.h>
|
||||
#include "ILogger.h"
|
||||
|
||||
class ThreadSafeLogger : public ILogger
|
||||
{
|
||||
std::unique_ptr<ILogger> _logger;
|
||||
rtos_mutex_t _mutex;
|
||||
|
||||
public:
|
||||
explicit ThreadSafeLogger(std::unique_ptr<ILogger> logger)
|
||||
: _logger(std::move(logger))
|
||||
{
|
||||
rtos_createMutex(&_mutex);
|
||||
}
|
||||
|
||||
void LogV(LogLevel level, const char* fmt, va_list vlist) override
|
||||
{
|
||||
rtos_lockMutex(&_mutex);
|
||||
{
|
||||
_logger->LogV(level, fmt, vlist);
|
||||
}
|
||||
rtos_unlockMutex(&_mutex);
|
||||
}
|
||||
};
|
||||
9
common/picoAgbAdapter.h
Normal file
9
common/picoAgbAdapter.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#define PICO_AGB_PRINT_ARM9_RING ((vu16*)0x08000000)
|
||||
#define PICO_AGB_PRINT_ARM9_READ_PTR (*(vu16*)0x08010000)
|
||||
#define PICO_AGB_PRINT_ARM9_WRITE_PTR (*(vu16*)0x08010002)
|
||||
#define PICO_AGB_PRINT_RING_LENGTH 0x8000
|
||||
|
||||
#define PICO_AGB_IDENTIFIER (*(vu32*)0x08010008)
|
||||
#define PICO_AGB_IDENTIFIER_VALUE 0x4F434950
|
||||
55
common/picoLoader7.h
Normal file
55
common/picoLoader7.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
/// @brief The Pico Loader API version supported by this header file.
|
||||
#define PICO_LOADER_API_VERSION 1
|
||||
|
||||
/// @brief Enum to specify the drive to boot from.
|
||||
typedef enum
|
||||
{
|
||||
/// @brief Flashcard through DLDI.
|
||||
PLOAD_BOOT_DRIVE_DLDI = 0,
|
||||
|
||||
/// @brief DSi SD card.
|
||||
PLOAD_BOOT_DRIVE_DSI_SD = 1,
|
||||
|
||||
/// @brief AGB semihosting on the IS-NITRO-EMULATOR.
|
||||
PLOAD_BOOT_DRIVE_AGB_SEMIHOSTING = 2,
|
||||
|
||||
/// @brief Flag to indicate that a multiboot rom needs to be loaded that is already in memory.
|
||||
PLOAD_BOOT_DRIVE_MULTIBOOT_FLAG = 1u << 15
|
||||
} PicoLoaderBootDrive;
|
||||
|
||||
/// @brief Struct containing the load params.
|
||||
typedef struct
|
||||
{
|
||||
/// @brief The path of the rom to load.
|
||||
char romPath[256];
|
||||
|
||||
/// @brief The path to the save file to use.
|
||||
char savePath[256];
|
||||
|
||||
/// @brief The actual length of the argv arguments buffer.
|
||||
u32 argumentsLength;
|
||||
|
||||
/// @brief Argv arguments buffer.
|
||||
char arguments[256];
|
||||
} pload_params_t;
|
||||
|
||||
/// @brief Struct representing the header of picoLoader7.bin.
|
||||
typedef struct
|
||||
{
|
||||
/// @brief Pointer to the Pico Loader arm7 entry point (read-only).
|
||||
void* const entryPoint;
|
||||
|
||||
/// @brief Sets the DLDI driver to use.
|
||||
void* dldiDriver;
|
||||
|
||||
/// @brief Sets the boot drive. See \see PicoLoaderBootDrive.
|
||||
u16 bootDrive;
|
||||
|
||||
/// @brief The supported Pico Loader API version (read-only).
|
||||
const u16 apiVersion;
|
||||
|
||||
/// @brief The load params, see \see pload_params_t.
|
||||
pload_params_t loadParams;
|
||||
} pload_header7_t;
|
||||
3
common/sharedMemory.h
Normal file
3
common/sharedMemory.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define SHARED_KEY_XY (*(vu16*)0x02FFFFA8)
|
||||
19
common/soundIpcCommand.h
Normal file
19
common/soundIpcCommand.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
enum SoundIpcCommand
|
||||
{
|
||||
SND_IPC_CMD_START_CHANNELS,
|
||||
SND_IPC_CMD_STOP_CHANNELS,
|
||||
SND_IPC_CMD_SETUP_CHANNEL
|
||||
};
|
||||
|
||||
struct snd_ipc_cmd_setup_channel_t
|
||||
{
|
||||
u32 cmd : 8;
|
||||
u32 channel : 24;
|
||||
const void* sourceAddress;
|
||||
u32 timer;
|
||||
u32 loopStart;
|
||||
u32 length;
|
||||
u32 control;
|
||||
};
|
||||
Reference in New Issue
Block a user