Browse Source

Improved comments, storing ambilight state.

Thomas Buck 7 years ago
parent
commit
4a36ea18f4
No account linked to committer's email address
3 changed files with 130 additions and 64 deletions
  1. 0
    2
      DisplayBacklight/AppDelegate.h
  2. 129
    61
      DisplayBacklight/AppDelegate.m
  3. 1
    1
      DisplayBacklight/Info.plist

+ 0
- 2
DisplayBacklight/AppDelegate.h View File

@@ -17,7 +17,5 @@
17 17
 - (void)stopAmbilight;
18 18
 - (void)newDisplayList:(NSArray *)displayIDs;
19 19
 
20
-+ (double)map:(double)val FromMin:(double)fmin FromMax:(double)fmax ToMin:(double)tmin ToMax:(double)tmax;
21
-
22 20
 @end
23 21
 

+ 129
- 61
DisplayBacklight/AppDelegate.m View File

@@ -10,11 +10,24 @@
10 10
 #import "Serial.h"
11 11
 #import "Screenshot.h"
12 12
 
13
+// This defined the update-speed of the Ambilight, in seconds.
14
+// With a baudrate of 115200 and 156 LEDs and 14-bytes Magic-Word,
15
+// theoretically you could transmit:
16
+//     115200 / (14 + (156 * 3) * 8) =~ 30 Frames per Second
17
+// Inserting (1.0 / 30.0) here would try to reach these 30FPS,
18
+// but will probably cause high CPU-Usage.
19
+// (Run-Time of the algorithm is ignored here, so real speed will be
20
+// slightly lower.)
21
+#define DISPLAY_DELAY (1.0 / 30.0)
22
+
23
+// Magic identifying string used to differntiate start of packets.
24
+// Has to be the same here and in the Arduino Sketch.
25
+#define MAGIC_WORD @"xythobuzRGBled"
26
+
13 27
 // These are the values stored persistently in the preferences
14 28
 #define PREF_SERIAL_PORT @"SerialPort"
15 29
 #define PREF_BRIGHTNESS @"Brightness"
16
-
17
-#define DISPLAY_DELAY (1.0 / 10.0)
30
+#define PREF_TURNED_ON @"IsEnabled"
18 31
 
19 32
 @interface AppDelegate ()
20 33
 
@@ -51,12 +64,14 @@
51 64
     NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
52 65
     NSMutableDictionary *appDefaults = [NSMutableDictionary dictionaryWithObject:@"" forKey:PREF_SERIAL_PORT];
53 66
     [appDefaults setObject:[NSNumber numberWithFloat:50.0] forKey:PREF_BRIGHTNESS];
67
+    [appDefaults setObject:[NSNumber numberWithBool:NO] forKey:PREF_TURNED_ON];
54 68
     [store registerDefaults:appDefaults];
55 69
     [store synchronize];
56 70
     
57 71
     // Load existing configuration values
58 72
     NSString *savedPort = [store stringForKey:PREF_SERIAL_PORT];
59 73
     float brightness = [store floatForKey:PREF_BRIGHTNESS];
74
+    BOOL ambilightIsOn = [store boolForKey:PREF_TURNED_ON];
60 75
     
61 76
     // Prepare status bar menu
62 77
     statusImage = [NSImage imageNamed:@"MenuIcon"];
@@ -71,7 +86,7 @@
71 86
     [brightnessLabel setTitle:[NSString stringWithFormat:@"Value: %.0f%%", brightness]];
72 87
     
73 88
     // Prepare serial port menu
74
-    BOOL startTimer = NO;
89
+    BOOL foundPort = NO;
75 90
     NSArray *ports = [Serial listSerialPorts];
76 91
     if ([ports count] > 0) {
77 92
         [menuPorts removeAllItems];
@@ -82,29 +97,42 @@
82 97
             
83 98
             // Set Enabled if it was used the last time
84 99
             if ((savedPort != nil) && [[ports objectAtIndex:i] isEqualToString:savedPort]) {
85
-                [[menuPorts itemAtIndex:i] setState:NSOnState];
86
-                
87 100
                 // Try to open serial port
88 101
                 [serial setPortName:savedPort];
89
-                if ([serial openPort]) {
90
-                    // Unselect it when an error occured opening the port
91
-                    [[menuPorts itemAtIndex:i] setState:NSOffState];
92
-                } else {
93
-                    startTimer = YES;
102
+                if (![serial openPort]) {
103
+                    foundPort = YES;
104
+                    [[menuPorts itemAtIndex:i] setState:NSOnState];
94 105
                 }
95 106
             }
96 107
         }
97 108
         
98
-        if (!startTimer) {
99
-            // TODO try to find out new UART port name for controller
109
+        if (!foundPort) {
110
+            // I'm using a cheap chinese Arduino Nano clone with a CH340 chipset.
111
+            // This driver creates device-files in /dev/cu.* that don't correspond
112
+            // to the chip-id and change every time the adapter is re-enumerated.
113
+            // That means we may have to try and find the device again after the
114
+            // stored name does no longer exist. In this case, we simply try the first
115
+            // device that starts with /dev/cu.wchusbserial*...
116
+            for (int i = 0; i < [ports count]; i++) {
117
+                if ([[ports objectAtIndex:i] hasPrefix:@"/dev/cu.wchusbserial"]) {
118
+                    // Try to open serial port
119
+                    [serial setPortName:savedPort];
120
+                    if (![serial openPort]) {
121
+                        [[menuPorts itemAtIndex:i] setState:NSOnState];
122
+                        
123
+                        // Reattempt next matching device when opening this one fails.
124
+                        break;
125
+                    }
126
+                }
127
+            }
100 128
         }
101 129
     }
102 130
     
103 131
     [Screenshot init:self];
104 132
     lastDisplayIDs = [Screenshot listDisplays];
105 133
     
106
-    if (startTimer) {
107
-        timer = [NSTimer scheduledTimerWithTimeInterval:DISPLAY_DELAY target:self selector:@selector(visualizeDisplay:) userInfo:nil repeats:YES];
134
+    if (ambilightIsOn) {
135
+        timer = [NSTimer scheduledTimerWithTimeInterval:DISPLAY_DELAY target:self selector:@selector(visualizeDisplay:) userInfo:nil repeats:NO];
108 136
         
109 137
         [buttonAmbilight setState:NSOnState];
110 138
     }
@@ -189,10 +217,22 @@
189 217
             [timer invalidate];
190 218
             timer = nil;
191 219
         }
220
+        
221
+        [self sendNullFrame];
222
+        
223
+        // Store state
224
+        NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
225
+        [store setObject:[NSNumber numberWithBool:NO] forKey:PREF_TURNED_ON];
226
+        [store synchronize];
192 227
     } else {
193 228
         [sender setState:NSOnState];
194 229
         
195
-        timer = [NSTimer scheduledTimerWithTimeInterval:DISPLAY_DELAY target:self selector:@selector(visualizeDisplay:) userInfo:nil repeats:YES];
230
+        timer = [NSTimer scheduledTimerWithTimeInterval:DISPLAY_DELAY target:self selector:@selector(visualizeDisplay:) userInfo:nil repeats:NO];
231
+        
232
+        // Store state
233
+        NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
234
+        [store setObject:[NSNumber numberWithBool:YES] forKey:PREF_TURNED_ON];
235
+        [store synchronize];
196 236
     }
197 237
 }
198 238
 
@@ -214,7 +254,7 @@
214 254
         restartAmbilight = NO;
215 255
         [buttonAmbilight setState:NSOnState];
216 256
         
217
-        timer = [NSTimer scheduledTimerWithTimeInterval:DISPLAY_DELAY target:self selector:@selector(visualizeDisplay:) userInfo:nil repeats:YES];
257
+        timer = [NSTimer scheduledTimerWithTimeInterval:DISPLAY_DELAY target:self selector:@selector(visualizeDisplay:) userInfo:nil repeats:NO];
218 258
     }
219 259
 }
220 260
 
@@ -232,6 +272,72 @@
232 272
     [application orderFrontStandardAboutPanel:self];
233 273
 }
234 274
 
275
+// ----------------------------------------------------
276
+// ------------ 'Ambilight' Visualizations ------------
277
+// ----------------------------------------------------
278
+
279
+// ToDo: add support for display names or IDs here, so we can distinguish
280
+// between multiple displays with the same resolution
281
+struct DisplayAssignment {
282
+    int width, height;
283
+};
284
+
285
+struct LEDStrand {
286
+    int idMin, idMax;
287
+    int display;
288
+    int startX, startY;
289
+    int direction;
290
+    int size;
291
+};
292
+
293
+#define DIR_LEFT 0
294
+#define DIR_RIGHT 1
295
+#define DIR_UP 2
296
+#define DIR_DOWN 3
297
+
298
+// ----------------------- Config starts here -----------------------
299
+
300
+// The idea behind this algorithm is very simple. It assumes that each LED strand
301
+// follows one edge of one of your displays. So one of the two coordinates should
302
+// always be zero or the width / height of your display.
303
+
304
+// Define the amount of LEDs in your strip here
305
+#define LED_COUNT 156
306
+
307
+// This defined how large the averaging-boxes should be in the dimension perpendicular
308
+// to the strand. So eg. for a bottom strand, how high the box should be in px.
309
+#define COLOR_AVERAGE_OTHER_DIMENSION_SIZE 150
310
+
311
+// Identify your displays here. Currently they're only distinguished by their resolution.
312
+// The ID will be the index in the list, so the first entry is display 0 and so on.
313
+struct DisplayAssignment displays[] = {
314
+    { 1920, 1080 },
315
+    {  900, 1600 }
316
+};
317
+
318
+// This defined the orientation and placement of your strands and is the most important part.
319
+// It begins with the LED IDs this strand includes, starting with ID 0 up to LED_COUNT - 1.
320
+// The third item is the display ID, defined by the previous struct.
321
+// The fourth and fifth items are the starting X and Y coordinates of the strand.
322
+// As described above, one should always be zero or the display width / height.
323
+// The sixth element is the direction the strand goes (no diagonals supported yet).
324
+// The last element is the size of the averaging-box for each LED, moving with the strand.
325
+// So, if your strand contains 33 LEDs and spans 1920 pixels, this should be (1920 / 33).
326
+struct LEDStrand strands[] = {
327
+    {   0,  32, 0, 1920, 1080,  DIR_LEFT, 1920 / 33 },
328
+    {  33,  51, 0,    0, 1080,    DIR_UP, 1080 / 19 },
329
+    {  52,  84, 0,    0,    0, DIR_RIGHT, 1920 / 33 },
330
+    {  85,  89, 1,    0,  250,    DIR_UP,  250 / 5 },
331
+    {  90, 106, 1,    0,    0, DIR_RIGHT,  900 / 17 },
332
+    { 107, 134, 1,  900,    0,  DIR_DOWN, 1600 / 28 },
333
+    { 135, 151, 1,  900, 1600,  DIR_LEFT,  900 / 17 },
334
+    { 152, 155, 1,    0, 1600,    DIR_UP,  180 / 4 }
335
+};
336
+
337
+// ------------------------ Config ends here ------------------------
338
+
339
+UInt8 ledColorData[LED_COUNT * 3];
340
+
235 341
 - (UInt32)calculateAverage:(unsigned char *)data Width:(NSInteger)width Height:(NSInteger)height SPP:(NSInteger)spp Alpha:(BOOL)alpha StartX:(NSInteger)startX StartY:(NSInteger)startY EndX:(NSInteger)endX EndY:(NSInteger)endY {
236 342
     int redC = 0, greenC = 1, blueC = 2;
237 343
     if (alpha) {
@@ -268,48 +374,13 @@
268 374
     green /= count;
269 375
     blue /= count;
270 376
     
377
+    red *= [brightnessSlider floatValue] / 100.0f;
378
+    green *= [brightnessSlider floatValue] / 100.0f;
379
+    blue *= [brightnessSlider floatValue] / 100.0f;
380
+    
271 381
     return ((UInt32)red << 16) | ((UInt32)green << 8) | ((UInt32)blue);
272 382
 }
273 383
 
274
-struct DisplayAssignment {
275
-    int n;
276
-    int width, height;
277
-};
278
-
279
-struct LEDStrand {
280
-    int idMin, idMax;
281
-    int display;
282
-    int startX, startY;
283
-    int direction;
284
-    int size;
285
-};
286
-
287
-#define DIR_LEFT 0
288
-#define DIR_RIGHT 1
289
-#define DIR_UP 2
290
-#define DIR_DOWN 3
291
-
292
-// TODO remove first
293
-struct DisplayAssignment displays[] = {
294
-    { 0, 1920, 1080 },
295
-    { 1,  900, 1600 }
296
-};
297
-
298
-struct LEDStrand strands[] = {
299
-    {   0,  32, 0, 1920, 1080,  DIR_LEFT, 1920 / 33 },
300
-    {  33,  51, 0,    0, 1080,    DIR_UP, 1080 / 19 },
301
-    {  52,  84, 0,    0,    0, DIR_RIGHT, 1920 / 33 },
302
-    {  85,  89, 1,    0,  250,    DIR_UP,  250 / 5 },
303
-    {  90, 106, 1,    0,    0, DIR_RIGHT,  900 / 17 },
304
-    { 107, 134, 1,  900,    0,  DIR_DOWN, 1600 / 28 },
305
-    { 135, 151, 1,  900, 1600,  DIR_LEFT,  900 / 17 },
306
-    { 152, 155, 1,    0, 1600,    DIR_UP,  180 / 4 }
307
-};
308
-
309
-UInt8 ledColorData[156 * 3];
310
-
311
-#define COLOR_AVERAGE_OTHER_DIMENSION_SIZE 150
312
-
313 384
 - (void)visualizeSingleDisplay:(NSInteger)disp Data:(unsigned char *)data Width:(unsigned long)width Height:(unsigned long)height SPP:(NSInteger)spp Alpha:(BOOL)alpha {
314 385
     for (int i = 0; i < (sizeof(strands) / sizeof(strands[0])); i++) {
315 386
         if (strands[i].display == disp) {
@@ -406,11 +477,13 @@ UInt8 ledColorData[156 * 3];
406 477
     }
407 478
     
408 479
     [self sendLEDFrame];
480
+    
481
+    timer = [NSTimer scheduledTimerWithTimeInterval:DISPLAY_DELAY target:self selector:@selector(visualizeDisplay:) userInfo:nil repeats:NO];
409 482
 }
410 483
 
411 484
 - (void)sendLEDFrame {
412 485
     if ([serial isOpen]) {
413
-        [serial sendString:@"xythobuzRGBled"];
486
+        [serial sendString:MAGIC_WORD];
414 487
         [serial sendData:(char *)ledColorData withLength:(sizeof(ledColorData) / sizeof(ledColorData[0]))];
415 488
     }
416 489
 }
@@ -422,9 +495,4 @@ UInt8 ledColorData[156 * 3];
422 495
     [self sendLEDFrame];
423 496
 }
424 497
 
425
-+ (double)map:(double)val FromMin:(double)fmin FromMax:(double)fmax ToMin:(double)tmin ToMax:(double)tmax {
426
-    double norm = (val - fmin) / (fmax - fmin);
427
-    return (norm * (tmax - tmin)) + tmin;
428
-}
429
-
430 498
 @end

+ 1
- 1
DisplayBacklight/Info.plist View File

@@ -21,7 +21,7 @@
21 21
 	<key>CFBundleSignature</key>
22 22
 	<string>????</string>
23 23
 	<key>CFBundleVersion</key>
24
-	<string>53</string>
24
+	<string>65</string>
25 25
 	<key>LSApplicationCategoryType</key>
26 26
 	<string>public.app-category.utilities</string>
27 27
 	<key>LSMinimumSystemVersion</key>

Loading…
Cancel
Save