light.c 27KB

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