Thursday, March 7, 2013

DPF - fix up permissions

Here we try to fix up the permissions for accessing the digital photo frame I am using to display information about what is playing. 

After a great deal of effort to build dpf-ax for the 7DayShop Pebble photo frame, it was a bit disappointing to only be able to access it as root - If I try to access it as a normal user, then it fails. I have to use sudo to get access. 

Here's some things I found out: 
  • Both the Python and C libraries allow you to connect to the dpf either as a SCSI device or a USB device 
  • However, after you have hacked the photo frame, it does not seem to want to appear as a SCSI device any more, so your only option is to access it as a USB device. 
  • Normally the system would set a USB device with relaxed permissions so users could access it. However the the photo frame is not being managed by the system, so has the restrictive default access applied. Only root can read and write to it. 
  • We (i.e. the C/Python libraries) need to write to it, so try to open it with write permissions. Because only root can write to the device, this fails unless you run as root. 

Here's how I fixed it on my Ubuntu machine (fix still pending on Pi) 

Notes included with reference to revision 40 of dpf-ax 


  1. Find the device, all of these photo frames seem to have a vendor ID of 1908 and a device ID of 0102. This particular one has no description string.
    dpflib note - It is the vendor ID and device ID that the library looks for in usbraw.c. If it does not find it you get the "No matching USB device found!" error. If it cannot open the device once it finds it  (e.g. because there is a permissions problem) then you get "Failed to claim usb device!"

    $lsusb
    Bus 002 Device 006: ID 1908:0102

    $ls -l /dev/bus/usb/002
    crw-rw-r-- 1 root root 189, 133 2013-03-06 19:19 006
    You get the Bus number and device number from lsusb to use in the ls command to see what the permissions are.
  2. So that's the problem. To fix it - you first need to make a new group and add to that group all the users you want to access the device, and root as well.
    $sudo groupadd lcdusers
    $sudo adduser pi lcdusers
    $sudo adduser rootlcdusers
  3. Then you have to add a udev rule. A udev rule basically gets run every time there's some interesting activity with the connected devices, including when the device boots up. This new rule I'm adding will give the group above read and write access to the photo frame usb device, and since pi is a member of that group, he should get write access as well. 
    $sudo gedit /etc/udev/rules.d/70-dpf.rules
    Put this single line in the file and save it:

    ATTRS{idVendor}=="1908", ATTRS{idProduct}=="0102", GROUP="lcdusers", MODE="0660"
  4. That should be it as the change is supposed to be picked up, but I found I had to restart because the device vanished and the dpf library could no longer find it, it came back after the restart. Now:
    $ls -l /dev/bus/usb/002
    crw-rw---- 1 root lcdusers 189, 129 2013-03-06 19:53 002
    This wills show that it's worked - anyone in the group lcdusers can both read and write to the device, you can go ahead and access the screen via the library with no sudo.

Wednesday, March 6, 2013

Basic i2c


Basic i2C Setup on Raspberry Pi 

My Furry Radio uses two i2c modules to extend it's i/o capabilities. 
Here is how to get the basic i2c connectivity going in 12 easy steps.
Relevant to "2012-12-16-wheezy-raspbian" 


1.  sudo nano /etc/modprobe.d/raspi-blacklist.conf

 
This file contains a list of blacklisted device drivers. one of the drivers we want (i2c-bpm2708) is blacklisted, so take it out of the blacklist by commenting out the line with it's name on the file should end up looking something like:

# blacklist spi and i2c by default (many users don't need them)
# modified to allow i2c

blacklist spi-bcm2708
#blacklist i2c-bcm2708


  2.  sudo nano /etc/modules

We need make sure the i2c module gets loaded every boot, which is done in this file. add the module to the end of the list, it should end up looking something like:

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.

snd-bcm2835
i2c-dev



  3.  sudo apt-get update
  4.  sudo apt-get install i2c-tools
  5.  sudo apt-get install python-smbus
  6.  sudo modprobe i2c-bcm2708
  7.  sudo modprobe i2c-dev
  8.  sudo i2cdetect -y 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -

  
Here we have installed all the necessary software that was not in the original image, loaded the correct modules into the kernel (without a reboot) and run the i2c utility as root. the output shows is detected one device at address 20, which is great because that's what's plugged in.




  9.  sudo adduser pi i2c
 10.  logout
 11.  <<log back in>>
 12.  i2cdetect -y 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -

Now so you don't need to be root to access the device - a new group "i2c" was created for you when the tools were installed. add your user to this group (int this case the user is "pi", then log out and back in again for this to have effect. You can now access i2C as a normal user.

Errors

If you follow these steps it should all work out smoothly, however here's some errors you may see.

.udevdb or .udev presence implies active udev.  Aborting MAKEDEV invocation. 
Ignore this one.

Error: Could not open file `/dev/i2c-0' or `/dev/i2c/0': No such file or directory 
Kernel module is not installed, Need to modprobe or restart (6, 7, 10)

Can't exec "i2cdetect": Permission denied at ... 
User has no permission to access the device. add the user to the i2c group and you need to log out and in again to fix group permissions (9, 10)

Start....

Here I shall occasionally write about the immense amount of time I have wasted creating a controller for my Sonos System using a Raspberry Pi mounted inside a furry radio that I got from off of ebay.

The motivating factor is - I like the Sonos a lot but I need knobs and buttons. The radio sits in my hallway and I can stab at it's physical protuberances to control what's playing around the house or plug things into it's exposed USB port without worrying my laptop.

The component parts are:
  • A load of expensive Sonos speakers
  • a Raspberry Pi running a pile of Python scripts which:
    • Control the Sonos speakers, based on SoCo the simple Sonos controller
    • Pull photos from my camera if one gets plugged in
    • Push random music tracks to fill a usb stick if one gets plugged in
    • Acts as NAS with a 64GB card, which is enough for all my music and photos.
  • A cheap lcd photo keyring thing from 7DayShop. 
    • dpf-ax - to control that
  • A load of rotary encoders (cheap off ebay)
    • Choose presets, set individual speaker volume.
  • A potentiometer (cheap off ebay)
    • Volume control
    • On/off 
  • Because the Pi does not have an analogue input, an i2c ADC module (cheap off... There's a pattern here)
  • I ran out out of GPIO ports to manage all the encoders, so a i2c port extender to get me more inputs