Simple RGB LED controller for Mac OS X
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

AppDelegate.m 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. //
  2. // AppDelegate.m
  3. // CaseLights
  4. //
  5. // Created by Thomas Buck on 21.12.15.
  6. // Copyright © 2015 xythobuz. All rights reserved.
  7. //
  8. #import "AppDelegate.h"
  9. #import "Serial.h"
  10. #import "GPUStats.h"
  11. #import "SystemInfoKit/SystemInfoKit.h"
  12. #define PREF_SERIAL_PORT @"SerialPort"
  13. #define PREF_LIGHTS_STATE @"LightState"
  14. #define PREF_LED_MODE @"LEDMode"
  15. #define PREF_BRIGHTNESS @"Brightness"
  16. #define TEXT_CPU_USAGE @"CPU Usage"
  17. #define TEXT_RAM_USAGE @"RAM Usage"
  18. #define TEXT_GPU_USAGE @"GPU Usage"
  19. #define TEXT_VRAM_USAGE @"VRAM Usage"
  20. #define TEXT_CPU_TEMPERATURE @"CPU Temperature"
  21. #define TEXT_GPU_TEMPERATURE @"GPU Temperature"
  22. #define TEXT_RGB_FADE @"RGB Fade"
  23. #define TEXT_HSV_FADE @"HSV Fade"
  24. #define TEXT_RANDOM @"Random"
  25. #define KEY_CPU_TEMPERATURE @"TC0D"
  26. #define KEY_GPU_TEMPERATURE @"TG0D"
  27. // Temperature in Celsius
  28. #define CPU_TEMP_MIN 20
  29. #define CPU_TEMP_MAX 90
  30. // HSV Color (S = V = 1)
  31. #define CPU_COLOR_MIN 120
  32. #define CPU_COLOR_MAX 0
  33. #define GPU_TEMP_MIN 20
  34. #define GPU_TEMP_MAX 90
  35. #define GPU_COLOR_MIN 120
  36. #define GPU_COLOR_MAX 0
  37. #define RAM_COLOR_MIN 0
  38. #define RAM_COLOR_MAX 120
  39. @interface AppDelegate ()
  40. @property (strong) NSStatusItem *statusItem;
  41. @property (strong) NSImage *statusImage;
  42. @property (strong) NSDictionary *staticColors;
  43. @property (strong) NSTimer *animation;
  44. @property (strong) Serial *serial;
  45. @property (strong) NSMenuItem *lastLEDMode;
  46. @end
  47. @implementation AppDelegate
  48. @synthesize statusMenu, application;
  49. @synthesize menuColors, menuAnimations, menuVisualizations, menuPorts;
  50. @synthesize buttonOff, buttonLights;
  51. @synthesize brightnessItem, brightnessSlider, brightnessLabel;
  52. @synthesize statusItem, statusImage;
  53. @synthesize staticColors, animation;
  54. @synthesize serial, lastLEDMode;
  55. - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
  56. srand((unsigned)time(NULL));
  57. serial = [[Serial alloc] init];
  58. lastLEDMode = nil;
  59. animation = nil;
  60. // Prepare status bar menu
  61. statusImage = [NSImage imageNamed:@"MenuIcon"];
  62. [statusImage setTemplate:YES];
  63. statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
  64. [statusItem setImage:statusImage];
  65. [statusItem setMenu:statusMenu];
  66. // Set default configuration values, load existing ones
  67. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  68. NSMutableDictionary *appDefaults = [NSMutableDictionary dictionaryWithObject:@"" forKey:PREF_SERIAL_PORT];
  69. [appDefaults setObject:[NSNumber numberWithBool:NO] forKey:PREF_LIGHTS_STATE];
  70. [appDefaults setObject:@"" forKey:PREF_LED_MODE];
  71. [appDefaults setObject:[NSNumber numberWithFloat:50.0] forKey:PREF_BRIGHTNESS];
  72. [store registerDefaults:appDefaults];
  73. [store synchronize];
  74. NSString *savedPort = [store stringForKey:PREF_SERIAL_PORT];
  75. BOOL turnOnLights = [store boolForKey:PREF_LIGHTS_STATE];
  76. NSString *lastMode = [store stringForKey:PREF_LED_MODE];
  77. float brightness = [store floatForKey:PREF_BRIGHTNESS];
  78. // Prepare brightness menu
  79. brightnessItem.view = brightnessSlider;
  80. [brightnessSlider setFloatValue:brightness];
  81. [brightnessLabel setTitle:[NSString stringWithFormat:@"Value: %.0f%%", brightness]];
  82. // Prepare serial port menu
  83. NSArray *ports = [Serial listSerialPorts];
  84. if ([ports count] > 0) {
  85. [menuPorts removeAllItems];
  86. for (int i = 0; i < [ports count]; i++) {
  87. // Add Menu Item for this port
  88. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[ports objectAtIndex:i] action:@selector(selectedSerialPort:) keyEquivalent:@""];
  89. [menuPorts addItem:item];
  90. // Set Enabled if it was used the last time
  91. if ((savedPort != nil) && [[ports objectAtIndex:i] isEqualToString:savedPort]) {
  92. [[menuPorts itemAtIndex:i] setState:NSOnState];
  93. // Try to open serial port
  94. [serial setPortName:savedPort];
  95. if ([serial openPort]) {
  96. // Unselect it when an error occured opening the port
  97. [[menuPorts itemAtIndex:i] setState:NSOffState];
  98. }
  99. }
  100. }
  101. }
  102. // Select "Off" button if it was last selected
  103. if ([lastMode isEqualToString:@""]) {
  104. [buttonOff setState:NSOffState];
  105. [self turnLEDsOff:buttonOff];
  106. }
  107. // Prepare static colors menu
  108. staticColors = [NSDictionary dictionaryWithObjectsAndKeys:
  109. [NSColor colorWithCalibratedRed:1.0f green:0.0f blue:0.0f alpha:0.0f], @"Red",
  110. [NSColor colorWithCalibratedRed:0.0f green:1.0f blue:0.0f alpha:0.0f], @"Green",
  111. [NSColor colorWithCalibratedRed:0.0f green:0.0f blue:1.0f alpha:0.0f], @"Blue",
  112. [NSColor colorWithCalibratedRed:0.0f green:1.0f blue:1.0f alpha:0.0f], @"Cyan",
  113. [NSColor colorWithCalibratedRed:1.0f green:0.0f blue:1.0f alpha:0.0f], @"Magenta",
  114. [NSColor colorWithCalibratedRed:1.0f green:1.0f blue:0.0f alpha:0.0f], @"Yellow",
  115. [NSColor colorWithCalibratedRed:1.0f green:1.0f blue:1.0f alpha:0.0f], @"White",
  116. nil];
  117. for (NSString *key in [staticColors allKeys]) {
  118. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:key action:@selector(selectedVisualization:) keyEquivalent:@""];
  119. if ([key isEqualToString:lastMode]) {
  120. [self selectedVisualization:item];
  121. }
  122. [menuColors addItem:item];
  123. }
  124. // Prepare animations menu
  125. NSArray *animationStrings = [NSArray arrayWithObjects:
  126. TEXT_RGB_FADE,
  127. TEXT_HSV_FADE,
  128. TEXT_RANDOM,
  129. nil];
  130. for (NSString *key in animationStrings) {
  131. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:key action:@selector(selectedVisualization:) keyEquivalent:@""];
  132. if ([key isEqualToString:lastMode]) {
  133. [self selectedVisualization:item];
  134. }
  135. [menuAnimations addItem:item];
  136. }
  137. // Add CPU Usage menu item
  138. NSMenuItem *cpuUsageItem = [[NSMenuItem alloc] initWithTitle:TEXT_CPU_USAGE action:@selector(selectedVisualization:) keyEquivalent:@""];
  139. if ([lastMode isEqualToString:TEXT_CPU_USAGE]) {
  140. [self selectedVisualization:cpuUsageItem];
  141. }
  142. [menuVisualizations addItem:cpuUsageItem];
  143. // Add Memory Usage item
  144. NSMenuItem *memoryUsageItem = [[NSMenuItem alloc] initWithTitle:TEXT_RAM_USAGE action:@selector(selectedVisualization:) keyEquivalent:@""];
  145. if ([lastMode isEqualToString:TEXT_RAM_USAGE]) {
  146. [self selectedVisualization:memoryUsageItem];
  147. }
  148. [menuVisualizations addItem:memoryUsageItem];
  149. // Check if GPU Stats are available, add menu items if so
  150. NSNumber *usage;
  151. NSNumber *freeVRAM;
  152. NSNumber *usedVRAM;
  153. if ([GPUStats getGPUUsage:&usage freeVRAM:&freeVRAM usedVRAM:&usedVRAM] != 0) {
  154. NSLog(@"Error reading GPU information\n");
  155. } else {
  156. NSMenuItem *itemUsage = [[NSMenuItem alloc] initWithTitle:TEXT_GPU_USAGE action:@selector(selectedVisualization:) keyEquivalent:@""];
  157. if ([lastMode isEqualToString:TEXT_GPU_USAGE]) {
  158. [self selectedVisualization:itemUsage];
  159. }
  160. [menuVisualizations addItem:itemUsage];
  161. NSMenuItem *itemVRAM = [[NSMenuItem alloc] initWithTitle:TEXT_VRAM_USAGE action:@selector(selectedVisualization:) keyEquivalent:@""];
  162. if ([lastMode isEqualToString:TEXT_VRAM_USAGE]) {
  163. [self selectedVisualization:itemVRAM];
  164. }
  165. [menuVisualizations addItem:itemVRAM];
  166. }
  167. // Check available temperatures and add menu items
  168. JSKSMC *smc = [JSKSMC smc];
  169. for (int i = 0; i < [[smc workingTempKeys] count]; i++) {
  170. NSString *key = [smc.workingTempKeys objectAtIndex:i];
  171. #ifdef DEBUG
  172. NSString *name = [smc humanReadableNameForKey:key];
  173. NSLog(@"Sensor \"%@\": \"%@\"\n", key, name);
  174. #endif
  175. if ([key isEqualToString:KEY_CPU_TEMPERATURE]) {
  176. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:TEXT_CPU_TEMPERATURE action:@selector(selectedVisualization:) keyEquivalent:@""];
  177. if ([lastMode isEqualToString:TEXT_CPU_TEMPERATURE]) {
  178. [self selectedVisualization:item];
  179. }
  180. [menuVisualizations addItem:item];
  181. }
  182. if ([key isEqualToString:KEY_GPU_TEMPERATURE]) {
  183. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:TEXT_GPU_TEMPERATURE action:@selector(selectedVisualization:) keyEquivalent:@""];
  184. if ([lastMode isEqualToString:TEXT_GPU_TEMPERATURE]) {
  185. [self selectedVisualization:item];
  186. }
  187. [menuVisualizations addItem:item];
  188. }
  189. }
  190. // Restore previously used lights configuration
  191. if (turnOnLights) {
  192. // Turn on lights
  193. if ([serial isOpen]) {
  194. [serial sendString:@"UV 1\n"];
  195. }
  196. [buttonLights setState:NSOnState];
  197. } else {
  198. // Turn off lights
  199. if ([serial isOpen]) {
  200. [serial sendString:@"UV 0\n"];
  201. }
  202. }
  203. }
  204. - (void)applicationWillTerminate:(NSNotification *)aNotification {
  205. if ([serial isOpen]) {
  206. [serial sendString:@"RGB 0 0 0\n"];
  207. [serial sendString:@"UV 0\n"];
  208. [serial closePort];
  209. }
  210. }
  211. - (void)setLightsR:(unsigned char)r G:(unsigned char)g B:(unsigned char)b {
  212. if ([serial isOpen]) {
  213. unsigned char red = r * ([brightnessSlider floatValue] / 100.0);
  214. unsigned char green = g * ([brightnessSlider floatValue] / 100.0);
  215. unsigned char blue = b * ([brightnessSlider floatValue] / 100.0);
  216. [serial sendString:[NSString stringWithFormat:@"RGB %d %d %d\n", red, green, blue]];
  217. } else {
  218. #ifdef DEBUG
  219. NSLog(@"Trying to send RGB without opened port!\n");
  220. #endif
  221. }
  222. }
  223. - (IBAction)relistSerialPorts:(id)sender {
  224. // Refill port list
  225. NSArray *ports = [Serial listSerialPorts];
  226. [menuPorts removeAllItems];
  227. for (int i = 0; i < [ports count]; i++) {
  228. // Add Menu Item for this port
  229. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[ports objectAtIndex:i] action:@selector(selectedSerialPort:) keyEquivalent:@""];
  230. [menuPorts addItem:item];
  231. // Mark it if it is currently open
  232. if ([serial isOpen]) {
  233. if ([[ports objectAtIndex:i] isEqualToString:[serial portName]]) {
  234. [[menuPorts itemAtIndex:i] setState:NSOnState];
  235. }
  236. }
  237. }
  238. }
  239. - (IBAction)brightnessMoved:(NSSlider *)sender {
  240. [brightnessLabel setTitle:[NSString stringWithFormat:@"Value: %.0f%%", [sender floatValue]]];
  241. // Restore the current configuration for items where it won't happen automatically
  242. for (int i = 0; i < [menuColors numberOfItems]; i++) {
  243. if ([[menuColors itemAtIndex:i] state] == NSOnState) {
  244. [self selectedVisualization:[menuColors itemAtIndex:i]];
  245. }
  246. }
  247. // Store changed value in preferences
  248. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  249. [store setObject:[NSNumber numberWithFloat:[sender floatValue]] forKey:PREF_BRIGHTNESS];
  250. [store synchronize];
  251. }
  252. - (IBAction)turnLEDsOff:(NSMenuItem *)sender {
  253. if ([sender state] == NSOffState) {
  254. lastLEDMode = nil;
  255. // Stop previous timer setting
  256. if (animation != nil) {
  257. [animation invalidate];
  258. animation = nil;
  259. }
  260. // Turn off all other LED menu items
  261. for (int i = 0; i < [menuColors numberOfItems]; i++) {
  262. if ([[menuColors itemAtIndex:i] state] == NSOnState) {
  263. lastLEDMode = [menuColors itemAtIndex:i];
  264. }
  265. [[menuColors itemAtIndex:i] setState:NSOffState];
  266. }
  267. for (int i = 0; i < [menuAnimations numberOfItems]; i++) {
  268. if ([[menuAnimations itemAtIndex:i] state] == NSOnState) {
  269. lastLEDMode = [menuAnimations itemAtIndex:i];
  270. }
  271. [[menuAnimations itemAtIndex:i] setState:NSOffState];
  272. }
  273. for (int i = 0; i < [menuVisualizations numberOfItems]; i++) {
  274. if ([[menuVisualizations itemAtIndex:i] state] == NSOnState) {
  275. lastLEDMode = [menuVisualizations itemAtIndex:i];
  276. }
  277. [[menuVisualizations itemAtIndex:i] setState:NSOffState];
  278. }
  279. // Turn on "off" menu item
  280. [sender setState:NSOnState];
  281. // Store changed value in preferences
  282. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  283. [store setObject:@"" forKey:PREF_LED_MODE];
  284. [store synchronize];
  285. #ifdef DEBUG
  286. NSLog(@"Stored new mode: \"off\"!\n");
  287. #endif
  288. // Send command to turn off LEDs
  289. [self setLightsR:0 G:0 B:0];
  290. } else {
  291. // Try to restore last LED setting
  292. if (lastLEDMode != nil) {
  293. [self selectedVisualization:lastLEDMode];
  294. }
  295. }
  296. }
  297. - (IBAction)toggleLights:(NSMenuItem *)sender {
  298. if ([sender state] == NSOffState) {
  299. // Turn on lights
  300. if ([serial isOpen]) {
  301. [serial sendString:@"UV 1\n"];
  302. }
  303. [sender setState:NSOnState];
  304. } else {
  305. // Turn off lights
  306. if ([serial isOpen]) {
  307. [serial sendString:@"UV 0\n"];
  308. }
  309. [sender setState:NSOffState];
  310. }
  311. // Store changed value in preferences
  312. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  313. [store setBool:([sender state] == NSOnState) forKey:PREF_LIGHTS_STATE];
  314. [store synchronize];
  315. }
  316. - (BOOL)timedVisualization:(NSString *)mode {
  317. // Stop previous timer setting
  318. if (animation != nil) {
  319. [animation invalidate];
  320. animation = nil;
  321. }
  322. // Schedule next invocation for this animation...
  323. if ([mode isEqualToString:TEXT_GPU_USAGE]) {
  324. animation = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(visualizeGPUUsage:) userInfo:mode repeats:YES];
  325. } else if ([mode isEqualToString:TEXT_VRAM_USAGE]) {
  326. animation = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(visualizeVRAMUsage:) userInfo:mode repeats:YES];
  327. } else if ([mode isEqualToString:TEXT_CPU_USAGE]) {
  328. animation = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(visualizeCPUUsage:) userInfo:mode repeats:YES];
  329. } else if ([mode isEqualToString:TEXT_RAM_USAGE]) {
  330. animation = [NSTimer scheduledTimerWithTimeInterval:20.0 target:self selector:@selector(visualizeRAMUsage:) userInfo:mode repeats:YES];
  331. } else if ([mode isEqualToString:TEXT_CPU_TEMPERATURE]) {
  332. animation = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(visualizeCPUTemperature:) userInfo:mode repeats:YES];
  333. } else if ([mode isEqualToString:TEXT_GPU_TEMPERATURE]) {
  334. animation = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(visualizeGPUTemperature:) userInfo:mode repeats:YES];
  335. } else if ([mode isEqualToString:TEXT_RGB_FADE]) {
  336. animation = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(visualizeRGBFade:) userInfo:mode repeats:YES];
  337. } else if ([mode isEqualToString:TEXT_HSV_FADE]) {
  338. animation = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(visualizeHSVFade:) userInfo:mode repeats:YES];
  339. } else if ([mode isEqualToString:TEXT_RANDOM]) {
  340. animation = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(visualizeRandom:) userInfo:mode repeats:YES];
  341. } else {
  342. return NO;
  343. }
  344. #ifdef DEBUG
  345. NSLog(@"Scheduled animation for \"%@\"!\n", mode);
  346. #endif
  347. // ...and also execute it right now
  348. [animation fire];
  349. return YES;
  350. }
  351. - (void)selectedVisualization:(NSMenuItem *)sender {
  352. // Turn off all other LED menu items
  353. if (menuColors != nil) {
  354. for (int i = 0; i < [menuColors numberOfItems]; i++) {
  355. [[menuColors itemAtIndex:i] setState:NSOffState];
  356. }
  357. }
  358. if (menuAnimations != nil) {
  359. for (int i = 0; i < [menuAnimations numberOfItems]; i++) {
  360. [[menuAnimations itemAtIndex:i] setState:NSOffState];
  361. }
  362. }
  363. if (menuVisualizations != nil) {
  364. for (int i = 0; i < [menuVisualizations numberOfItems]; i++) {
  365. [[menuVisualizations itemAtIndex:i] setState:NSOffState];
  366. }
  367. }
  368. [buttonOff setState:NSOffState];
  369. [sender setState:NSOnState];
  370. // Check if a static color was selected
  371. BOOL found = NO;
  372. if (staticColors != nil) {
  373. for (NSString *key in [staticColors allKeys]) {
  374. if ([sender.title isEqualToString:key]) {
  375. found = YES;
  376. // Stop previous timer setting
  377. if (animation != nil) {
  378. [animation invalidate];
  379. animation = nil;
  380. }
  381. NSColor *color = [staticColors valueForKey:key];
  382. unsigned char red = [color redComponent] * 255;
  383. unsigned char green = [color greenComponent] * 255;
  384. unsigned char blue = [color blueComponent] * 255;
  385. [self setLightsR:red G:green B:blue];
  386. break;
  387. }
  388. }
  389. }
  390. if (!found) {
  391. // Check if an animated visualization was selected
  392. if ([self timedVisualization:[sender title]] == NO) {
  393. NSLog(@"Unknown LED Visualization selected!\n");
  394. return;
  395. }
  396. }
  397. // Store changed value in preferences
  398. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  399. [store setObject:[sender title] forKey:PREF_LED_MODE];
  400. [store synchronize];
  401. #ifdef DEBUG
  402. NSLog(@"Stored new mode: \"%@\"!\n", [sender title]);
  403. #endif
  404. }
  405. - (void)selectedSerialPort:(NSMenuItem *)source {
  406. // Store selection for next start-up
  407. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  408. [store setObject:[source title] forKey:PREF_SERIAL_PORT];
  409. [store synchronize];
  410. // De-select all other ports
  411. for (int i = 0; i < [menuPorts numberOfItems]; i++) {
  412. [[menuPorts itemAtIndex:i] setState:NSOffState];
  413. }
  414. // Select only the current port
  415. [source setState:NSOnState];
  416. // Close previously opened port, if any
  417. if ([serial isOpen]) {
  418. [serial closePort];
  419. }
  420. // Try to open selected port
  421. [serial setPortName:[source title]];
  422. if ([serial openPort] != 0) {
  423. [source setState:NSOffState];
  424. } else {
  425. // Restore the current configuration
  426. for (int i = 0; i < [menuColors numberOfItems]; i++) {
  427. if ([[menuColors itemAtIndex:i] state] == NSOnState) {
  428. [self selectedVisualization:[menuColors itemAtIndex:i]];
  429. }
  430. }
  431. for (int i = 0; i < [menuAnimations numberOfItems]; i++) {
  432. if ([[menuAnimations itemAtIndex:i] state] == NSOnState) {
  433. [self selectedVisualization:[menuAnimations itemAtIndex:i]];
  434. }
  435. }
  436. for (int i = 0; i < [menuVisualizations numberOfItems]; i++) {
  437. if ([[menuVisualizations itemAtIndex:i] state] == NSOnState) {
  438. [self selectedVisualization:[menuVisualizations itemAtIndex:i]];
  439. }
  440. }
  441. if ([buttonOff state] == NSOnState) {
  442. [buttonOff setState:NSOffState];
  443. [self turnLEDsOff:buttonOff];
  444. }
  445. if ([buttonLights state] == NSOnState) {
  446. [serial sendString:@"UV 1\n"];
  447. } else {
  448. [serial sendString:@"UV 0\n"];
  449. }
  450. }
  451. }
  452. - (IBAction)showAbout:(id)sender {
  453. [NSApp activateIgnoringOtherApps:YES];
  454. [application orderFrontStandardAboutPanel:self];
  455. }
  456. // ------------------------------------------------------
  457. // ------------------- Visualizations -------------------
  458. // ------------------------------------------------------
  459. - (void)visualizeGPUUsage:(NSTimer *)timer {
  460. NSNumber *usage;
  461. NSNumber *freeVRAM;
  462. NSNumber *usedVRAM;
  463. if ([GPUStats getGPUUsage:&usage freeVRAM:&freeVRAM usedVRAM:&usedVRAM] != 0) {
  464. NSLog(@"Error reading GPU information\n");
  465. } else {
  466. double h = [self map:[usage doubleValue] FromMin:0.0 FromMax:100.0 ToMin:GPU_COLOR_MIN ToMax:GPU_COLOR_MAX];
  467. #ifdef DEBUG
  468. NSLog(@"GPU Usage: %.3f%%\n", [usage doubleValue]);
  469. #endif
  470. unsigned char r, g, b;
  471. [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
  472. [self setLightsR:r G:g B:b];
  473. }
  474. }
  475. - (void)visualizeVRAMUsage:(NSTimer *)timer {
  476. NSNumber *usage;
  477. NSNumber *freeVRAM;
  478. NSNumber *usedVRAM;
  479. if ([GPUStats getGPUUsage:&usage freeVRAM:&freeVRAM usedVRAM:&usedVRAM] != 0) {
  480. NSLog(@"Error reading GPU information\n");
  481. } else {
  482. double h = [self map:[freeVRAM doubleValue] FromMin:0.0 FromMax:([freeVRAM doubleValue] + [usedVRAM doubleValue]) ToMin:RAM_COLOR_MIN ToMax:RAM_COLOR_MAX];
  483. #ifdef DEBUG
  484. NSLog(@"VRAM %.2fGB Free + %.2fGB Used = %.2fGB mapped to color %.2f!\n", [freeVRAM doubleValue] / (1024.0 * 1024.0 * 1024.0), [usedVRAM doubleValue] / (1024.0 * 1024.0 * 1024.0), ([freeVRAM doubleValue] + [usedVRAM doubleValue]) / (1024.0 * 1024.0 * 1024.0), h);
  485. #endif
  486. unsigned char r, g, b;
  487. [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
  488. [self setLightsR:r G:g B:b];
  489. }
  490. }
  491. - (void)visualizeCPUUsage:(NSTimer *)timer {
  492. JSKMCPUUsageInfo cpuUsageInfo = [JSKSystemMonitor systemMonitor].cpuUsageInfo;
  493. double h = [self map:cpuUsageInfo.usage FromMin:0.0 FromMax:100.0 ToMin:CPU_COLOR_MIN ToMax:CPU_COLOR_MAX];
  494. #ifdef DEBUG
  495. NSLog(@"CPU Usage: %.3f%%\n", cpuUsageInfo.usage);
  496. #endif
  497. unsigned char r, g, b;
  498. [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
  499. [self setLightsR:r G:g B:b];
  500. }
  501. - (void)visualizeRAMUsage:(NSTimer *)timer {
  502. JSKMMemoryUsageInfo memoryUsageInfo = [JSKSystemMonitor systemMonitor].memoryUsageInfo;
  503. double h = [self map:memoryUsageInfo.freeMemory FromMin:0.0 FromMax:(memoryUsageInfo.usedMemory + memoryUsageInfo.freeMemory) ToMin:RAM_COLOR_MIN ToMax:RAM_COLOR_MAX];
  504. #ifdef DEBUG
  505. NSLog(@"RAM %.2fGB Free + %.2fGB Used = %.2fGB mapped to color %.2f!\n", memoryUsageInfo.freeMemory / (1024.0 * 1024.0 * 1024.0), memoryUsageInfo.usedMemory / (1024.0 * 1024.0 * 1024.0), (memoryUsageInfo.freeMemory + memoryUsageInfo.usedMemory) / (1024.0 * 1024.0 * 1024.0), h);
  506. #endif
  507. unsigned char r, g, b;
  508. [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
  509. [self setLightsR:r G:g B:b];
  510. }
  511. - (void)visualizeGPUTemperature:(NSTimer *)timer {
  512. JSKSMC *smc = [JSKSMC smc];
  513. double temp = [smc temperatureInCelsiusForKey:KEY_GPU_TEMPERATURE];
  514. if (temp > 1000.0) {
  515. temp /= 1000.0;
  516. }
  517. if (temp > GPU_TEMP_MAX) {
  518. temp = GPU_TEMP_MAX;
  519. }
  520. if (temp < GPU_TEMP_MIN) {
  521. temp = GPU_TEMP_MIN;
  522. }
  523. double h = [self map:temp FromMin:GPU_TEMP_MIN FromMax:GPU_TEMP_MAX ToMin:GPU_COLOR_MIN ToMax:GPU_COLOR_MAX];
  524. #ifdef DEBUG
  525. NSLog(@"GPU Temp %.2f mapped to color %.2f!\n", temp, h);
  526. #endif
  527. unsigned char r, g, b;
  528. [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
  529. [self setLightsR:r G:g B:b];
  530. }
  531. - (void)visualizeCPUTemperature:(NSTimer *)timer {
  532. JSKSMC *smc = [JSKSMC smc];
  533. double temp = [smc temperatureInCelsiusForKey:KEY_CPU_TEMPERATURE];
  534. if (temp > 1000.0) {
  535. temp /= 1000.0;
  536. }
  537. if (temp > CPU_TEMP_MAX) {
  538. temp = CPU_TEMP_MAX;
  539. }
  540. if (temp < CPU_TEMP_MIN) {
  541. temp = CPU_TEMP_MIN;
  542. }
  543. double h = [self map:temp FromMin:CPU_TEMP_MIN FromMax:CPU_TEMP_MAX ToMin:CPU_COLOR_MIN ToMax:CPU_COLOR_MAX];
  544. #ifdef DEBUG
  545. NSLog(@"CPU Temp %.2f mapped to color %.2f!\n", temp, h);
  546. #endif
  547. unsigned char r, g, b;
  548. [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
  549. [self setLightsR:r G:g B:b];
  550. }
  551. - (void)visualizeRGBFade:(NSTimer *)timer {
  552. static unsigned char color[3] = { 255, 0, 0 };
  553. static int dec = 0;
  554. static int val = 0;
  555. // Adapted from:
  556. // https://gist.github.com/jamesotron/766994
  557. if (dec < 3) {
  558. int inc = (dec == 2) ? 0 : (dec + 1);
  559. if (val < 255) {
  560. color[dec] -= 1;
  561. color[inc] += 1;
  562. val++;
  563. } else {
  564. val = 0;
  565. dec++;
  566. }
  567. } else {
  568. dec = 0;
  569. }
  570. [self setLightsR:color[0] G:color[1] B:color[2]];
  571. }
  572. - (void)visualizeHSVFade:(NSTimer *)timer {
  573. static float h = 0.0;
  574. if (h < 359.0) {
  575. h += 0.5;
  576. } else {
  577. h = 0.0;
  578. }
  579. unsigned char r, g, b;
  580. [self convertH:h S:1.0 V:1.0 toR:&r G:&g B:&b];
  581. [self setLightsR:r G:g B:b];
  582. }
  583. - (void)visualizeRandom:(NSTimer *)timer {
  584. [self setLightsR:rand() % 256 G:rand() % 256 B:rand() % 256];
  585. }
  586. // -----------------------------------------------------
  587. // --------------------- Utilities ---------------------
  588. // -----------------------------------------------------
  589. - (double)map:(double)val FromMin:(double)fmin FromMax:(double)fmax ToMin:(double)tmin ToMax:(double)tmax {
  590. double norm = (val - fmin) / (fmax - fmin);
  591. return (norm * (tmax - tmin)) + tmin;
  592. }
  593. - (void)convertH:(double)h S:(double)s V:(double)v toR:(unsigned char *)r G:(unsigned char *)g B:(unsigned char *)b {
  594. // Adapted from:
  595. // https://gist.github.com/hdznrrd/656996
  596. if (s == 0.0) {
  597. // Achromatic
  598. *r = *g = *b = (unsigned char)(v * 255);
  599. return;
  600. }
  601. h /= 60; // sector 0 to 5
  602. int i = floor(h);
  603. double f = h - i; // factorial part of h
  604. double p = v * (1 - s);
  605. double q = v * (1 - s * f);
  606. double t = v * (1 - s * (1 - f));
  607. switch (i) {
  608. case 0:
  609. *r = (unsigned char)round(255 * v);
  610. *g = (unsigned char)round(255 * t);
  611. *b = (unsigned char)round(255 * p);
  612. break;
  613. case 1:
  614. *r = (unsigned char)round(255 * q);
  615. *g = (unsigned char)round(255 * v);
  616. *b = (unsigned char)round(255 * p);
  617. break;
  618. case 2:
  619. *r = (unsigned char)round(255 * p);
  620. *g = (unsigned char)round(255 * v);
  621. *b = (unsigned char)round(255 * t);
  622. break;
  623. case 3:
  624. *r = (unsigned char)round(255 * p);
  625. *g = (unsigned char)round(255 * q);
  626. *b = (unsigned char)round(255 * v);
  627. break;
  628. case 4:
  629. *r = (unsigned char)round(255 * t);
  630. *g = (unsigned char)round(255 * p);
  631. *b = (unsigned char)round(255 * v);
  632. break;
  633. default: case 5:
  634. *r = (unsigned char)round(255 * v);
  635. *g = (unsigned char)round(255 * p);
  636. *b = (unsigned char)round(255 * q);
  637. break;
  638. }
  639. }
  640. @end