123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. #include "light.h"
  2. #include "helpers.h"
  3. // The different device implementations
  4. #include "impl/sysfs.h"
  5. //#include "impl/razer.h"
  6. #include <stdlib.h> // malloc, free
  7. #include <string.h> // strstr
  8. #include <stdio.h> // snprintf
  9. #include <unistd.h> // geteuid
  10. #include <sys/types.h> // geteuid
  11. #include <errno.h>
  12. /* Static helper functions for this file only, prefix with _ */
  13. static uint64_t _light_get_min_cap(light_context_t *ctx)
  14. {
  15. char target_path[NAME_MAX];
  16. snprintf(target_path, sizeof(target_path),
  17. "%s/targets/%s/%s/%s/minimum",
  18. ctx->sys_params.conf_dir,
  19. ctx->run_params.device_target->device->enumerator->name,
  20. ctx->run_params.device_target->device->name,
  21. ctx->run_params.device_target->name
  22. );
  23. uint64_t minimum_value = 0;
  24. if(!light_file_read_uint64(target_path, &minimum_value))
  25. {
  26. return 0;
  27. }
  28. return minimum_value;
  29. }
  30. static light_device_enumerator_t* _light_find_enumerator(light_context_t *ctx, char const *comp)
  31. {
  32. for(uint64_t e = 0; e < ctx->num_enumerators; e++)
  33. {
  34. if(strcmp(comp, ctx->enumerators[e]->name) == 0)
  35. {
  36. return ctx->enumerators[e];
  37. }
  38. }
  39. return NULL;
  40. }
  41. static light_device_t* _light_find_device(light_device_enumerator_t *en, char const *comp)
  42. {
  43. for(uint64_t d = 0; d < en->num_devices; d++)
  44. {
  45. if(strcmp(comp, en->devices[d]->name) == 0)
  46. {
  47. return en->devices[d];
  48. }
  49. }
  50. return NULL;
  51. }
  52. static light_device_target_t* _light_find_target(light_device_t * dev, char const *comp)
  53. {
  54. for(uint64_t t = 0; t < dev->num_targets; t++)
  55. {
  56. if(strcmp(comp, dev->targets[t]->name) == 0)
  57. {
  58. return dev->targets[t];
  59. }
  60. }
  61. return NULL;
  62. }
  63. static bool _light_raw_to_percent(light_device_target_t *target, uint64_t inraw, double *outpercent)
  64. {
  65. double inraw_d = (double)inraw;
  66. uint64_t max_value = 0;
  67. if(!target->get_max_value(target, &max_value))
  68. {
  69. LIGHT_ERR("couldn't read from target");
  70. return false;
  71. }
  72. double max_value_d = (double)max_value;
  73. double percent = light_percent_clamp((inraw_d / max_value_d) * 100.0);
  74. *outpercent = percent;
  75. return true;
  76. }
  77. static bool _light_percent_to_raw(light_device_target_t *target, double inpercent, uint64_t *outraw)
  78. {
  79. uint64_t max_value = 0;
  80. if(!target->get_max_value(target, &max_value))
  81. {
  82. LIGHT_ERR("couldn't read from target");
  83. return false;
  84. }
  85. double max_value_d = (double)max_value;
  86. double target_value_d = max_value_d * (light_percent_clamp(inpercent) / 100.0);
  87. uint64_t target_value = LIGHT_CLAMP((uint64_t)target_value_d, 0, max_value);
  88. *outraw = target_value;
  89. return true;
  90. }
  91. static void _light_print_usage()
  92. {
  93. printf("Usage:\n"
  94. " light [OPTIONS] <COMMAND> [VALUE]\n"
  95. "\n"
  96. "Commands:\n"
  97. " -H, -h Show this help and exit\n"
  98. " -V Show program version and exit\n"
  99. " -L List available devices\n"
  100. " -A <value> Increase brightness by value\n"
  101. " -U <value> Decrease brightness by value\n"
  102. " -S <value> Set brightness to value\n"
  103. " -G Get brightness\n"
  104. " -N <value> Set minimum brightness to value\n"
  105. " -P Get minimum brightness\n"
  106. " -I Save the current brightness\n"
  107. " -O Restore the previously saved brightness\n"
  108. "\n"
  109. "Options:\n"
  110. " -r Interpret input and output values in raw mode\n"
  111. " -s <value> Specify device target path to use, use -L to list available\n"
  112. " -v <value> Specify the verbosity level (default 0)\n"
  113. " 0: Values only\n"
  114. " 1: Values, Errors.\n"
  115. " 2: Values, Errors, Warnings.\n"
  116. " 3: Values, Errors, Warnings, Notices.\n"
  117. "\n");
  118. printf("Copyright (C) %s %s\n", LIGHT_YEAR, LIGHT_AUTHOR);
  119. printf("This is free software, see the source for copying conditions. There is NO\n"
  120. "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\n"
  121. "\n");
  122. }
  123. static bool _light_set_context_command(light_context_t *ctx, LFUNCCOMMAND new_cmd)
  124. {
  125. if(ctx->run_params.command != NULL)
  126. {
  127. LIGHT_WARN("a command was already set. ignoring.");
  128. return false;
  129. }
  130. ctx->run_params.command = new_cmd;
  131. return true;
  132. }
  133. static bool _light_parse_arguments(light_context_t *ctx, int argc, char** argv)
  134. {
  135. int32_t curr_arg = -1;
  136. int32_t log_level = 0;
  137. char ctrl_name[NAME_MAX];
  138. bool need_value = false;
  139. bool need_target = true; // default cmd is get brightness
  140. snprintf(ctrl_name, sizeof(ctrl_name), "%s", "sysfs/backlight/auto");
  141. while((curr_arg = getopt(argc, argv, "HhVGSLMNPAUOIv:s:r")) != -1)
  142. {
  143. switch(curr_arg)
  144. {
  145. // Options
  146. case 'v':
  147. if (sscanf(optarg, "%i", &log_level) != 1)
  148. {
  149. fprintf(stderr, "-v argument is not an integer.\n\n");
  150. _light_print_usage();
  151. return false;
  152. }
  153. if (log_level < 0 || log_level > 3)
  154. {
  155. fprintf(stderr, "-v argument must be between 0 and 3.\n\n");
  156. _light_print_usage();
  157. return false;
  158. }
  159. light_loglevel = (light_loglevel_t)log_level;
  160. break;
  161. case 's':
  162. snprintf(ctrl_name, sizeof(ctrl_name), "%s", optarg);
  163. break;
  164. case 'r':
  165. ctx->run_params.raw_mode = true;
  166. break;
  167. // Commands
  168. case 'H':
  169. case 'h':
  170. _light_set_context_command(ctx, light_cmd_print_help);
  171. break;
  172. case 'V':
  173. _light_set_context_command(ctx, light_cmd_print_version);
  174. break;
  175. case 'G':
  176. _light_set_context_command(ctx, light_cmd_get_brightness);
  177. need_target = true;
  178. break;
  179. case 'S':
  180. _light_set_context_command(ctx, light_cmd_set_brightness);
  181. need_value = true;
  182. need_target = true;
  183. break;
  184. case 'L':
  185. _light_set_context_command(ctx, light_cmd_list_devices);
  186. break;
  187. case 'M':
  188. _light_set_context_command(ctx, light_cmd_get_max_brightness);
  189. need_target = true;
  190. break;
  191. case 'N':
  192. _light_set_context_command(ctx, light_cmd_set_min_brightness);
  193. need_target = true;
  194. need_value = true;
  195. break;
  196. case 'P':
  197. _light_set_context_command(ctx, light_cmd_get_min_brightness);
  198. need_target = true;
  199. break;
  200. case 'A':
  201. _light_set_context_command(ctx, light_cmd_add_brightness);
  202. need_target = true;
  203. need_value = true;
  204. break;
  205. case 'U':
  206. _light_set_context_command(ctx, light_cmd_sub_brightness);
  207. need_target = true;
  208. need_value = true;
  209. break;
  210. case 'O':
  211. _light_set_context_command(ctx, light_cmd_save_brightness);
  212. need_target = true;
  213. break;
  214. case 'I':
  215. _light_set_context_command(ctx, light_cmd_restore_brightness);
  216. need_target = true;
  217. break;
  218. }
  219. }
  220. if(ctx->run_params.command == NULL)
  221. {
  222. _light_set_context_command(ctx, light_cmd_get_brightness);
  223. }
  224. if(need_target)
  225. {
  226. light_device_target_t *curr_target = light_find_device_target(ctx, ctrl_name);
  227. if(curr_target == NULL)
  228. {
  229. fprintf(stderr, "couldn't find a device target at the path \"%s\". Use -L to find one.\n\n", ctrl_name);
  230. return false;
  231. }
  232. ctx->run_params.device_target = curr_target;
  233. }
  234. if(need_value)
  235. {
  236. if ( (argc - optind) != 1)
  237. {
  238. fprintf(stderr, "please specify a <value> for this command.\n\n");
  239. _light_print_usage();
  240. return false;
  241. }
  242. if (ctx->run_params.raw_mode)
  243. {
  244. if (sscanf(argv[optind], "%lu", &ctx->run_params.value) != 1)
  245. {
  246. fprintf(stderr, "<value> is not an integer.\n\n");
  247. _light_print_usage();
  248. return false;
  249. }
  250. }
  251. else
  252. {
  253. double percent_value = 0.0;
  254. if (sscanf(argv[optind], "%lf", &percent_value) != 1)
  255. {
  256. fprintf(stderr, "<value> is not a decimal.\n\n");
  257. _light_print_usage();
  258. return false;
  259. }
  260. percent_value = light_percent_clamp(percent_value);
  261. uint64_t raw_value = 0;
  262. if(!_light_percent_to_raw(ctx->run_params.device_target, percent_value, &raw_value))
  263. {
  264. LIGHT_ERR("failed to convert from percent to raw for device target");
  265. return false;
  266. }
  267. ctx->run_params.value = raw_value;
  268. }
  269. }
  270. return true;
  271. }
  272. /* API function definitions */
  273. light_context_t* light_initialize(int argc, char **argv)
  274. {
  275. light_context_t *new_ctx = malloc(sizeof(light_context_t));
  276. // Setup default values and runtime params
  277. new_ctx->enumerators = NULL;
  278. new_ctx->num_enumerators = 0;
  279. new_ctx->run_params.command = NULL;
  280. new_ctx->run_params.device_target = NULL;
  281. new_ctx->run_params.value = 0;
  282. new_ctx->run_params.raw_mode = false;
  283. // Setup the configuration folder
  284. // If we are root, use the system-wide configuration folder, otherwise try to find a user-specific folder, or fall back to ~/.config
  285. if (geteuid() == 0)
  286. {
  287. snprintf(new_ctx->sys_params.conf_dir, sizeof(new_ctx->sys_params.conf_dir), "%s", "/etc/light");
  288. }
  289. else
  290. {
  291. char *xdg_conf = getenv("XDG_CONFIG_HOME");
  292. if (xdg_conf != NULL)
  293. {
  294. snprintf(new_ctx->sys_params.conf_dir, sizeof(new_ctx->sys_params.conf_dir), "%s/light", xdg_conf);
  295. }
  296. else
  297. {
  298. snprintf(new_ctx->sys_params.conf_dir, sizeof(new_ctx->sys_params.conf_dir), "%s/.config/light", getenv("HOME"));
  299. }
  300. }
  301. // Make sure the configuration folder exists, otherwise attempt to create it
  302. int32_t rc = light_mkpath(new_ctx->sys_params.conf_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  303. if (rc && errno != EEXIST)
  304. {
  305. LIGHT_WARN("couldn't create configuration directory");
  306. return false;
  307. }
  308. // Create the built-in enumerators
  309. light_create_enumerator(new_ctx, "sysfs", &impl_sysfs_init, &impl_sysfs_free);
  310. //light_create_enumerator(new_ctx, "razer", &impl_razer_init, &impl_razer_free);
  311. // This is where we would create enumerators from plugins as well
  312. // 1. Run the plugins get_name() function to get its name
  313. // 2. Point to the plugins init() and free() functions when creating the enumerator
  314. // initialize all enumerators, this will create all the devices and their targets
  315. if(!light_init_enumerators(new_ctx))
  316. {
  317. LIGHT_WARN("failed to initialize all enumerators");
  318. }
  319. // Parse arguments
  320. if(!_light_parse_arguments(new_ctx, argc, argv))
  321. {
  322. LIGHT_ERR("failed to parse arguments");
  323. return NULL;
  324. }
  325. return new_ctx;
  326. }
  327. bool light_execute(light_context_t *ctx)
  328. {
  329. if(ctx->run_params.command == NULL)
  330. {
  331. LIGHT_ERR("run parameters command was null, can't execute");
  332. return false;
  333. }
  334. return ctx->run_params.command(ctx);
  335. }
  336. void light_free(light_context_t *ctx)
  337. {
  338. if(!light_free_enumerators(ctx))
  339. {
  340. LIGHT_WARN("failed to free all enumerators");
  341. }
  342. free(ctx);
  343. }
  344. light_device_enumerator_t * light_create_enumerator(light_context_t *ctx, char const * name, LFUNCENUMINIT init_func, LFUNCENUMFREE free_func)
  345. {
  346. // Create a new enumerator array
  347. uint64_t new_num_enumerators = ctx->num_enumerators + 1;
  348. light_device_enumerator_t **new_enumerators = malloc(new_num_enumerators * sizeof(light_device_enumerator_t*));
  349. // Copy old enumerator array to new one
  350. for(uint64_t i = 0; i < ctx->num_enumerators; i++)
  351. {
  352. new_enumerators[i] = ctx->enumerators[i];
  353. }
  354. // Allocate the new enumerator
  355. new_enumerators[ctx->num_enumerators] = malloc(sizeof(light_device_enumerator_t*));
  356. light_device_enumerator_t *returner = new_enumerators[ctx->num_enumerators];
  357. returner->devices = NULL;
  358. returner->num_devices = 0;
  359. returner->init = init_func;
  360. returner->free = free_func;
  361. snprintf(returner->name, sizeof(returner->name), "%s", name);
  362. // Free the old enumerator array, if needed
  363. if(ctx->enumerators != NULL)
  364. {
  365. free(ctx->enumerators);
  366. }
  367. // Replace the enumerator array with the new one
  368. ctx->enumerators = new_enumerators;
  369. ctx->num_enumerators = new_num_enumerators;
  370. // Return newly created device
  371. return returner;
  372. }
  373. bool light_init_enumerators(light_context_t *ctx)
  374. {
  375. bool success = true;
  376. for(uint64_t i = 0; i < ctx->num_enumerators; i++)
  377. {
  378. light_device_enumerator_t * curr_enumerator = ctx->enumerators[i];
  379. if(!curr_enumerator->init(curr_enumerator))
  380. {
  381. success = false;
  382. }
  383. }
  384. return success;
  385. }
  386. bool light_free_enumerators(light_context_t *ctx)
  387. {
  388. bool success = true;
  389. for(uint64_t i = 0; i < ctx->num_enumerators; i++)
  390. {
  391. light_device_enumerator_t * curr_enumerator = ctx->enumerators[i];
  392. if(!curr_enumerator->free(curr_enumerator))
  393. {
  394. success = false;
  395. }
  396. free(curr_enumerator);
  397. }
  398. free(ctx->enumerators);
  399. ctx->enumerators = NULL;
  400. ctx->num_enumerators = 0;
  401. return success;
  402. }
  403. void light_add_enumerator_device(light_device_enumerator_t *enumerator, light_device_t *new_device)
  404. {
  405. // Create a new device array
  406. uint64_t new_num_devices = enumerator->num_devices + 1;
  407. light_device_t **new_devices = malloc(new_num_devices * sizeof(light_device_t*));
  408. // Copy old device array to new one
  409. for(uint64_t i = 0; i < enumerator->num_devices; i++)
  410. {
  411. new_devices[i] = enumerator->devices[i];
  412. }
  413. // Set the new device
  414. new_devices[enumerator->num_devices] = new_device;
  415. // Free the old devices array, if needed
  416. if(enumerator->devices != NULL)
  417. {
  418. free(enumerator->devices);
  419. }
  420. // Replace the devices array with the new one
  421. enumerator->devices = new_devices;
  422. enumerator->num_devices = new_num_devices;
  423. new_device->enumerator = enumerator;
  424. }
  425. void light_add_device_target(light_device_t *device, light_device_target_t *new_target)
  426. {
  427. // Create a new targets array
  428. uint64_t new_num_targets = device->num_targets + 1;
  429. light_device_target_t **new_targets = malloc(new_num_targets * sizeof(light_device_target_t*));
  430. // Copy old targets array to new one
  431. for(uint64_t i = 0; i < device->num_targets; i++)
  432. {
  433. new_targets[i] = device->targets[i];
  434. }
  435. // Set the new target
  436. new_targets[device->num_targets] = new_target;
  437. // Free the old targets array, if needed
  438. if(device->targets != NULL)
  439. {
  440. free(device->targets);
  441. }
  442. // Replace the targets array with the new one
  443. device->targets= new_targets;
  444. device->num_targets = new_num_targets;
  445. new_target->device = device;
  446. }
  447. bool light_split_target_path(char const *in_path, light_target_path_t *out_path)
  448. {
  449. char const * begin = in_path;
  450. char const * end = strstr(begin, "/");
  451. if(end == NULL)
  452. {
  453. LIGHT_WARN("invalid path passed to split_target_path");
  454. return false;
  455. }
  456. size_t size = end - begin;
  457. strncpy(out_path->enumerator, begin, size);
  458. out_path->enumerator[size] = '\0';
  459. begin = end + 1;
  460. end = strstr(begin, "/");
  461. if(end == NULL)
  462. {
  463. LIGHT_WARN("invalid path passed to split_target_path");
  464. return false;
  465. }
  466. size = end - begin;
  467. strncpy(out_path->device, begin, size);
  468. out_path->device[size] = '\0';
  469. strcpy(out_path->target, end + 1);
  470. return true;
  471. }
  472. light_device_target_t* light_find_device_target(light_context_t *ctx, char const * name)
  473. {
  474. light_target_path_t new_path;
  475. light_split_target_path(name, &new_path);
  476. /*
  477. Uncomment to debug the split function
  478. printf("enumerator: %s %u\ndevice: %s %u\ntarget: %s %u\n",
  479. new_path.enumerator, strlen(new_path.enumerator),
  480. new_path.device, strlen(new_path.device),
  481. new_path.target, strlen(new_path.target));
  482. */
  483. // find a matching enumerator
  484. light_device_enumerator_t *enumerator = _light_find_enumerator(ctx, new_path.enumerator);
  485. if(enumerator == NULL)
  486. {
  487. LIGHT_WARN("no such enumerator, \"%s\"", new_path.enumerator);
  488. return NULL;
  489. }
  490. light_device_t *device = _light_find_device(enumerator, new_path.device);
  491. if(device == NULL)
  492. {
  493. LIGHT_WARN("no such device, \"%s\"", new_path.device);
  494. return NULL;
  495. }
  496. light_device_target_t *target = _light_find_target(device, new_path.target);
  497. if(target == NULL)
  498. {
  499. LIGHT_WARN("no such target, \"%s\"", new_path.target);
  500. return NULL;
  501. }
  502. return target;
  503. }
  504. bool light_cmd_print_help(light_context_t *ctx)
  505. {
  506. _light_print_usage();
  507. return true;
  508. }
  509. bool light_cmd_print_version(light_context_t *ctx)
  510. {
  511. printf("v%s\n", VERSION);
  512. return true;
  513. }
  514. bool light_cmd_list_devices(light_context_t *ctx)
  515. {
  516. printf("Listing device targets:\n");
  517. for(uint64_t enumerator = 0; enumerator < ctx->num_enumerators; enumerator++)
  518. {
  519. light_device_enumerator_t *curr_enumerator = ctx->enumerators[enumerator];
  520. for(uint64_t device = 0; device < curr_enumerator->num_devices; device++)
  521. {
  522. light_device_t *curr_device = curr_enumerator->devices[device];
  523. for(uint64_t target = 0; target < curr_device->num_targets; target++)
  524. {
  525. light_device_target_t *curr_target = curr_device->targets[target];
  526. printf("\t%s/%s/%s\n", curr_enumerator->name, curr_device->name, curr_target->name);
  527. }
  528. }
  529. }
  530. return true;
  531. }
  532. bool light_cmd_set_brightness(light_context_t *ctx)
  533. {
  534. light_device_target_t *target = ctx->run_params.device_target;
  535. if(target == NULL)
  536. {
  537. LIGHT_ERR("didn't have a valid target, programmer mistake");
  538. return false;
  539. }
  540. uint64_t mincap = _light_get_min_cap(ctx);
  541. uint64_t value = ctx->run_params.value;
  542. if(mincap > value)
  543. {
  544. value = mincap;
  545. }
  546. if(!target->set_value(target, value))
  547. {
  548. LIGHT_ERR("failed to write to target");
  549. return false;
  550. }
  551. return true;
  552. }
  553. bool light_cmd_get_brightness(light_context_t *ctx)
  554. {
  555. light_device_target_t *target = ctx->run_params.device_target;
  556. if(target == NULL)
  557. {
  558. LIGHT_ERR("didn't have a valid target, programmer mistake");
  559. return false;
  560. }
  561. uint64_t value = 0;
  562. if(!target->get_value(target, &value))
  563. {
  564. LIGHT_ERR("failed to read from target");
  565. return false;
  566. }
  567. if(ctx->run_params.raw_mode)
  568. {
  569. printf("%u\n", value);
  570. }
  571. else
  572. {
  573. double percent = 0.0;
  574. if(!_light_raw_to_percent(target, value, &percent))
  575. {
  576. LIGHT_ERR("failed to convert from raw to percent from device target");
  577. return false;
  578. }
  579. printf("%.2f\n", percent);
  580. }
  581. return true;
  582. }
  583. bool light_cmd_get_max_brightness(light_context_t *ctx)
  584. {
  585. light_device_target_t *target = ctx->run_params.device_target;
  586. if(target == NULL)
  587. {
  588. LIGHT_ERR("didn't have a valid target, programmer mistake");
  589. return false;
  590. }
  591. if(!ctx->run_params.raw_mode)
  592. {
  593. printf("100.0\n");
  594. return true;
  595. }
  596. uint64_t max_value = 0;
  597. if(!target->get_max_value(target, &max_value))
  598. {
  599. LIGHT_ERR("failed to read from device target");
  600. return false;
  601. }
  602. printf("%u\n", max_value);
  603. return true;
  604. }
  605. bool light_cmd_set_min_brightness(light_context_t *ctx)
  606. {
  607. char target_path[NAME_MAX];
  608. snprintf(target_path, sizeof(target_path),
  609. "%s/targets/%s/%s/%s",
  610. ctx->sys_params.conf_dir,
  611. ctx->run_params.device_target->device->enumerator->name,
  612. ctx->run_params.device_target->device->name,
  613. ctx->run_params.device_target->name
  614. );
  615. // Make sure the target folder exists, otherwise attempt to create it
  616. int32_t rc = light_mkpath(target_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  617. if (rc && errno != EEXIST)
  618. {
  619. LIGHT_ERR("couldn't create target directory for minimum brightness");
  620. return false;
  621. }
  622. char target_filepath[NAME_MAX];
  623. snprintf(target_filepath, sizeof(target_filepath), "%s/minimum", target_path);
  624. if(!light_file_write_uint64(target_filepath, ctx->run_params.value))
  625. {
  626. LIGHT_ERR("couldn't write value to minimum file");
  627. return false;
  628. }
  629. return true;
  630. }
  631. bool light_cmd_get_min_brightness(light_context_t *ctx)
  632. {
  633. char target_path[NAME_MAX];
  634. snprintf(target_path, sizeof(target_path),
  635. "%s/targets/%s/%s/%s/minimum",
  636. ctx->sys_params.conf_dir,
  637. ctx->run_params.device_target->device->enumerator->name,
  638. ctx->run_params.device_target->device->name,
  639. ctx->run_params.device_target->name
  640. );
  641. uint64_t minimum_value = 0;
  642. if(!light_file_read_uint64(target_path, &minimum_value))
  643. {
  644. if(ctx->run_params.raw_mode)
  645. {
  646. printf("0\n");
  647. }
  648. else
  649. {
  650. printf("0.00\n");
  651. }
  652. return true;
  653. }
  654. if(ctx->run_params.raw_mode)
  655. {
  656. printf("%u\n", minimum_value);
  657. }
  658. else
  659. {
  660. double minimum_d = 0.0;
  661. if(!_light_raw_to_percent(ctx->run_params.device_target, minimum_value, &minimum_d))
  662. {
  663. LIGHT_ERR("failed to convert value from raw to percent for device target");
  664. return false;
  665. }
  666. printf("%.2f\n", minimum_d);
  667. }
  668. return true;
  669. }
  670. bool light_cmd_add_brightness(light_context_t *ctx)
  671. {
  672. light_device_target_t *target = ctx->run_params.device_target;
  673. if(target == NULL)
  674. {
  675. LIGHT_ERR("didn't have a valid target, programmer mistake");
  676. return false;
  677. }
  678. uint64_t value = 0;
  679. if(!target->get_value(target, &value))
  680. {
  681. LIGHT_ERR("failed to read from target");
  682. return false;
  683. }
  684. uint64_t max_value = 0;
  685. if(!target->get_max_value(target, &max_value))
  686. {
  687. LIGHT_ERR("failed to read from target");
  688. return false;
  689. }
  690. value += ctx->run_params.value;
  691. uint64_t mincap = _light_get_min_cap(ctx);
  692. if(mincap > value)
  693. {
  694. value = mincap;
  695. }
  696. if(value > max_value)
  697. {
  698. value = max_value;
  699. }
  700. if(!target->set_value(target, value))
  701. {
  702. LIGHT_ERR("failed to write to target");
  703. return false;
  704. }
  705. return true;
  706. }
  707. bool light_cmd_sub_brightness(light_context_t *ctx)
  708. {
  709. light_device_target_t *target = ctx->run_params.device_target;
  710. if(target == NULL)
  711. {
  712. LIGHT_ERR("didn't have a valid target, programmer mistake");
  713. return false;
  714. }
  715. uint64_t value = 0;
  716. if(!target->get_value(target, &value))
  717. {
  718. LIGHT_ERR("failed to read from target");
  719. return false;
  720. }
  721. if(value > ctx->run_params.value)
  722. {
  723. value -= ctx->run_params.value;
  724. }
  725. else
  726. {
  727. value = 0;
  728. }
  729. uint64_t mincap = _light_get_min_cap(ctx);
  730. if(mincap > value)
  731. {
  732. value = mincap;
  733. }
  734. if(!target->set_value(target, value))
  735. {
  736. LIGHT_ERR("failed to write to target");
  737. return false;
  738. }
  739. return true;
  740. }
  741. bool light_cmd_save_brightness(light_context_t *ctx)
  742. {
  743. char target_path[NAME_MAX];
  744. snprintf(target_path, sizeof(target_path),
  745. "%s/targets/%s/%s/%s",
  746. ctx->sys_params.conf_dir,
  747. ctx->run_params.device_target->device->enumerator->name,
  748. ctx->run_params.device_target->device->name,
  749. ctx->run_params.device_target->name
  750. );
  751. // Make sure the target folder exists, otherwise attempt to create it
  752. int32_t rc = light_mkpath(target_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  753. if (rc && errno != EEXIST)
  754. {
  755. LIGHT_ERR("couldn't create target directory for save brightness");
  756. return false;
  757. }
  758. char target_filepath[NAME_MAX];
  759. snprintf(target_filepath, sizeof(target_filepath), "%s/save", target_path);
  760. uint64_t curr_value = 0;
  761. if(!ctx->run_params.device_target->get_value(ctx->run_params.device_target, &curr_value))
  762. {
  763. LIGHT_ERR("couldn't read from device target");
  764. return false;
  765. }
  766. if(!light_file_write_uint64(target_filepath, curr_value))
  767. {
  768. LIGHT_ERR("couldn't write value to savefile");
  769. return false;
  770. }
  771. return true;
  772. }
  773. bool light_cmd_restore_brightness(light_context_t *ctx)
  774. {
  775. char target_path[NAME_MAX];
  776. snprintf(target_path, sizeof(target_path),
  777. "%s/targets/%s/%s/%s/save",
  778. ctx->sys_params.conf_dir,
  779. ctx->run_params.device_target->device->enumerator->name,
  780. ctx->run_params.device_target->device->name,
  781. ctx->run_params.device_target->name
  782. );
  783. uint64_t saved_value = 0;
  784. if(!light_file_read_uint64(target_path, &saved_value))
  785. {
  786. LIGHT_ERR("couldn't read value from savefile");
  787. return false;
  788. }
  789. uint64_t mincap = _light_get_min_cap(ctx);
  790. if(mincap > saved_value)
  791. {
  792. saved_value = mincap;
  793. }
  794. if(!ctx->run_params.device_target->set_value(ctx->run_params.device_target, saved_value))
  795. {
  796. LIGHT_ERR("couldn't write saved value to device target");
  797. return false;
  798. }
  799. return true;
  800. }