mirror of https://github.com/probonopd/MiniDexed
parent
0a9eb7f565
commit
893b9f60f1
@ -0,0 +1,111 @@ |
|||||||
|
//
|
||||||
|
// ftpdaemon.cpp
|
||||||
|
//
|
||||||
|
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
|
||||||
|
// Copyright (C) 2020-2023 Dale Whinham <daleyo@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of mt32-pi.
|
||||||
|
//
|
||||||
|
// mt32-pi is free software: you can redistribute it and/or modify it under the
|
||||||
|
// terms of the GNU General Public License as published by the Free Software
|
||||||
|
// Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
// version.
|
||||||
|
//
|
||||||
|
// mt32-pi is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
// details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <circle/logger.h> |
||||||
|
#include <circle/net/in.h> |
||||||
|
#include <circle/net/ipaddress.h> |
||||||
|
#include <circle/net/netsubsystem.h> |
||||||
|
#include <circle/string.h> |
||||||
|
|
||||||
|
#include "ftpdaemon.h" |
||||||
|
#include "ftpworker.h" |
||||||
|
|
||||||
|
LOGMODULE("ftpd"); |
||||||
|
|
||||||
|
constexpr u16 ListenPort = 21; |
||||||
|
constexpr u8 MaxConnections = 1; |
||||||
|
|
||||||
|
CFTPDaemon::CFTPDaemon(const char* pUser, const char* pPassword) |
||||||
|
: CTask(TASK_STACK_SIZE, true), |
||||||
|
m_pListenSocket(nullptr), |
||||||
|
m_pUser(pUser), |
||||||
|
m_pPassword(pPassword) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
CFTPDaemon::~CFTPDaemon() |
||||||
|
{ |
||||||
|
if (m_pListenSocket) |
||||||
|
delete m_pListenSocket; |
||||||
|
} |
||||||
|
|
||||||
|
bool CFTPDaemon::Initialize() |
||||||
|
{ |
||||||
|
CNetSubSystem* const pNet = CNetSubSystem::Get(); |
||||||
|
|
||||||
|
if ((m_pListenSocket = new CSocket(pNet, IPPROTO_TCP)) == nullptr) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (m_pListenSocket->Bind(ListenPort) != 0) |
||||||
|
{ |
||||||
|
LOGERR("Couldn't bind to port %d", ListenPort); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (m_pListenSocket->Listen() != 0) |
||||||
|
{ |
||||||
|
LOGERR("Failed to listen on control socket"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// We started as a suspended task; run now that initialization is successful
|
||||||
|
Start(); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void CFTPDaemon::Run() |
||||||
|
{ |
||||||
|
assert(m_pListenSocket != nullptr); |
||||||
|
|
||||||
|
LOGNOTE("Listener task spawned"); |
||||||
|
|
||||||
|
while (true) |
||||||
|
{ |
||||||
|
CIPAddress ClientIPAddress; |
||||||
|
u16 nClientPort; |
||||||
|
|
||||||
|
LOGDBG("Listener: waiting for connection"); |
||||||
|
CSocket* pConnection = m_pListenSocket->Accept(&ClientIPAddress, &nClientPort); |
||||||
|
|
||||||
|
if (pConnection == nullptr) |
||||||
|
{ |
||||||
|
LOGERR("Unable to accept connection"); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
CString IPAddressString; |
||||||
|
ClientIPAddress.Format(&IPAddressString); |
||||||
|
LOGNOTE("Incoming connection from %s:%d", static_cast<const char*>(IPAddressString), nClientPort); |
||||||
|
|
||||||
|
if (CFTPWorker::GetInstanceCount() >= MaxConnections) |
||||||
|
{ |
||||||
|
pConnection->Send("421 Maximum number of connections reached.\r\n", 45, 0); |
||||||
|
delete pConnection; |
||||||
|
LOGWARN("Maximum number of connections reached"); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// Spawn new worker
|
||||||
|
new CFTPWorker(pConnection, m_pUser, m_pPassword); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
//
|
||||||
|
// ftpdaemon.h
|
||||||
|
//
|
||||||
|
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
|
||||||
|
// Copyright (C) 2020-2023 Dale Whinham <daleyo@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of mt32-pi.
|
||||||
|
//
|
||||||
|
// mt32-pi is free software: you can redistribute it and/or modify it under the
|
||||||
|
// terms of the GNU General Public License as published by the Free Software
|
||||||
|
// Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
// version.
|
||||||
|
//
|
||||||
|
// mt32-pi is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
// details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef _ftpdaemon_h |
||||||
|
#define _ftpdaemon_h |
||||||
|
|
||||||
|
#include <circle/net/socket.h> |
||||||
|
#include <circle/sched/task.h> |
||||||
|
|
||||||
|
class CFTPDaemon : protected CTask |
||||||
|
{ |
||||||
|
public: |
||||||
|
CFTPDaemon(const char* pUser, const char* pPassword); |
||||||
|
virtual ~CFTPDaemon() override; |
||||||
|
|
||||||
|
bool Initialize(); |
||||||
|
|
||||||
|
virtual void Run() override; |
||||||
|
|
||||||
|
private: |
||||||
|
// TCP sockets
|
||||||
|
CSocket* m_pListenSocket; |
||||||
|
|
||||||
|
const char* m_pUser; |
||||||
|
const char* m_pPassword; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,157 @@ |
|||||||
|
//
|
||||||
|
// ftpworker.h
|
||||||
|
//
|
||||||
|
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
|
||||||
|
// Copyright (C) 2020-2023 Dale Whinham <daleyo@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of mt32-pi.
|
||||||
|
//
|
||||||
|
// mt32-pi is free software: you can redistribute it and/or modify it under the
|
||||||
|
// terms of the GNU General Public License as published by the Free Software
|
||||||
|
// Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
// version.
|
||||||
|
//
|
||||||
|
// mt32-pi is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
// details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef _ftpworker_h |
||||||
|
#define _ftpworker_h |
||||||
|
|
||||||
|
#include <circle/net/ipaddress.h> |
||||||
|
#include <circle/net/socket.h> |
||||||
|
#include <circle/sched/task.h> |
||||||
|
#include <circle/string.h> |
||||||
|
|
||||||
|
// TODO: These may be incomplete/inaccurate
|
||||||
|
enum TFTPStatus |
||||||
|
{ |
||||||
|
FileStatusOk = 150, |
||||||
|
|
||||||
|
Success = 200, |
||||||
|
SystemType = 215, |
||||||
|
ReadyForNewUser = 220, |
||||||
|
ClosingControl = 221, |
||||||
|
TransferComplete = 226, |
||||||
|
EnteringPassiveMode = 227, |
||||||
|
UserLoggedIn = 230, |
||||||
|
FileActionOk = 250, |
||||||
|
PathCreated = 257, |
||||||
|
|
||||||
|
PasswordRequired = 331, |
||||||
|
AccountRequired = 332, |
||||||
|
PendingFurtherInfo = 350, |
||||||
|
|
||||||
|
ServiceNotAvailable = 421, |
||||||
|
DataConnectionFailed = 425, |
||||||
|
FileActionNotTaken = 450, |
||||||
|
ActionAborted = 451, |
||||||
|
|
||||||
|
CommandUnrecognized = 500, |
||||||
|
SyntaxError = 501, |
||||||
|
CommandNotImplemented = 502, |
||||||
|
BadCommandSequence = 503, |
||||||
|
NotLoggedIn = 530, |
||||||
|
FileNotFound = 550, |
||||||
|
FileNameNotAllowed = 553, |
||||||
|
}; |
||||||
|
|
||||||
|
enum class TTransferMode |
||||||
|
{ |
||||||
|
Active, |
||||||
|
Passive, |
||||||
|
}; |
||||||
|
|
||||||
|
enum class TDataType |
||||||
|
{ |
||||||
|
ASCII, |
||||||
|
Binary, |
||||||
|
}; |
||||||
|
|
||||||
|
struct TFTPCommand; |
||||||
|
struct TDirectoryListEntry; |
||||||
|
|
||||||
|
class CFTPWorker : protected CTask |
||||||
|
{ |
||||||
|
public: |
||||||
|
CFTPWorker(CSocket* pControlSocket, const char* pExpectedUser, const char* pExpectedPassword); |
||||||
|
virtual ~CFTPWorker() override; |
||||||
|
|
||||||
|
virtual void Run() override; |
||||||
|
|
||||||
|
static u8 GetInstanceCount() { return s_nInstanceCount; } |
||||||
|
|
||||||
|
private: |
||||||
|
CSocket* OpenDataConnection(); |
||||||
|
|
||||||
|
bool SendStatus(TFTPStatus StatusCode, const char* pMessage); |
||||||
|
|
||||||
|
bool CheckLoggedIn(); |
||||||
|
|
||||||
|
// Directory navigation
|
||||||
|
CString RealPath(const char* pInBuffer) const; |
||||||
|
const TDirectoryListEntry* BuildDirectoryList(size_t& nOutEntries) const; |
||||||
|
|
||||||
|
// FTP command handlers
|
||||||
|
bool System(const char* pArgs); |
||||||
|
bool Username(const char* pArgs); |
||||||
|
bool Port(const char* pArgs); |
||||||
|
bool Passive(const char* pArgs); |
||||||
|
bool Password(const char* pArgs); |
||||||
|
bool Type(const char* pArgs); |
||||||
|
bool Retrieve(const char* pArgs); |
||||||
|
bool Store(const char* pArgs); |
||||||
|
bool Delete(const char* pArgs); |
||||||
|
bool MakeDirectory(const char* pArgs); |
||||||
|
bool ChangeWorkingDirectory(const char* pArgs); |
||||||
|
bool ChangeToParentDirectory(const char* pArgs); |
||||||
|
bool PrintWorkingDirectory(const char* pArgs); |
||||||
|
bool List(const char* pArgs); |
||||||
|
bool ListFileNames(const char* pArgs); |
||||||
|
bool RenameFrom(const char* pArgs); |
||||||
|
bool RenameTo(const char* pArgs); |
||||||
|
bool Bye(const char* pArgs); |
||||||
|
bool NoOp(const char* pArgs); |
||||||
|
|
||||||
|
CString m_LogName; |
||||||
|
|
||||||
|
// Authentication
|
||||||
|
const char* m_pExpectedUser; |
||||||
|
const char* m_pExpectedPassword; |
||||||
|
|
||||||
|
// TCP sockets
|
||||||
|
CSocket* m_pControlSocket; |
||||||
|
CSocket* m_pDataSocket; |
||||||
|
u16 m_nDataSocketPort; |
||||||
|
CIPAddress m_DataSocketIPAddress; |
||||||
|
|
||||||
|
// Command/data buffers
|
||||||
|
char m_CommandBuffer[FRAME_BUFFER_SIZE]; |
||||||
|
u8 m_DataBuffer[FRAME_BUFFER_SIZE]; |
||||||
|
|
||||||
|
// Session state
|
||||||
|
CString m_User; |
||||||
|
CString m_Password; |
||||||
|
TDataType m_DataType; |
||||||
|
TTransferMode m_TransferMode; |
||||||
|
CString m_CurrentPath; |
||||||
|
CString m_RenameFrom; |
||||||
|
|
||||||
|
static void FatFsPathToFTPPath(const char* pInBuffer, char* pOutBuffer, size_t nSize); |
||||||
|
static void FTPPathToFatFsPath(const char* pInBuffer, char* pOutBuffer, size_t nSize); |
||||||
|
|
||||||
|
static void FatFsParentPath(const char* pInBuffer, char* pOutBuffer, size_t nSize); |
||||||
|
|
||||||
|
static void FormatLastModifiedDate(u16 nDate, char* pOutBuffer, size_t nSize); |
||||||
|
static void FormatLastModifiedTime(u16 nDate, char* pOutBuffer, size_t nSize); |
||||||
|
|
||||||
|
static const TFTPCommand Commands[]; |
||||||
|
static u8 s_nInstanceCount; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,193 @@ |
|||||||
|
|
||||||
|
//
|
||||||
|
// utility.h
|
||||||
|
//
|
||||||
|
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
|
||||||
|
// Copyright (C) 2020-2023 Dale Whinham <daleyo@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of mt32-pi.
|
||||||
|
//
|
||||||
|
// mt32-pi is free software: you can redistribute it and/or modify it under the
|
||||||
|
// terms of the GNU General Public License as published by the Free Software
|
||||||
|
// Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
// version.
|
||||||
|
//
|
||||||
|
// mt32-pi is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
// details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef _utility_h |
||||||
|
#define _utility_h |
||||||
|
|
||||||
|
#include <circle/string.h> |
||||||
|
#include <circle/util.h> |
||||||
|
|
||||||
|
// Macro to extract the string representation of an enum
|
||||||
|
#define CONFIG_ENUM_VALUE(VALUE, STRING) VALUE, |
||||||
|
|
||||||
|
// Macro to extract the enum value
|
||||||
|
#define CONFIG_ENUM_STRING(VALUE, STRING) #STRING, |
||||||
|
|
||||||
|
// Macro to declare the enum itself
|
||||||
|
#define CONFIG_ENUM(NAME, VALUES) enum class NAME { VALUES(CONFIG_ENUM_VALUE) } |
||||||
|
|
||||||
|
// Macro to declare an array of string representations for an enum
|
||||||
|
#define CONFIG_ENUM_STRINGS(NAME, DATA) static const char* NAME##Strings[] = { DATA(CONFIG_ENUM_STRING) } |
||||||
|
|
||||||
|
namespace Utility |
||||||
|
{ |
||||||
|
// Templated function for clamping a value between a minimum and a maximum
|
||||||
|
template <class T> |
||||||
|
constexpr T Clamp(const T& nValue, const T& nMin, const T& nMax) |
||||||
|
{ |
||||||
|
return (nValue < nMin) ? nMin : (nValue > nMax) ? nMax : nValue; |
||||||
|
} |
||||||
|
|
||||||
|
// Templated function for taking the minimum of two values
|
||||||
|
template <class T> |
||||||
|
constexpr T Min(const T& nLHS, const T& nRHS) |
||||||
|
{ |
||||||
|
return nLHS < nRHS ? nLHS : nRHS; |
||||||
|
} |
||||||
|
|
||||||
|
// Templated function for taking the maximum of two values
|
||||||
|
template <class T> |
||||||
|
constexpr T Max(const T& nLHS, const T& nRHS) |
||||||
|
{ |
||||||
|
return nLHS > nRHS ? nLHS : nRHS; |
||||||
|
} |
||||||
|
|
||||||
|
// Function for performing a linear interpolation of a value
|
||||||
|
constexpr float Lerp(float nValue, float nMinA, float nMaxA, float nMinB, float nMaxB) |
||||||
|
{ |
||||||
|
return nMinB + (nValue - nMinA) * ((nMaxB - nMinB) / (nMaxA - nMinA)); |
||||||
|
} |
||||||
|
|
||||||
|
// Return number of elements in an array
|
||||||
|
template <class T, size_t N> |
||||||
|
constexpr size_t ArraySize(const T(&)[N]) { return N; } |
||||||
|
|
||||||
|
// Returns whether some value is a power of 2
|
||||||
|
template <class T> |
||||||
|
constexpr bool IsPowerOfTwo(const T& nValue) |
||||||
|
{ |
||||||
|
return nValue && ((nValue & (nValue - 1)) == 0); |
||||||
|
} |
||||||
|
|
||||||
|
// Rounds a number to a nearest multiple; only works for integer values/multiples
|
||||||
|
template <class T> |
||||||
|
constexpr T RoundToNearestMultiple(const T& nValue, const T& nMultiple) |
||||||
|
{ |
||||||
|
return ((nValue + nMultiple / 2) / nMultiple) * nMultiple; |
||||||
|
} |
||||||
|
|
||||||
|
// Convert between milliseconds and ticks of a 1MHz clock
|
||||||
|
template <class T> |
||||||
|
constexpr T MillisToTicks(const T& nMillis) |
||||||
|
{ |
||||||
|
return nMillis * 1000; |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
constexpr T TicksToMillis(const T& nTicks) |
||||||
|
{ |
||||||
|
return nTicks / 1000; |
||||||
|
} |
||||||
|
|
||||||
|
// Computes the Roland checksum
|
||||||
|
constexpr u8 RolandChecksum(const u8* pData, size_t nSize) |
||||||
|
{ |
||||||
|
u8 nSum = 0; |
||||||
|
for (size_t i = 0; i < nSize; ++i) |
||||||
|
nSum = (nSum + pData[i]) & 0x7F; |
||||||
|
|
||||||
|
return 128 - nSum; |
||||||
|
} |
||||||
|
|
||||||
|
// Comparators for sorting
|
||||||
|
namespace Comparator |
||||||
|
{ |
||||||
|
template<class T> |
||||||
|
using TComparator = bool (*)(const T&, const T&); |
||||||
|
|
||||||
|
template<class T> |
||||||
|
inline bool LessThan(const T& ObjectA, const T& ObjectB) |
||||||
|
{ |
||||||
|
return ObjectA < ObjectB; |
||||||
|
} |
||||||
|
|
||||||
|
template<class T> |
||||||
|
inline bool GreaterThan(const T& ObjectA, const T& ObjectB) |
||||||
|
{ |
||||||
|
return ObjectA > ObjectB; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool CaseInsensitiveAscending(const CString& StringA, const CString& StringB) |
||||||
|
{ |
||||||
|
return strcasecmp(StringA, StringB) < 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Swaps two objects in-place
|
||||||
|
template<class T> |
||||||
|
inline void Swap(T& ObjectA, T& ObjectB) |
||||||
|
{ |
||||||
|
u8 Buffer[sizeof(T)]; |
||||||
|
memcpy(Buffer, &ObjectA, sizeof(T)); |
||||||
|
memcpy(&ObjectA, &ObjectB, sizeof(T)); |
||||||
|
memcpy(&ObjectB, Buffer, sizeof(T)); |
||||||
|
} |
||||||
|
|
||||||
|
namespace |
||||||
|
{ |
||||||
|
// Quicksort partition function (private)
|
||||||
|
template<class T> |
||||||
|
size_t Partition(T* Items, Comparator::TComparator<T> Comparator, size_t nLow, size_t nHigh) |
||||||
|
{ |
||||||
|
const size_t nPivotIndex = (nHigh + nLow) / 2; |
||||||
|
T* Pivot = &Items[nPivotIndex]; |
||||||
|
|
||||||
|
while (true) |
||||||
|
{ |
||||||
|
while (Comparator(Items[nLow], *Pivot)) |
||||||
|
++nLow; |
||||||
|
|
||||||
|
while (Comparator(*Pivot, Items[nHigh])) |
||||||
|
--nHigh; |
||||||
|
|
||||||
|
if (nLow >= nHigh) |
||||||
|
return nHigh; |
||||||
|
|
||||||
|
Swap(Items[nLow], Items[nHigh]); |
||||||
|
|
||||||
|
// Update pointer if pivot was swapped
|
||||||
|
if (nPivotIndex == nLow) |
||||||
|
Pivot = &Items[nHigh]; |
||||||
|
else if (nPivotIndex == nHigh) |
||||||
|
Pivot = &Items[nLow]; |
||||||
|
|
||||||
|
++nLow; |
||||||
|
--nHigh; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Sorts an array in-place using the Tony Hoare Quicksort algorithm
|
||||||
|
template <class T> |
||||||
|
void QSort(T* Items, Comparator::TComparator<T> Comparator, size_t nLow, size_t nHigh) |
||||||
|
{ |
||||||
|
if (nLow < nHigh) |
||||||
|
{ |
||||||
|
size_t p = Partition(Items, Comparator, nLow, nHigh); |
||||||
|
QSort(Items, Comparator, nLow, p); |
||||||
|
QSort(Items, Comparator, p + 1, nHigh); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,106 @@ |
|||||||
|
//
|
||||||
|
// udpmididevice.cpp
|
||||||
|
//
|
||||||
|
// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi
|
||||||
|
// Copyright (C) 2022 The MiniDexed Team
|
||||||
|
//
|
||||||
|
// Original author of this class:
|
||||||
|
// R. Stange <rsta2@o2online.de>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <circle/logger.h> |
||||||
|
#include <cstring> |
||||||
|
#include "udpmididevice.h" |
||||||
|
#include <assert.h> |
||||||
|
|
||||||
|
//#define VIRTUALCABLE 24
|
||||||
|
|
||||||
|
LOGMODULE("rtpmididevice"); |
||||||
|
|
||||||
|
CUDPMIDIDevice::CUDPMIDIDevice (CMiniDexed *pSynthesizer, |
||||||
|
CConfig *pConfig, CUserInterface *pUI) |
||||||
|
: CMIDIDevice (pSynthesizer, pConfig, pUI), |
||||||
|
m_pSynthesizer (pSynthesizer), |
||||||
|
m_pConfig (pConfig) |
||||||
|
|
||||||
|
|
||||||
|
//m_Serial (pInterrupt, TRUE),
|
||||||
|
//m_nSerialState (0),
|
||||||
|
//m_nSysEx (0),
|
||||||
|
//m_SendBuffer (&m_Serial)
|
||||||
|
{ |
||||||
|
AddDevice ("udp"); |
||||||
|
/*for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
|
||||||
|
{ |
||||||
|
m_ChannelMap[nTG] = Disabled; |
||||||
|
}*/ |
||||||
|
} |
||||||
|
|
||||||
|
CUDPMIDIDevice::~CUDPMIDIDevice (void) |
||||||
|
{ |
||||||
|
m_pSynthesizer = 0; |
||||||
|
} |
||||||
|
|
||||||
|
boolean CUDPMIDIDevice::Initialize (void) |
||||||
|
{ |
||||||
|
m_pAppleMIDIParticipant = new CAppleMIDIParticipant(&m_Random, this); |
||||||
|
if (!m_pAppleMIDIParticipant->Initialize()) |
||||||
|
{ |
||||||
|
LOGERR("Failed to init RTP listener"); |
||||||
|
return false; //continue without rtp midi
|
||||||
|
} |
||||||
|
else |
||||||
|
LOGNOTE("RTP Listener initialized"); |
||||||
|
return true; |
||||||
|
m_pUDPMIDIReceiver = new CUDPMIDIReceiver(this); |
||||||
|
if (!m_pUDPMIDIReceiver->Initialize()) |
||||||
|
{ |
||||||
|
LOGERR("Failed to init UDP MIDI receiver"); |
||||||
|
delete m_pUDPMIDIReceiver; |
||||||
|
m_pUDPMIDIReceiver = nullptr; |
||||||
|
} |
||||||
|
else |
||||||
|
LOGNOTE("UDP MIDI receiver initialized"); |
||||||
|
} |
||||||
|
|
||||||
|
// Methods to handle MIDI events
|
||||||
|
|
||||||
|
void CUDPMIDIDevice::OnAppleMIDIDataReceived(const u8* pData, size_t nSize) |
||||||
|
{ |
||||||
|
LOGNOTE("Recieved RTPUDP MIDI Data"); |
||||||
|
printf ("MIDI-RTP: %02X %02X\n", |
||||||
|
(unsigned) pData[0], (unsigned) pData[1]); |
||||||
|
MIDIMessageHandler(pData, nSize); |
||||||
|
} |
||||||
|
|
||||||
|
void CUDPMIDIDevice::OnAppleMIDIConnect(const CIPAddress* pIPAddress, const char* pName) |
||||||
|
{ |
||||||
|
LOGNOTE("RTP Device connected"); |
||||||
|
//AddDevice ("udp1");
|
||||||
|
} |
||||||
|
|
||||||
|
void CUDPMIDIDevice::OnAppleMIDIDisconnect(const CIPAddress* pIPAddress, const char* pName) |
||||||
|
{ |
||||||
|
LOGNOTE("RTP Device disconnected"); |
||||||
|
} |
||||||
|
|
||||||
|
void CUDPMIDIDevice::OnUDPMIDIDataReceived(const u8* pData, size_t nSize) |
||||||
|
{ |
||||||
|
LOGNOTE("Recieved UDP MIDI Data"); |
||||||
|
printf ("MIDI-UDP: %02X %02X\n", |
||||||
|
(unsigned) pData[0], (unsigned) pData[1]); |
||||||
|
MIDIMessageHandler(pData, nSize); |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
//
|
||||||
|
// udpmididevice.h
|
||||||
|
//
|
||||||
|
// Virtual midi device for data recieved on network
|
||||||
|
//
|
||||||
|
// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi
|
||||||
|
// Copyright (C) 2022 The MiniDexed Team
|
||||||
|
//
|
||||||
|
// Original author of this class:
|
||||||
|
// R. Stange <rsta2@o2online.de>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
#ifndef _rtpmididevice_h |
||||||
|
#define _rtpmididevice_h |
||||||
|
|
||||||
|
#include "mididevice.h" |
||||||
|
#include "config.h" |
||||||
|
#include "net/applemidi.h" |
||||||
|
#include "net/udpmidi.h" |
||||||
|
|
||||||
|
//#include <circle/interrupt.h>
|
||||||
|
//#include <circle/serial.h>
|
||||||
|
//#include <circle/writebuffer.h>
|
||||||
|
//#include <circle/types.h>
|
||||||
|
|
||||||
|
class CMiniDexed; |
||||||
|
|
||||||
|
class CUDPMIDIDevice : CAppleMIDIHandler, CUDPMIDIHandler, public CMIDIDevice |
||||||
|
{ |
||||||
|
public: |
||||||
|
CUDPMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI); |
||||||
|
~CUDPMIDIDevice (void); |
||||||
|
|
||||||
|
boolean Initialize (void); |
||||||
|
virtual void OnAppleMIDIDataReceived(const u8* pData, size_t nSize) override; |
||||||
|
virtual void OnAppleMIDIConnect(const CIPAddress* pIPAddress, const char* pName) override; |
||||||
|
virtual void OnAppleMIDIDisconnect(const CIPAddress* pIPAddress, const char* pName) override; |
||||||
|
virtual void OnUDPMIDIDataReceived(const u8* pData, size_t nSize) override; |
||||||
|
//void OnAppleMIDIDataReceived(const u8* pData, size_t nSize);
|
||||||
|
//void OnAppleMIDIConnect(const CIPAddress* pIPAddress, const char* pName);
|
||||||
|
//void OnAppleMIDIDisconnect(const CIPAddress* pIPAddress, const char* pName);
|
||||||
|
|
||||||
|
//void Process (void);
|
||||||
|
|
||||||
|
//void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) override;
|
||||||
|
|
||||||
|
private: |
||||||
|
CMiniDexed *m_pSynthesizer; |
||||||
|
CConfig *m_pConfig; |
||||||
|
//u8 m_ChannelMap[CConfig::ToneGenerators];
|
||||||
|
//CSerialDevice m_Serial;
|
||||||
|
//unsigned m_nSerialState;
|
||||||
|
//unsigned m_nSysEx;
|
||||||
|
//u8 m_SerialMessage[MAX_MIDI_MESSAGE];
|
||||||
|
|
||||||
|
//CWriteBufferDevice m_SendBuffer;
|
||||||
|
CBcmRandomNumberGenerator m_Random; |
||||||
|
//CAppleMIDIHandler* m_MIDIHandler;
|
||||||
|
CAppleMIDIParticipant* m_pAppleMIDIParticipant; // AppleMIDI participant instance
|
||||||
|
CUDPMIDIReceiver* m_pUDPMIDIReceiver; |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue