Asynchronous pointcloud stream

This example shows how to asynchronous fetch a pointcloud with a stream and how to get a status at the same time.

/*
 * Copyright (c) 2020 Blickfeld GmbH.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE.md file in the root directory of this source tree.
 */
#include <stdio.h>

#include <blickfeld/scanner.h>
#include <blickfeld/utils.h>

int example(int argc, char* argv[]) {
	std::string scanner_ip_or_host = "localhost";
	std::string dump_fn;
	if(argc > 1)
		scanner_ip_or_host = argv[1];
	if(argc > 2)
		dump_fn = argv[2];

	std::shared_ptr<blickfeld::scanner> scanner = blickfeld::scanner::connect(scanner_ip_or_host);
	printf("Connected.\n");

	// Synchronous request for scan_pattern
	printf("ScanPattern: %s", scanner->get_scan_pattern().DebugString().c_str());

	// Asynchronous request for status
	scanner->subscribe([](const blickfeld::protocol::Status& status) {
		printf("Got scanner status (async): %s", status.scanner().DebugString().c_str());
	});

	// Synchronous request for status
	printf("Got status (sync): %s", scanner->get_status().DebugString().c_str());

	std::shared_ptr<std::thread> scanner_thread = scanner->async_run_thread();

	// Subscribe for point cloud stream
	auto stream = scanner->get_point_cloud_stream();
	stream->subscribe([scanner](const blickfeld::protocol::data::Frame& frame) {
		// Format of frame is described in protocol/blickfeld/data/frame.proto or doc/protocol.md
		// Protobuf API is described in https://developers.google.com/protocol-buffers/docs/cpptutorial
		time_t time_s = frame.start_time_ns() / 1e9;
		auto timepoint = localtime(&time_s);
		printf ("Frame:  scanlines %u (max %0.2f Hz - current %0.2f Hz) - timestamp %f - %s",
			frame.scanlines_size(),
			frame.scan_pattern().frame_rate().maximum(),
			frame.scan_pattern().frame_rate().target(),
			frame.start_time_ns() / 1e9,
			asctime(timepoint)
			);

		// Example for scanline and point iteration
		for (int s_ind = 0; s_ind < frame.scanlines_size(); s_ind++) {
			for (int p_ind = 0; p_ind < frame.scanlines(s_ind).points_size(); p_ind++) {
				auto& point = frame.scanlines(s_ind).points(p_ind);

		                // Iterate through all the returns for each points
				for (int r_ind = 0; r_ind < point.returns_size(); r_ind++) {
					auto& ret = point.returns(r_ind);

		                        // Print information for the first 10 points in the first scanline of each frame
		                        // ret.cartesian(0) equals frame.scanlines(s_ind).points(p_ind).returns(r_ind).cartesian(0)
					if (p_ind < 10 && s_ind == 0)
						printf("Point %u -ret %u [x: %4.2f, y: %4.2f, z: %4.2f] - intensity: %u\n",
						       point.id(), ret.id(),
						       ret.cartesian(0), ret.cartesian(1), ret.cartesian(2),
						       ret.intensity());
				}
			}
		}
	});

	// Join thread of scanner
	scanner_thread->join();

	return 0;
}

int main(int argc, char* argv[]) {
	try {
		return example(argc, argv);
	} catch(const std::exception& e) {
		fprintf(stderr, "main caught exception:\n%s\n", e.what());
	}
	return 1;
}