// // begin license header // // This file is part of Pixy CMUcam5 or "Pixy" for short // // All Pixy source code is provided under the terms of the // GNU General Public License v2 (http://www.gnu.org/licenses/gpl-2.0.html). // Those wishing to use Pixy source code, software and/or // technologies under different licensing terms should contact us at // cmucam@cs.cmu.edu. Such licensing terms are available for // all portions of the Pixy codebase presented here. // // end license header // #include #include #include "pixyinterpreter.hpp" PixyInterpreter::PixyInterpreter() { init_ = false; receiver_ = NULL; } PixyInterpreter::~PixyInterpreter() { close(); } int PixyInterpreter::init() { int USB_return_value; if(init_ == true) { fprintf(stderr, "libpixy: Already initialized."); return 0; } USB_return_value = link_.open(); if(USB_return_value < 0) { return USB_return_value; } receiver_ = new ChirpReceiver(&link_, this); init_ = true; return 0; } void PixyInterpreter::close() { if (receiver_) { delete receiver_; receiver_ = NULL; } init_ = false; } int PixyInterpreter::get_blocks(int max_blocks, Block * blocks) { uint16_t number_of_blocks_to_copy; uint16_t index; // Check parameters // if(max_blocks < 0 || blocks == 0) { return PIXY_ERROR_INVALID_PARAMETER; } number_of_blocks_to_copy = (max_blocks >= blocks_.size() ? blocks_.size() : max_blocks); // Copy blocks // for (index = 0; index != number_of_blocks_to_copy; ++index) { memcpy(&blocks[index], &blocks_[index], sizeof(Block)); } blocks_are_new_ = false; return number_of_blocks_to_copy; } int PixyInterpreter::send_command(const char * name, ...) { va_list arguments; int return_value; va_start(arguments, name); return_value = send_command(name, arguments); va_end(arguments); return return_value; } int PixyInterpreter::send_command(const char * name, va_list args) { ChirpProc procedure_id; int return_value; va_list arguments; va_copy(arguments, args); // Request chirp procedure id for 'name'. // procedure_id = receiver_->getProc(name); // Was there an error requesting procedure id? // if (procedure_id < 0) { // Request error // va_end(arguments); return PIXY_ERROR_INVALID_COMMAND; } // Execute chirp synchronous remote procedure call // return_value = receiver_->call(SYNC, procedure_id, arguments); va_end(arguments); return return_value; } int PixyInterpreter::service() { if(!init_) return -1; receiver_->service(false); return 0; //success } void PixyInterpreter::interpret_data(const void * chirp_data[]) { uint8_t chirp_message; uint32_t chirp_type; if (chirp_data[0]) { chirp_message = Chirp::getType(chirp_data[0]); switch(chirp_message) { case CRP_TYPE_HINT: chirp_type = * static_cast(chirp_data[0]); switch(chirp_type) { case FOURCC('B', 'A', '8', '1'): break; case FOURCC('C', 'C', 'Q', '1'): break; case FOURCC('C', 'C', 'B', '1'): interpret_CCB1(chirp_data + 1); break; case FOURCC('C', 'C', 'B', '2'): interpret_CCB2(chirp_data + 1); break; case FOURCC('C', 'M', 'V', '1'): break; default: fprintf(stderr,"libpixy: Chirp hint [%u] not recognized.\n", chirp_type); break; } break; case CRP_HSTRING: break; default: fprintf(stderr, "libpixy: Unknown message received from Pixy: [%u]\n", chirp_message); break; } } } void PixyInterpreter::interpret_CCB1(const void * CCB1_data[]) { uint32_t number_of_blobs; const BlobA * blobs; // Add blocks with normal signatures // number_of_blobs = * static_cast(CCB1_data[3]); blobs = static_cast(CCB1_data[4]); number_of_blobs /= sizeof(BlobA) / sizeof(uint16_t); add_normal_blocks(blobs, number_of_blobs); blocks_are_new_ = true; } void PixyInterpreter::interpret_CCB2(const void * CCB2_data[]) { uint32_t number_of_blobs; const BlobA * A_blobs; const BlobB * B_blobs; // The blocks container will only contain the newest // // blocks // blocks_.clear(); // Add blocks with color code signatures // number_of_blobs = * static_cast(CCB2_data[5]); B_blobs = static_cast(CCB2_data[6]); number_of_blobs /= sizeof(BlobB) / sizeof(uint16_t); add_color_code_blocks(B_blobs, number_of_blobs); // Add blocks with normal signatures // number_of_blobs = * static_cast(CCB2_data[3]); A_blobs = static_cast(CCB2_data[4]); number_of_blobs /= sizeof(BlobA) / sizeof(uint16_t); add_normal_blocks(A_blobs, number_of_blobs); blocks_are_new_ = true; } void PixyInterpreter::add_normal_blocks(const BlobA * blocks, uint32_t count) { uint32_t index; Block block; for (index = 0; index != count; ++index) { // Decode CCB1 'Normal' Signature Type // block.type = PIXY_BLOCKTYPE_NORMAL; block.signature = blocks[index].m_model; block.width = blocks[index].m_right - blocks[index].m_left; block.height = blocks[index].m_bottom - blocks[index].m_top; block.x = blocks[index].m_left + block.width / 2; block.y = blocks[index].m_top + block.height / 2; // Angle is not a valid parameter for 'Normal' // // signature types. Setting to zero by default. // block.angle = 0; // Store new block in block buffer // if (blocks_.size() == PIXY_BLOCK_CAPACITY) { // Blocks buffer is full - replace oldest received block with newest block // blocks_.erase(blocks_.begin()); blocks_.push_back(block); } else { // Add new block to blocks buffer // blocks_.push_back(block); } } } void PixyInterpreter::add_color_code_blocks(const BlobB * blocks, uint32_t count) { uint32_t index; Block block; for (index = 0; index != count; ++index) { // Decode 'Color Code' Signature Type // block.type = PIXY_BLOCKTYPE_COLOR_CODE; block.signature = blocks[index].m_model; block.width = blocks[index].m_right - blocks[index].m_left; block.height = blocks[index].m_bottom - blocks[index].m_top; block.x = blocks[index].m_left + block.width / 2; block.y = blocks[index].m_top + block.height / 2; block.angle = blocks[index].m_angle; // Store new block in block buffer // if (blocks_.size() == PIXY_BLOCK_CAPACITY) { // Blocks buffer is full - replace oldest received block with newest block // blocks_.erase(blocks_.begin()); blocks_.push_back(block); } else { // Add new block to blocks buffer // blocks_.push_back(block); } } } int PixyInterpreter::blocks_are_new() { if (blocks_are_new_) { // Fresh blocks!! :D // return 1; } else { // Stale blocks... :\ // return 0; } }