lsnes/include/library/controller-data.hpp
2012-10-12 14:27:07 +03:00

1295 lines
32 KiB
C++

#ifndef _library__controller_data__hpp__included__
#define _library__controller_data__hpp__included__
#include <cstring>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstdio>
#include <cstdint>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include <map>
#include <list>
#include <set>
/**
* Memory to allocate for controller frame.
*/
#define MAXIMUM_CONTROLLER_FRAME_SIZE 128
/**
* Maximum amount of data controller_frame::display() can write.
*/
#define MAX_DISPLAY_LENGTH 128
/**
* Maximum amount of data controller_frame::serialize() can write.
*/
#define MAX_SERIALIZED_SIZE 256
/**
* Size of controller page.
*/
#define CONTROLLER_PAGE_SIZE 65500
/**
* Special return value for deserialize() indicating no input was taken.
*/
#define DESERIALIZE_SPECIAL_BLANK 0xFFFFFFFFUL
/**
* Is not field terminator.
*
* Parameter ch: The character.
* Returns: True if character is not terminator, false if character is terminator.
*/
inline bool is_nonterminator(char ch) throw()
{
return (ch != '|' && ch != '\r' && ch != '\n' && ch != '\0');
}
/**
* Read button value.
*
* Parameter buf: Buffer to read from.
* Parameter idx: Index to buffer. Updated.
* Returns: The read value.
*/
inline bool read_button_value(const char* buf, size_t& idx) throw()
{
char ch = buf[idx];
if(is_nonterminator(ch))
idx++;
return (ch != '|' && ch != '\r' && ch != '\n' && ch != '\0' && ch != '.' && ch != ' ' && ch != '\t');
}
/**
* Read axis value.
*
* Parameter buf: Buffer to read from.
* Parameter idx: Index to buffer. Updated.
* Returns: The read value.
*/
short read_axis_value(const char* buf, size_t& idx) throw();
/**
* Skip whitespace.
*
* Parameter buf: Buffer to read from.
* Parameter idx: Index to buffer. Updated.
*/
inline void skip_field_whitespace(const char* buf, size_t& idx) throw()
{
while(buf[idx] == ' ' || buf[idx] == '\t')
idx++;
}
/**
* Skip rest of the field.
*
* Parameter buf: Buffer to read from.
* Parameter idx: Index to buffer. Updated.
* Parameter include_pipe: If true, also skip the '|'.
*/
inline void skip_rest_of_field(const char* buf, size_t& idx, bool include_pipe) throw()
{
while(is_nonterminator(buf[idx]))
idx++;
if(include_pipe && buf[idx] == '|')
idx++;
}
/**
* Serialize short.
*/
inline void serialize_short(unsigned char* buf, short val)
{
buf[0] = static_cast<unsigned short>(val) >> 8;
buf[1] = static_cast<unsigned short>(val);
}
/**
* Serialize short.
*/
inline short unserialize_short(const unsigned char* buf)
{
return static_cast<short>((static_cast<unsigned short>(buf[0]) << 8) | static_cast<unsigned short>(buf[1]));
}
class port_type;
/**
* Group of port types.
*/
class port_type_group
{
public:
/**
* Construct a group.
*
* Throws std::bad_alloc: Not enough memory.
*/
port_type_group() throw(std::bad_alloc);
/**
* Destroy a group.
*/
~port_type_group() throw();
/**
* Get port type with specified name.
*
* Parameter name: The name of port type.
* Returns: The port type structure.
* Throws std::runtime_error: Specified port type unknown.
*/
port_type& get_type(const std::string& name) const throw(std::runtime_error);
/**
* Get set of all port types.
*
* Returns: The set of all port types.
* Throws std::bad_alloc: Not enough memory.
*/
std::set<port_type*> get_types() const throw(std::bad_alloc);
/**
* Get default port type for specified port.
*
* Parameter port: The port.
* Returns: The default port type.
* Throws std::runtime_error: Bad port.
*/
port_type& get_default_type(unsigned port) const throw(std::runtime_error);
/**
* Add a port type.
*
* Parameter type: Name of the type.
* Parameter port: The port type structure.
* Throws std::bad_alloc: Not enough memory.
*/
void register_type(const std::string& type, port_type& port);
/**
* Remove a port type.
*
* Parameter type: Name of the type.
* Throws std::bad_alloc: Not enough memory.
*/
void unregister_type(const std::string& type);
/**
* Set default type for port.
*
* Parameter port: The port.
* Parameter ptype: The port type to make default.
*/
void set_default(unsigned port, port_type& ptype);
private:
std::map<std::string, port_type*> types;
std::map<unsigned, port_type*> defaults;
};
/**
* Type of controller.
*/
class port_type
{
public:
/**
* Create a new port type.
*
* Parameter group: The group the type will belong to.
* Parameter iname: Internal name of the port type.
* Parameter hname: Human-readable name of the port type.
* Parameter id: Identifier.
* Parameter ssize: The storage size in bytes.
* Throws std::bad_alloc: Not enough memory.
*/
port_type(port_type_group& group, const std::string& iname, const std::string& hname, unsigned id,
size_t ssize) throw(std::bad_alloc);
/**
* Unregister a port type.
*/
virtual ~port_type() throw();
/**
* Writes controller data into compressed representation.
*
* Parameter buffer: The buffer storing compressed representation of controller state.
* Parameter idx: Index of controller.
* Parameter ctrl: The control to manipulate.
* Parameter x: New value for control. Only zero/nonzero matters for buttons.
*/
void (*write)(unsigned char* buffer, unsigned idx, unsigned ctrl, short x);
/**
* Read controller data from compressed representation.
*
* Parameter buffer: The buffer storing compressed representation of controller state.
* Parameter idx: Index of controller.
* Parameter ctrl: The control to query.
* Returns: The value of control. Buttons return 0 or 1.
*/
short (*read)(const unsigned char* buffer, unsigned idx, unsigned ctrl);
/**
* Format compressed controller data into input display.
*
* Parameter buffer: The buffer storing compressed representation of controller state.
* Parameter idx: Index of controller.
* Parameter buf: The buffer to write NUL-terminated display string to. Assumed to be MAX_DISPLAY_LENGTH bytes in size.
*/
void (*display)(const unsigned char* buffer, unsigned idx, char* buf);
/**
* Take compressed controller data and serialize it into textual representation.
*
* - The initial '|' is also written.
*
* Parameter buffer: The buffer storing compressed representation of controller state.
* Parameter textbuf: The text buffer to write to.
* Returns: Number of bytes written.
*/
size_t (*serialize)(const unsigned char* buffer, char* textbuf);
/**
* Unserialize textual representation into compressed controller state.
*
* - Only stops reading on '|', NUL, CR or LF in the final read field. That byte is not read.
*
* Parameter buffer: The buffer storing compressed representation of controller state.
* Parameter textbuf: The text buffer to read.
* Returns: Number of bytes read.
* Throws std::runtime_error: Bad serialization.
*/
size_t (*deserialize)(unsigned char* buffer, const char* textbuf);
/**
* Get device flags for given index.
*
* Parameter idx: The index of controller.
* Returns: The device flags.
* Bit 0: Present.
* Bit 1: Has absolute analog axes 0 and 1.
* Bit 2: Has relative analog axes 0 and 1.
*/
unsigned (*deviceflags)(unsigned idx);
/**
* Is the device legal for port?
*
* Parameter port: Port to query.
* Returns: Nonzero if legal, zero if illegal.
*/
int (*legal)(unsigned port);
/**
* Number of controllers connected to this port.
*/
unsigned controllers;
/**
* Translate controller and logical button id pair into physical button id.
*
* Parameter controller: The number of controller.
* Parameter lbid: Logigal button ID.
* Returns: The physical button ID, or -1 if no such button exists.
*/
int (*button_id)(unsigned controller, unsigned lbid);
/**
* Set this controller as core controller.
*
* Parameter port: Port to set to.
*/
void (*set_core_controller)(unsigned port);
/**
* Does the controller exist?
*
* Parameter controller: Controller number.
*/
bool is_present(unsigned controller) const throw();
/**
* Does the controller have analog function?
*
* Parameter controller: Controller number.
*/
bool is_analog(unsigned controller) const throw();
/**
* Does the controller have mouse-type function?
*
* Parameter controller: Controller number.
*/
bool is_mouse(unsigned controller) const throw();
/**
* Number of control indices claimed.
*/
unsigned index_count;
/**
* Number of control indices used per controller.
*/
unsigned* controller_indices;
/**
* Human-readable name.
*/
std::string hname;
/**
* Number of bytes it takes to store this.
*/
size_t storage_size;
/**
* Name of port type.
*/
std::string name;
/**
* Name of controller.
*/
std::string ctrlname;
/**
* Id of the port.
*/
unsigned pt_id;
/**
* Low-priority flag.
*/
bool priority;
/**
* Group this port is in.
*/
port_type_group& ingroup;
private:
port_type(const port_type&);
port_type& operator=(const port_type&);
};
/**
* A set of port types.
*/
class port_type_set
{
public:
/**
* Controller index triplet.
*/
struct triplet
{
triplet() {}
triplet(unsigned p, unsigned c, unsigned i) : port(p), controller(c), control(i) {}
unsigned port;
unsigned controller;
unsigned control;
};
/**
* Create empty port type set.
*/
port_type_set() throw();
/**
* Make a port type set with specified types. If called again with the same parameters, returns the same object.
*
* Parameter types: The types.
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Illegal port types.
*/
static port_type_set& make(std::vector<port_type*> types) throw(std::bad_alloc, std::runtime_error);
/**
* Compare sets for equality.
*/
bool operator==(const port_type_set& s) const throw() { return this == &s; }
/**
* Compare sets for non-equality.
*/
bool operator!=(const port_type_set& s) const throw() { return this != &s; }
/**
* Get offset of specified port.
*
* Parameter port: The number of port.
* Returns: The offset of port.
* Throws std::runtime_error: Bad port number.
*/
size_t port_offset(unsigned port) const throw(std::runtime_error)
{
if(port >= port_count)
throw std::runtime_error("Invalid port index");
return port_offsets[port];
}
/**
* Get type of specified port.
*
* Parameter port: The number of port.
* Returns: The port type.
* Throws std::runtime_error: Bad port number.
*/
const class port_type& port_type(unsigned port) const throw(std::runtime_error)
{
if(port >= port_count)
throw std::runtime_error("Invalid port index");
return *(port_types[port]);
}
/**
* Get number of ports.
*
* Returns: The port count.
*/
unsigned ports() const throw()
{
return port_count;
}
/**
* Get total size of controller data.
*
* Returns the size.
*/
unsigned size() const throw()
{
return total_size;
}
/**
* Get total index count.
*/
unsigned indices() const throw()
{
return index_count;
}
/**
* Look up the triplet for given control.
*
* Parameter index: The index to look up.
* Returns: The triplet (may have out of range indices)
* Throws std::runtime_error: Index out of range.
*/
triplet index_to_triple(unsigned index) const throw(std::runtime_error)
{
if(index >= index_count)
throw std::runtime_error("Invalid index");
return triples[index];
}
/**
* Translate triplet into index.
*
* Parameter port: The port.
* Parameter controller: The controller.
* Parameter index: The control index.
* Returns: The index.
* Throws std::runtime_error: No such triplet.
*/
unsigned triple_to_index(unsigned port, unsigned controller, unsigned index) const throw(std::runtime_error)
{
size_t i = port * triple_port_m + controller * triple_controller_m + index;
if(i >= indexes_size || indexes_tab[i] == 0xFFFFFFFFUL)
return 0xFFFFFFFFUL;
return indexes_tab[i];
}
private:
port_type_set(std::vector<class port_type*> types);
size_t* port_offsets;
class port_type** port_types;
unsigned port_count;
unsigned index_count;
size_t total_size;
size_t triple_port_m;
size_t triple_controller_m;
size_t indexes_size;
unsigned* indexes_tab;
triplet* triples;
};
/**
* Poll counter vector.
*/
class pollcounter_vector
{
public:
/**
* Create new pollcounter vector filled with all zeroes and all DRDY bits clear.
*
* Throws std::bad_alloc: Not enough memory.
*/
pollcounter_vector() throw(std::bad_alloc);
/**
* Create new pollcounter vector suitably sized for given type set.
*
* Parameter p: The port types.
* Throws std::bad_alloc: Not enough memory.
*/
pollcounter_vector(const port_type_set& p) throw(std::bad_alloc);
/**
* Destructor.
*/
~pollcounter_vector() throw();
/**
* Copy the pollcounter_vector.
*/
pollcounter_vector(const pollcounter_vector& v) throw(std::bad_alloc);
/**
* Assign the pollcounter_vector.
*/
pollcounter_vector& operator=(const pollcounter_vector& v) throw(std::bad_alloc);
/**
* Zero all poll counters and clear all DRDY bits. System flag is cleared.
*/
void clear() throw();
/**
* Set all DRDY bits.
*/
void set_all_DRDY() throw();
/**
* Clear specified DRDY bit.
*
* Parameter port: The port.
* Parameter controller: The controller
* Parameter ctrl: The control id.
*/
void clear_DRDY(unsigned port, unsigned controller, unsigned ctrl) throw()
{
unsigned i = types->triple_to_index(port, controller, ctrl);
if(i != 0xFFFFFFFFU)
clear_DRDY(i);
}
/**
* Clear state of DRDY bit.
*
* Parameter idx: The control index.
*/
void clear_DRDY(unsigned idx) throw();
/**
* Get state of DRDY bit.
*
* Parameter port: The port.
* Parameter controller: The controller
* Parameter ctrl: The control id.
* Returns: The DRDY state.
*/
bool get_DRDY(unsigned port, unsigned controller, unsigned ctrl) throw()
{
unsigned i = types->triple_to_index(port, controller, ctrl);
if(i != 0xFFFFFFFFU)
return get_DRDY(i);
else
return false;
}
/**
* Get state of DRDY bit.
*
* Parameter idx: The control index.
* Returns: The DRDY state.
*/
bool get_DRDY(unsigned idx) throw();
/**
* Is any poll count nonzero or is system flag set?
*
* Returns: True if at least one poll count is nonzero or if system flag is set. False otherwise.
*/
bool has_polled() throw();
/**
* Read the actual poll count on specified control.
*
* Parameter port: The port.
* Parameter controller: The controller
* Parameter ctrl: The control id.
* Return: The poll count.
*/
uint32_t get_polls(unsigned port, unsigned controller, unsigned ctrl) throw()
{
unsigned i = types->triple_to_index(port, controller, ctrl);
if(i != 0xFFFFFFFFU)
return get_polls(i);
else
return 0;
}
/**
* Read the actual poll count on specified control.
*
* Parameter idx: The control index.
* Return: The poll count.
*/
uint32_t get_polls(unsigned idx) throw();
/**
* Increment poll count on specified control.
*
* Parameter port: The port.
* Parameter controller: The controller
* Parameter ctrl: The control id.
* Return: The poll count pre-increment.
*/
uint32_t increment_polls(unsigned port, unsigned controller, unsigned ctrl) throw()
{
unsigned i = types->triple_to_index(port, controller, ctrl);
if(i != 0xFFFFFFFFU)
return increment_polls(i);
else
return 0;
}
/**
* Increment poll count on specified index.
*
* Parameter idx: The index.
* Return: The poll count pre-increment.
*/
uint32_t increment_polls(unsigned idx) throw();
/**
* Get highest poll counter value.
*
* - System flag counts as 1 poll.
*
* Returns: The maximum poll count (at least 1 if system flag is set).
*/
uint32_t max_polls() throw();
/**
* Save state to memory block.
*
* Parameter mem: The memory block to save to.
* Throws std::bad_alloc: Not enough memory.
*/
void save_state(std::vector<uint32_t>& mem) throw(std::bad_alloc);
/**
* Load state from memory block.
*
* Parameter mem: The block from restore from.
*/
void load_state(const std::vector<uint32_t>& mem) throw();
/**
* Check if state can be loaded without errors.
*
* Returns: True if load is possible, false otherwise.
*/
bool check(const std::vector<uint32_t>& mem) throw();
private:
uint32_t* ctrs;
const port_type_set* types;
};
/**
* Single (sub)frame of controls.
*/
class controller_frame
{
public:
/**
* Default constructor. Invalid port types, dedicated memory.
*/
controller_frame() throw();
/**
* Create subframe of controls with specified controller types and dedicated memory.
*
* Parameter p: Types of ports.
*/
controller_frame(const port_type_set& p) throw(std::runtime_error);
/**
* Create subframe of controls with specified controller types and specified memory.
*
* Parameter memory: The backing memory.
* Parameter p: Types of ports.
*
* Throws std::runtime_error: NULL memory.
*/
controller_frame(unsigned char* memory, const port_type_set& p) throw(std::runtime_error);
/**
* Copy construct a frame. The memory will be dedicated.
*
* Parameter obj: The object to copy.
*/
controller_frame(const controller_frame& obj) throw();
/**
* Assign a frame. The types must either match or memory must be dedicated.
*
* Parameter obj: The object to copy.
* Returns: Reference to this.
* Throws std::runtime_error: The types don't match and memory is not dedicated.
*/
controller_frame& operator=(const controller_frame& obj) throw(std::runtime_error);
/**
* Get type of port.
*
* Parameter port: Number of port.
* Returns: The type of port.
*/
const port_type& get_port_type(unsigned port) throw()
{
return types->port_type(port);
}
/**
* Get port count.
*/
unsigned get_port_count() throw()
{
return types->ports();
}
/**
* Get index count.
*/
unsigned get_index_count() throw()
{
return types->indices();
}
/**
* Set types of ports.
*
* Parameter ptype: New port types.
* Throws std::runtime_error: Memory is mapped.
*/
void set_types(const port_type_set& ptype) throw(std::runtime_error)
{
if(memory != backing)
throw std::runtime_error("Can't change type of mapped controller_frame");
types = &ptype;
}
/**
* Get blank dedicated frame of same port types.
*
* Return blank frame.
*/
controller_frame blank_frame() throw()
{
return controller_frame(*types);
}
/**
* Check that types match.
*
* Parameter obj: Another object.
* Returns: True if types match, false otherwise.
*/
bool types_match(const controller_frame& obj) const throw()
{
return types == obj.types;
}
/**
* Perform XOR between controller frames.
*
* Parameter another: The another object.
* Returns: The XOR result (dedicated memory).
* Throws std::runtime_error: Type mismatch.
*/
controller_frame operator^(const controller_frame& another) throw(std::runtime_error)
{
controller_frame x(*this);
if(types != another.types)
throw std::runtime_error("controller_frame::operator^: Type mismatch");
for(size_t i = 0; i < types->size(); i++)
x.backing[i] ^= another.backing[i];
return x;
}
/**
* Set the sync flag.
*
* Parameter x: The value to set the sync flag to.
*/
void sync(bool x) throw()
{
if(x)
backing[0] |= 1;
else
backing[0] &= ~1;
}
/**
* Get the sync flag.
*
* Return value: Value of sync flag.
*/
bool sync() throw()
{
return ((backing[0] & 1) != 0);
}
/**
* Quick get sync flag for buffer.
*/
static bool sync(const unsigned char* mem) throw()
{
return ((mem[0] & 1) != 0);
}
/**
* Get size of frame.
*
* Returns: The number of bytes it takes to store frame of this type.
*/
size_t size()
{
return types->size();
}
/**
* Set axis/button value.
*
* Parameter port: The port.
* Parameter controller: The controllre
* Parameter ctrl: The control id.
* Parameter x: The new value.
*/
void axis3(unsigned port, unsigned controller, unsigned ctrl, short x) throw()
{
if(port >= types->ports())
return;
types->port_type(port).write(backing + types->port_offset(port), controller, ctrl, x);
}
/**
* Set axis/button value.
*
* Parameter idx: Control index.
* Parameter x: The new value.
*/
void axis2(unsigned idx, short x) throw()
{
port_type_set::triplet t = types->index_to_triple(idx);
axis3(t.port, t.controller, t.control, x);
}
/**
* Get axis/button value.
*
* Parameter port: The port.
* Parameter controller: The controller
* Parameter ctrl: The control id.
* Return value: The axis value.
*/
short axis3(unsigned port, unsigned controller, unsigned ctrl) throw()
{
if(port >= types->ports())
return 0;
return types->port_type(port).read(backing + types->port_offset(port), controller, ctrl);
}
/**
* Get axis/button value.
*
* Parameter idx: Index of control.
* Return value: The axis value.
*/
short axis2(unsigned idx) throw()
{
port_type_set::triplet t = types->index_to_triple(idx);
return axis3(t.port, t.controller, t.control);
}
/**
* Get controller display.
*
* Parameter port: The port.
* Parameter controller: The controller
* Parameter buf: Buffer to write nul-terminated display to.
*/
void display(unsigned port, unsigned controller, char* buf) throw()
{
if(port >= types->ports()) {
*buf = '\0';
return;
}
types->port_type(port).display(backing + types->port_offset(port), controller, buf);
}
/**
* Is device present?
*
* Parameter port: The port.
* Parameter controller: The controller
* Returns: True if present, false if not.
*/
bool is_present(unsigned port, unsigned controller) throw()
{
if(port >= types->ports())
return false;
return types->port_type(port).is_present(controller);
}
/**
* Deserialize frame from text format.
*
* Parameter buf: The buffer containing text representation. Terminated by NUL, CR or LF.
* Throws std::runtime_error: Bad serialized representation.
*/
void deserialize(const char* buf) throw(std::runtime_error)
{
size_t offset = 0;
for(size_t i = 0; i < types->ports(); i++) {
size_t s;
s = types->port_type(i).deserialize(backing + types->port_offset(i), buf + offset);
if(s != DESERIALIZE_SPECIAL_BLANK) {
offset += s;
if(buf[offset] == '|')
offset++;
}
}
}
/**
* Serialize frame to text format.
*
* Parameter buf: The buffer to write NUL-terminated text representation to.
*/
void serialize(char* buf) throw()
{
size_t offset = 0;
for(size_t i = 0; i < types->ports(); i++)
offset += types->port_type(i).serialize(backing + types->port_offset(i), buf + offset);
buf[offset++] = '\0';
}
/**
* Return copy with dedicated memory.
*
* Parameter sync: If set, the frame will have sync flag set, otherwise it will have sync flag clear.
* Returns: Copy of this frame.
*/
controller_frame copy(bool sync)
{
controller_frame c(*this);
c.sync(sync);
return c;
}
/**
* Compare two frames.
*
* Parameter obj: Another frame.
* Returns: True if equal, false if not.
*/
bool operator==(const controller_frame& obj) const throw()
{
if(!types_match(obj))
return false;
return !memcmp(backing, obj.backing, totalsize);
}
/**
* Compare two frames.
*
* Parameter obj: Another frame.
* Returns: True if not equal, false if equal.
*/
bool operator!=(const controller_frame& obj) const throw()
{
return !(*this == obj);
}
/**
* Get physical button ID for physical controller ID and logical button ID.
*
* Parameter port: The port.
* Parameter controller: The controller
* Parameter lbid: Logical button id.
* Returns: The physical button id, or -1 if no such button.
*/
int button_id(unsigned port, unsigned controller, unsigned lbid)
{
if(port >= types->ports())
return -1;
return types->port_type(port).button_id(controller, lbid);
}
/**
* Does the specified controller have analog function.
*
* Parameter port: The port.
* Parameter controller: The controller
*/
bool is_analog(unsigned port, unsigned controller)
{
if(port >= types->ports())
return false;
return types->port_type(port).is_analog(controller);
}
/**
* Does the specified controller have mouse-type function.
*
* Parameter port: The port.
* Parameter controller: The controller
*/
bool is_mouse(unsigned port, unsigned controller)
{
if(port >= types->ports())
return false;
return types->port_type(port).is_mouse(controller);
}
private:
size_t totalsize;
unsigned char memory[MAXIMUM_CONTROLLER_FRAME_SIZE];
unsigned char* backing;
const port_type_set* types;
};
/**
* Vector of controller frames.
*/
class controller_frame_vector
{
public:
/**
* Construct new controller frame vector.
*/
controller_frame_vector() throw();
/**
* Construct new controller frame vector.
*
* Parameter p: The port types.
*/
controller_frame_vector(const port_type_set& p) throw();
/**
* Destroy controller frame vector
*/
~controller_frame_vector() throw();
/**
* Copy controller frame vector.
*
* Parameter obj: The object to copy.
* Throws std::bad_alloc: Not enough memory.
*/
controller_frame_vector(const controller_frame_vector& vector) throw(std::bad_alloc);
/**
* Assign controller frame vector.
*
* Parameter obj: The object to copy.
* Returns: Reference to this.
* Throws std::bad_alloc: Not enough memory.
*/
controller_frame_vector& operator=(const controller_frame_vector& vector) throw(std::bad_alloc);
/**
* Blank vector and change the type of ports.
*
* Parameter p: The port types.
*/
void clear(const port_type_set& p) throw(std::runtime_error);
/**
* Blank vector.
*/
void clear() throw()
{
clear(*types);
}
/**
* Get number of subframes.
*/
size_t size()
{
return frames;
}
/**
* Get the typeset.
*/
const port_type_set& get_types()
{
return *types;
}
/**
* Access specified subframe.
*
* Parameter x: The frame number.
* Returns: The controller frame.
* Throws std::runtime_error: Invalid frame index.
*/
controller_frame operator[](size_t x)
{
size_t page = x / frames_per_page;
size_t pageoffset = frame_size * (x % frames_per_page);
if(x >= frames)
throw std::runtime_error("controller_frame_vector::operator[]: Illegal index");
if(page != cache_page_num) {
cache_page = &pages[page];
cache_page_num = page;
}
return controller_frame(cache_page->content + pageoffset, *types);
}
/**
* Append a subframe.
*
* Parameter frame: The frame to append.
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Port type mismatch.
*/
void append(controller_frame frame) throw(std::bad_alloc, std::runtime_error);
/**
* Change length of vector.
*
* - Reducing length of vector will discard extra elements.
* - Extending length of vector will add all-zero elements.
*
* Parameter newsize: New size of vector.
* Throws std::bad_alloc: Not enough memory.
*/
void resize(size_t newsize) throw(std::bad_alloc);
/**
* Walk the indexes of sync subframes.
*
* - If frame is in range and there is at least one more sync subframe after it, the index of first sync subframe
* after given frame.
* - If frame is in range, but there are no more sync subframes after it, the length of vector is returned.
* - If frame is out of range, the given frame is returned.
*
* Parameter frame: The frame number to start search from.
* Returns: Index of next sync frame.
*/
size_t walk_sync(size_t frame) throw()
{
return walk_helper(frame, true);
}
/**
* Get number of subframes in frame. The given subframe is assumed to be sync subframe.
*
* - The return value is the same as (walk_sync(frame) - frame).
*
* Parameter frame: The frame number to start search from.
* Returns: Number of subframes in this frame.
*/
size_t subframe_count(size_t frame) throw()
{
return walk_helper(frame, false);
}
/**
* Count number of subframes in vector with sync flag set.
*
* Returns: The number of frames.
*/
size_t count_frames() throw();
/**
* Return blank controller frame with correct type and dedicated memory.
*
* Parameter sync: If set, the frame will have sync flag set, otherwise it will have sync flag clear.
* Returns: Blank frame.
*/
controller_frame blank_frame(bool sync)
{
controller_frame c(*types);
c.sync(sync);
return c;
}
private:
class page
{
public:
page() { memset(content, 0, CONTROLLER_PAGE_SIZE); }
unsigned char content[CONTROLLER_PAGE_SIZE];
};
size_t frames_per_page;
size_t frame_size;
size_t frames;
const port_type_set* types;
size_t cache_page_num;
page* cache_page;
std::map<size_t, page> pages;
size_t walk_helper(size_t frame, bool sflag) throw();
void clear_cache()
{
cache_page_num = 0;
cache_page_num--;
cache_page = NULL;
}
};
/**
* Get a dummy port type.
*
* Return value: Dummy port type.
*/
port_type& get_dummy_port_type() throw(std::bad_alloc);
/**
* Generic port write function.
*/
template<unsigned controllers, unsigned analog_axis, unsigned buttons>
inline void generic_port_write(unsigned char* buffer, unsigned idx, unsigned ctrl, short x) throw()
{
if(idx >= controllers)
return;
if(ctrl < analog_axis) {
buffer[2 * idx * analog_axis + 2 * ctrl] = (x >> 8);
buffer[2 * idx * analog_axis + 2 * ctrl + 1] = x;
} else if(ctrl < analog_axis + buttons) {
size_t bit = 16 * controllers * analog_axis + idx * buttons + ctrl - analog_axis;
if(x)
buffer[bit / 8] |= (1 << (bit % 8));
else
buffer[bit / 8] &= ~(1 << (bit % 8));
}
}
/**
* Generic port read function.
*/
template<unsigned controllers, unsigned analog_axis, unsigned buttons>
inline short generic_port_read(const unsigned char* buffer, unsigned idx, unsigned ctrl) throw()
{
if(idx >= controllers)
return 0;
if(ctrl < analog_axis) {
uint16_t a = buffer[2 * idx * analog_axis + 2 * ctrl];
uint16_t b = buffer[2 * idx * analog_axis + 2 * ctrl + 1];
return static_cast<short>(256 * a + b);
} else if(ctrl < analog_axis + buttons) {
size_t bit = 16 * controllers * analog_axis + idx * buttons + ctrl - analog_axis;
return ((buffer[bit / 8] & (1 << (bit % 8))) != 0);
} else
return 0;
}
extern const char* button_symbols;
/**
* Generic port display function.
*/
template<unsigned controllers, unsigned analog_axis, unsigned buttons, unsigned sidx>
inline void generic_port_display(const unsigned char* buffer, unsigned idx, char* buf) throw()
{
if(idx > controllers) {
buf[0] = '\0';
return;
}
size_t ptr = 0;
for(unsigned i = 0; i < analog_axis; i++) {
uint16_t a = buffer[2 * idx * analog_axis + 2 * i];
uint16_t b = buffer[2 * idx * analog_axis + 2 * i + 1];
ptr += sprintf(buf + ptr, "%i ", static_cast<short>(256 * a + b));
}
for(unsigned i = 0; i < buttons; i++) {
size_t bit = 16 * controllers * analog_axis + idx * buttons + i;
buf[ptr++] = ((buffer[bit / 8] & (1 << (bit % 8))) != 0) ? button_symbols[i + sidx] : '-';
}
buf[ptr] = '\0';
}
/**
* Generic port serialization function.
*/
template<unsigned controllers, unsigned analog_axis, unsigned buttons, unsigned sidx>
inline size_t generic_port_serialize(const unsigned char* buffer, char* textbuf) throw()
{
size_t ptr = 0;
for(unsigned j = 0; j < controllers; j++) {
textbuf[ptr++] = '|';
for(unsigned i = 0; i < buttons; i++) {
size_t bit = 16 * controllers * analog_axis + j * buttons + i;
textbuf[ptr++] = ((buffer[bit / 8] & (1 << (bit % 8))) != 0) ? button_symbols[i + sidx] : '.';
}
for(unsigned i = 0; i < analog_axis; i++) {
uint16_t a = buffer[2 * j * analog_axis + 2 * i];
uint16_t b = buffer[2 * j * analog_axis + 2 * i + 1];
ptr += sprintf(textbuf + ptr, " %i", static_cast<short>(256 * a + b));
}
}
return ptr;
}
/**
* Generic port size function.
*/
template<unsigned controllers, unsigned analog_axis, unsigned buttons>
inline size_t generic_port_size()
{
return 2 * controllers * analog_axis + (controllers * buttons + 7) / 8;
}
/**
* Generic port deserialization function.
*/
template<unsigned controllers, unsigned analog_axis, unsigned buttons>
inline size_t generic_port_deserialize(unsigned char* buffer, const char* textbuf) throw()
{
if(!controllers)
return DESERIALIZE_SPECIAL_BLANK;
memset(buffer, 0, generic_port_size<controllers, analog_axis, buttons>());
size_t ptr = 0;
for(unsigned j = 0; j < controllers; j++) {
for(unsigned i = 0; i < buttons; i++) {
size_t bit = 16 * controllers * analog_axis + j * buttons + i;
if(read_button_value(textbuf, ptr))
buffer[bit / 8] |= (1 << (bit % 8));
}
for(unsigned i = 0; i < analog_axis; i++) {
short v = read_axis_value(textbuf, ptr);
buffer[2 * j * analog_axis + 2 * i] = v >> 8;
buffer[2 * j * analog_axis + 2 * i + 1] = v;
}
skip_rest_of_field(textbuf, ptr, j + 1 < controllers);
}
return ptr;
}
template<unsigned mask>
inline int generic_port_legal(unsigned port) throw()
{
if(port >= CHAR_BIT * sizeof(unsigned))
port = CHAR_BIT * sizeof(unsigned) - 1;
return ((mask >> port) & 1);
}
/**
* Generic port type function.
*/
template<unsigned controllers, unsigned flags>
inline unsigned generic_port_deviceflags(unsigned idx) throw()
{
return (idx < controllers) ? flags : 0;
}
#endif