mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	viewpng and writeconfig removed
Former-commit-id: ee46218e71df3090336754353566e7b659b3a801
This commit is contained in:
		| @@ -1,4 +1,2 @@ | ||||
| add_subdirectory(hyperiond) | ||||
| add_subdirectory(hyperion-remote) | ||||
| add_subdirectory(viewpng) | ||||
| add_subdirectory(writeconfig) | ||||
|   | ||||
| @@ -1,15 +0,0 @@ | ||||
| # Find the libPNG | ||||
| find_package(PNG QUIET) | ||||
|  | ||||
| if(PNG_FOUND) | ||||
| 	# Add additional includes dirs | ||||
| 	include_directories(${PNG_INCLUDE_DIR}) | ||||
|  | ||||
| 	add_executable(viewpng | ||||
| 			FbWriter.h | ||||
| 			ViewPng.cpp) | ||||
|  | ||||
| 	target_link_libraries(viewpng | ||||
| 			hyperion | ||||
| 			${PNG_LIBRARIES}) | ||||
| endif(PNG_FOUND) | ||||
| @@ -1,135 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
| #include <fcntl.h> | ||||
| #include <linux/fb.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/ioctl.h> | ||||
|  | ||||
| #include <utils/Image.h> | ||||
| #include <utils/ColorRgb.h> | ||||
|  | ||||
| /// | ||||
| /// FbWriter allows direct access tot the FrameBuffer. It writes and image to the framebuffer, | ||||
| /// adjusting the resolution as required. When destructed the FrameBuffer is switch to original | ||||
| /// configuration. | ||||
| /// | ||||
| class FbWriter | ||||
| { | ||||
| public: | ||||
| 	/// | ||||
| 	/// Constructs the FrameBuffer writer opening the FrameBuffer device and storing the current | ||||
| 	/// configuration. | ||||
| 	/// | ||||
| 	FbWriter() | ||||
| 	{ | ||||
| 		initialise(); | ||||
| 	} | ||||
|  | ||||
| 	/// | ||||
| 	/// Destructor of the write. Switches the FrameBuffer to its origianl configuration and closes | ||||
| 	/// the FrameBuffer | ||||
| 	/// | ||||
| 	~FbWriter() | ||||
| 	{ | ||||
| 		if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo)) | ||||
| 		{ | ||||
| 			printf("Error re-setting variable information.\n"); | ||||
| 		} | ||||
|  | ||||
| 		close(fbfd); | ||||
| 	} | ||||
|  | ||||
| 	/// | ||||
| 	/// Initialises the write, opening the FrameBuffer | ||||
| 	/// | ||||
| 	/// @return Zero on succes else negative | ||||
| 	/// | ||||
| 	int initialise() | ||||
| 	{ | ||||
| 		// Open the file for reading and writing | ||||
| 		fbfd = open("/dev/fb0", O_RDWR); | ||||
| 		if (!fbfd) | ||||
| 		{ | ||||
| 			std::cerr << "Error: cannot open framebuffer device." << std::endl; | ||||
| 			return -1; | ||||
| 		} | ||||
| 		printf("The framebuffer device was opened successfully.\n"); | ||||
|  | ||||
| 		// Get fixed screen information | ||||
| 		if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) | ||||
| 		{ | ||||
| 			std::cerr << "Error reading fixed information.\n" << std::endl; | ||||
| 			return -1; | ||||
| 		} | ||||
| 		// Get variable screen information | ||||
| 		if (ioctl(fbfd, FBIOGET_VSCREENINFO, &orig_vinfo)) | ||||
| 		{ | ||||
| 			std::cerr << "Error reading variable information.\n" << std::endl; | ||||
| 			return -1; | ||||
| 		} | ||||
| 		printf("Original %dx%d, %dbpp\n", orig_vinfo.xres, orig_vinfo.yres, orig_vinfo.bits_per_pixel ); | ||||
|  | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/// | ||||
| 	/// Writes the given RGB Image to the FrameBuffer. When required the resolution of the | ||||
| 	/// FrameBuffer is asjusted to match the given image | ||||
| 	/// | ||||
| 	/// @param image  The RGB Image | ||||
| 	/// | ||||
| 	void writeImage(const Image<ColorRgb>& image) | ||||
| 	{ | ||||
| 		std::cout << "Writing image [" << image.width() << "x" << image.height() << "]" << std::endl; | ||||
|  | ||||
| 		// Make a copy of the original screen-info | ||||
| 		fb_var_screeninfo vinfo = orig_vinfo; | ||||
| //		memcpy(&vinfo, &orig_vinfo, sizeof(fb_var_screeninfo)); | ||||
|  | ||||
| 		// Configure the frame-buffer for the new image | ||||
| 		vinfo.xres = image.width(); | ||||
| 		vinfo.yres = image.height(); | ||||
| 		vinfo.bits_per_pixel = 24; | ||||
| 		if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) | ||||
| 		{ | ||||
| 			printf("Error configuring frame-buffer"); | ||||
| 		} | ||||
|  | ||||
| 		ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo); | ||||
| 		std::cout << "New set resolution: " << vinfo.xres << "x" << vinfo.yres << std::endl; | ||||
|  | ||||
| 		// map fb to user mem | ||||
| 		long screensize = vinfo.yres * finfo.line_length;//vinfo.yres * vinfo.bits_per_pixel / 8; | ||||
| 		char* fbp = (char*)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd,  0); | ||||
| 		if (!fbp) | ||||
| 		{ | ||||
| 			// Failed to create memory map | ||||
| 			std::cout << "Failed to create the memory map" << std::endl; | ||||
| 			return; | ||||
| 		} | ||||
| 		std::cout << "Screensize  : " << screensize << std::endl; | ||||
| 		std::cout << "Max fb-index: " << (image.width()-1)*3 + (image.height()-1)*finfo.line_length << std::endl; | ||||
| 		std::cout << "[" << vinfo.xres << "x" << vinfo.yres << "] == [" << image.width() << "x" << image.height() << "]" << std::endl; | ||||
|  | ||||
| 		for (unsigned iY=0; iY<image.height(); ++iY) | ||||
| 		{ | ||||
| 			memcpy(fbp + iY*finfo.line_length, &(image(0, iY)), image.width()*3); | ||||
| 		} | ||||
| 		std::cout << "FINISHED COPYING IMAGE TO FRAMEBUFFER" << std::endl; | ||||
| 		// cleanup | ||||
| 		munmap(fbp, screensize); | ||||
| 	} | ||||
|  | ||||
| 	/// The identifier of the FrameBuffer File-Device | ||||
| 	int fbfd; | ||||
| 	/// The 'Fixed' screen information | ||||
| 	fb_fix_screeninfo finfo; | ||||
| 	/// The original 'Variable' screen information | ||||
| 	fb_var_screeninfo orig_vinfo; | ||||
| }; | ||||
| @@ -1,156 +0,0 @@ | ||||
|  | ||||
| // STL includes | ||||
| #include <iostream> | ||||
|  | ||||
| // LibPNG includes | ||||
| #include <png.h> | ||||
|  | ||||
| // Utils includes | ||||
| #include <utils/Image.h> | ||||
| #include <utils/ColorRgb.h> | ||||
| #include <utils/jsonschema/JsonFactory.h> | ||||
|  | ||||
| // Raspilight includes | ||||
| #include <hyperion/Hyperion.h> | ||||
|  | ||||
| // Local includes | ||||
| #include "FbWriter.h" | ||||
|  | ||||
| bool read_png(std::string file_name, Image<ColorRgb>*& rgbImage) | ||||
| { | ||||
| 	png_structp png_ptr; | ||||
| 	png_infop info_ptr; | ||||
| 	FILE *fp; | ||||
|  | ||||
| 	if ((fp = fopen(file_name.c_str(), "rb")) == NULL) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | ||||
|  | ||||
| 	if (png_ptr == NULL) | ||||
| 	{ | ||||
| 		fclose(fp); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	info_ptr = png_create_info_struct(png_ptr); | ||||
| 	if (info_ptr == NULL) | ||||
| 	{ | ||||
| 		fclose(fp); | ||||
| 		png_destroy_read_struct(&png_ptr, NULL, NULL); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	if (setjmp(png_jmpbuf(png_ptr))) | ||||
| 	{ | ||||
| 		png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||||
| 		fclose(fp); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	png_init_io(png_ptr, fp); | ||||
|  | ||||
| 	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_SWAP_ALPHA | PNG_TRANSFORM_EXPAND, NULL); | ||||
|  | ||||
| 	png_uint_32 width = png_get_image_width(png_ptr, info_ptr); | ||||
| 	png_uint_32 height = png_get_image_height(png_ptr, info_ptr); | ||||
|  | ||||
| 	png_uint_32 bitdepth   = png_get_bit_depth(png_ptr, info_ptr); | ||||
| 	png_uint_32 channels   = png_get_channels(png_ptr, info_ptr); | ||||
| 	png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); | ||||
|  | ||||
| 	std::cout << "BitDepth" << std::endl; | ||||
| 	std::cout << bitdepth << std::endl; | ||||
| 	std::cout << "Channels" << std::endl; | ||||
| 	std::cout << channels << std::endl; | ||||
| 	std::cout << "ColorType" << std::endl; | ||||
| 	std::cout << color_type << std::endl; | ||||
|  | ||||
| 	png_bytepp row_pointers; | ||||
| 	row_pointers = png_get_rows(png_ptr, info_ptr); | ||||
|  | ||||
| 	rgbImage = new Image<ColorRgb>(width, height); | ||||
|  | ||||
| 	for (unsigned iRow=0; iRow<height; ++iRow) | ||||
| 	{ | ||||
| 		if (color_type == PNG_COLOR_TYPE_RGB) | ||||
| 		{ | ||||
| 			ColorRgb* rowPtr = reinterpret_cast<ColorRgb*>(row_pointers[iRow]); | ||||
| 			for (unsigned iCol=0; iCol<width; ++iCol) | ||||
| 			{ | ||||
| 				(*rgbImage)(iCol, iRow) = rowPtr[iCol]; | ||||
| 			} | ||||
| 		} | ||||
| 		else if (color_type == PNG_COLOR_TYPE_RGBA) | ||||
| 		{ | ||||
| 			unsigned* rowPtr = reinterpret_cast<unsigned*>(row_pointers[iRow]); | ||||
| 			for (unsigned iCol=0; iCol<width; ++iCol) | ||||
| 			{ | ||||
| 				const unsigned argbValue = rowPtr[iCol]; | ||||
| 				(*rgbImage)(iCol, iRow) = ColorRgb{uint8_t((argbValue >> 16) & 0xFF), uint8_t((argbValue >> 8) & 0xFF), uint8_t((argbValue) & 0xFF)}; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// Unknown/Unimplemented color-format | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||||
| 	fclose(fp); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	if (argc < 2) | ||||
| 	{ | ||||
| 		// Missing required argument | ||||
| 		std::cout << "Missing PNG-argumet. Usage: 'ViewPng [png-file]" << std::endl; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	const std::string pngFilename = argv[1]; | ||||
|  | ||||
| 	Image<ColorRgb>* image = nullptr; | ||||
| 	if (!read_png(pngFilename, image) || image == nullptr) | ||||
| 	{ | ||||
| 		std::cout << "Failed to load image" << std::endl; | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	const char* homeDir = getenv("RASPILIGHT_HOME"); | ||||
| 	if (!homeDir) | ||||
| 	{ | ||||
| 		homeDir = "/home/pi"; | ||||
| 	} | ||||
|  | ||||
| 	std::cout << "RASPILIGHT HOME DIR: " << homeDir << std::endl; | ||||
|  | ||||
| 	const std::string schemaFile = std::string(homeDir) + "/hyperion.schema.json"; | ||||
| 	const std::string configFile = std::string(homeDir) + "/hyperion.config.json"; | ||||
|  | ||||
| 	Json::Value raspiConfig; | ||||
| 	if (JsonFactory::load(schemaFile, configFile, raspiConfig) < 0) | ||||
| 	{ | ||||
| 		std::cerr << "UNABLE TO LOAD CONFIGURATION" << std::endl; | ||||
| 		return -1; | ||||
| 	} | ||||
| 	std::cout << "Loaded configuration: " << raspiConfig << std::endl; | ||||
|  | ||||
| 	FbWriter fbWriter; | ||||
|  | ||||
| 	Hyperion raspiLight(raspiConfig); | ||||
| //	raspiLight.setInputSize(image->width(), image->height()); | ||||
|  | ||||
| 	fbWriter.writeImage(*image); | ||||
| //	raspiLight(*image); | ||||
|  | ||||
| 	sleep(5); | ||||
|  | ||||
| 	delete image; | ||||
| } | ||||
| @@ -1,2 +0,0 @@ | ||||
| add_executable(WriteConfig | ||||
| 		WriteConfig.cpp) | ||||
| @@ -1,212 +0,0 @@ | ||||
| // STL includes | ||||
| #include <string> | ||||
| #include <fstream> | ||||
| #include <vector> | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
|  | ||||
| using namespace std; | ||||
|  | ||||
| ofstream& indent(ofstream& ofs, unsigned indent) | ||||
| { | ||||
| 	for (unsigned i=0; i<indent; ++i) | ||||
| 	{ | ||||
| 		ofs << '\t'; | ||||
| 	} | ||||
| 	return ofs; | ||||
| } | ||||
|  | ||||
| struct LedFrame | ||||
| { | ||||
| 	unsigned topLedCnt; | ||||
| 	unsigned rightLedCnt; | ||||
| 	unsigned bottomLedCnt; | ||||
| 	unsigned leftLedCnt; | ||||
|  | ||||
| 	unsigned topLeftOffset; | ||||
|  | ||||
| 	unsigned borderWidth; | ||||
| 	unsigned borderHeight; | ||||
|  | ||||
| 	LedFrame() : | ||||
| 		topLedCnt(17), | ||||
| 		rightLedCnt(8), | ||||
| 		bottomLedCnt(17), | ||||
| 		leftLedCnt(8), | ||||
|  | ||||
| 		topLeftOffset(17), | ||||
|  | ||||
| 		borderWidth(10), | ||||
| 		borderHeight(10) | ||||
| 	{ | ||||
| 		// empty | ||||
| 	} | ||||
|  | ||||
| 	unsigned totalLedCnt() const | ||||
| 	{ | ||||
| 		return topLeftOffset + rightLedCnt + bottomLedCnt + leftLedCnt; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct Led | ||||
| { | ||||
| 	unsigned index; | ||||
| 	double minX; | ||||
| 	double maxX; | ||||
| 	double minY; | ||||
| 	double maxY; | ||||
| }; | ||||
|  | ||||
| void determineBoundaries(const LedFrame& ledFrame, const unsigned iLed, double& minX, double& maxX, double& minY, double& maxY) | ||||
| { | ||||
| 	if (iLed < ledFrame.topLedCnt) | ||||
| 	{ | ||||
| 		// TOP of screen | ||||
| 		minX =     iLed * 100.0/ledFrame.topLedCnt; | ||||
| 		maxX = (iLed+1) * 100.0/ledFrame.topLedCnt; | ||||
|  | ||||
| 		minY = 100.0 - ledFrame.borderHeight; | ||||
| 		maxY = 100.0; | ||||
| 	} | ||||
| 	else if (iLed < (ledFrame.topLedCnt+ledFrame.rightLedCnt)) | ||||
| 	{ | ||||
| 		// RIGHT of screen | ||||
| 		minX = 100.0 - ledFrame.borderWidth; | ||||
| 		maxX = 100.0; | ||||
|  | ||||
| 		minY = 100.0 - (iLed-15) * 100.0/(ledFrame.rightLedCnt+2); | ||||
| 		maxY = 100.0 - (iLed-16) * 100.0/(ledFrame.rightLedCnt+2); | ||||
| 	} | ||||
| 	else if (iLed < (ledFrame.topLedCnt+ledFrame.rightLedCnt+ledFrame.bottomLedCnt)) | ||||
| 	{ | ||||
| 		// BOTTOM of screen | ||||
| 		minX = 100.0 - (iLed-24) * 100.0/ledFrame.bottomLedCnt; | ||||
| 		maxX = 100.0 - (iLed-25) * 100.0/ledFrame.bottomLedCnt; | ||||
|  | ||||
| 		minY =  0.0; | ||||
| 		maxY = ledFrame.borderHeight; | ||||
| 	} | ||||
| 	else if (iLed < (ledFrame.topLedCnt+ledFrame.rightLedCnt+ledFrame.bottomLedCnt+ledFrame.leftLedCnt)) | ||||
| 	{ | ||||
| 		// LEFT of screen | ||||
| 		minX =  0.0; | ||||
| 		maxX = ledFrame.borderWidth; | ||||
|  | ||||
| 		minY = (iLed-41) * 100.0/(ledFrame.leftLedCnt+2); | ||||
| 		maxY = (iLed-40) * 100.0/(ledFrame.leftLedCnt+2); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		std::cerr << "Requested led index(" << iLed << ") out of bound" << endl; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::vector<Led> createLedMapping(const LedFrame ledFrame) | ||||
| { | ||||
| 	std::vector<Led> leds; | ||||
| 	for (unsigned iLed=0; iLed<ledFrame.totalLedCnt(); ++iLed) | ||||
| 	{ | ||||
| 		Led led; | ||||
|  | ||||
| 		led.index = (iLed + ledFrame.topLeftOffset)%ledFrame.totalLedCnt(); | ||||
| 		determineBoundaries(ledFrame, iLed, led.minX, led.maxX, led.minY, led.maxY); | ||||
|  | ||||
| 		leds.push_back(led); | ||||
| 	} | ||||
|  | ||||
| 	std::sort(leds.begin(), leds.end(), [](const Led& lhs, const Led& rhs){ return lhs.index < rhs.index; }); | ||||
|  | ||||
| 	return leds; | ||||
| } | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	const std::string filename = "hyperion.config.json"; | ||||
|  | ||||
| 	LedFrame myFrame; | ||||
| 	std::vector<Led> leds = createLedMapping(myFrame); | ||||
| 	ofstream configOfs(filename.c_str()); | ||||
|  | ||||
| 	configOfs << "// Automatically generated configuration file for 'Hyperion'" << endl; | ||||
| 	configOfs << "// Generation script: " << argv[0] << endl; | ||||
| 	configOfs << endl; | ||||
| 	configOfs << "{" << endl; | ||||
|  | ||||
| 	// Write the device section | ||||
| 	indent(configOfs, 1) << R"("device" : )" << endl; | ||||
| 	indent(configOfs, 1) << "{" << endl; | ||||
| 	indent(configOfs, 2) << R"("name"     : "MyPi",)" << endl; | ||||
| 	indent(configOfs, 2) << R"("type"     : "ws2801",)" << endl; | ||||
| 	indent(configOfs, 2) << R"("output"   : "/dev/spidev0.0",)" << endl; | ||||
| 	indent(configOfs, 2) << R"("interval" : 20000,)" << endl; | ||||
| 	indent(configOfs, 2) << R"("rate"     : 48000)" << endl; | ||||
| 	indent(configOfs, 1) << "}," << endl; | ||||
|  | ||||
| 	// Write the color-correction section | ||||
| 	indent(configOfs, 1) << R"("color" : )" << endl; | ||||
| 	indent(configOfs, 1) << "{" << endl; | ||||
| 	indent(configOfs, 2) << R"("red" : )" << endl; | ||||
| 	indent(configOfs, 2) << "{" << endl; | ||||
| 	indent(configOfs, 3) << R"("gamma"      : 1.0,)" << endl; | ||||
| 	indent(configOfs, 3) << R"("adjust"     : 1.0,)" << endl; | ||||
| 	indent(configOfs, 3) << R"("blacklevel" : 0.0)" << endl; | ||||
| 	indent(configOfs, 2) << "}," << endl; | ||||
| 	indent(configOfs, 2) << R"("green" : )" << endl; | ||||
| 	indent(configOfs, 2) << "{" << endl; | ||||
| 	indent(configOfs, 3) << R"("gamma"      : 1.0,)" << endl; | ||||
| 	indent(configOfs, 3) << R"("adjust"     : 1.0,)" << endl; | ||||
| 	indent(configOfs, 3) << R"("blacklevel" : 0.0)" << endl; | ||||
| 	indent(configOfs, 2) << "}," << endl; | ||||
| 	indent(configOfs, 2) << R"("blue" : )" << endl; | ||||
| 	indent(configOfs, 2) << "{" << endl; | ||||
| 	indent(configOfs, 3) << R"("gamma"      : 1.0,)" << endl; | ||||
| 	indent(configOfs, 3) << R"("adjust"     : 1.0,)" << endl; | ||||
| 	indent(configOfs, 3) << R"("blacklevel" : 0.0)" << endl; | ||||
| 	indent(configOfs, 2) << "}" << endl; | ||||
| 	indent(configOfs, 1) << "}," << endl; | ||||
|  | ||||
| 	// Write the leds section | ||||
| 	indent(configOfs, 1) << R"("leds" : )" << endl; | ||||
| 	indent(configOfs, 1) << "[" << endl; | ||||
| 	for (const Led& led : leds) | ||||
| 	{ | ||||
| 		// Add comments indicating the corners of the configuration | ||||
| 		if (led.minX == 0.0) | ||||
| 		{ | ||||
| 			if (led.minY == 0.0) | ||||
| 			{ | ||||
| 				indent(configOfs, 2) << "// TOP-LEFT Corner" << endl; | ||||
| 			} | ||||
| 			else if (led.maxY == 100.0) | ||||
| 			{ | ||||
| 				indent(configOfs, 2) << "// BOTTOM-LEFT Corner" << endl; | ||||
| 			} | ||||
| 		} | ||||
| 		else if (led.maxX == 100.0) | ||||
| 		{ | ||||
| 			if (led.minY == 0.0) | ||||
| 			{ | ||||
| 				indent(configOfs, 2) << "// TOP-RIGHT Corner" << endl; | ||||
| 			} | ||||
| 			else if (led.maxY == 100.0) | ||||
| 			{ | ||||
| 				indent(configOfs, 2) << "// BOTTOM-RIGHT Corner" << endl; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Write the configuration of the led | ||||
| 		indent(configOfs, 2) << "{" << endl; | ||||
| 		indent(configOfs, 3) << R"("index" : )" << led.index << "," << endl; | ||||
| 		indent(configOfs, 3) << R"("hscan" : { "minimum" : )" << led.minX << R"(, "maximum" : )" << led.maxX << R"( },)" << endl; | ||||
| 		indent(configOfs, 3) << R"("vscan" : { "minimum" : )" << led.minY << R"(, "maximum" : )" << led.maxY << R"( })" << endl; | ||||
| 		indent(configOfs, 2) << "}"; | ||||
| 		if (led.index != leds.back().index) | ||||
| 		{ | ||||
| 			configOfs << ","; | ||||
| 		} | ||||
| 		configOfs << endl; | ||||
| 	} | ||||
| 	indent(configOfs, 1) << "]" << endl; | ||||
|  | ||||
| 	configOfs << "}" << endl; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user