mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/master'
Former-commit-id: 9b4da8b8c5f61f9507b4775d0f28e187a0246605
This commit is contained in:
		@@ -355,15 +355,30 @@
 | 
				
			|||||||
	/// The black border configuration, contains the following items: 
 | 
						/// The black border configuration, contains the following items: 
 | 
				
			||||||
	///  * enable    : true if the detector should be activated
 | 
						///  * enable    : true if the detector should be activated
 | 
				
			||||||
	///  * threshold : Value below which a pixel is regarded as black (value between 0.0 and 1.0)
 | 
						///  * threshold : Value below which a pixel is regarded as black (value between 0.0 and 1.0)
 | 
				
			||||||
	"blackborderdetector" : 
 | 
						///  * unknownFrameCnt : Number of frames without any detection before the border is set to 0 (default 600) - optional
 | 
				
			||||||
 | 
						///  * borderFrameCnt : Number of frames before a consistent detected border gets set (default 50) - optional
 | 
				
			||||||
 | 
						///  * maxInconsistentCnt : Number of inconsistent frames that are ignored before a new border gets a chance to proof consistency - optional
 | 
				
			||||||
 | 
						///  * blurRemoveCnt : Number of pixels that get removed from the detected border to cut away blur (default 1) - optional
 | 
				
			||||||
 | 
						///  * mode : Border detection mode (values "default","classic","osd") - optional
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						"blackborderdetector" :
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"enable" : true,
 | 
							"enable" : true,
 | 
				
			||||||
		"threshold" : 0.01
 | 
							"threshold" : 0.01,
 | 
				
			||||||
 | 
							"unknownFrameCnt": 600,
 | 
				
			||||||
 | 
							"borderFrameCnt" : 50,
 | 
				
			||||||
 | 
							"maxInconsistentCnt" : 10,
 | 
				
			||||||
 | 
							"blurRemoveCnt": 1,
 | 
				
			||||||
 | 
							"mode" : "default"
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// The configuration of the effect engine, contains the following items: 
 | 
						/// The configuration of the effect engine, contains the following items: 
 | 
				
			||||||
	///  * paths        : An array with absolute location(s) of directories with effects 
 | 
						///  * paths        : An array with absolute location(s) of directories with effects 
 | 
				
			||||||
	///  * bootsequence : The effect selected as 'boot sequence'
 | 
						///  * bootsequence : The effect selected as 'boot sequence'
 | 
				
			||||||
 | 
						///    * effect : name of the effect you want to start. Set to empty if no effect wanted
 | 
				
			||||||
 | 
						///    * color  : switch to static color after effect is done
 | 
				
			||||||
 | 
						///    * duration_ms : duration of boot effect in ms. 0 means effect stays forever
 | 
				
			||||||
 | 
						///    * priority : priority of boot effect and static color
 | 
				
			||||||
	"effects" : 
 | 
						"effects" : 
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"paths" : 
 | 
							"paths" : 
 | 
				
			||||||
@@ -374,8 +389,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"bootsequence" : 
 | 
						"bootsequence" : 
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"effect" : "Rainbow swirl fast",
 | 
							"color"       : [0,0,0],
 | 
				
			||||||
		"duration_ms" : 3000
 | 
							"effect"      : "Rainbow swirl fast",
 | 
				
			||||||
 | 
							"duration_ms" : 3000,
 | 
				
			||||||
 | 
							"priority"    : 0
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	///  The configuration for the frame-grabber, contains the following items: 
 | 
						///  The configuration for the frame-grabber, contains the following items: 
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -359,6 +359,10 @@
 | 
				
			|||||||
	/// The configuration of the effect engine, contains the following items: 
 | 
						/// The configuration of the effect engine, contains the following items: 
 | 
				
			||||||
	///  * paths        : An array with absolute location(s) of directories with effects 
 | 
						///  * paths        : An array with absolute location(s) of directories with effects 
 | 
				
			||||||
	///  * bootsequence : The effect selected as 'boot sequence'
 | 
						///  * bootsequence : The effect selected as 'boot sequence'
 | 
				
			||||||
 | 
						///    * effect : name of the effect you want to start. Set to empty if no effect wanted
 | 
				
			||||||
 | 
						///    * color  : switch to static color after effect is done
 | 
				
			||||||
 | 
						///    * duration_ms : duration of boot effect in ms. 0 means effect stays forever
 | 
				
			||||||
 | 
						///    * priority : priority of boot effect and static color
 | 
				
			||||||
	"effects" : 
 | 
						"effects" : 
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"paths" : 
 | 
							"paths" : 
 | 
				
			||||||
@@ -369,8 +373,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"bootsequence" : 
 | 
						"bootsequence" : 
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"effect" : "Rainbow swirl fast",
 | 
							"color"       : [0,0,0],
 | 
				
			||||||
		"duration_ms" : 3000
 | 
							"effect"      : "Rainbow swirl fast",
 | 
				
			||||||
 | 
							"duration_ms" : 3000,
 | 
				
			||||||
 | 
							"priority"    : 900
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	///  The configuration for the frame-grabber, contains the following items: 
 | 
						///  The configuration for the frame-grabber, contains the following items: 
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										79
									
								
								doc/datasheets/fadecandy_opc_protocol.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								doc/datasheets/fadecandy_opc_protocol.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					Fadecandy: Open Pixel Control Protocol
 | 
				
			||||||
 | 
					======================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The Fadecandy Server (`fcserver`) operates as a bridge between LED controllers attached over USB, and visual effects that communicate via a TCP socket.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The primary protocol supported by `fcserver` is [Open Pixel Control](http://openpixelcontrol.org), a super simple way to send RGB values over a socket. We support the standard Open Pixel Control commands, as well as some Fadecandy extensions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Socket
 | 
				
			||||||
 | 
					------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Open Pixel Control uses a TCP socket, by default on port 7890. For the best performance, remember to set TCP_NODELAY socket option.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Command Format
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All OPC commands follow the same general format. All multi-byte values in Open Pixel Control are in network byte order, high byte followed by low byte.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Channel    | Command   | Length (N) | Data
 | 
				
			||||||
 | 
					---------- | --------- | ---------- | --------------------------
 | 
				
			||||||
 | 
					1 byte     | 1 byte    | 2 bytes    | N bytes of message data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Set Pixel Colors
 | 
				
			||||||
 | 
					----------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Video data arrives in a **Set Pixel Colors** command:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Byte   | **Set Pixel Colors** command
 | 
				
			||||||
 | 
					------ | --------------------------------
 | 
				
			||||||
 | 
					0      | Channel Number
 | 
				
			||||||
 | 
					1      | Command (0x00)
 | 
				
			||||||
 | 
					2 - 3  | Data length
 | 
				
			||||||
 | 
					4      | Pixel #0, Red
 | 
				
			||||||
 | 
					5      | Pixel #0, Green
 | 
				
			||||||
 | 
					6      | Pixel #0, Blue
 | 
				
			||||||
 | 
					7      | Pixel #1, Red
 | 
				
			||||||
 | 
					8      | Pixel #1, Green
 | 
				
			||||||
 | 
					9      | Pixel #1, Blue
 | 
				
			||||||
 | 
					…      | …
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As soon as a complete Set Pixel Colors command is received, a new frame of video will be broadcast simultaneously to all attached Fadecandy devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Set Global Color Correction
 | 
				
			||||||
 | 
					---------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The color correction data (from the 'color' configuration key) can also be changed at runtime, by sending a new blob of JSON text in a Fadecandy-specific command. Fadecandy's 16-bit System ID for Open Pixel Control's System Exclusive (0xFF) command is **0x0001**.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Byte   | **Set Global Color Correction** command
 | 
				
			||||||
 | 
					------ | ------------------------------------------
 | 
				
			||||||
 | 
					0      | Channel Number (0x00, reserved)
 | 
				
			||||||
 | 
					1      | Command (0xFF, System Exclusive)
 | 
				
			||||||
 | 
					2 - 3  | Data length (JSON Length + 4)
 | 
				
			||||||
 | 
					4 - 5  | System ID (0x0001, Fadecandy)
 | 
				
			||||||
 | 
					6 - 7  | SysEx ID (0x0001, Set Global Color Correction)
 | 
				
			||||||
 | 
					8 - …  | JSON Text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Set Firmware Configuration
 | 
				
			||||||
 | 
					--------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The firmware supports some runtime configuration options. Any OPC client can send a new firmware configuration packet using this command. If the supplied data is shorter than the firmware's configuration buffer, only the provided bytes will be changed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Byte   | **Set Firmware Configuration** command
 | 
				
			||||||
 | 
					------ | ------------------------------------------
 | 
				
			||||||
 | 
					0      | Channel Number (0x00, reserved)
 | 
				
			||||||
 | 
					1      | Command (0xFF, System Exclusive)
 | 
				
			||||||
 | 
					2 - 3  | Data length (Configuration Length + 4)
 | 
				
			||||||
 | 
					4 - 5  | System ID (0x0001, Fadecandy)
 | 
				
			||||||
 | 
					6 - 7  | SysEx ID (0x0002, Set Firmware Configuration)
 | 
				
			||||||
 | 
					8 - …  | Configuration Data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Current firmwares support the following configuration options:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Byte Offset | Bits   | Description
 | 
				
			||||||
 | 
					----------- | ------ | ------------
 | 
				
			||||||
 | 
					0           | 7 … 4  | (reserved)
 | 
				
			||||||
 | 
					0           | 3      | Manual LED control bit
 | 
				
			||||||
 | 
					0           | 2      | 0 = LED shows USB activity, 1 = LED under manual control
 | 
				
			||||||
 | 
					0           | 1      | Disable keyframe interpolation
 | 
				
			||||||
 | 
					0           | 0      | Disable dithering
 | 
				
			||||||
 | 
					1 … 62      | 7 … 0  | (reserved)
 | 
				
			||||||
@@ -49,7 +49,7 @@ namespace hyperion
 | 
				
			|||||||
		/// Constructs a black-border detector
 | 
							/// Constructs a black-border detector
 | 
				
			||||||
		/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
 | 
							/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
 | 
				
			||||||
		///
 | 
							///
 | 
				
			||||||
		BlackBorderDetector(uint8_t blackborderThreshold);
 | 
							BlackBorderDetector(double threshold);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		///
 | 
							///
 | 
				
			||||||
		/// Performs the actual black-border detection on the given image
 | 
							/// Performs the actual black-border detection on the given image
 | 
				
			||||||
@@ -58,13 +58,17 @@ namespace hyperion
 | 
				
			|||||||
		///
 | 
							///
 | 
				
			||||||
		/// @return The detected (or not detected) black border info
 | 
							/// @return The detected (or not detected) black border info
 | 
				
			||||||
		///
 | 
							///
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint8_t calculateThreshold(double blackborderThreshold);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							///
 | 
				
			||||||
 | 
							/// default detection mode (3lines 4side detection)
 | 
				
			||||||
		template <typename Pixel_T>
 | 
							template <typename Pixel_T>
 | 
				
			||||||
		BlackBorder process(const Image<Pixel_T> & image)
 | 
							BlackBorder process(const Image<Pixel_T> & image)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 | 
					 | 
				
			||||||
			// test center and 33%, 66% of width/heigth
 | 
								// test center and 33%, 66% of width/heigth
 | 
				
			||||||
			// 33 and 66 will check left and top
 | 
								// 33 and 66 will check left and top
 | 
				
			||||||
			// center ill check right and bottom sids
 | 
								// center will check right and bottom sids
 | 
				
			||||||
			int width = image.width();
 | 
								int width = image.width();
 | 
				
			||||||
			int height = image.height();
 | 
								int height = image.height();
 | 
				
			||||||
			int width33percent = width / 3;
 | 
								int width33percent = width / 3;
 | 
				
			||||||
@@ -79,9 +83,9 @@ namespace hyperion
 | 
				
			|||||||
			int firstNonBlackYPixelIndex = -1;
 | 
								int firstNonBlackYPixelIndex = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// find first X pixel of the image
 | 
								// find first X pixel of the image
 | 
				
			||||||
			for (int x = 0; x < width; ++x)
 | 
								for (int x = 0; x < width33percent; ++x)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				const Pixel_T & color1 = image( (width - x), yCenter); // right side center line check
 | 
									const Pixel_T & color1 = image( (width - 1 - x), yCenter); // right side center line check
 | 
				
			||||||
				const Pixel_T & color2 = image(x, height33percent);
 | 
									const Pixel_T & color2 = image(x, height33percent);
 | 
				
			||||||
				const Pixel_T & color3 = image(x, height66percent);
 | 
									const Pixel_T & color3 = image(x, height66percent);
 | 
				
			||||||
				if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3))
 | 
									if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3))
 | 
				
			||||||
@@ -92,9 +96,9 @@ namespace hyperion
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// find first Y pixel of the image
 | 
								// find first Y pixel of the image
 | 
				
			||||||
			for (int y = 0; y < height; ++y)
 | 
								for (int y = 0; y < height33percent; ++y)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				const Pixel_T & color1 = image(xCenter, (height - y)); // bottom center line check
 | 
									const Pixel_T & color1 = image(xCenter, (height - 1 - y)); // bottom center line check
 | 
				
			||||||
				const Pixel_T & color2 = image(width33percent, y );
 | 
									const Pixel_T & color2 = image(width33percent, y );
 | 
				
			||||||
				const Pixel_T & color3 = image(width66percent, y);
 | 
									const Pixel_T & color3 = image(width66percent, y);
 | 
				
			||||||
				if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3))
 | 
									if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3))
 | 
				
			||||||
@@ -112,6 +116,120 @@ namespace hyperion
 | 
				
			|||||||
			return detectedBorder;
 | 
								return detectedBorder;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							///
 | 
				
			||||||
 | 
							/// classic detection mode (topleft single line mode)
 | 
				
			||||||
 | 
							template <typename Pixel_T>
 | 
				
			||||||
 | 
							BlackBorder process_classic(const Image<Pixel_T> & image)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// only test the topleft third of the image
 | 
				
			||||||
 | 
								int width = image.width() /3;
 | 
				
			||||||
 | 
								int height = image.height() / 3;
 | 
				
			||||||
 | 
								int maxSize = std::max(width, height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int firstNonBlackXPixelIndex = -1;
 | 
				
			||||||
 | 
								int firstNonBlackYPixelIndex = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// find some pixel of the image
 | 
				
			||||||
 | 
								for (int i = 0; i < maxSize; ++i)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									int x = std::min(i, width);
 | 
				
			||||||
 | 
									int y = std::min(i, height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									const Pixel_T & color = image(x, y);
 | 
				
			||||||
 | 
									if (!isBlack(color))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										firstNonBlackXPixelIndex = x;
 | 
				
			||||||
 | 
										firstNonBlackYPixelIndex = y;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// expand image to the left
 | 
				
			||||||
 | 
								for(; firstNonBlackXPixelIndex > 0; --firstNonBlackXPixelIndex)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									const Pixel_T & color = image(firstNonBlackXPixelIndex-1, firstNonBlackYPixelIndex);
 | 
				
			||||||
 | 
									if (isBlack(color))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// expand image to the top
 | 
				
			||||||
 | 
								for(; firstNonBlackYPixelIndex > 0; --firstNonBlackYPixelIndex)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									const Pixel_T & color = image(firstNonBlackXPixelIndex, firstNonBlackYPixelIndex-1);
 | 
				
			||||||
 | 
									if (isBlack(color))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Construct result
 | 
				
			||||||
 | 
								BlackBorder detectedBorder;
 | 
				
			||||||
 | 
								detectedBorder.unknown = firstNonBlackXPixelIndex == -1 || firstNonBlackYPixelIndex == -1;
 | 
				
			||||||
 | 
								detectedBorder.horizontalSize = firstNonBlackYPixelIndex;
 | 
				
			||||||
 | 
								detectedBorder.verticalSize = firstNonBlackXPixelIndex;
 | 
				
			||||||
 | 
								return detectedBorder;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// osd detection mode (find x then y at detected x to avoid changes by osd overlays)
 | 
				
			||||||
 | 
							template <typename Pixel_T>
 | 
				
			||||||
 | 
							BlackBorder process_osd(const Image<Pixel_T> & image)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// find X position at height33 and height66 we check from the left side, Ycenter will check from right side
 | 
				
			||||||
 | 
								// then we try to find a pixel at this X position from top and bottom and right side from top
 | 
				
			||||||
 | 
								int width = image.width();
 | 
				
			||||||
 | 
								int height = image.height();
 | 
				
			||||||
 | 
								int width33percent = width / 3;
 | 
				
			||||||
 | 
								int height33percent = height / 3;
 | 
				
			||||||
 | 
					//			int width66percent = width33percent * 2;
 | 
				
			||||||
 | 
								int height66percent = height33percent * 2;
 | 
				
			||||||
 | 
					//			int xCenter = width / 2;
 | 
				
			||||||
 | 
								int yCenter = height / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int firstNonBlackXPixelIndex = -1;
 | 
				
			||||||
 | 
								int firstNonBlackYPixelIndex = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// find first X pixel of the image
 | 
				
			||||||
 | 
								int x;
 | 
				
			||||||
 | 
								for (x = 0; x < width33percent; ++x)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									const Pixel_T & color1 = image( (width - 1 - x), yCenter); // right side center line check
 | 
				
			||||||
 | 
									const Pixel_T & color2 = image(x, height33percent);
 | 
				
			||||||
 | 
									const Pixel_T & color3 = image(x, height66percent);
 | 
				
			||||||
 | 
									if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										firstNonBlackXPixelIndex = x;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// find first Y pixel of the image
 | 
				
			||||||
 | 
								for (int y = 0; y < height33percent; ++y)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									const Pixel_T & color1 = image(x, (height - 1 - y)); // left side bottom check
 | 
				
			||||||
 | 
									const Pixel_T & color2 = image(x, y );// left side top check
 | 
				
			||||||
 | 
									const Pixel_T & color3 = image( (width - 1 - x), y); // right side top check
 | 
				
			||||||
 | 
									if (!isBlack(color1) || !isBlack(color2) || !isBlack(color3))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										firstNonBlackYPixelIndex = y;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Construct result
 | 
				
			||||||
 | 
								BlackBorder detectedBorder;
 | 
				
			||||||
 | 
								detectedBorder.unknown = firstNonBlackXPixelIndex == -1 || firstNonBlackYPixelIndex == -1;
 | 
				
			||||||
 | 
								detectedBorder.horizontalSize = firstNonBlackYPixelIndex;
 | 
				
			||||||
 | 
								detectedBorder.verticalSize = firstNonBlackXPixelIndex;
 | 
				
			||||||
 | 
								return detectedBorder;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		///
 | 
							///
 | 
				
			||||||
@@ -131,5 +249,6 @@ namespace hyperion
 | 
				
			|||||||
	private:
 | 
						private:
 | 
				
			||||||
		/// Threshold for the blackborder detector [0 .. 255]
 | 
							/// Threshold for the blackborder detector [0 .. 255]
 | 
				
			||||||
		const uint8_t _blackborderThreshold;
 | 
							const uint8_t _blackborderThreshold;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
} // end namespace hyperion
 | 
					} // end namespace hyperion
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Jsoncpp includes
 | 
				
			||||||
 | 
					#include <json/json.h>
 | 
				
			||||||
// Local Hyperion includes
 | 
					// Local Hyperion includes
 | 
				
			||||||
#include "BlackBorderDetector.h"
 | 
					#include "BlackBorderDetector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,11 +25,7 @@ namespace hyperion
 | 
				
			|||||||
		///                      outer pixels is blurred (black and color combined due to image scaling))
 | 
							///                      outer pixels is blurred (black and color combined due to image scaling))
 | 
				
			||||||
		/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
 | 
							/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
 | 
				
			||||||
		///
 | 
							///
 | 
				
			||||||
		BlackBorderProcessor(
 | 
							BlackBorderProcessor(const Json::Value &blackborderConfig);
 | 
				
			||||||
				const unsigned unknownFrameCnt,
 | 
					 | 
				
			||||||
				const unsigned borderFrameCnt,
 | 
					 | 
				
			||||||
				const unsigned blurRemoveCnt,
 | 
					 | 
				
			||||||
				uint8_t blackborderThreshold);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		///
 | 
							///
 | 
				
			||||||
		/// Return the current (detected) border
 | 
							/// Return the current (detected) border
 | 
				
			||||||
@@ -48,7 +46,14 @@ namespace hyperion
 | 
				
			|||||||
		bool process(const Image<Pixel_T> & image)
 | 
							bool process(const Image<Pixel_T> & image)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// get the border for the single image
 | 
								// get the border for the single image
 | 
				
			||||||
			BlackBorder imageBorder = _detector.process(image);
 | 
								BlackBorder imageBorder;
 | 
				
			||||||
 | 
								if (_detectionMode == "default") {
 | 
				
			||||||
 | 
									imageBorder = _detector.process(image);
 | 
				
			||||||
 | 
								} else if (_detectionMode == "classic") {
 | 
				
			||||||
 | 
									imageBorder = _detector.process_classic(image);
 | 
				
			||||||
 | 
								} else if (_detectionMode == "osd") {
 | 
				
			||||||
 | 
									imageBorder = _detector.process_osd(image);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			// add blur to the border
 | 
								// add blur to the border
 | 
				
			||||||
			if (imageBorder.horizontalSize > 0)
 | 
								if (imageBorder.horizontalSize > 0)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
@@ -80,9 +85,15 @@ namespace hyperion
 | 
				
			|||||||
		/// The number of horizontal/vertical borders detected before it becomes the current border
 | 
							/// The number of horizontal/vertical borders detected before it becomes the current border
 | 
				
			||||||
		const unsigned _borderSwitchCnt;
 | 
							const unsigned _borderSwitchCnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// The number of frames that are "ignored" before a new border gets set as _previousDetectedBorder
 | 
				
			||||||
 | 
							const unsigned _maxInconsistentCnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/// The number of pixels to increase a detected border for removing blury pixels
 | 
							/// The number of pixels to increase a detected border for removing blury pixels
 | 
				
			||||||
		unsigned _blurRemoveCnt;
 | 
							unsigned _blurRemoveCnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/// The border detection mode
 | 
				
			||||||
 | 
							const std::string _detectionMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/// The blackborder detector
 | 
							/// The blackborder detector
 | 
				
			||||||
		BlackBorderDetector _detector;
 | 
							BlackBorderDetector _detector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,5 +107,6 @@ namespace hyperion
 | 
				
			|||||||
		unsigned _consistentCnt;
 | 
							unsigned _consistentCnt;
 | 
				
			||||||
		/// The number of frame the previous detected border NOT matched the incomming border
 | 
							/// The number of frame the previous detected border NOT matched the incomming border
 | 
				
			||||||
		unsigned _inconsistentCnt;
 | 
							unsigned _inconsistentCnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
} // end namespace hyperion
 | 
					} // end namespace hyperion
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,7 +106,7 @@ private:
 | 
				
			|||||||
	/// @param[in] enableBlackBorderDetector Flag indicating if the blacborder detector should be enabled
 | 
						/// @param[in] enableBlackBorderDetector Flag indicating if the blacborder detector should be enabled
 | 
				
			||||||
	/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
 | 
						/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	ImageProcessor(const LedString &ledString, bool enableBlackBorderDetector, uint8_t blackborderThreshold);
 | 
						ImageProcessor(const LedString &ledString, const Json::Value &blackborderConfig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// Performs black-border detection (if enabled) on the given image
 | 
						/// Performs black-border detection (if enabled) on the given image
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ public:
 | 
				
			|||||||
	/// @param[in] enableBlackBorderDetector Flag indicating if the blacborder detector should be enabled
 | 
						/// @param[in] enableBlackBorderDetector Flag indicating if the blacborder detector should be enabled
 | 
				
			||||||
	/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
 | 
						/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	void init(const LedString& ledString, bool enableBlackBorderDetector, double blackborderThreshold);
 | 
						void init(const LedString& ledString, const Json::Value &blackborderConfig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// Creates a new ImageProcessor. The onwership of the processor is transferred to the caller.
 | 
						/// Creates a new ImageProcessor. The onwership of the processor is transferred to the caller.
 | 
				
			||||||
@@ -46,9 +46,6 @@ private:
 | 
				
			|||||||
	/// The Led-string specification
 | 
						/// The Led-string specification
 | 
				
			||||||
	LedString _ledString;
 | 
						LedString _ledString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Flag indicating if the black border detector should be used
 | 
						// Reference to the blackborder json configuration values
 | 
				
			||||||
	bool _enableBlackBorderDetector;
 | 
						Json::Value _blackborderConfig;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/// Threshold for the blackborder detector [0 .. 255]
 | 
					 | 
				
			||||||
	uint8_t _blackborderThreshold;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,26 @@
 | 
				
			|||||||
 | 
					#include <iostream>
 | 
				
			||||||
// BlackBorders includes
 | 
					// BlackBorders includes
 | 
				
			||||||
#include <blackborder/BlackBorderDetector.h>
 | 
					#include <blackborder/BlackBorderDetector.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace hyperion;
 | 
					using namespace hyperion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BlackBorderDetector::BlackBorderDetector(uint8_t blackborderThreshold) :
 | 
					BlackBorderDetector::BlackBorderDetector(double threshold) :
 | 
				
			||||||
	_blackborderThreshold(blackborderThreshold)
 | 
						_blackborderThreshold(calculateThreshold(threshold))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// empty
 | 
						// empty
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t BlackBorderDetector::calculateThreshold(double threshold)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rgbThreshold = int(std::ceil(threshold * 255));
 | 
				
			||||||
 | 
						if (rgbThreshold < 0)
 | 
				
			||||||
 | 
							rgbThreshold = 0;
 | 
				
			||||||
 | 
						else if (rgbThreshold > 255)
 | 
				
			||||||
 | 
							rgbThreshold = 255;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint8_t blackborderThreshold = uint8_t(rgbThreshold);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::cout << "Black border threshold set to " << threshold << " (" << int(blackborderThreshold) << ")" << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return blackborderThreshold;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,31 @@
 | 
				
			|||||||
//#include <iostream>
 | 
					//*
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					#include <iomanip>
 | 
				
			||||||
 | 
					using std::cout;
 | 
				
			||||||
 | 
					using std::endl;
 | 
				
			||||||
 | 
					using std::setw;
 | 
				
			||||||
 | 
					using std::left;
 | 
				
			||||||
 | 
					//*/
 | 
				
			||||||
// Blackborder includes
 | 
					// Blackborder includes
 | 
				
			||||||
#include <blackborder/BlackBorderProcessor.h>
 | 
					#include <blackborder/BlackBorderProcessor.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace hyperion;
 | 
					using namespace hyperion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BlackBorderProcessor::BlackBorderProcessor(const unsigned unknownFrameCnt,
 | 
					BlackBorderProcessor::BlackBorderProcessor(const Json::Value &blackborderConfig) :
 | 
				
			||||||
		const unsigned borderFrameCnt,
 | 
						_unknownSwitchCnt(blackborderConfig.get("unknownFrameCnt", 600).asUInt()),
 | 
				
			||||||
		const unsigned blurRemoveCnt,
 | 
						_borderSwitchCnt(blackborderConfig.get("borderFrameCnt", 50).asUInt()),
 | 
				
			||||||
		uint8_t blackborderThreshold) :
 | 
						_maxInconsistentCnt(blackborderConfig.get("maxInconsistentCnt", 10).asUInt()),
 | 
				
			||||||
	_unknownSwitchCnt(unknownFrameCnt),
 | 
						_blurRemoveCnt(blackborderConfig.get("blurRemoveCnt", 1).asUInt()),
 | 
				
			||||||
	_borderSwitchCnt(borderFrameCnt),
 | 
						_detectionMode(blackborderConfig.get("mode", "default").asString()),
 | 
				
			||||||
	_blurRemoveCnt(blurRemoveCnt),
 | 
						_detector(blackborderConfig.get("threshold", 0.01).asDouble()),
 | 
				
			||||||
	_detector(blackborderThreshold),
 | 
					 | 
				
			||||||
	_currentBorder({true, -1, -1}),
 | 
						_currentBorder({true, -1, -1}),
 | 
				
			||||||
	_previousDetectedBorder({true, -1, -1}),
 | 
						_previousDetectedBorder({true, -1, -1}),
 | 
				
			||||||
	_consistentCnt(0),
 | 
						_consistentCnt(0),
 | 
				
			||||||
	_inconsistentCnt(10)
 | 
						_inconsistentCnt(10)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						std::cout << "DETECTION MODE:" << _detectionMode << std::endl;
 | 
				
			||||||
	// empty
 | 
						// empty
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,7 +47,7 @@ bool BlackBorderProcessor::updateBorder(const BlackBorder & newDetectedBorder)
 | 
				
			|||||||
// makes it look like the border detectionn is not working - since the new 3 line detection algorithm is more precise this became a problem specialy in dark scenes
 | 
					// makes it look like the border detectionn is not working - since the new 3 line detection algorithm is more precise this became a problem specialy in dark scenes
 | 
				
			||||||
// wisc
 | 
					// wisc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//	std::cout << "cur: " << _currentBorder.verticalSize << " " << _currentBorder.horizontalSize << " new: " << newDetectedBorder.verticalSize << " " << newDetectedBorder.horizontalSize << " c:i " << _consistentCnt << ":" << _inconsistentCnt << std::endl;
 | 
					//	std::cout << "c: " << setw(2) << _currentBorder.verticalSize << " " << setw(2) << _currentBorder.horizontalSize << " p: " << setw(2) << _previousDetectedBorder.verticalSize << " " << setw(2) << _previousDetectedBorder.horizontalSize << " n: " << setw(2) << newDetectedBorder.verticalSize << " " << setw(2) << newDetectedBorder.horizontalSize << " c:i " << setw(2) << _consistentCnt << ":" << setw(2) << _inconsistentCnt << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// set the consistency counter
 | 
						// set the consistency counter
 | 
				
			||||||
	if (newDetectedBorder == _previousDetectedBorder)
 | 
						if (newDetectedBorder == _previousDetectedBorder)
 | 
				
			||||||
@@ -50,7 +58,7 @@ bool BlackBorderProcessor::updateBorder(const BlackBorder & newDetectedBorder)
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		++_inconsistentCnt;
 | 
							++_inconsistentCnt;
 | 
				
			||||||
		if (_inconsistentCnt <= 10)// few inconsistent frames
 | 
							if (_inconsistentCnt <= _maxInconsistentCnt)// only few inconsistent frames
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			//discard the newDetectedBorder -> keep the consistent count for previousDetectedBorder
 | 
								//discard the newDetectedBorder -> keep the consistent count for previousDetectedBorder
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -282,8 +282,8 @@ Hyperion::Hyperion(const Json::Value &jsonConfig) :
 | 
				
			|||||||
	// initialize the image processor factory
 | 
						// initialize the image processor factory
 | 
				
			||||||
	ImageProcessorFactory::getInstance().init(
 | 
						ImageProcessorFactory::getInstance().init(
 | 
				
			||||||
				_ledString,
 | 
									_ledString,
 | 
				
			||||||
				jsonConfig["blackborderdetector"].get("enable", true).asBool(),
 | 
									jsonConfig["blackborderdetector"]
 | 
				
			||||||
				jsonConfig["blackborderdetector"].get("threshold", 0.01).asDouble());
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// initialize the color smoothing filter
 | 
						// initialize the color smoothing filter
 | 
				
			||||||
	_device = createColorSmoothing(jsonConfig["color"]["smoothing"], _device);
 | 
						_device = createColorSmoothing(jsonConfig["color"]["smoothing"], _device);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using namespace hyperion;
 | 
					using namespace hyperion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ImageProcessor::ImageProcessor(const LedString& ledString, bool enableBlackBorderDetector, uint8_t blackborderThreshold) :
 | 
					//ImageProcessor::ImageProcessor(const LedString& ledString, bool enableBlackBorderDetector, uint8_t blackborderThreshold) :
 | 
				
			||||||
 | 
					ImageProcessor::ImageProcessor(const LedString& ledString, const Json::Value & blackborderConfig) :
 | 
				
			||||||
	_ledString(ledString),
 | 
						_ledString(ledString),
 | 
				
			||||||
	_enableBlackBorderRemoval(enableBlackBorderDetector),
 | 
						_enableBlackBorderRemoval(blackborderConfig.get("enable", true).asBool()),
 | 
				
			||||||
	_borderProcessor(new BlackBorderProcessor(600, 50, 1, blackborderThreshold)),
 | 
						_borderProcessor(new BlackBorderProcessor(blackborderConfig) ),
 | 
				
			||||||
	_imageToLeds(nullptr)
 | 
						_imageToLeds(nullptr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// empty
 | 
						// empty
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,25 +13,13 @@ ImageProcessorFactory& ImageProcessorFactory::getInstance()
 | 
				
			|||||||
	return instance;
 | 
						return instance;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ImageProcessorFactory::init(const LedString& ledString, bool enableBlackBorderDetector, double blackborderThreshold)
 | 
					void ImageProcessorFactory::init(const LedString& ledString, const Json::Value & blackborderConfig)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	_ledString = ledString;
 | 
						_ledString = ledString;
 | 
				
			||||||
	_enableBlackBorderDetector = enableBlackBorderDetector;
 | 
						_blackborderConfig = blackborderConfig;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	int threshold = int(std::ceil(blackborderThreshold * 255));
 | 
					 | 
				
			||||||
	if (threshold < 0)
 | 
					 | 
				
			||||||
		threshold = 0;
 | 
					 | 
				
			||||||
	else if (threshold > 255)
 | 
					 | 
				
			||||||
		threshold = 255;
 | 
					 | 
				
			||||||
	_blackborderThreshold = uint8_t(threshold);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (_enableBlackBorderDetector)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		std::cout << "Black border threshold set to " << blackborderThreshold << " (" << int(_blackborderThreshold) << ")" << std::endl;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ImageProcessor* ImageProcessorFactory::newImageProcessor() const
 | 
					ImageProcessor* ImageProcessorFactory::newImageProcessor() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return new ImageProcessor(_ledString, _enableBlackBorderDetector, _blackborderThreshold);
 | 
						return new ImageProcessor(_ledString, _blackborderConfig);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
// STL includes
 | 
					// STL includes
 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
#include <cstdio>
 | 
					#include <cstdio>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <algorithm>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Linux includes
 | 
					// Linux includes
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
@@ -19,27 +17,46 @@ LedDeviceAPA102::LedDeviceAPA102(const std::string& outputDevice, const unsigned
 | 
				
			|||||||
	// empty
 | 
						// empty
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MIN(a,b)	((a)<(b)?(a):(b))
 | 
				
			||||||
 | 
					#define MAX(a,b)	((a)>(b)?(a):(b))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define APA102_START_FRAME_BYTES	4
 | 
				
			||||||
 | 
					#define APA102_LED_BYTES		4
 | 
				
			||||||
 | 
					#define APA102_END_FRAME_BITS_MIN	32
 | 
				
			||||||
 | 
					#define APA102_END_FRAME_BITS(leds)	MAX((((leds-1)/2)+1),APA102_END_FRAME_BITS_MIN)
 | 
				
			||||||
 | 
					#define APA102_END_FRAME_BYTES(leds)	(((APA102_END_FRAME_BITS(leds)-1)/8)+1)
 | 
				
			||||||
 | 
					#define APA102_LED_HEADER		0xe0
 | 
				
			||||||
 | 
					#define APA102_LED_MAX_INTENSITY	0x1f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int LedDeviceAPA102::write(const std::vector<ColorRgb> &ledValues)
 | 
					int LedDeviceAPA102::write(const std::vector<ColorRgb> &ledValues)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const unsigned int startFrameSize = 4;
 | 
						const unsigned int startFrameSize = APA102_START_FRAME_BYTES;
 | 
				
			||||||
	const unsigned int endFrameSize = std::max<unsigned int>(((ledValues.size() + 15) / 16), 4);
 | 
						const unsigned int ledsCount = ledValues.size() ;
 | 
				
			||||||
	const unsigned int mLedCount = (ledValues.size() * 4) + startFrameSize + endFrameSize;
 | 
						const unsigned int ledsSize = ledsCount * APA102_LED_BYTES ;
 | 
				
			||||||
	if(_ledBuffer.size() != mLedCount){
 | 
						const unsigned int endFrameBits = APA102_END_FRAME_BITS(ledsCount) ;
 | 
				
			||||||
		_ledBuffer.resize(mLedCount, 0xFF);
 | 
						const unsigned int endFrameSize = APA102_END_FRAME_BYTES(ledsCount) ;
 | 
				
			||||||
		_ledBuffer[0] = 0x00; 
 | 
						const unsigned int transferSize = startFrameSize + ledsSize + endFrameSize ;
 | 
				
			||||||
		_ledBuffer[1] = 0x00; 
 | 
					
 | 
				
			||||||
		_ledBuffer[2] = 0x00; 
 | 
						if(_ledBuffer.size() != transferSize){
 | 
				
			||||||
		_ledBuffer[3] = 0x00; 
 | 
							_ledBuffer.resize(transferSize, 0x00);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	for (unsigned iLed=1; iLed<=ledValues.size(); ++iLed) {
 | 
						unsigned idx = 0, i;
 | 
				
			||||||
		const ColorRgb& rgb = ledValues[iLed-1];
 | 
						for (i=0; i<APA102_START_FRAME_BYTES; i++) {
 | 
				
			||||||
		_ledBuffer[iLed*4]   = 0xFF;
 | 
							_ledBuffer[idx++] = 0x00 ;
 | 
				
			||||||
		_ledBuffer[iLed*4+1] = rgb.red;
 | 
					 | 
				
			||||||
		_ledBuffer[iLed*4+2] = rgb.green;
 | 
					 | 
				
			||||||
		_ledBuffer[iLed*4+3] = rgb.blue;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i=0; i<ledsCount; i++) {
 | 
				
			||||||
 | 
							const ColorRgb& rgb = ledValues[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							_ledBuffer[idx++]   = APA102_LED_HEADER + APA102_LED_MAX_INTENSITY;
 | 
				
			||||||
 | 
							_ledBuffer[idx++] = rgb.red;
 | 
				
			||||||
 | 
							_ledBuffer[idx++] = rgb.green;
 | 
				
			||||||
 | 
							_ledBuffer[idx++] = rgb.blue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for(i=0; i<endFrameSize; i++)
 | 
				
			||||||
 | 
							_ledBuffer[idx++] = 0x00 ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return writeBytes(_ledBuffer.size(), _ledBuffer.data());
 | 
						return writeBytes(_ledBuffer.size(), _ledBuffer.data());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -246,9 +246,10 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	else if (type == "fadecandy")
 | 
						else if (type == "fadecandy")
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		const std::string host 	= deviceConfig.get("output", "127.0.0.1").asString();
 | 
							const std::string host  = deviceConfig.get("output", "127.0.0.1").asString();
 | 
				
			||||||
		const uint16_t port 		= deviceConfig.get("port", 7890).asInt();
 | 
							const uint16_t port     = deviceConfig.get("port", 7890).asInt();
 | 
				
			||||||
		device = new LedDeviceFadeCandy(host,port);
 | 
							const uint16_t channel  = deviceConfig.get("channel", 0).asInt();
 | 
				
			||||||
 | 
							device = new LedDeviceFadeCandy(host, port, channel);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (type == "tpm2")
 | 
						else if (type == "tpm2")
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,15 @@
 | 
				
			|||||||
#include "LedDeviceFadeCandy.h"
 | 
					#include "LedDeviceFadeCandy.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const unsigned MAX_NUM_LEDS    = 512;
 | 
					static const unsigned MAX_NUM_LEDS    = 10000; // OPC can handle 21845 leds - in theory, fadecandy device should handle 10000 leds
 | 
				
			||||||
static const unsigned OPC_BROADCAST   = 0;    // OPC broadcast channel
 | 
					static const unsigned OPC_SET_PIXELS  = 0;     // OPC command codes
 | 
				
			||||||
static const unsigned OPC_SET_PIXELS  = 0;    // OPC command codes
 | 
					static const unsigned OPC_HEADER_SIZE = 4;     // OPC header size
 | 
				
			||||||
static const unsigned OPC_HEADER_SIZE = 4;    // OPC header size
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LedDeviceFadeCandy::LedDeviceFadeCandy(const std::string& host, const uint16_t port) :
 | 
					LedDeviceFadeCandy::LedDeviceFadeCandy(const std::string& host, const uint16_t port, const unsigned channel) :
 | 
				
			||||||
	_host(host), _port(port)
 | 
						_host(host), _port(port), _channel(channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	_opc_data.resize( OPC_HEADER_SIZE );
 | 
						_opc_data.resize( OPC_HEADER_SIZE );
 | 
				
			||||||
	_opc_data[0] = OPC_BROADCAST;
 | 
						_opc_data[0] = channel;
 | 
				
			||||||
	_opc_data[1] = OPC_SET_PIXELS;
 | 
						_opc_data[1] = OPC_SET_PIXELS;
 | 
				
			||||||
	_opc_data[2] = 0;
 | 
						_opc_data[2] = 0;
 | 
				
			||||||
	_opc_data[3] = 0;
 | 
						_opc_data[3] = 0;
 | 
				
			||||||
@@ -32,11 +31,9 @@ bool LedDeviceFadeCandy::isConnected()
 | 
				
			|||||||
bool LedDeviceFadeCandy::tryConnect()
 | 
					bool LedDeviceFadeCandy::tryConnect()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (  _client.state() == QAbstractSocket::UnconnectedState ) {
 | 
						if (  _client.state() == QAbstractSocket::UnconnectedState ) {
 | 
				
			||||||
		qDebug("connecting to %s %i",_host.c_str(),_port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		_client.connectToHost( _host.c_str(), _port);
 | 
							_client.connectToHost( _host.c_str(), _port);
 | 
				
			||||||
		if ( _client.waitForConnected(1000) )
 | 
							if ( _client.waitForConnected(1000) )
 | 
				
			||||||
			qDebug("connected");
 | 
								qDebug("fadecandy/opc: connected to %s:%i on channel %i", _host.c_str(), _port, _channel);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return isConnected();
 | 
						return isConnected();
 | 
				
			||||||
@@ -51,7 +48,7 @@ int LedDeviceFadeCandy::write( const std::vector<ColorRgb> & ledValues )
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (nrLedValues > MAX_NUM_LEDS)
 | 
						if (nrLedValues > MAX_NUM_LEDS)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		std::cerr << "Invalid attempt to write led values. Not more than " << MAX_NUM_LEDS << " leds are allowed." << std::endl;
 | 
							std::cerr << "fadecandy/opc: Invalid attempt to write led values. Not more than " << MAX_NUM_LEDS << " leds are allowed." << std::endl;
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ public:
 | 
				
			|||||||
	/// @param host The ip address/host name of fadecandy/opc server
 | 
						/// @param host The ip address/host name of fadecandy/opc server
 | 
				
			||||||
	/// @param port The port to use (fadecandy default is 7890)
 | 
						/// @param port The port to use (fadecandy default is 7890)
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	LedDeviceFadeCandy(const std::string& host, const uint16_t port);
 | 
						LedDeviceFadeCandy(const std::string& host, const uint16_t port, const unsigned channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// Destructor of the LedDevice; closes the tcp client
 | 
						/// Destructor of the LedDevice; closes the tcp client
 | 
				
			||||||
@@ -46,6 +46,7 @@ private:
 | 
				
			|||||||
	QTcpSocket        _client;
 | 
						QTcpSocket        _client;
 | 
				
			||||||
	const std::string _host;
 | 
						const std::string _host;
 | 
				
			||||||
	const uint16_t    _port;
 | 
						const uint16_t    _port;
 | 
				
			||||||
 | 
						const unsigned    _channel;
 | 
				
			||||||
	QByteArray        _opc_data;
 | 
						QByteArray        _opc_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// try to establish connection to opc server, if not connected yet
 | 
						/// try to establish connection to opc server, if not connected yet
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -218,7 +218,7 @@ void LedDevicePhilipsHue::put(QString route, QString content) {
 | 
				
			|||||||
	QString url = QString("http://%1/api/%2/%3").arg(host).arg(username).arg(route);
 | 
						QString url = QString("http://%1/api/%2/%3").arg(host).arg(username).arg(route);
 | 
				
			||||||
	// Perfrom request
 | 
						// Perfrom request
 | 
				
			||||||
	QNetworkRequest request(url);
 | 
						QNetworkRequest request(url);
 | 
				
			||||||
	QNetworkReply* reply = manager->put(request, content.toAscii());
 | 
						QNetworkReply* reply = manager->put(request, content.toLatin1());
 | 
				
			||||||
	// Connect finished signal to quit slot of the loop.
 | 
						// Connect finished signal to quit slot of the loop.
 | 
				
			||||||
	QEventLoop loop;
 | 
						QEventLoop loop;
 | 
				
			||||||
	loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
 | 
						loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -126,20 +126,34 @@ int main(int argc, char** argv)
 | 
				
			|||||||
		// Get the parameters for the bootsequence
 | 
							// Get the parameters for the bootsequence
 | 
				
			||||||
		const std::string effectName = effectConfig["effect"].asString();
 | 
							const std::string effectName = effectConfig["effect"].asString();
 | 
				
			||||||
		const unsigned duration_ms   = effectConfig["duration_ms"].asUInt();
 | 
							const unsigned duration_ms   = effectConfig["duration_ms"].asUInt();
 | 
				
			||||||
		const int priority = 0;
 | 
							const int priority           = effectConfig["priority"].asUInt();
 | 
				
			||||||
 | 
							const int bootcolor_priority = (priority > 990) ? priority+1 : 990;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		hyperion.setColor(priority+1, ColorRgb::BLACK, duration_ms, false);
 | 
							if ( ! effectConfig["color"].isNull() && effectConfig["color"].isArray() && effectConfig["color"].size() == 3 )
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								ColorRgb boot_color = {
 | 
				
			||||||
 | 
									(uint8_t)effectConfig["color"][0].asUInt(),
 | 
				
			||||||
 | 
									(uint8_t)effectConfig["color"][1].asUInt(),
 | 
				
			||||||
 | 
									(uint8_t)effectConfig["color"][2].asUInt()
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								hyperion.setColor(bootcolor_priority, boot_color, 0, false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								hyperion.setColor(bootcolor_priority, ColorRgb::BLACK, duration_ms, false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (effectConfig.isMember("args"))
 | 
							if (effectConfig.isMember("args"))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			const Json::Value effectConfigArgs = effectConfig["args"];
 | 
								const Json::Value effectConfigArgs = effectConfig["args"];
 | 
				
			||||||
			if (hyperion.setEffect(effectName, effectConfigArgs, priority, duration_ms) == 0)
 | 
								if (hyperion.setEffect(effectName, effectConfigArgs, priority, duration_ms) == 0)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
					std::cout << "Boot sequence(" << effectName << ") with user-defined arguments created and started" << std::endl;
 | 
									std::cout << "Boot sequence(" << effectName << ") with user-defined arguments created and started" << std::endl;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
					std::cout << "Failed to start boot sequence: " << effectName << " with user-defined arguments" << std::endl;
 | 
									std::cout << "Failed to start boot sequence: " << effectName << " with user-defined arguments" << std::endl;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,11 +44,13 @@ Image<ColorRgb> createImage(unsigned width, unsigned height, unsigned topBorder,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int main()
 | 
					int main()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned unknownCnt = 600;
 | 
					//	unsigned unknownCnt = 600;
 | 
				
			||||||
	unsigned borderCnt  = 50;
 | 
						unsigned borderCnt  = 50;
 | 
				
			||||||
	unsigned blurCnt    = 0;
 | 
					//	unsigned blurCnt    = 0;
 | 
				
			||||||
 | 
						Json::Value config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BlackBorderProcessor processor(unknownCnt, borderCnt, blurCnt, 3);
 | 
					//	BlackBorderProcessor processor(unknownCnt, borderCnt, blurCnt, 3, config);
 | 
				
			||||||
 | 
						BlackBorderProcessor processor(config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Start with 'no border' detection
 | 
						// Start with 'no border' detection
 | 
				
			||||||
	Image<ColorRgb> noBorderImage = createImage(64, 64, 0, 0);
 | 
						Image<ColorRgb> noBorderImage = createImage(64, 64, 0, 0);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user