size_t m_offset;
public:
CDeserialiser(size_t Length, const uint8_t *Buffer);
+ bool IsConsumed() const;
::uint8_t ReadU8();
::uint16_t ReadU16();
::int16_t ReadS16();
- ::std::string ReadString();
+ const ::std::string ReadString();
};
class CSerialiser
void WriteU8(::uint8_t val);
void WriteU16(::uint16_t val);
void WriteS16(::int16_t val);
+ void WriteBuffer(size_t n, const void* val);
void WriteString(const char* val, size_t n);
void WriteString(const char* val) {
WriteString(val, ::std::char_traits<char>::length(val));
WriteString(val.data(), val.size());
}
void WriteSub(const CSerialiser& val);
+
+ const ::std::vector<uint8_t>& Compact();
};
};
*/
#include <serialisation.hpp>
#include <cstddef>
+#include <stdexcept>
namespace AxWin {
{
}
+bool CDeserialiser::IsConsumed() const
+{
+ return m_offset == m_length;
+}
+
::uint8_t CDeserialiser::ReadU8()
{
- return 0;
+ if( m_offset + 1 >= m_length )
+ throw ::std::out_of_range("CDeserialiser::ReadU8");
+ uint8_t rv = m_data[m_offset];
+ m_offset ++;
+ return rv;
}
::uint16_t CDeserialiser::ReadU16()
{
- return 0;
+ if( m_offset + 2 >= m_length )
+ throw ::std::out_of_range("CDeserialiser::ReadU16");
+
+ uint16_t rv = m_data[m_offset] | ((uint16_t)m_data[m_offset+1] << 8);
+ m_offset += 2;
+ return rv;
}
::int16_t CDeserialiser::ReadS16()
{
- return 0;
+ uint16_t rv_u = ReadU16();
+ if( rv_u < 0x8000 )
+ return rv_u;
+ else
+ return ~rv_u + 1;
}
-::std::string CDeserialiser::ReadString()
+const ::std::string CDeserialiser::ReadString()
{
- return "";
+ if( m_offset + 1 >= m_length )
+ throw ::std::out_of_range("CDeserialiser::ReadString");
+ uint8_t len = m_data[m_offset];
+ m_offset ++;
+
+ if( m_offset + len >= m_length )
+ throw ::std::out_of_range("CDeserialiser::ReadString");
+
+ ::std::string ret( reinterpret_cast<const char*>(m_data+m_offset), len );
+ m_offset += len;
+ return ret;
}
CSerialiser::CSerialiser()
}
}
+void CSerialiser::WriteBuffer(size_t n, const void* val)
+{
+ const uint8_t* val8 = static_cast<const uint8_t*>(val);
+ if( n > 0xFFFF )
+ throw ::std::length_error("CSerialiser::WriteBuffer");
+ m_data.reserve( m_data.size() + 2 + n );
+ WriteU16(n);
+ for( size_t i = 0; i < n; i ++ )
+ m_data.push_back(val8[i]);
+}
+
void CSerialiser::WriteString(const char* val, size_t n)
{
- //if( n >= 256 )
- // throw ::std::out_of_range("CSerialiser::WriteString");
+ if( n > 0xFF )
+ throw ::std::length_error("CSerialiser::WriteString");
+ m_data.reserve( m_data.size() + 1 + n );
WriteU8(n);
for( size_t i = 0; i < n; i ++ )
- WriteU8(val[i]);
+ m_data.push_back(val[i]);
}
void CSerialiser::WriteSub(const CSerialiser& val)
{
+ // TODO: Append reference to sub-buffer contents
m_data.reserve( m_data.size() + val.m_data.size() );
for( auto byte : val.m_data )
m_data.push_back( byte );
}
+const ::std::vector<uint8_t>& CSerialiser::Compact()
+{
+ return m_data;
+}
+
}; // namespace AxWin
* - IPC Client
*/
#include <CClient.hpp>
+#include <IIPCChannel.hpp>
+#include <ipc.hpp>
namespace AxWin {
-CClient::CClient(IIPCChannel& channel):
+CClient::CClient(::AxWin::IIPCChannel& channel):
m_channel(channel)
{
}
+CClient::~CClient()
+{
+ ::AxWin::IPC::DeregisterClient(*this);
+}
+
CWindow* CClient::GetWindow(int ID)
{
if( ID == 0 )
m_windows[ID] = window;
}
-void CClient::SendMessage(CSerialiser& reply)
+void CClient::HandleMessage(CDeserialiser& message)
{
+ try {
+ IPC::HandleMessage(*this, message);
+ if( !message.IsConsumed() )
+ {
+ _SysDebug("NOTICE - CClient::HandleMessage - Trailing data in message");
+ }
+ }
+ catch( const ::std::exception& e )
+ {
+ _SysDebug("ERROR - Exception while processing message from client: %s", e.what());
+ }
+ catch( ... )
+ {
+ _SysDebug("ERROR - Unknown exception while processing message from client");
+ }
}
}; // namespace AxWin
* CIPCChannel_AcessIPCPipe.cpp
* - IPC Channel :: Acess' IPC Pipe /Devices/ipcpipe/<name>
*/
+#include <ipc.hpp>
#include <CIPCChannel_AcessIPCPipe.hpp>
+#include <cerrno>
+#include <system_error>
+#include <acess/sys.h>
+#include <algorithm>
namespace AxWin {
CIPCChannel_AcessIPCPipe::CIPCChannel_AcessIPCPipe(const ::std::string& suffix)
{
-
+ ::std::string path = "/Devices/ipcpipe/" + suffix;
+ m_fd = _SysOpen(path.c_str(), OPENFLAG_CREATE);
+ if(m_fd == -1) {
+ _SysDebug("Failed to open %s: %s", path.c_str(), strerror(errno));
+ throw ::std::system_error(errno, ::std::system_category());
+ }
}
CIPCChannel_AcessIPCPipe::~CIPCChannel_AcessIPCPipe()
{
+ _SysClose(m_fd);
}
int CIPCChannel_AcessIPCPipe::FillSelect(fd_set& rfds)
{
- return 0;
+ _SysDebug("CIPCChannel_AcessIPCPipe::FillSelect");
+ int maxfd = m_fd;
+ FD_SET(m_fd, &rfds);
+
+ for( auto& clientref : m_clients )
+ {
+ _SysDebug("CIPCChannel_AcessIPCPipe::FillSelect - FD%i", clientref.m_fd);
+ maxfd = ::std::max(maxfd, clientref.m_fd);
+ FD_SET(clientref.m_fd, &rfds);
+ }
+
+ return maxfd+1;
}
void CIPCChannel_AcessIPCPipe::HandleSelect(const fd_set& rfds)
{
+ _SysDebug("CIPCChannel_AcessIPCPipe::HandleSelect");
+ if( FD_ISSET(m_fd, &rfds) )
+ {
+ _SysDebug("CIPCChannel_AcessIPCPipe::HandleSelect - New client on FD %i", m_fd);
+ int newfd = _SysOpenChild(m_fd, "newclient", OPENFLAG_READ|OPENFLAG_WRITE);
+ _SysDebug("newfd = %i", newfd);
+
+ // emplace creates a new object within the list
+ m_clients.emplace( m_clients.end(), *this, newfd );
+ IPC::RegisterClient( m_clients.back() );
+ }
+
+ for( auto it = m_clients.begin(); it != m_clients.end(); )
+ {
+ CClient_AcessIPCPipe& clientref = *it;
+ _SysDebug("CIPCChannel_AcessIPCPipe::HandleSelect - Trying FD%i", clientref.m_fd);
+ ++ it;
+
+ if( FD_ISSET(clientref.m_fd, &rfds) )
+ {
+ try {
+ clientref.HandleReceive();
+ }
+ catch( const ::std::exception& e ) {
+ _SysDebug("ERROR - Exception processing IPCPipe FD%i: %s",
+ clientref.m_fd, e.what()
+ );
+ it = m_clients.erase(--it);
+ }
+ }
+ }
+ _SysDebug("CIPCChannel_AcessIPCPipe::HandleSelect - END");
+}
+
+
+CClient_AcessIPCPipe::CClient_AcessIPCPipe(::AxWin::IIPCChannel& channel, int fd):
+ CClient(channel),
+ m_fd(fd),
+ m_rxbuf(0x1000)
+{
+}
+
+CClient_AcessIPCPipe::~CClient_AcessIPCPipe()
+{
+ _SysClose(m_fd);
+ _SysDebug("Closed client FD%i", m_fd);
+}
+
+void CClient_AcessIPCPipe::SendMessage(CSerialiser& message)
+{
+ const ::std::vector<uint8_t>& data = message.Compact();
+
+ _SysDebug("CClient_AcessIPCPipe::SendMessage - %i bytes to %i", data.size(), m_fd);
+ _SysWrite(m_fd, data.data(), data.size());
+}
+
+void CClient_AcessIPCPipe::HandleReceive()
+{
+ size_t len = _SysRead(m_fd, &m_rxbuf[0], m_rxbuf.capacity());
+ if( len == (size_t)-1 )
+ throw ::std::system_error(errno, ::std::system_category());
+
+ CDeserialiser message(len, &m_rxbuf[0]);
+ CClient::HandleMessage(message);
}
};
include ../../Makefile.cfg
+DIR := Apps/AxWin/4.0
+
CPPFLAGS += -Iinclude/ -I../Common/include/
OBJ := main.o ipc.o CConfig.o video.o input.o timing.o
OBJ += compositor.o CWindow.o
#include "CWindow.hpp"
#include "serialisation.hpp"
-class IIPCChannel;
-
namespace AxWin {
+class IIPCChannel;
+
class CClient
{
IIPCChannel& m_channel;
//::std::map<unsigned int,CWindow*> m_windows;
CWindow* m_windows[1];
public:
- CClient(IIPCChannel& channel);
- ~CClient();
+ CClient(::AxWin::IIPCChannel& channel);
+ virtual ~CClient();
CWindow* GetWindow(int ID);
void SetWindow(int ID, CWindow* window);
- void SendMessage(CSerialiser& reply);
+ virtual void SendMessage(CSerialiser& reply) = 0;
+ void HandleMessage(CDeserialiser& message);
};
#define _CIPCCHANNEL_ACESSIPCPIPE_HPP_
#include <IIPCChannel.hpp>
+#include <CClient.hpp>
#include <string>
#include <list>
namespace AxWin {
-class CClient_AcessIPCPipe
+class CClient_AcessIPCPipe:
+ public CClient
{
+ friend class CIPCChannel_AcessIPCPipe;
+ int m_fd;
+ ::std::vector<uint8_t> m_rxbuf;
public:
+ CClient_AcessIPCPipe(IIPCChannel& channel, int fd);
+ ~CClient_AcessIPCPipe();
+
+ void SendMessage(CSerialiser& message);
+
+ void HandleReceive();
};
class CIPCChannel_AcessIPCPipe:
public IIPCChannel
{
- int m_mainFD;
+ int m_fd;
::std::list<CClient_AcessIPCPipe> m_clients;
public:
CIPCChannel_AcessIPCPipe(const ::std::string& suffix);
#include <acess/sys.h>
};
+#include <serialisation.hpp>
#include <CConfigIPC.hpp>
namespace AxWin {
+
class CCompositor;
+class CClient;
namespace IPC {
extern void Initialise(const CConfigIPC& config, CCompositor& compositor);
extern int FillSelect(::fd_set& rfds);
-extern void HandleSelect(::fd_set& rfds);
+extern void HandleSelect(const ::fd_set& rfds);
+extern void RegisterClient(CClient& client);
+extern void DeregisterClient(CClient& client);
+extern void HandleMessage(CClient& client, CDeserialiser& message);
class CClientFailure:
public ::std::exception
int CInput::FillSelect(::fd_set& rfds)
{
FD_SET(m_keyboardFD, &rfds);
- FD_SET(m_mouseFD, &rfds);
+ if( m_mouseFD != -1 )
+ FD_SET(m_mouseFD, &rfds);
return ::std::max(m_keyboardFD, m_mouseFD)+1;
}
{
if( FD_ISSET(m_keyboardFD, &rfds) )
{
- // TODO: Read keystroke and handle
+ uint32_t codepoint;
+ static uint32_t scancode;
+ #define KEY_CODEPOINT_MASK 0x3FFFFFFF
+
+ size_t readlen = _SysRead(m_keyboardFD, &codepoint, sizeof(codepoint));
+ if( readlen != sizeof(codepoint) )
+ {
+ // oops, error
+ _SysDebug("Terminal read failed? (%i != %i)", readlen, sizeof(codepoint));
+ }
+
+// _SysDebug("Keypress 0x%x", codepoint);
+
+ switch(codepoint & 0xC0000000)
+ {
+ case 0x00000000: // Key pressed
+ //WM_Input_KeyDown(codepoint & KEY_CODEPOINT_MASK, scancode);
+ case 0x80000000: // Key release
+ //WM_Input_KeyFire(codepoint & KEY_CODEPOINT_MASK, scancode);
+ scancode = 0;
+ break;
+ case 0x40000000: // Key refire
+ //WM_Input_KeyUp(codepoint & KEY_CODEPOINT_MASK, scancode);
+ scancode = 0;
+ break;
+ case 0xC0000000: // Raw scancode
+ scancode = codepoint & KEY_CODEPOINT_MASK;
+ break;
+ }
}
- if( FD_ISSET(m_mouseFD, &rfds) )
+ if( m_mouseFD != -1 && FD_ISSET(m_mouseFD, &rfds) )
{
// TODO: Read mouse event and handle
}
int FillSelect(fd_set& rfds)
{
int ret = 0;
+ _SysDebug("IPC::FillSelect");
for( auto channel : glChannels )
{
+ _SysDebug("IPC::FillSelect - channel=%p", channel);
ret = ::std::max(ret, channel->FillSelect(rfds));
}
return ret;
}
-void HandleSelect(fd_set& rfds)
+void HandleSelect(const fd_set& rfds)
{
+ _SysDebug("IPC::HandleSelect");
for( auto channel : glChannels )
{
+ _SysDebug("IPC::HandleSelect - channel=%p", channel);
channel->HandleSelect(rfds);
}
}
#include <algorithm>
#include <common.hpp>
+#include <system_error>
+#include <cerrno>
+
extern "C" {
#include <stdio.h>
#include <stdint.h>
}
catch(const std::exception& e) {
fprintf(stderr, "Exception: %s\n", e.what());
+ _SysDebug("Config threw exception: %s", e.what());
+ return 1;
+ }
+
+ CVideo* vid = 0;
+ CCompositor* compositor = 0;
+ CInput* input = 0;
+
+ try {
+ // - Open graphics
+ vid = new CVideo(config.m_video);
+ ::_SysDebug("vid = %p", vid);
+ // - Initialise compositor structures
+ compositor = new CCompositor(/*config.m_compositor,*/ *vid);
+ ::_SysDebug("compositor = %p", compositor);
+ // - Open input
+ input = new CInput(config.m_input, *compositor);
+ ::_SysDebug("input = %p", input);
+ // > Handles hotkeys?
+ // - Bind IPC channels
+ IPC::Initialise(config.m_ipc, *compositor);
+ ::_SysDebug("IPC up");
+ // - Start root child process (from config)
+ // TODO: Spin up child process
+
+ {
+ const char *interface_app = "/Acess/Apps/AxWin/4.0/AxWinUI";
+ const char *argv[] = {interface_app, NULL};
+ int rv = _SysSpawn(interface_app, argv, NULL, 0, NULL, NULL);
+ if( rv < 0 ) {
+ _SysDebug("_SysSpawn chucked a sad, rv=%i, errno=%i", rv, _errno);
+ throw ::std::system_error(errno, ::std::system_category());
+ }
+ }
+ }
+ catch(const ::std::exception& e) {
+ fprintf(stderr, "Startup threw exception: %s\n", e.what());
+ _SysDebug("Startup threw exception: %s", e.what());
+ delete input;
+ delete compositor;
+ delete vid;
return 1;
}
- // - Open graphics
- CVideo* vid = new CVideo(config.m_video);
- // - Initialise compositor structures
- CCompositor* compositor = new CCompositor(/*config.m_compositor,*/ *vid);
- // - Open input
- CInput* input = new CInput(config.m_input, *compositor);
- // > Handles hotkeys?
- // - Bind IPC channels
- IPC::Initialise(config.m_ipc, *compositor);
- // - Start root child process (from config)
- // TODO: Spin up child process
// - Event loop
for( ;; )
{
int nfd = 0;
- fd_set rfds;
+ fd_set rfds, efds;
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+
nfd = ::std::max(nfd, input->FillSelect(rfds));
nfd = ::std::max(nfd, IPC::FillSelect(rfds));
+ for( int i = 0; i < nfd; i ++ )
+ if( FD_ISSET(i, &rfds) )
+ FD_SET(i, &efds);
+
+ for( int i = 0; i < nfd; i ++ ) {
+ if( FD_ISSET(i, &rfds) ) {
+ _SysDebug("FD%i", i);
+ }
+ }
+
// TODO: Support _SysSendMessage IPC?
int64_t timeout = Timing::GetTimeToNextEvent();
- int rv = ::_SysSelect(nfd, &rfds, NULL, &rfds, &timeout, 0);
+ int64_t *timeoutp;
+ if( timeout >= 0 ) {
+ ::_SysDebug("Calling select with timeout %lli", timeout);
+ timeoutp = &timeout;
+ }
+ else {
+ ::_SysDebug("Calling select with no timeout");
+ timeoutp = 0;
+ }
+ int rv = ::_SysSelect(nfd, &rfds, NULL, NULL/*&efds*/, timeoutp, 0);
+
+ for( int i = 0; i < nfd; i ++ ) {
+ if( FD_ISSET(i, &rfds) ) {
+ _SysDebug("FD%i", i);
+ }
+ }
+ _SysDebug("rv=%i, timeout=%lli", rv, timeout);
Timing::CheckEvents();
int64_t GetTimeToNextEvent()
{
- return 10*1000;
+ return -1;
}
void CheckEvents()