In the next rewrite round, I suggest to cleanup Order implementation using
something reassembling the attached files
Steph
--
http://nct.ysagoon.com
#include "msg.h"
#include "../utils/utils.h"
#include <cassert>
#include <iostream>
#include <iomanip>
#include <map>
namespace Aseba
{
//! Static class that fills a table of known messages types in its constructor
class MessageTypesInitializer
{
public:
//! Constructor, register all known messages types
MessageTypesInitializer()
{
registerMessageType<Presence>(ASEBA_MESSAGE_PRESENCE);
registerMessageType<Description>(ASEBA_MESSAGE_DESCRIPTION);
registerMessageType<Variables>(ASEBA_MESSAGE_VARIABLES);
registerMessageType<ExecutionState>(ASEBA_MESSAGE_EXECUTION_STATE);
registerMessageType<ArrayAccessOutOfBounds>(ASEBA_MESSAGE_ARRAY_ACCESS_OUT_OF_BOUND);
registerMessageType<DivisionByZero>(ASEBA_MESSAGE_DIVISION_BY_ZERO);
registerMessageType<AttachDebugger>(ASEBA_MESSAGE_ATTACH_DEBUGGER);
registerMessageType<DetachDebugger>(ASEBA_MESSAGE_DETACH_DEBUGGER);
registerMessageType<SetBytecode>(ASEBA_MESSAGE_SET_BYTECODE);
registerMessageType<SetupEvent>(ASEBA_MESSAGE_SETUP_EVENT);
registerMessageType<BackgroundRun>(ASEBA_MESSAGE_BACKGROUND_RUN);
registerMessageType<Stop>(ASEBA_MESSAGE_STOP);
registerMessageType<Step>(ASEBA_MESSAGE_STEP);
registerMessageType<BreakpointSet>(ASEBA_MESSAGE_BREAKPOINT_SET);
registerMessageType<BreakpointClear>(ASEBA_MESSAGE_BREAKPOINT_CLEAR);
registerMessageType<BreakpointClearAll>(ASEBA_MESSAGE_BREAKPOINT_CLEAR_ALL);
registerMessageType<GetVariables>(ASEBA_MESSAGE_GET_VARIABLES);
}
//! Register a message type by storing a pointer to its constructor
template<typename Sub>
void registerMessageType(uint16 type)
{
messagesTypes[type] = &Creator<Sub>;
}
//! Create an instance of a registered message type
Message *createMessage(uint16 type)
{
if (messagesTypes.find(type) == messagesTypes.end())
{
std::cerr << "Message of type " << std::hex << std::showbase << std::setw(4) << type << " is unknown, aborting.\n\nKnown messages are:\n";
dumpKnownMessagesTypes(std::cerr);
std::cerr << std::endl;
assert(false);
}
return messagesTypes[type]();
}
//! Print the list of registered messages types to stream
void dumpKnownMessagesTypes(std::ostream &stream)
{
for (std::map<uint16, CreatorFunc>::iterator it = messagesTypes.begin(); it != messagesTypes.end(); ++it)
stream << "\t" << std::hex << std::showbase << std::setw(4) << it->first << "\n";
}
protected:
//! Pointer to constructor of class Message
typedef Message* (*CreatorFunc)();
std::map<uint16, CreatorFunc> messagesTypes; //!< table of known messages types
//! Create a new message of type Sub
template<typename Sub>
static Message* Creator()
{
return new Sub();
}
} messageTypesInitializer; //!< static instance, used only to have its constructor called on startup
//
Message::Message()
{
readPos = 0;
}
Message::~Message()
{
}
void Message::serialize(int fd)
{
data.resize(0);
serializeSpecific();
assert(data.size() + 2 < 65536);
uint16 len = static_cast<uint16>(data.size());
write(fd, &len, 2);
write(fd, &type, 2);
write(fd, &data[0], data.size());
}
Message *Message::receive(int fd)
{
// read header
uint16 len, type;
read(fd, &len, 2);
read(fd, &type, 2);
// create message
Message *message = messageTypesInitializer.createMessage(type);
// preapare message
message->type = type;
message->data.resize(len);
read(fd, &message->data[0], len);
message->readPos = 0;
// deserialize it
message->deserializeSpecific();
assert(message->readPos == message->data.size());
return message;
}
void Message::dump(std::ostream &stream)
{
stream << std::hex << std::showbase << std::setw(4) << type << " " << *this << " : ";
dumpSpecific(stream);
}
template<typename T>
void Message::add(const T& val)
{
size_t pos = data.size();
data.resize(pos + sizeof(T));
const uint8 *ptr = reinterpret_cast<const uint8 *>(&val);
std::copy(ptr, ptr + sizeof(T), &data[pos]);
}
template<>
void Message::add(const std::string& val)
{
assert(val.length() <= 255);
add(static_cast<uint8>(val.length()));
for (size_t i = 0; i < val.length(); i++)
add(val[i]);
}
template<typename T>
T Message::get()
{
assert(readPos + sizeof(T) <= data.size());
size_t pos = readPos;
readPos += sizeof(T);
T val;
uint8 *ptr = reinterpret_cast<uint8 *>(&val);
std::copy(&data[pos], &data[pos + sizeof(T)], ptr);
return val;
}
template<>
std::string Message::get()
{
std::string s;
size_t len = get<uint8>();
s.resize(len);
for (size_t i = 0; i < len; i++)
s[i] = get<uint8>();
return s;
}
//
void UserMessage::dumpSpecific(std::ostream &stream)
{
stream << "user message of size " << data.size();
}
//
void BootloaderDataRead::serializeSpecific()
{
for (size_t i = 0 ; i < sizeof(data); i++)
add(data[i]);
}
void BootloaderDataRead::deserializeSpecific()
{
for (size_t i = 0 ; i < sizeof(data); i++)
data[i] = get<uint8>();
}
void BootloaderDataRead::dumpSpecific(std::ostream &stream)
{
for (size_t i = 0 ; i < sizeof(data); i++)
stream << std::hex << (unsigned)data[i] << " ";
}
//
void BootloaderAck::serializeSpecific()
{
add(errorCode);
if (errorCode == 2)
add(errorAddress);
}
void BootloaderAck::deserializeSpecific()
{
errorCode = get<uint16>();
if (errorCode == 2)
errorAddress = get<uint16>();
}
void BootloaderAck::dumpSpecific(std::ostream &stream)
{
switch (errorCode)
{
case 0: stream << "success"; break;
case 1: stream << "error, invalid frame size"; break;
case 2: stream << "error, programming failed at low address " << std::hex << errorAddress; break;
case 3: stream << "error, not programming"; break;
default: stream << "unknown error"; break;
}
}
//
void Description::serializeSpecific()
{
add(bytecodeSize);
add(stackSize);
add(variablesSize);
add(nodeName);
assert(variablesNames.size() == variablesSizes.size());
add(static_cast<uint16>(variablesNames.size()));
for (size_t i = 0; i < variablesNames.size(); i++)
{
add(variablesNames[i]);
add(variablesSizes[i]);
}
}
void Description::deserializeSpecific()
{
bytecodeSize = get<uint16>();
stackSize = get<uint16>();
variablesSize = get<uint16>();
nodeName = get<std::string>();
uint16 namedVariablesCount = get<uint16>();
variablesNames.resize(namedVariablesCount);
variablesSizes.resize(namedVariablesCount);
for (size_t i = 0; i < variablesNames.size(); i++)
{
variablesNames[i] = get<std::string>();
variablesSizes[i] = get<uint16>();
}
}
void Description::dumpSpecific(std::ostream &stream)
{
stream << "Node " << nodeName << "\n";
stream << "bytecode " << bytecodeSize << ", stack " << stackSize << ", variables " << variablesSize;
for (size_t i = 0; i < variablesNames.size(); i++)
stream << "\n\t" << variablesNames[i] << " : " << variablesSizes[i];
}
//
void Variables::serializeSpecific()
{
add(start);
for (size_t i = 0; i < variables.size(); i++)
add(variables[i]);
}
void Variables::deserializeSpecific()
{
start = get<uint16>();
variables.resize((data.size() - readPos) / 2);
for (size_t i = 0; i < variables.size(); i++)
variables[i] = get<sint16>();
}
void Variables::dumpSpecific(std::ostream &stream)
{
stream << "start " << start << ", variables vector of size " << variables.size();
}
//
void ExecutionState::serializeSpecific()
{
add(pc);
add(flags);
}
void ExecutionState::deserializeSpecific()
{
pc = get<uint16>();
flags = get<uint16>();
}
void ExecutionState::dumpSpecific(std::ostream &stream)
{
stream << "pc " << pc << ", flags " << flags;
}
//
void ArrayAccessOutOfBounds::serializeSpecific()
{
add(pc);
add(index);
}
void ArrayAccessOutOfBounds::deserializeSpecific()
{
pc = get<uint16>();
index = get<uint16>();
}
void ArrayAccessOutOfBounds::dumpSpecific(std::ostream &stream)
{
stream << "pc " << pc << ", index " << index;
}
//
void DivisionByZero::serializeSpecific()
{
add(pc);
}
void DivisionByZero::deserializeSpecific()
{
pc = get<uint16>();
}
void DivisionByZero::dumpSpecific(std::ostream &stream)
{
stream << "pc " << pc;
}
//
void CmdMessage::serializeSpecific()
{
add(dest);
}
void CmdMessage::deserializeSpecific()
{
dest = get<uint8>();
}
void CmdMessage::dumpSpecific(std::ostream &stream)
{
stream << "debug message dest " << std::hex << (unsigned)dest;
}
//
void BootloaderReadPage::serializeSpecific()
{
add(pageNumber);
}
void BootloaderReadPage::deserializeSpecific()
{
pageNumber = get<uint16>();
}
void BootloaderReadPage::dumpSpecific(std::ostream &stream)
{
stream << "page " << std::hex << pageNumber;
}
//
void BootloaderWritePage::serializeSpecific()
{
add(pageNumber);
}
void BootloaderWritePage::deserializeSpecific()
{
pageNumber = get<uint16>();
}
void BootloaderWritePage::dumpSpecific(std::ostream &stream)
{
stream << "page " << std::hex << pageNumber;
}
//
void BootloaderPageDataWrite::serializeSpecific()
{
for (size_t i = 0 ; i < sizeof(data); i++)
add(data[i]);
}
void BootloaderPageDataWrite::deserializeSpecific()
{
for (size_t i = 0 ; i < sizeof(data); i++)
data[i] = get<uint8>();
}
void BootloaderPageDataWrite::dumpSpecific(std::ostream &stream)
{
for (size_t i = 0 ; i < sizeof(data); i++)
stream << std::hex << (unsigned)data[i] << " ";
}
//
void SetBytecode::serializeSpecific()
{
CmdMessage::serializeSpecific();
for (size_t i = 0; i < bytecode.size(); i++)
add(bytecode[i]);
}
void SetBytecode::deserializeSpecific()
{
CmdMessage::deserializeSpecific();
bytecode.resize((data.size() - readPos) / 2);
for (size_t i = 0; i < bytecode.size(); i++)
bytecode[i] = get<uint16>();
}
void SetBytecode::dumpSpecific(std::ostream &stream)
{
CmdMessage::dumpSpecific(stream);
stream << "bytecode of size " << bytecode.size();
}
//
void SetupEvent::serializeSpecific()
{
CmdMessage::serializeSpecific();
add(eventId);
for (size_t i = 0; i < arguments.size(); i++)
add(arguments[i]);
}
void SetupEvent::deserializeSpecific()
{
CmdMessage::deserializeSpecific();
eventId = get<uint16>();
arguments.resize((data.size() - readPos) / 2);
for (size_t i = 0; i < arguments.size(); i++)
arguments[i] = get<uint16>();
}
void SetupEvent::dumpSpecific(std::ostream &stream)
{
CmdMessage::dumpSpecific(stream);
stream << "event id " << eventId << ", arguments vector of size " << arguments.size();
}
//
void BreakpointSet::serializeSpecific()
{
CmdMessage::serializeSpecific();
add(pc);
}
void BreakpointSet::deserializeSpecific()
{
CmdMessage::deserializeSpecific();
pc = get<uint16>();
}
void BreakpointSet::dumpSpecific(std::ostream &stream)
{
CmdMessage::dumpSpecific(stream);
stream << "pc " << pc;
}
//
void BreakpointClear::serializeSpecific()
{
CmdMessage::serializeSpecific();
add(pc);
}
void BreakpointClear::deserializeSpecific()
{
CmdMessage::deserializeSpecific();
pc = get<uint16>();
}
void BreakpointClear::dumpSpecific(std::ostream &stream)
{
CmdMessage::dumpSpecific(stream);
stream << "pc " << pc;
}
}
#ifndef ASEBA_MSG
#define ASEBA_MSG
#include "../common/types.h"
#include "../common/consts.h"
#include <cstring>
#include <valarray>
namespace Aseba
{
class Message
{
public:
uint16 type;
public:
Message();
virtual ~Message();
void serialize(int fd);
static Message *receive(int fd);
void dump(std::ostream &stream);
protected:
virtual void serializeSpecific() = 0;
virtual void deserializeSpecific() = 0;
virtual void dumpSpecific(std::ostream &stream) = 0;
virtual operator const char * () const { return "message super class"; }
protected:
template<typename T> void add(const T& val);
template<typename T> T get();
protected:
std::valarray<uint8> data;
size_t readPos;
};
class UserMessage : public Message
{
protected:
virtual void serializeSpecific() {}
virtual void deserializeSpecific() {}
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "user message"; }
};
class BootloaderDataRead : public Message
{
public:
uint8 data[6];
public:
BootloaderDataRead() { type = ASEBA_MESSAGE_BOOTLOADER_PAGE_DATA_READ; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "bootloader page data read"; }
};
class BootloaderAck : public Message
{
public:
uint16 errorCode;
uint16 errorAddress;
public:
BootloaderAck() { type = ASEBA_MESSAGE_BOOTLOADER_ACK; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "bootloader ack"; }
};
class Presence : public Message
{
public:
Presence() { type = ASEBA_MESSAGE_PRESENCE; }
protected:
virtual void serializeSpecific() {}
virtual void deserializeSpecific() {}
virtual void dumpSpecific(std::ostream &stream) {}
virtual operator const char * () const { return "presence message"; }
};
class Description : public Message
{
public:
uint16 bytecodeSize;
uint16 stackSize;
uint16 variablesSize;
std::string nodeName;
std::valarray<std::string> variablesNames;
std::valarray<uint16> variablesSizes;
public:
Description() { type = ASEBA_MESSAGE_DESCRIPTION; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "description"; }
};
class Variables : public Message
{
public:
uint16 start;
std::valarray<sint16> variables;
public:
Variables() { type = ASEBA_MESSAGE_VARIABLES; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "variables"; }
};
class ExecutionState : public Message
{
public:
uint16 pc;
uint16 flags;
public:
ExecutionState() { type = ASEBA_MESSAGE_EXECUTION_STATE; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "execution state"; }
};
class ArrayAccessOutOfBounds : public Message
{
public:
uint16 pc;
uint16 index;
public:
ArrayAccessOutOfBounds() { type = ASEBA_MESSAGE_ARRAY_ACCESS_OUT_OF_BOUND; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "array access out of bounds"; }
};
class DivisionByZero : public Message
{
public:
uint16 pc;
public:
DivisionByZero() { type = ASEBA_MESSAGE_DIVISION_BY_ZERO; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "division by zero"; }
};
//! Cammands messages talk to a specific node
class CmdMessage : public Message
{
public:
uint8 dest;
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "cammand message super class"; }
};
class BootloaderReset : public CmdMessage
{
public:
BootloaderReset() { type = ASEBA_MESSAGE_BOOTLOADER_RESET; }
protected:
virtual operator const char * () const { return "bootloader reset"; }
};
class BootloaderReadPage : public CmdMessage
{
public:
uint16 pageNumber;
public:
BootloaderReadPage() { type = ASEBA_MESSAGE_BOOTLOADER_READ_PAGE; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "bootloader read page"; }
};
class BootloaderWritePage : public CmdMessage
{
public:
uint16 pageNumber;
public:
BootloaderWritePage() { type = ASEBA_MESSAGE_BOOTLOADER_WRITE_PAGE; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "bootloader write page"; }
};
class BootloaderPageDataWrite : public CmdMessage
{
public:
uint8 data[4];
public:
BootloaderPageDataWrite() { type = ASEBA_MESSAGE_BOOTLOADER_PAGE_DATA_WRITE; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "bootloader page data write"; }
};
class AttachDebugger : public CmdMessage
{
public:
AttachDebugger() { type = ASEBA_MESSAGE_ATTACH_DEBUGGER; }
protected:
virtual operator const char * () const { return "attach debugger"; }
};
class DetachDebugger : public CmdMessage
{
public:
DetachDebugger() { type = ASEBA_MESSAGE_DETACH_DEBUGGER; }
protected:
virtual operator const char * () const { return "detach debugger"; }
};
class SetBytecode : public CmdMessage
{
public:
std::valarray<uint16> bytecode;
public:
SetBytecode() { type = ASEBA_MESSAGE_SET_BYTECODE; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "set bytecode"; }
};
class SetupEvent : public CmdMessage
{
public:
uint16 eventId;
std::valarray<uint16> arguments;
public:
SetupEvent() { type = ASEBA_MESSAGE_SETUP_EVENT; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "setup event"; }
};
class BackgroundRun : public CmdMessage
{
public:
BackgroundRun() { type = ASEBA_MESSAGE_BACKGROUND_RUN; }
protected:
virtual operator const char * () const { return "background run"; }
};
class Stop : public CmdMessage
{
public:
Stop() { type = ASEBA_MESSAGE_STOP; }
protected:
virtual operator const char * () const { return "stop"; }
};
class Step : public CmdMessage
{
public:
Step() { type = ASEBA_MESSAGE_STEP; }
protected:
virtual operator const char * () const { return "step"; }
};
class BreakpointSet : public CmdMessage
{
public:
uint16 pc;
public:
BreakpointSet() { type = ASEBA_MESSAGE_BREAKPOINT_SET; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "breakpoint set"; }
};
class BreakpointClear : public CmdMessage
{
public:
uint16 pc;
public:
BreakpointClear() { type = ASEBA_MESSAGE_BREAKPOINT_CLEAR; }
protected:
virtual void serializeSpecific();
virtual void deserializeSpecific();
virtual void dumpSpecific(std::ostream &stream);
virtual operator const char * () const { return "breakpoint clear"; }
};
class BreakpointClearAll : public CmdMessage
{
public:
BreakpointClearAll() { type = ASEBA_MESSAGE_BREAKPOINT_CLEAR_ALL; }
protected:
virtual operator const char * () const { return "breakpoint clear all"; }
};
class GetVariables : public CmdMessage
{
public:
GetVariables() { type = ASEBA_MESSAGE_GET_VARIABLES; }
protected:
virtual operator const char * () const { return "get variables"; }
};
}
#endif
_______________________________________________
glob2-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/glob2-devel