Backlight Control


CyberLeo

Member
Joined
Jun 29, 2011
Messages
31
The Pandora does not have an ambient light sensor; nor will the Pyra, it seems. So I faked it.

Since I live in the dark, I like to have the screen dim; but occasionally, I must venture outside amidst the accursed daystar, and the screen is nigh-unreadable unless cranked to maximum brightness. Navigating the menus, or Fn-IIII Fn-UUUU, are too tedious; so I hijacked the Pandora key.

This is atop my previous hack to make the Pandora key bring up the xfrun dialog: if I hold the Left or Right shoulder buttons and poke the Pandora button, it will fade the backlight to minimum or maximum brightness.
 

It suits me; perhaps it will suit you as well?

First, I directed /usr/pandora/scripts/op_xfcemenu.sh to invoke pandora.sh :


#!/bin/sh -e

# http://wiki.cyberleo.net/wiki/CyberLeo/COPYRIGHT?version=5

evkeys="$(dirname "${0}")/evkeys"
keys="$("${evkeys}")"

case "${keys}" in
L) exec "$(dirname "${0}")/backlight.sh" min ;;
R) exec "$(dirname "${0}")/backlight.sh" max ;;
*) exec xfrun4
esac

If I don't hold down anything, it pops the xfce run dialog as normal. If I hold down one of the shoulder buttons, it invokes backlight.sh:


#!/bin/sh -e

# http://wiki.cyberleo.net/wiki/CyberLeo/COPYRIGHT?version=5

# Requires sudoers NOPASSWD entry
[ "$(id -u)" -eq 0 ] || exec sudo "${0}" "${@}"

. /usr/pandora/scripts/op_paths.sh

bl_min=8
bl_max="$(cat "${SYSFS_BACKLIGHT}/max_brightness")"

pebkac() {
cat <<"EOF" >&2
Usage: $(basename "${0}") <off|min|max>

off - Turn backlight off
min - Fade backlight to min preset
max - Fade backlight to max preset
EOF
exit 1
}

# Because seq is not ambidextrous
biseq() {
cur="${1}"
tgt="${2}"
if [ "${tgt}" -lt "${cur}" ]
then
seq "${cur}" -1 "${tgt}"
else
seq "${cur}" "${tgt}"
fi
}

fade() {
to="${1}"
for i in $(biseq "$(cat "${SYSFS_BACKLIGHT}/actual_brightness")" "${to}")
do
echo ${i} > "${SYSFS_BACKLIGHT_BRIGHTNESS}"
sleep 0
done
}

case "${1}" in
off) fade 0 ;;
min) fade "${bl_min}" ;;
max) fade "${bl_max}" ;;
*) pebkac ;;
esac

And, of course, to actually detect which button is held down, I had to delve into c for evkeys.c, and built it in-situ with cdevtools :


/* http://wiki.cyberleo.net/wiki/CyberLeo/COPYRIGHT?version=5 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <linux/input.h>

const char *evdev = "/dev/input/by-path/platform-gpio-keys-event";

typedef struct {
  int code;
  const char *name;
} interesting_key;

static interesting_key interesting_keys[] = {
  { KEY_RIGHTSHIFT, "L" },
  { KEY_RIGHTCTRL,  "R" },
  { KEY_UP,         "^" },
  { KEY_LEFT,       "<" },
  { KEY_RIGHT,      ">" },
  { KEY_DOWN,       "v" },
  { KEY_PAGEUP,     "Y" },
  { KEY_HOME,       "A" },
  { KEY_END,        "B" },
  { KEY_PAGEDOWN,   "X" }
};

#define interesting_keys_count (sizeof(interesting_keys) / sizeof(interesting_keys[0]))

int main(int argc, char *argv[], char *env[]) {
  char key_map[KEY_MAX / 8 + 1];
  memset(key_map, 0, sizeof(key_map));

  FILE *kbd = fopen(evdev, "r");
  if (!kbd)
    error(1, errno, evdev);

  if (!ioctl(fileno(kbd), EVIOCGKEY(sizeof(key_map)), key_map))
    error(1, errno, "ioctl(EVIOCGKEY)");

  int key_index = 0;
  for (key_index = 0; key_index < interesting_keys_count; key_index++) {
    interesting_key key = interesting_keys[key_index];
    int keyb = key_map[key.code / 8];
    int mask = 1 << ( key.code % 8 );
    if (keyb & mask)
      printf("%s", key.name);
  }
  printf("\n");
  return 0;
}


Bonus Makefile, to truly illustrate my Gnu-ineptitude:


OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,evkeys.o)
EXE := evkeys

all: $(EXE)

$(OBJDIR):
mkdir $(OBJDIR)

$(OBJDIR)/%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<

$(OBJS): | $(OBJDIR)

$(EXE): $(OBJS)
$(LINK.c) $(OUTPUT_OPTION) $<

.PHONY: clean
clean:
rm -rf $(OBJDIR) $(EXE)

Probably not polished at all, but not bad for an hour of screwing around on the bus. Feel free to provide feedback if you have ideas on how I might have done something better.

Thanks!
 
Last edited by a moderator:
This is exactly what I like about FOSS software: if you want to fix or improve something, you can just go ahead and do it!

Always nice to see someone do exactly that.

Is that the 3-clause BSD license? ;)
 
This is exactly what I like about FOSS software: if you want to fix or improve something, you can just go ahead and do it!

Always nice to see someone do exactly that.
A very big part of the reason I prefer open-source to closed-source whenever possible.

Is that the 3-clause BSD license? ;)
 It certainly is!
 
Last edited by a moderator:
All looks good to me.  I'm not a C expert, but even that makes sense to me.  Looks like you're assigning 0 to key_index twice - once at the start of the for loop, and once on the line before, but this is hardly performance critical code, so I wouldn't raise it as a bug or probably even note in in a code review, but you did ask, so eh.

I'm a little confused by $OBJS in your makefile, but it appears I'm even more gnumake inept than you are, so if it works it doesn't look overly complex.

Personally I like a little more than the minimum for most of the time I'm indoors, but can also see the use of an absolute minimum for after dark, so I need three levels - outdoor, indoor and night.  Might see if I can hack this to work.
 
All looks good to me.  I'm not a C expert, but even that makes sense to me.  Looks like you're assigning 0 to key_index twice - once at the start of the for loop, and once on the line before, but this is hardly performance critical code, so I wouldn't raise it as a bug or probably even note in in a code review, but you did ask, so eh.
 GCC was complaining that I couldn't assign a variable inside a for, so I had to assign it beforehand; then it complained that I couldn't not assign it in the for loop. What more than to appease the fickle compiler gods?

I'm a little confused by $OBJS in your makefile, but it appears I'm even more gnumake inept than you are, so if it works it doesn't look overly complex.
That whole makefile is pretty much seletively copy-pasted from the Gnu Make handbook. I kind of understand what it's doing, but there's a lot of magical behaviour there for something intended solely to compile a single c file into a single executable.

Personally I like a little more than the minimum for most of the time I'm indoors, but can also see the use of an absolute minimum for after dark, so I need three levels - outdoor, indoor and night.  Might see if I can hack this to work.
It should be possible. I went overboard with the key detection, as I intend on adding more functions later. If you do make something neat, feel free to post!
 
Sure it wasn't complaining that you couldn't declare the variable in the for loop?  I think you can get away with:

int num; # declaration

for(num=0;num<max;num++){ # assignment

...or something like that.  Like I say, I've never coded C professionally, and only done a little C++, so I may be wrong.
 
Sure it wasn't complaining that you couldn't declare the variable in the for loop?  I think you can get away with:

int num; # declaration

for(num=0;num<max;num++){ # assignment
You are in all likelihood correct. Once it compiled without errors and gave the expected output in all cases, I stuck a fork in it and called it done.

...or something like that.  Like I say, I've never coded C professionally, and only done a little C++, so I may be wrong.
Pretty much the same here. I do the lion's share of my work in tokenized or interpreted languages like Ruby or Bourne Shell, or in assembly mnemonics; C is an awkward middle-ground for me.
 
Back
Top