Program Listing for File cuecontroller.cpp¶
↰ Return to documentation for file (src/cue/cuecontroller.cpp
)
/*
* CueController - Class for converting PixelMaestro commands to and from serialized strings.
*/
#include "cuecontroller.h"
#include "animationcuehandler.h"
#include "canvascuehandler.h"
#include "maestrocuehandler.h"
#include "sectioncuehandler.h"
#include "showcuehandler.h"
namespace PixelMaestro {
CueController::CueController(Maestro& maestro, uint32_t buffer_size) : maestro_(maestro) {
this->buffer_size_ = buffer_size;
this->buffer_ = new uint8_t[buffer_size] {0};
}
uint8_t* CueController::assemble(uint32_t payload_size) {
/*
* Final Cue has the following form: [ID] [Checksum] [Size] [Payload]
*
* [ID] is a set of pre-defined characters marking the start of a Cue.
* [Size] is the size of the payload.
* [Checksum] is a value generated for error detection.
* [Payload] contains the actual command with parameters.
*/
for (uint8_t i = 0; i < (uint8_t)Byte::ChecksumByte; i++) {
buffer_[i] = id_[i];
}
IntByteConvert size(payload_size);
buffer_[(uint8_t)Byte::SizeByte1] = size.converted_0;
buffer_[(uint8_t)Byte::SizeByte2] = size.converted_1;
buffer_[(uint8_t)Byte::SizeByte3] = size.converted_2;
buffer_[(uint8_t)Byte::SizeByte4] = size.converted_3;
buffer_[(uint8_t)Byte::ChecksumByte] = checksum(buffer_, payload_size);
return buffer_;
}
uint8_t CueController::checksum(const uint8_t* cue, uint32_t cue_size) {
uint32_t sum = 0;
for (uint32_t i = 0; i < cue_size; i++) {
// Make sure we don't include the checksum in its own calculation
if (i != (uint8_t)Byte::ChecksumByte) {
sum += cue[i];
}
}
return (sum % 256);
}
CueHandler& CueController::enable_animation_cue_handler() {
uint8_t handler = (uint8_t)Handler::AnimationCueHandler;
if (handlers_[handler] == nullptr) {
handlers_[handler] = new AnimationCueHandler(*this);
}
return *handlers_[handler];
}
CueHandler& CueController::enable_canvas_cue_handler() {
uint8_t handler = (uint8_t)Handler::CanvasCueHandler;
if (handlers_[handler] == nullptr) {
handlers_[handler] = new CanvasCueHandler(*this);
}
return *handlers_[handler];
}
CueHandler& CueController::enable_maestro_cue_handler() {
uint8_t handler = (uint8_t)Handler::MaestroCueHandler;
if (handlers_[handler] == nullptr) {
handlers_[handler] = new MaestroCueHandler(*this);
}
return *handlers_[handler];
}
CueHandler& CueController::enable_section_cue_handler() {
uint8_t handler = (uint8_t)Handler::SectionCueHandler;
if (handlers_[handler] == nullptr) {
handlers_[handler] = new SectionCueHandler(*this);
}
return *handlers_[handler];
}
CueHandler& CueController::enable_show_cue_handler() {
uint8_t handler = (uint8_t)Handler::ShowCueHandler;
if (handlers_[handler] == nullptr) {
handlers_[handler] = new ShowCueHandler(*this);
}
return *handlers_[handler];
}
uint8_t* CueController::get_buffer() const {
return buffer_;
}
uint32_t CueController::get_cue_size() const {
return IntByteConvert::byte_to_uint32(&buffer_[(uint8_t)CueController::Byte::SizeByte1]);
}
uint32_t CueController::get_cue_size(uint8_t *cue) const {
return (IntByteConvert::byte_to_uint32(&cue[(uint8_t)CueController::Byte::SizeByte1]));
}
CueHandler* CueController::get_handler(Handler handler) const {
return handlers_[(uint8_t)handler];
}
Maestro& CueController::get_maestro() const {
return maestro_;
}
bool CueController::is_blocked(const uint8_t *cue) const {
for (uint8_t i = 0; i < num_blocked_cues_; i++) {
BlockedCue& block = blocked_cues_[i];
if ((cue[(uint8_t)Byte::PayloadByte] == (uint8_t)block.handler) &&
(cue[(uint8_t)Byte::PayloadByte + 1] == block.action)) {
return true;
}
}
return false;
}
bool CueController::read(uint8_t byte) {
buffer_[read_index_] = byte;
read_index_++;
/*
* Check to see if we should reset the read index in order to make room for the Cue.
*/
if (read_index_ > (uint8_t)Byte::IDByte3) {
/*
* First, make sure this isn't a list of Show Events.
* If it is, the index will reset while reading an Event, which is a problem.
*/
if (!(buffer_[(uint8_t)Byte::PayloadByte] == (uint8_t)Handler::ShowCueHandler && buffer_[(uint8_t)ShowCueHandler::Byte::ActionByte] == (uint8_t)ShowCueHandler::Action::SetEvents)) {
/*
* Next, move the read index to the start of the buffer and write the ID.
* Then, start reading after the last ID byte.
*/
if (buffer_[read_index_ - (uint8_t)Byte::IDByte3] == id_[(uint8_t)Byte::IDByte1] &&
buffer_[read_index_ - (uint8_t)Byte::IDByte2] == id_[(uint8_t)Byte::IDByte2] &&
buffer_[read_index_] == id_[(uint8_t)Byte::IDByte3]) {
buffer_[(uint8_t)Byte::IDByte1] = id_[(uint8_t)Byte::IDByte1];
buffer_[(uint8_t)Byte::IDByte2] = id_[(uint8_t)Byte::IDByte2];
buffer_[(uint8_t)Byte::IDByte3] = id_[(uint8_t)Byte::IDByte3];
read_index_ = (uint8_t)Byte::IDByte3 + 1;
return false;
}
}
}
/*
* Check the size of the buffered Cue.
* If it's valid, we know how far to read the Cue.
* After reaching the end, run the Cue.
*/
if (read_index_ >= (uint8_t)Byte::SizeByte4) {
uint32_t buffered_cue_size = IntByteConvert::byte_to_uint32(&buffer_[(uint8_t)Byte::SizeByte1]);
if (buffered_cue_size > 0 && read_index_ >= buffered_cue_size) {
run(buffer_);
read_index_ = 0;
return true;
}
}
return false;
}
void CueController::run() {
if (handlers_[buffer_[(uint8_t)Byte::PayloadByte]] != nullptr && !is_blocked(buffer_)) {
handlers_[buffer_[(uint8_t)Byte::PayloadByte]]->run(buffer_);
}
}
void CueController::run(uint8_t *cue) {
if (handlers_[cue[(uint8_t)Byte::PayloadByte]] != nullptr && !is_blocked(cue) && validate_header(cue)) {
handlers_[cue[(uint8_t)Byte::PayloadByte]]->run(cue);
}
}
void CueController::set_blocked_cues(BlockedCue *blocks, uint8_t num_blocks) {
this->blocked_cues_ = blocks;
this->num_blocked_cues_ = num_blocks;
}
bool CueController::validate_header(uint8_t *cue) {
// Check the ID
for (uint8_t i = 0; i < (uint8_t)Byte::ChecksumByte; i++) {
if (cue[i] != id_[i]) {
return false;
}
}
// Validate the Checksum
uint32_t size = IntByteConvert::byte_to_uint32(&cue[(uint8_t)Byte::SizeByte1]);
return (cue[(uint8_t)Byte::ChecksumByte] == checksum(cue, size));
}
CueController::~CueController() {
delete [] buffer_;
for (uint8_t i = 0; i < 5; i++) {
delete handlers_[i];
}
}
}