-
Notifications
You must be signed in to change notification settings - Fork 2
[WIP] Add zmq xpub feature to camerad and add write_to_zmq function #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,7 @@ namespace Archon { | |
| this->is_longexposure_set = false; | ||
| this->is_window = false; | ||
| this->is_autofetch = false; | ||
| this->is_zmq = false; | ||
| this->win_hstart = 0; | ||
| this->win_hstop = 2047; | ||
| this->win_vstart = 0; | ||
|
|
@@ -4527,6 +4528,160 @@ namespace Archon { | |
| } | ||
| /**************** Archon::Interface::autofetch *******************************/ | ||
|
|
||
| /**************** Archon::Interface::zmq ******************************/ | ||
| /** | ||
| * @fn zmq | ||
| * @brief turn zmq server on/off | ||
| * @param state_in, string "TRUE, FALSE, 0, or 1" | ||
| * @return ERROR or NO_ERROR | ||
| * | ||
| * NOTE: this assumes LVDS is module 10 | ||
| * This function does the following: | ||
| * 1) turns zmq server on | ||
| * | ||
| */ | ||
| long Interface::zmq(std::string state_in, std::string &state_out) { | ||
| std::string function = "Archon::Interface::zmq"; | ||
| std::stringstream message; | ||
| long error = NO_ERROR; | ||
| const std::string& endpoint = "tcp://*:5555"; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make endpoint configurable rather than hard-coded? |
||
|
|
||
| if ( !state_in.empty() ) { | ||
| try { | ||
| std::transform( state_in.begin(), state_in.end(), state_in.begin(), ::toupper ); // make uppercase | ||
|
|
||
| if ( state_in == "FALSE" || state_in == "0" ) { | ||
| // Shut down ZMQ server | ||
| if (!this->is_zmq) { | ||
| return (error); | ||
| } | ||
|
|
||
| this->is_zmq = false; | ||
|
|
||
| if (this->serverThread_.joinable()) { | ||
| this->serverThread_.join(); | ||
| } | ||
| this->publisher_.reset(); | ||
| this->context_.reset(); | ||
|
|
||
| if (error != NO_ERROR) { | ||
| message << "shutting down ZMQ server: "; | ||
| } else { | ||
| message << "shutting down ZMQ server: "; | ||
| } | ||
|
|
||
| logwrite(function, message.str()); | ||
| } else if ( state_in == "TRUE" || state_in == "1" ) { | ||
| // Turn on ZMQ server | ||
| if (this->is_zmq) { | ||
| return (error); | ||
| } | ||
|
|
||
| std::lock_guard<std::mutex> lock(this->serverMutex_); | ||
|
|
||
| try { | ||
| context_ = std::make_unique<zmq::context_t>(1); | ||
| this->publisher_ = std::make_unique<zmq::socket_t>(*context_, zmq::socket_type::xpub); | ||
| this->publisher_->bind(endpoint); | ||
| std::cout << "ZMQ server started in XPUB mode on " << endpoint << std::endl; | ||
| this->is_zmq = true; | ||
|
|
||
| serverThread_ = std::thread([this]() { | ||
| while (this->is_zmq) { | ||
| try { | ||
| zmq::message_t message; | ||
| publisher_->recv(message, zmq::recv_flags::dontwait); // Non-blocking receive | ||
| if (message.size() > 0) { | ||
| std::string received_message(static_cast<char*>(message.data()), message.size()); | ||
| // Process subscription messages | ||
| std::cout << "Received ZMQ message: " << received_message << std::endl; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens here? Maybe this puts data in a dequeue? |
||
| } | ||
| } catch (const zmq::error_t& e) { | ||
| if (e.num() != EWOULDBLOCK) { // Ignore would block errors. | ||
| std::cerr << "ZMQ receive error: " << e.what() << std::endl; | ||
| } | ||
| } | ||
| std::this_thread::sleep_for(std::chrono::milliseconds(10)); // Prevent busy waiting | ||
| } | ||
|
|
||
| if(this->publisher_){ | ||
| this->publisher_->close(); | ||
| } | ||
|
|
||
| if(this->context_){ | ||
| this->context_->shutdown(); | ||
| } | ||
|
|
||
| std::cout << "ZMQ server stopped." << std::endl; | ||
| }); | ||
| } catch (const zmq::error_t& e) { | ||
| std::cerr << "Error starting ZMQ server: " << e.what() << std::endl; | ||
| this->is_zmq = false; // Ensure the flag is reset in case of error. | ||
| } | ||
|
|
||
| if (error != NO_ERROR) { | ||
| message << "turning on ZMQ server: "; | ||
| } else { | ||
| message << "turning on ZMQ server: "; | ||
| } | ||
|
|
||
| logwrite(function, message.str()); | ||
| } else { | ||
| message.str(""); message << "ZMQ server " << state_in << " is invalid. Expecting {true,false,0,1}"; | ||
| this->camera.log_error( function, message.str() ); | ||
| return ERROR; | ||
| } | ||
|
|
||
| } catch (...) { | ||
| message.str(""); message << "unknown exception converting zmq state " << state_in << " to uppercase"; | ||
| this->camera.log_error( function, message.str() ); | ||
| return ERROR; | ||
| } | ||
| } | ||
|
|
||
| state_out = ( this->is_zmq ? "true" : "false" ); | ||
|
|
||
| if (error != NO_ERROR) { | ||
| message.str(""); message << "setting autofetch state to " << state_in; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. autofetch state? |
||
| this->camera.log_error( function, message.str() ); | ||
| return ERROR; | ||
| } | ||
|
|
||
| return (error); | ||
| } | ||
| /**************** Archon::Interface::zmq *******************************/ | ||
|
|
||
| /**************** Archon::Interface::write_to_zmq **************************/ | ||
| /** | ||
| * @fn write_to_zmq | ||
| * @brief write data on zmq socket | ||
| * @param string | ||
| * @return ERROR or NO_ERROR | ||
| * | ||
| */ | ||
| long Interface::write_to_zmq(const std::string& message) { | ||
| std::string function = "Archon::Interface::write_to_zmq"; | ||
| std::lock_guard<std::mutex> lock(this->serverMutex_); // Protect access | ||
| long error = NO_ERROR; | ||
|
|
||
| if (this->is_zmq && this->publisher_) { | ||
| try { | ||
| zmq::message_t zmq_message(message.size()); | ||
| memcpy(zmq_message.data(), message.data(), message.size()); | ||
| publisher_->send(zmq_message, zmq::send_flags::none); | ||
| error = NO_ERROR; | ||
| } catch (const zmq::error_t& e) { | ||
| std::cerr << "Error publishing message: " << e.what() << std::endl; | ||
| } | ||
| } else { | ||
| error = ERROR; | ||
| std::cerr << "ZMQ server is not running or publisher is not available." << std::endl; | ||
| } | ||
|
|
||
| return (error); | ||
| } | ||
| /**************** Archon::Interface::get_parameter **************************/ | ||
|
|
||
| /**************** Archon::Interface::hexpose ******************************/ | ||
| /** | ||
| * @fn hexpose | ||
|
|
@@ -4723,6 +4878,19 @@ namespace Archon { | |
| return error; | ||
| } | ||
|
|
||
| std::cout << "Image bitpix: " << std::to_string(this->camera_info.bitpix) << ", data type: " << std::to_string(this->camera_info.datatype) << std::endl; | ||
| int16_t *cbuf16s; | ||
| cbuf16s = (int16_t *)this->image_data; // cast to 16b signed int | ||
| std::stringstream ss; | ||
| for (size_t i=0; i < this->camera_info.section_size; i++) { | ||
| ss << cbuf16s[i]; | ||
| if (i < this->camera_info.section_size - 1) { | ||
| ss << ","; | ||
| } | ||
| } | ||
| // std::cout << "Image data: " << ss.str() << std::endl; | ||
| this->write_to_zmq(ss.str()); | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if write_to_zmq( accepted *buf, bufsz ) and then did something like, |
||
| // ASYNC status message on completion of each readout | ||
| nread++; | ||
| message.str(""); message << "READOUT COMPLETE (" << nread << " of " << nseq << " read)"; | ||
|
|
@@ -5437,7 +5605,7 @@ namespace Archon { | |
| message << "waiting for new frame: current frame=" << this->lastframe << " current buffer=" << this->frame.index+1; | ||
| logwrite(function, message.str()); | ||
|
|
||
| usleep( 700 ); // tune for size of window | ||
| // usleep( 700 ); // tune for size of window | ||
|
|
||
| this->frame.index += 1; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a misplaced comment, as there's no relationship between ZMQ and LVDS?