Simple RGB LED controller for Mac OS X
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AppDelegate.m 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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 TEXT_CPU_USAGE @"CPU Usage"
  16. #define TEXT_RAM_USAGE @"RAM Usage"
  17. #define TEXT_GPU_USAGE @"GPU Usage"
  18. #define TEXT_VRAM_USAGE @"VRAM Usage"
  19. #define TEXT_CPU_TEMPERATURE @"CPU Temperature"
  20. #define TEXT_GPU_TEMPERATURE @"GPU Temperature"
  21. #define KEY_CPU_TEMPERATURE @"TC0D"
  22. #define KEY_GPU_TEMPERATURE @"TG0D"
  23. @interface AppDelegate ()
  24. @property (weak) NSMenuItem *lastLEDMode;
  25. @end
  26. @implementation AppDelegate
  27. @synthesize statusMenu, application;
  28. @synthesize menuColors, menuAnimations, menuVisualizations, menuPorts;
  29. @synthesize buttonOff, buttonLights;
  30. @synthesize statusItem, statusImage;
  31. @synthesize staticColors;
  32. @synthesize serial, lastLEDMode;
  33. - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
  34. serial = [[Serial alloc] init];
  35. lastLEDMode = nil;
  36. // Prepare status bar menu
  37. statusImage = [NSImage imageNamed:@"MenuIcon"];
  38. [statusImage setTemplate:YES];
  39. statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
  40. [statusItem setImage:statusImage];
  41. [statusItem setMenu:statusMenu];
  42. // Set default configuration values, load existing ones
  43. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  44. NSMutableDictionary *appDefaults = [NSMutableDictionary dictionaryWithObject:@"" forKey:PREF_SERIAL_PORT];
  45. [appDefaults setObject:[NSNumber numberWithBool:NO] forKey:PREF_LIGHTS_STATE];
  46. [appDefaults setObject:@"" forKey:PREF_LED_MODE];
  47. [store registerDefaults:appDefaults];
  48. [store synchronize];
  49. NSString *savedPort = [store stringForKey:PREF_SERIAL_PORT];
  50. BOOL turnOnLights = [store boolForKey:PREF_LIGHTS_STATE];
  51. NSString *lastMode = [store stringForKey:PREF_LED_MODE];
  52. // Prepare serial port menu
  53. NSArray *ports = [Serial listSerialPorts];
  54. if ([ports count] > 0) {
  55. [menuPorts removeAllItems];
  56. for (int i = 0; i < [ports count]; i++) {
  57. // Add Menu Item for this port
  58. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[ports objectAtIndex:i] action:@selector(selectedSerialPort:) keyEquivalent:@""];
  59. [menuPorts addItem:item];
  60. // Set Enabled if it was used the last time
  61. if ((savedPort != nil) && [[ports objectAtIndex:i] isEqualToString:savedPort]) {
  62. [[menuPorts itemAtIndex:i] setState:NSOnState];
  63. // Try to open serial port
  64. [serial setPortName:savedPort];
  65. if ([serial openPort]) {
  66. // Unselect it when an error occured opening the port
  67. [[menuPorts itemAtIndex:i] setState:NSOffState];
  68. }
  69. }
  70. }
  71. }
  72. // Select "Off" button if it was last selected
  73. if ([lastMode isEqualToString:@""]) {
  74. [buttonOff setState:NSOffState];
  75. [self turnLEDsOff:buttonOff];
  76. }
  77. // Prepare static colors menu
  78. staticColors = [NSDictionary dictionaryWithObjectsAndKeys:
  79. [NSColor colorWithCalibratedRed:1.0f green:0.0f blue:0.0f alpha:0.0f], @"Red",
  80. [NSColor colorWithCalibratedRed:0.0f green:1.0f blue:0.0f alpha:0.0f], @"Green",
  81. [NSColor colorWithCalibratedRed:0.0f green:0.0f blue:1.0f alpha:0.0f], @"Blue",
  82. [NSColor colorWithCalibratedRed:0.0f green:1.0f blue:1.0f alpha:0.0f], @"Cyan",
  83. [NSColor colorWithCalibratedRed:1.0f green:0.0f blue:1.0f alpha:0.0f], @"Magenta",
  84. [NSColor colorWithCalibratedRed:1.0f green:1.0f blue:0.0f alpha:0.0f], @"Yellow",
  85. [NSColor colorWithCalibratedRed:1.0f green:1.0f blue:1.0f alpha:0.0f], @"White",
  86. nil];
  87. for (NSString *key in [staticColors allKeys]) {
  88. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:key action:@selector(selectedVisualization:) keyEquivalent:@""];
  89. if ([key isEqualToString:lastMode]) {
  90. [self selectedVisualization:item];
  91. }
  92. [menuColors addItem:item];
  93. }
  94. // TODO Prepare animations menu
  95. JSKSystemMonitor *systemMonitor = [JSKSystemMonitor systemMonitor];
  96. #ifdef DEBUG
  97. JSKMCPUUsageInfo cpuUsageInfo = systemMonitor.cpuUsageInfo;
  98. NSLog(@"CPU Usage: %.3f%%\n", cpuUsageInfo.usage);
  99. JSKMMemoryUsageInfo memoryUsageInfo = systemMonitor.memoryUsageInfo;
  100. NSLog(@"Memory Usage: %.2fGB Free + %.2fGB Used = %.2fGB\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));
  101. #endif
  102. // Add CPU Usage menu item
  103. NSMenuItem *cpuUsageItem = [[NSMenuItem alloc] initWithTitle:TEXT_CPU_USAGE action:@selector(selectedVisualization:) keyEquivalent:@""];
  104. if ([lastMode isEqualToString:TEXT_CPU_USAGE]) {
  105. [self selectedVisualization:cpuUsageItem];
  106. }
  107. [menuVisualizations addItem:cpuUsageItem];
  108. // Add Memory Usage item
  109. NSMenuItem *memoryUsageItem = [[NSMenuItem alloc] initWithTitle:TEXT_RAM_USAGE action:@selector(selectedVisualization:) keyEquivalent:@""];
  110. if ([lastMode isEqualToString:TEXT_RAM_USAGE]) {
  111. [self selectedVisualization:memoryUsageItem];
  112. }
  113. [menuVisualizations addItem:memoryUsageItem];
  114. // Check if GPU Stats are available, add menu items if so
  115. NSNumber *usage;
  116. NSNumber *freeVRAM;
  117. NSNumber *usedVRAM;
  118. if ([GPUStats getGPUUsage:&usage freeVRAM:&freeVRAM usedVRAM:&usedVRAM] != 0) {
  119. NSLog(@"Error reading GPU information\n");
  120. } else {
  121. NSMenuItem *itemUsage = [[NSMenuItem alloc] initWithTitle:TEXT_GPU_USAGE action:@selector(selectedVisualization:) keyEquivalent:@""];
  122. if ([lastMode isEqualToString:TEXT_GPU_USAGE]) {
  123. [self selectedVisualization:itemUsage];
  124. }
  125. [menuVisualizations addItem:itemUsage];
  126. NSMenuItem *itemVRAM = [[NSMenuItem alloc] initWithTitle:TEXT_VRAM_USAGE action:@selector(selectedVisualization:) keyEquivalent:@""];
  127. if ([lastMode isEqualToString:TEXT_VRAM_USAGE]) {
  128. [self selectedVisualization:itemVRAM];
  129. }
  130. [menuVisualizations addItem:itemVRAM];
  131. }
  132. // Check available temperatures and add menu items
  133. JSKSMC *smc = [JSKSMC smc];
  134. for (int i = 0; i < [[smc workingTempKeys] count]; i++) {
  135. NSString *key = [smc.workingTempKeys objectAtIndex:i];
  136. #ifdef DEBUG
  137. NSString *name = [smc humanReadableNameForKey:key];
  138. NSLog(@"Sensor \"%@\": \"%@\"\n", key, name);
  139. #endif
  140. if ([key isEqualToString:KEY_CPU_TEMPERATURE]) {
  141. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:TEXT_CPU_TEMPERATURE action:@selector(selectedVisualization:) keyEquivalent:@""];
  142. if ([lastMode isEqualToString:TEXT_CPU_TEMPERATURE]) {
  143. [self selectedVisualization:item];
  144. }
  145. [menuVisualizations addItem:item];
  146. }
  147. if ([key isEqualToString:KEY_GPU_TEMPERATURE]) {
  148. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:TEXT_GPU_TEMPERATURE action:@selector(selectedVisualization:) keyEquivalent:@""];
  149. if ([lastMode isEqualToString:TEXT_GPU_TEMPERATURE]) {
  150. [self selectedVisualization:item];
  151. }
  152. [menuVisualizations addItem:item];
  153. }
  154. }
  155. // Restore previously used lights configuration
  156. if (turnOnLights) {
  157. // Turn on lights
  158. if ([serial isOpen]) {
  159. [serial sendString:@"UV 1\n"];
  160. }
  161. [buttonLights setState:NSOnState];
  162. } else {
  163. // Turn off lights
  164. if ([serial isOpen]) {
  165. [serial sendString:@"UV 0\n"];
  166. }
  167. }
  168. }
  169. - (void)applicationWillTerminate:(NSNotification *)aNotification {
  170. // Close serial port, if it was opened
  171. if ([serial isOpen]) {
  172. [serial closePort];
  173. }
  174. }
  175. - (IBAction)relistSerialPorts:(id)sender {
  176. // Refill port list
  177. NSArray *ports = [Serial listSerialPorts];
  178. [menuPorts removeAllItems];
  179. for (int i = 0; i < [ports count]; i++) {
  180. // Add Menu Item for this port
  181. NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[ports objectAtIndex:i] action:@selector(selectedSerialPort:) keyEquivalent:@""];
  182. [menuPorts addItem:item];
  183. // Mark it if it is currently open
  184. if ([serial isOpen]) {
  185. if ([[ports objectAtIndex:i] isEqualToString:[serial portName]]) {
  186. [[menuPorts itemAtIndex:i] setState:NSOnState];
  187. }
  188. }
  189. }
  190. }
  191. - (IBAction)turnLEDsOff:(NSMenuItem *)sender {
  192. if ([sender state] == NSOffState) {
  193. lastLEDMode = nil;
  194. // Turn off all other LED menu items
  195. for (int i = 0; i < [menuColors numberOfItems]; i++) {
  196. if ([[menuColors itemAtIndex:i] state] == NSOnState) {
  197. lastLEDMode = [menuColors itemAtIndex:i];
  198. }
  199. [[menuColors itemAtIndex:i] setState:NSOffState];
  200. }
  201. for (int i = 0; i < [menuAnimations numberOfItems]; i++) {
  202. if ([[menuAnimations itemAtIndex:i] state] == NSOnState) {
  203. lastLEDMode = [menuAnimations itemAtIndex:i];
  204. }
  205. [[menuAnimations itemAtIndex:i] setState:NSOffState];
  206. }
  207. for (int i = 0; i < [menuVisualizations numberOfItems]; i++) {
  208. if ([[menuVisualizations itemAtIndex:i] state] == NSOnState) {
  209. lastLEDMode = [menuVisualizations itemAtIndex:i];
  210. }
  211. [[menuVisualizations itemAtIndex:i] setState:NSOffState];
  212. }
  213. // Turn on "off" menu item
  214. [sender setState:NSOnState];
  215. // Store changed value in preferences
  216. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  217. [store setObject:@"" forKey:PREF_LED_MODE];
  218. [store synchronize];
  219. #ifdef DEBUG
  220. NSLog(@"Stored new mode: \"off\"!\n");
  221. #endif
  222. // Send command to turn off LEDs
  223. if ([serial isOpen]) {
  224. [serial sendString:@"RGB 0 0 0\n"];
  225. }
  226. } else {
  227. // Try to restore last LED setting
  228. if (lastLEDMode != nil) {
  229. [self selectedVisualization:lastLEDMode];
  230. }
  231. }
  232. }
  233. - (IBAction)toggleLights:(NSMenuItem *)sender {
  234. if ([sender state] == NSOffState) {
  235. // Turn on lights
  236. if ([serial isOpen]) {
  237. [serial sendString:@"UV 1\n"];
  238. }
  239. [sender setState:NSOnState];
  240. } else {
  241. // Turn off lights
  242. if ([serial isOpen]) {
  243. [serial sendString:@"UV 0\n"];
  244. }
  245. [sender setState:NSOffState];
  246. }
  247. // Store changed value in preferences
  248. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  249. [store setBool:([sender state] == NSOnState) forKey:PREF_LIGHTS_STATE];
  250. [store synchronize];
  251. }
  252. - (void)selectedVisualization:(NSMenuItem *)sender {
  253. // Turn off all other LED menu items
  254. if (menuColors != nil) {
  255. for (int i = 0; i < [menuColors numberOfItems]; i++) {
  256. [[menuColors itemAtIndex:i] setState:NSOffState];
  257. }
  258. }
  259. if (menuAnimations != nil) {
  260. for (int i = 0; i < [menuAnimations numberOfItems]; i++) {
  261. [[menuAnimations itemAtIndex:i] setState:NSOffState];
  262. }
  263. }
  264. if (menuVisualizations != nil) {
  265. for (int i = 0; i < [menuVisualizations numberOfItems]; i++) {
  266. [[menuVisualizations itemAtIndex:i] setState:NSOffState];
  267. }
  268. }
  269. [buttonOff setState:NSOffState];
  270. [sender setState:NSOnState];
  271. if ([sender.title isEqualToString:TEXT_GPU_USAGE]) {
  272. // TODO send command
  273. } else if ([sender.title isEqualToString:TEXT_VRAM_USAGE]) {
  274. // TODO send command
  275. } else if ([sender.title isEqualToString:TEXT_GPU_TEMPERATURE]) {
  276. // TODO send command
  277. } else if ([sender.title isEqualToString:TEXT_CPU_USAGE]) {
  278. // TODO send command
  279. } else if ([sender.title isEqualToString:TEXT_CPU_TEMPERATURE]) {
  280. // TODO send command
  281. } else if ([sender.title isEqualToString:TEXT_RAM_USAGE]) {
  282. // TODO send command
  283. } else {
  284. BOOL found = NO;
  285. // Check if a static color was selected
  286. if (staticColors != nil) {
  287. for (NSString *key in [staticColors allKeys]) {
  288. if ([sender.title isEqualToString:key]) {
  289. found = YES;
  290. NSColor *color = [staticColors valueForKey:key];
  291. unsigned char red = [color redComponent] * 255;
  292. unsigned char green = [color greenComponent] * 255;
  293. unsigned char blue = [color blueComponent] * 255;
  294. NSString *string = [NSString stringWithFormat:@"RGB %d %d %d\n", red, green, blue];
  295. if ([serial isOpen]) {
  296. [serial sendString:string];
  297. }
  298. }
  299. }
  300. }
  301. if (found) goto end_found;
  302. // TODO Check if an animation was selected
  303. NSLog(@"Unknown LED Visualization selected!\n");
  304. return;
  305. }
  306. end_found: {
  307. // Store changed value in preferences
  308. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  309. [store setObject:[sender title] forKey:PREF_LED_MODE];
  310. [store synchronize];
  311. #ifdef DEBUG
  312. NSLog(@"Stored new mode: \"%@\"!\n", [sender title]);
  313. #endif
  314. }
  315. }
  316. - (void)selectedSerialPort:(NSMenuItem *)source {
  317. // Store selection for next start-up
  318. NSUserDefaults *store = [NSUserDefaults standardUserDefaults];
  319. [store setObject:[source title] forKey:PREF_SERIAL_PORT];
  320. [store synchronize];
  321. // De-select all other ports
  322. for (int i = 0; i < [menuPorts numberOfItems]; i++) {
  323. [[menuPorts itemAtIndex:i] setState:NSOffState];
  324. }
  325. // Select only the current port
  326. [source setState:NSOnState];
  327. // Close previously opened port, if any
  328. if ([serial isOpen]) {
  329. [serial closePort];
  330. }
  331. // Try to open selected port
  332. [serial setPortName:[source title]];
  333. if ([serial openPort] != 0) {
  334. [source setState:NSOffState];
  335. } else {
  336. // TODO Restore the current configuration
  337. }
  338. }
  339. - (IBAction)showAbout:(id)sender {
  340. [NSApp activateIgnoringOtherApps:YES];
  341. [application orderFrontStandardAboutPanel:self];
  342. }
  343. @end