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

Reply via email to