├── python ├── piface │ ├── __init__.py │ ├── images │ │ ├── pi.png │ │ ├── led_on.png │ │ └── smt_led_on.png │ ├── spivisualiser.py │ ├── pfion.py │ ├── spimodule.c │ ├── emulator.py │ ├── pfio.py │ └── emulator_parts.py ├── .gitignore ├── demos │ ├── racingpi.sh │ ├── racingpi │ │ ├── racingPi.png │ │ ├── __init__.py │ │ ├── questions.txt │ │ ├── gui.py │ │ ├── racingpi_db_helper.py │ │ └── game.py │ ├── flash.py │ ├── sweep.py │ ├── twitterMoodCube.py │ ├── toggle.py │ ├── twitter_chicken │ │ ├── twitter_listen_user.py │ │ ├── twitter_listen.py │ │ └── raspberry_pi_farm.py │ ├── whackAMole.py │ └── simon.py ├── setup.py └── tests │ └── piface_test.py ├── easyteach ├── easyteach │ ├── __init__.py │ └── talker.py └── setup.py ├── .gitignore ├── django ├── projects │ └── httpi │ │ ├── httpi │ │ ├── __init__.py │ │ ├── views.py │ │ ├── urls.py │ │ ├── static │ │ │ ├── js │ │ │ │ ├── plugins.js │ │ │ │ └── vendor │ │ │ │ │ └── modernizr-2.6.1.min.js │ │ │ └── css │ │ │ │ └── main.css │ │ ├── wsgi.py │ │ └── settings.py │ │ ├── httpiface │ │ ├── __init__.py │ │ ├── models.py │ │ ├── static │ │ │ ├── images │ │ │ │ ├── pi.png │ │ │ │ └── led_on.png │ │ │ ├── css │ │ │ │ └── piface.css │ │ │ └── js │ │ │ │ └── piface.js │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py │ │ └── manage.py └── templates │ ├── httpi │ └── index.html │ └── httpiface │ └── index.html ├── c ├── src │ └── piface │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── pfio.h │ │ └── pfio.c ├── autogen.sh ├── examples │ ├── board_reset.c │ ├── input_reader.c │ ├── Makefile │ └── the_amazing_led_show.c ├── configure.ac ├── piface-1.0.pc.in ├── Makefile.am ├── .gitignore └── unitytest │ ├── README.md │ ├── Makefile │ └── test │ └── tests.c ├── scripts ├── piface-emulator ├── spivisualiser ├── stopwebserver ├── startwebserver ├── i2c-setup └── spidev-setup ├── misc ├── Desktop │ ├── scratch_handler.desktop │ └── piface.desktop ├── emmisions_testing │ ├── emtest_all.py │ └── emtest1.py └── icons │ └── piface.xpm ├── README.md └── scratch └── scratch_handler.py /python/piface/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /easyteach/easyteach/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.sw? 2 | Session.vim 3 | -------------------------------------------------------------------------------- /django/projects/httpi/httpi/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /django/projects/httpi/httpiface/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /c/src/piface/.gitignore: -------------------------------------------------------------------------------- 1 | /*.lo 2 | /*.o 3 | /.deps/ 4 | /.dirstamp 5 | /.libs/ 6 | -------------------------------------------------------------------------------- /c/autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | touch NEWS README AUTHORS ChangeLog 3 | autoreconf --force --install 4 | -------------------------------------------------------------------------------- /python/demos/racingpi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo python -c "import racingpi; racingpi.begin(\"$1\")"& 3 | -------------------------------------------------------------------------------- /django/projects/httpi/httpiface/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /python/piface/images/pi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasmacpherson/piface/HEAD/python/piface/images/pi.png -------------------------------------------------------------------------------- /python/piface/images/led_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasmacpherson/piface/HEAD/python/piface/images/led_on.png -------------------------------------------------------------------------------- /python/demos/racingpi/racingPi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasmacpherson/piface/HEAD/python/demos/racingpi/racingPi.png -------------------------------------------------------------------------------- /python/piface/images/smt_led_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasmacpherson/piface/HEAD/python/piface/images/smt_led_on.png -------------------------------------------------------------------------------- /c/src/piface/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-Wall 3 | 4 | pfio.o: pfio.c 5 | $(CC) $(CFLAGS) -c -o pfio.o pfio.c 6 | 7 | clean: 8 | rm *.o 9 | -------------------------------------------------------------------------------- /scripts/piface-emulator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import piface.emulator as emu 4 | 5 | emu.init() 6 | 7 | # vim:ts=2:sw=2:sts=2:et:ft=python 8 | 9 | -------------------------------------------------------------------------------- /django/projects/httpi/httpiface/static/images/pi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasmacpherson/piface/HEAD/django/projects/httpi/httpiface/static/images/pi.png -------------------------------------------------------------------------------- /django/projects/httpi/httpiface/static/images/led_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasmacpherson/piface/HEAD/django/projects/httpi/httpiface/static/images/led_on.png -------------------------------------------------------------------------------- /scripts/spivisualiser: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #: Description: Starts the stand alone spivisualiser 3 | #: Author: Thomas Preston 4 | 5 | python -c "import piface.spivisualiser as s; s.init()" 6 | -------------------------------------------------------------------------------- /c/examples/board_reset.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | if (pfio_init() < 0) 6 | exit(-1); 7 | 8 | pfio_deinit(); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /misc/Desktop/scratch_handler.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Scratch PiFace Handler 3 | Exec=lxterminal -e /home/pi/piface/scratch/scratch_handler.py 4 | Icon=scratch.xpm 5 | Type=Application 6 | Categories=Application; 7 | -------------------------------------------------------------------------------- /misc/Desktop/piface.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=PiFace Emulator 3 | Comment=From http://piface.openlx.org.uk 4 | Exec=/home/pi/piface/scripts/piface-emulator 5 | Icon=/home/pi/piface/piface.xpm 6 | Terminal=false 7 | Type=Application 8 | Categories=Application; 9 | StartupNotify=true 10 | -------------------------------------------------------------------------------- /c/configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([PiFace], [0.1], [thomasmarkpreston+piface_c_bugs@gmail.com], [piface], [http://pi.cs.man.ac.uk/]) 2 | AC_PREREQ([2.59]) 3 | AM_INIT_AUTOMAKE([1.10 -Wall no-define]) 4 | AC_CONFIG_HEADERS([config.h]) 5 | AC_PROG_CC 6 | LT_INIT 7 | AC_CONFIG_FILES([Makefile piface-1.0.pc]) 8 | AC_OUTPUT 9 | -------------------------------------------------------------------------------- /python/demos/flash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import time 4 | import piface.pfio 5 | 6 | piface.pfio.init() 7 | 8 | led1 = piface.pfio.LED(1) 9 | 10 | while True: 11 | led1.turn_on() 12 | time.sleep(1) 13 | led1.turn_off() 14 | time.sleep(1) 15 | 16 | # vim:ts=2:sw=2:sts=2:et:ft=python 17 | 18 | -------------------------------------------------------------------------------- /django/projects/httpi/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "httpi.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /misc/emmisions_testing/emtest_all.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | #import piface.emulator as pfio 4 | import piface.pfio as pfio 5 | 6 | 7 | if __name__ == "__main__": 8 | pfio.init() 9 | while True: 10 | pfio.write_output(0xff) 11 | sleep(1) 12 | pfio.write_output(0) 13 | sleep(1) 14 | -------------------------------------------------------------------------------- /c/examples/input_reader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | if (pfio_init() < 0) 7 | exit(-1); 8 | 9 | while (1) 10 | { 11 | printf("Input port: 0x%x\n", pfio_read_input()); 12 | sleep(1); 13 | } 14 | 15 | pfio_deinit(); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /c/piface-1.0.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: PiFace 7 | Description: C interface for the PiFace Raspberry Pi add on. 8 | Requires: 9 | Version: @PACKAGE_VERSION@ 10 | Libs: -L${libdir} -lpiface-1.0 11 | Cflags: -I${includedir}/piface-1.0 -I${libdir}/piface-1.0/include 12 | -------------------------------------------------------------------------------- /c/Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = subdir-objects 2 | ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} 3 | 4 | lib_LTLIBRARIES = libpiface-1.0.la 5 | libpiface_1_0_la_SOURCES = src/piface/pfio.c 6 | 7 | library_includedir=$(includedir)/libpiface-1.0 8 | library_include_HEADERS = src/piface/pfio.h 9 | 10 | pkgconfigdir = $(libdir)/pkgconfig 11 | pkgconfig_DATA = piface-1.0.pc 12 | -------------------------------------------------------------------------------- /scripts/stopwebserver: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #: Description: Starts the apache webserver 3 | #: Author: Thomas Preston 4 | 5 | udev_rules_file='/etc/udev/rules.d/50-spi.rules' 6 | 7 | # check if the script is being run as root 8 | if [[ $EUID -ne 0 ]] 9 | then 10 | printf 'This script must be run as root.\nExiting..\n' 11 | exit 1 12 | fi 13 | 14 | service apache2 stop 15 | -------------------------------------------------------------------------------- /django/projects/httpi/httpi/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render_to_response 2 | from django.http import HttpResponse, QueryDict 3 | from django.template import RequestContext 4 | 5 | 6 | def index(request): 7 | return render_to_response( 8 | "httpi/index.html", 9 | {'test' : 1}, 10 | context_instance=RequestContext(request)) 11 | -------------------------------------------------------------------------------- /scripts/startwebserver: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #: Description: Starts the apache webserver 3 | #: Author: Thomas Preston 4 | 5 | udev_rules_file='/etc/udev/rules.d/50-spi.rules' 6 | 7 | # check if the script is being run as root 8 | if [[ $EUID -ne 0 ]] 9 | then 10 | printf 'This script must be run as root.\nExiting..\n' 11 | exit 1 12 | fi 13 | 14 | service apache2 start 15 | -------------------------------------------------------------------------------- /python/demos/racingpi/__init__.py: -------------------------------------------------------------------------------- 1 | import gtk 2 | 3 | import game 4 | import gui 5 | 6 | 7 | def begin(question_file=None): 8 | gtk.gdk.threads_init() # init the gdk threads 9 | the_gui = gui.RacingPiGUI() 10 | the_game = game.RacingPiGame(the_gui, question_file) 11 | the_gui.the_game = the_game 12 | 13 | the_game.start() 14 | the_gui.main() 15 | 16 | the_game.join() 17 | -------------------------------------------------------------------------------- /c/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | /.libs/ 3 | /AUTHORS 4 | /COPYING 5 | /ChangeLog 6 | /INSTALL 7 | /Makefile 8 | /Makefile.in 9 | /NEWS 10 | /README 11 | /aclocal.m4 12 | /autom4te.cache/ 13 | /config.guess 14 | /config.h 15 | /config.h.in 16 | /config.log 17 | /config.status 18 | /config.sub 19 | /configure 20 | /depcomp 21 | /install-sh 22 | /libpiface-1.0.la 23 | /libtool 24 | /ltmain.sh 25 | /missing 26 | /piface-1.0.pc 27 | /stamp-h1 28 | -------------------------------------------------------------------------------- /misc/emmisions_testing/emtest1.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | import piface.emulator as pfio 4 | #import piface.pfio as pfio 5 | 6 | 7 | if __name__ == "__main__": 8 | pfio.init() 9 | while True: 10 | # turn each output off, one by one 11 | for i in range(1, 9): 12 | pfio.digital_write(i, 1) 13 | sleep(1) 14 | pfio.digital_write(i, 0) 15 | sleep(1) 16 | -------------------------------------------------------------------------------- /easyteach/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from distutils.core import setup 4 | 5 | DISTUTILS_DEBUG=True 6 | 7 | setup(name='easyteach', 8 | version='1.0', 9 | description='Tools that simplify some tasks on the Raspberry Pi in order to make teaching core programming concepts simpler.', 10 | author='Thomas Preston', 11 | author_email='thomasmarkpreston@gmail.com', 12 | license='GPLv3', 13 | packages=['easyteach'], 14 | ) 15 | -------------------------------------------------------------------------------- /c/examples/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-Wall 3 | INCLUDES=-L/usr/local/lib/ -lpiface-1.0 4 | 5 | input_reader: input_reader.c 6 | $(CC) $(CFLAGS) $(INCLUDES) -o input_reader input_reader.c 7 | 8 | the_amazing_led_show: the_amazing_led_show.c 9 | $(CC) $(CFLAGS) $(INCLUDES) -o the_amazing_led_show the_amazing_led_show.c 10 | 11 | board_reset: board_reset.c 12 | $(CC) $(CFLAGS) $(INCLUDES) -o board_reset board_reset.c 13 | 14 | clean: 15 | rm *.o 16 | -------------------------------------------------------------------------------- /c/examples/the_amazing_led_show.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | if (pfio_init() < 0) 7 | exit(-1); 8 | 9 | char patterns[] = {0x1, 0xc, 0xd, 0x3, 0x1, 0x2, 0x4, 0x5, 0x6, 0x7}; 10 | 11 | int i; 12 | for (i = 0; i < ARRAY_SIZE(patterns); i++) 13 | { 14 | pfio_write_output(patterns[i]); 15 | sleep(1); 16 | } 17 | 18 | pfio_deinit(); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /django/projects/httpi/httpiface/tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file demonstrates writing tests using the unittest module. These will pass 3 | when you run "manage.py test". 4 | 5 | Replace this with more appropriate tests for your application. 6 | """ 7 | 8 | from django.test import TestCase 9 | 10 | 11 | class SimpleTest(TestCase): 12 | def test_basic_addition(self): 13 | """ 14 | Tests that 1 + 1 always equals 2. 15 | """ 16 | self.assertEqual(1 + 1, 2) 17 | -------------------------------------------------------------------------------- /python/demos/sweep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import time 4 | import piface.pfio 5 | import piface.emulator 6 | 7 | # Set thing to 8 | # piface.emulator to run with emulator 9 | # piface.pfio to run without emulator 10 | 11 | #thing = piface.emulator 12 | thing = piface.pfio 13 | 14 | thing.init() 15 | 16 | led1 = thing.LED(1) 17 | 18 | while True: 19 | for i in range(1, 5): 20 | led = thing.LED(i) 21 | led.turn_on() 22 | time.sleep(0.5) 23 | led.turn_off() 24 | 25 | # vim:ts=2:sw=2:sts=2:et:ft=python 26 | 27 | -------------------------------------------------------------------------------- /python/demos/twitterMoodCube.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | twitterMoodCube.py 4 | 5 | Simple moode cube that reflects the mood of the world and allows you to send your mood via a status post 6 | author: Thomas Macpherson-Pope 7 | date : 20/06/2012 8 | """ 9 | 10 | from time import sleep 11 | import twitter 12 | import piface.pfio as pfio 13 | 14 | 15 | pfio.init() 16 | 17 | twitter = twitter.Api() 18 | 19 | terms = ["#happy","#sad","#angry","#jelous","#guilty"] 20 | 21 | search_term = terms[0] 22 | 23 | twitter.GetSearch(term=search_term) 24 | -------------------------------------------------------------------------------- /django/projects/httpi/httpiface/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | url(r'^$', 'httpiface.views.index'), 9 | url(r'^ajax', 'httpiface.views.ajax'), 10 | 11 | # Uncomment the admin/doc line below to enable admin documentation: 12 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 13 | 14 | # Uncomment the next line to enable the admin: 15 | # url(r'^admin/', include(admin.site.urls)), 16 | ) 17 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from distutils.core import setup, Extension 4 | 5 | DISTUTILS_DEBUG=True 6 | 7 | setup(name='piface', 8 | version='1.0', 9 | description='Tools for interacting with the Pi Face add-on to the Raspberry Pi', 10 | author='Thomas Macpherson-Pope, Thomas Preston', 11 | author_email='thomas.macpherson-pope@student.manchester.ac.uk, thomasmarkpreston@gmail.com', 12 | license='GPLv3', 13 | url='http://pi.cs.man.ac.uk/interface.htm', 14 | packages=['piface'], 15 | ext_modules=[Extension('piface/spi', ['piface/spimodule.c'])], 16 | package_data={'piface' : ['images/*.png']}, 17 | ) 18 | -------------------------------------------------------------------------------- /c/src/piface/pfio.h: -------------------------------------------------------------------------------- 1 | /** 2 | * pfio.h 3 | * functions for accessing the PiFace add-on for the Raspberry Pi 4 | */ 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | 11 | int pfio_init(void); 12 | int pfio_deinit(void); 13 | uint8_t pfio_digital_read(uint8_t pin_number); 14 | void pfio_digital_write(uint8_t pin_number, uint8_t value); 15 | uint8_t pfio_read_input(void); 16 | uint8_t pfio_read_output(void); 17 | void pfio_write_output(uint8_t value); 18 | uint8_t pfio_get_pin_bit_mask(uint8_t pin_number); 19 | uint8_t pfio_get_pin_number(uint8_t bit_mask); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | -------------------------------------------------------------------------------- /django/projects/httpi/httpi/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | from django.conf import settings 3 | 4 | # Uncomment the next two lines to enable the admin: 5 | # from django.contrib import admin 6 | # admin.autodiscover() 7 | 8 | urlpatterns = patterns('', 9 | url(r'^$', 'httpi.views.index'), 10 | url(r'^piface/', include('httpiface.urls')), 11 | 12 | # Uncomment the admin/doc line below to enable admin documentation: 13 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | # url(r'^admin/', include(admin.site.urls)), 17 | ) 18 | -------------------------------------------------------------------------------- /python/demos/toggle.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from time import sleep 4 | import piface.pfio 5 | 6 | piface.pfio.init() 7 | 8 | # Make arrays of LEDs... 9 | led = [ piface.pfio.LED(i) for i in range(1, 5) ] 10 | # ...Switches... 11 | switch = [ piface.pfio.Switch(i) for i in range(1, 5) ] 12 | # ...and an array to store the switch states 13 | down = [ False for i in range(1, 5) ] 14 | 15 | while True: 16 | for i in range(0, 4): 17 | if switch[i].value: 18 | if not down[i]: 19 | down[i] = True 20 | led[i].toggle() 21 | else: 22 | down[i] = False 23 | sleep(0.1) 24 | 25 | # vim:ts=2:sw=2:sts=2:et:ft=python 26 | 27 | -------------------------------------------------------------------------------- /django/projects/httpi/httpi/static/js/plugins.js: -------------------------------------------------------------------------------- 1 | // Avoid `console` errors in browsers that lack a console 2 | if (!(window.console && console.log)) { 3 | (function() { 4 | var noop = function() {}; 5 | var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn']; 6 | var length = methods.length; 7 | var console = window.console = {}; 8 | while (length--) { 9 | console[methods[length]] = noop; 10 | } 11 | }()); 12 | } 13 | 14 | // place any jQuery/helper plugins in here, instead of separate, slower script files. 15 | -------------------------------------------------------------------------------- /c/unitytest/README.md: -------------------------------------------------------------------------------- 1 | USING UNITY FOR Piface C Interace Refactoring (pfio.h & pfio.c) 2 | 3 | 1. Download CMock (which includes Unity) to an approriate directory. The Makefile assumes it has been put into /usr/share but CMock can be locaed anywhere 4 | $ wget http://downloads.sourceforge.net/project/cmock/cmock/cmock2.0/cmock_2_0_204.zip 5 | $ unzip cmock_2_0_204.zip 6 | 7 | 2. You should now find a directory cmock; the unity files are found under cmock/vendor/unity 8 | 9 | 3. Install ruby 10 | $ sudo apt-get instal ruby 11 | 12 | 4. The Unity test file is found at piface/c/unitytest/test/tests.c 13 | 14 | 5. To run the tests, in the unitytest directory type 15 | $ make 16 | 17 | 6. Unity automatically builds a new test main() function and executes the tests 18 | 19 | NOTE 20 | To use the automatic test hardess, then you will need to wire output.0 to input.0, output.1 to input.1, etc. 21 | 22 | -------------------------------------------------------------------------------- /scripts/i2c-setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #: Description: Sets up permissions for the i2c devices 3 | #: Author: Thomas Preston 4 | 5 | udev_rules_file='/etc/udev/rules.d/51-i2c.rules' 6 | 7 | # check if the script is being run as root 8 | if [[ $EUID -ne 0 ]] 9 | then 10 | printf 'This script must be run as root.\nExiting..\n' 11 | exit 1 12 | fi 13 | 14 | # check that the rules file doesn't already exist 15 | if [ -f $udev_rules_file ] 16 | then 17 | printf 'The i2c rules file already exists.\nExiting...\n' 18 | exit 1 19 | fi 20 | 21 | 22 | # create the rules file 23 | printf 'Creating udev rule\n' 24 | echo 'KERNEL=="i2cdev*", GROUP="i2cuser", MODE="0660"' > $udev_rules_file 25 | 26 | groupadd i2cuser # create the i2cuser group 27 | gpasswd -a pi i2cuser # add pi to the i2cuser group 28 | 29 | printf 'User "pi" can now access the /dev/i2cdev* devices\n' 30 | printf 'Please REBOOT for the changes to take effect\n' 31 | -------------------------------------------------------------------------------- /django/projects/httpi/httpiface/static/css/piface.css: -------------------------------------------------------------------------------- 1 | #piface_canvas_holder 2 | { 3 | position: relative; 4 | float:left; 5 | } 6 | 7 | #pifacecanvas 8 | { 9 | position: absolute; 10 | top: 0; 11 | left: 0; 12 | } 13 | 14 | .pifaceled 15 | { 16 | position: absolute; 17 | display: none; 18 | } 19 | 20 | #pifaceled0 21 | { 22 | top: 123px; 23 | left: 175px; 24 | } 25 | 26 | #pifaceled1 27 | { 28 | top: 64px; 29 | left: 175px; 30 | } 31 | 32 | #pifaceled2 33 | { 34 | top: 14px; 35 | left: 214px; 36 | } 37 | 38 | #pifaceled3 39 | { 40 | top: 14px; 41 | left: 231px; 42 | } 43 | 44 | #output_controller_holder 45 | { 46 | float: left; 47 | margin-left: 1em; 48 | } 49 | 50 | #content 51 | { 52 | padding-bottom: 3em; 53 | } 54 | 55 | #footer 56 | { 57 | clear: both; 58 | position: relative; 59 | z-index: 10; 60 | height: 3em; 61 | margin-top: -3em; 62 | } 63 | -------------------------------------------------------------------------------- /c/unitytest/Makefile: -------------------------------------------------------------------------------- 1 | # ========================================== 2 | # Unity Project - A Test Framework for C 3 | # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams 4 | # [Released under MIT License. Please refer to license.txt for details] 5 | # ========================================== 6 | 7 | C_COMPILER=gcc 8 | TARGET = tests 9 | OUT_FILE=-o $(TARGET) 10 | SRC_FILES=/usr/share/cmock/vendor/unity/src/unity.c test/$(TARGET).c build/$(TARGET)_Runner.c ../src/piface/pfio.c 11 | INC_DIRS=-I/usr/share/cmock/vendor/unity/src/ -I../src/piface/ 12 | SYMBOLS=-DTEST -DUNITY_SUPPORT_64 -std=c99 -Wall 13 | 14 | CLEANUP = rm -f build/*.o ; rm -f $(TARGET) 15 | 16 | all: clean default 17 | 18 | default: 19 | ruby /usr/share/cmock/vendor/unity/auto/generate_test_runner.rb test/$(TARGET).c build/$(TARGET)_Runner.c 20 | $(C_COMPILER) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES) $(OUT_FILE) 21 | clear 22 | ./$(TARGET) 23 | 24 | clean: 25 | $(CLEANUP) 26 | 27 | -------------------------------------------------------------------------------- /scripts/spidev-setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #: Description: Sets up permissions for the spi devices 3 | #: Author: Thomas Preston 4 | 5 | udev_rules_file='/etc/udev/rules.d/50-spi.rules' 6 | 7 | # check if the script is being run as root 8 | if [[ $EUID -ne 0 ]] 9 | then 10 | printf 'This script must be run as root.\nExiting..\n' 11 | exit 1 12 | fi 13 | 14 | # check that the rules file doesn't already exist 15 | if [ -f $udev_rules_file ] 16 | then 17 | printf 'The spi rules file already exists.\nExiting...\n' 18 | exit 1 19 | fi 20 | 21 | 22 | # create the rules file 23 | printf 'Creating udev rule\n' 24 | echo 'KERNEL=="spidev*", GROUP="spiuser", MODE="0660"' > $udev_rules_file 25 | 26 | groupadd spiuser # create the spiuser group 27 | gpasswd -a pi spiuser # add pi to the spiuser group 28 | gpasswd -a www-data spiuser # add the webserver user to the spiuser group 29 | 30 | printf 'User "pi" can now access the /dev/spidev* devices\n' 31 | printf 'Please REBOOT for the changes to take effect\n' 32 | -------------------------------------------------------------------------------- /easyteach/easyteach/talker.py: -------------------------------------------------------------------------------- 1 | """ 2 | talker.py 3 | A speech module for the Pi Face package. Provides a simple method of talking 4 | with the Raspberry Pi. 5 | Note: this modules doesn't actually require a Pi Face board 6 | 7 | Essentially this is just a wrapper around espeak 8 | """ 9 | import subprocess 10 | 11 | 12 | DEFAULT_PITCH = 50 # 0-99 13 | DEFAULT_SPEED = 160 # words per min 14 | 15 | 16 | class PiFaceTalkerError(Exception): 17 | pass 18 | 19 | 20 | def say(words, pitch=None, speed=None): 21 | """Says words through the audio jack on the Raspberry Pi""" 22 | if not pitch: 23 | pitch = DEFAULT_PITCH 24 | 25 | if not speed: 26 | speed = DEFAULT_SPEED 27 | 28 | devnull = open("/dev/null", "w") 29 | try: 30 | subprocess.call([ 31 | "espeak", 32 | "-v", "en-rp", # english received pronounciation 33 | "-p", str(pitch), 34 | "-s", str(speed), 35 | words], 36 | stderr=devnull) 37 | 38 | except OSError: 39 | raise PiFaceTalkerError( 40 | "There was an error running 'espeak'. Is it installed?") 41 | -------------------------------------------------------------------------------- /django/projects/httpi/httpi/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for httpi project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "httpi.settings") 19 | 20 | # This application object is used by any WSGI server configured to use this 21 | # file. This includes Django's development server, if the WSGI_APPLICATION 22 | # setting points here. 23 | from django.core.wsgi import get_wsgi_application 24 | application = get_wsgi_application() 25 | 26 | # Apply WSGI middleware here. 27 | # from helloworld.wsgi import HelloWorldApplication 28 | # application = HelloWorldApplication(application) 29 | -------------------------------------------------------------------------------- /python/demos/twitter_chicken/twitter_listen_user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | twitter_listen_user.py 4 | listens for new tweets and then wobbles a chicken 5 | 6 | author: Thomas Preston 7 | date : 18/06/2012 8 | """ 9 | 10 | import time 11 | import sys 12 | import twitter 13 | 14 | import raspberry_pi_farm 15 | 16 | 17 | DEFAULT_USER = "tommarkpreston" # the default user we should follow 18 | TIME_DELAY = 2 # seconds between each status check 19 | 20 | def main(): 21 | api = twitter.Api() 22 | previous_status = twitter.Status() 23 | raspberry_pi_farm.init() 24 | chicken = raspberry_pi_farm.Chicken() 25 | 26 | # who are we listening to? 27 | if len(sys.argv) > 1: 28 | user = sys.argv[1] 29 | else: 30 | user = DEFAULT_USER 31 | 32 | print "Listening to tweets from '%s'." % user 33 | 34 | while True: 35 | # grab the users current status 36 | current_status = api.GetUser(user).status 37 | 38 | # if the status is different then give it to the chicken 39 | if current_status.id != previous_status.id: 40 | chicken.start_wobble() 41 | chicken.say(current_status.text) 42 | chicken.stop_wobble() 43 | 44 | previous_status = current_status 45 | 46 | # wait for a short while before checking again 47 | time.sleep(TIME_DELAY) 48 | 49 | if __name__ == "__main__": 50 | main() 51 | -------------------------------------------------------------------------------- /python/demos/twitter_chicken/twitter_listen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | twitter_listen.py 4 | listens for new tweets containing a search term and then wobbles a chicken 5 | 6 | author: Thomas Preston 7 | date : 18/06/2012 8 | """ 9 | 10 | import time 11 | import sys 12 | import twitter 13 | 14 | import raspberry_pi_farm 15 | 16 | 17 | DEFAULT_SEARCH_TERM = "chicken" 18 | TIME_DELAY = 2 # seconds between each status check 19 | 20 | def main(): 21 | api = twitter.Api() 22 | previous_status = twitter.Status() 23 | raspberry_pi_farm.init() 24 | chicken = raspberry_pi_farm.Chicken() 25 | 26 | # what are we searching for? 27 | if len(sys.argv) > 1: 28 | search_term = sys.argv[1] 29 | else: 30 | search_term = DEFAULT_SEARCH_TERM 31 | 32 | print "Listening to tweets containing the word '%s'." % search_term 33 | 34 | while True: 35 | # grab the first tweet containing the search_term 36 | current_status = api.GetSearch(term=search_term, per_page=1)[0] 37 | 38 | # if the status is different then give it to the chicken 39 | if current_status.id != previous_status.id: 40 | chicken.start_wobble() 41 | chicken.say(current_status.text) 42 | chicken.stop_wobble() 43 | 44 | previous_status = current_status 45 | 46 | # wait for a short while before checking again 47 | time.sleep(TIME_DELAY) 48 | 49 | if __name__ == "__main__": 50 | main() 51 | -------------------------------------------------------------------------------- /python/demos/twitter_chicken/raspberry_pi_farm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | raspberry_pi_farm.py 4 | contains a some singing/dancing animals on the Raspberry Pi! 5 | 6 | author: Thomas Preston 7 | date : 18/06/2012 8 | """ 9 | 10 | import subprocess 11 | import piface.pfio as pfio 12 | #import piface.emulator as pfio 13 | import easyteach.talker as talker 14 | 15 | 16 | VERBOSE_MODE = True 17 | 18 | 19 | class Chicken(pfio.Relay): 20 | """The wobbling/talking chicken""" 21 | def __init__(self): 22 | pfio.Relay.__init__(self, 1) # chicken is on pin 23 | self.relay_pin = 1 24 | self.voice_pitch = 50 # 0-99 25 | self.voice_speed = 160 # words per min 26 | 27 | def start_wobble(self): 28 | """Starts wobbling the chicken""" 29 | self.turn_on() 30 | if VERBOSE_MODE: 31 | print "Chicken has started wobbling." 32 | 33 | def stop_wobble(self): 34 | """Stops wobbling the chicken""" 35 | self.turn_off() 36 | if VERBOSE_MODE: 37 | print "Chicken has stopped wobbling." 38 | 39 | def say(self, text_to_say): 40 | """Makes the chicken say something""" 41 | if VERBOSE_MODE: 42 | print "Chicken says: %s" % text_to_say 43 | 44 | talker.say(text_to_say, self.voice_pitch, self.voice_speed) 45 | 46 | 47 | def init(): 48 | """Initialises the raspberry pi farm""" 49 | pfio.init() 50 | -------------------------------------------------------------------------------- /django/templates/httpi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | Raspberry Pi Web Interface 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 |

Welcome to the Raspberry Pi web interface!

29 | Control Pi Face 30 | 31 | 32 | -------------------------------------------------------------------------------- /django/templates/httpiface/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Pi Face Control - Raspberry Pi Web Interface 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Pi Face Control

13 |
14 | {% if not piface_detected %} 15 |

Error: {{ piface_error_msg }}

16 | {% else %} 17 |
18 | 19 | {% for i in led_range %} 20 | 21 | {% endfor %} 22 | 23 |
24 | 25 |
26 | {% for i in button_range %} 27 | Output {{ i|add:1 }}
28 | {% endfor %} 29 |
30 | {% endif %} 31 |
32 | 33 | 36 | 37 | {% if piface_detected %} 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {% endif %} 47 | 48 | 49 | -------------------------------------------------------------------------------- /python/demos/racingpi/questions.txt: -------------------------------------------------------------------------------- 1 | How many bits in a byte?, 8, 10 2 | What does RAM stand for?, Random Access Memory, Real Auditing Memory 3 | Which company did Bill Gates start?, Microsoft, Apple 4 | What is larger a Gigabyte or a Megabyte?, Gigabyte, Megabyte 5 | What are the two home keys on a keyboard?, F and J, P and Q 6 | Which country owns this WWW suffix .de ?, Germany, France 7 | Which type of file has this file format .jpg ?, Image, Spreadsheet 8 | Computers are great True or False, True, False 9 | What type of processor does the RaspberryPi use?, ARM, LEG 10 | Which famous computer scientist broke the Enigma codes at Bletchley Park?, Alan Turing, Steve Jobs 11 | What were Cathode Ray Tubes used in?, Monitors, Keyboards 12 | What does CPU stand for?, Central Processing Unit, Computer Power Unit 13 | What is the command to list files in Windows?, dir, ls 14 | What does UNIX stand for?, Nothing, UNIt eXchange 15 | Which of the following is an operating system?, Linux, Bantex 16 | What computer language uses these tags and ?, HTML, Java 17 | What does DBMS stand for?, Datbase management system, Database migration statistics 18 | Who invented the web?, Tim Berners-Lee, Donald Rumsfeld 19 | What was the forerunner to the Internet called?, ARPANET, SKYNET 20 | What does LAN stand for?, Local Area Network, Legitimate Access Network 21 | What was the first stored-program computer called?, The Baby, The Infant 22 | What is the most suitable input device for inputting a short report?, Keyboard, Mouse 23 | What is another name for a CPU?, Processor, Disk drive 24 | What is Magnetic Ink Character Recognition often used on?, Cheques, Barcodes 25 | Which of these is a mobile operating system?, Android, Windows Vista 26 | What are the tiny points of colour on your monitor called?, Pixels, Pacsels 27 | What does CAD stand for?, Computer Aided Design, Computer Assembley Description 28 | What does WYSIWYG stand for?, What you see is what you get, What you see is where you go 29 | What application should you use to view web pages?, Web browser, Text editor 30 | What does HTML stand for?, Hyper Text Mark-up Language, Histogram Tape Mark-up Language 31 | What is a computer virus?, A program written to cause harm to a computer, A fault with the CPU which loses data 32 | What law makes it illegal to knowingly spread a computer virus?, Computer Misuse Act, Data Protection Act 33 | What do we call buying and selling on the Internet?, Electronic Commerce, Internet Trading -------------------------------------------------------------------------------- /python/tests/piface_test.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | import sys 3 | import unittest 4 | 5 | import piface.emulator as pfio 6 | 7 | 8 | class TestPiFace(unittest.TestCase): 9 | def setUp(self): 10 | '''Called at the start of each test''' 11 | pass 12 | 13 | def tearDown(self): 14 | '''Called at the end of each test''' 15 | pass 16 | 17 | def test_pin_translation(self): 18 | '''Tests the pin translation functions''' 19 | for pin in range(1, 9): 20 | bit_mask = pfio.get_pin_bit_mask(pin) 21 | self.assertEqual(bit_mask, 1 << (pin-1)) 22 | number = pfio.get_pin_number(bit_mask) 23 | self.assertEqual(number, pin) 24 | 25 | def test_switches(self): 26 | print 'The left most switch is switch 1' 27 | for switch_num in range(1,5): 28 | sys.stdout.write('Press switch %d...' % switch_num) 29 | sys.stdout.flush() 30 | 31 | switch_values = self.get_switch_values() 32 | while switch_values == 0: 33 | switch_values = self.get_switch_values() 34 | 35 | pressed_switch = pfio.get_pin_number(switch_values) 36 | self.assertEqual(pressed_switch, switch_num, 37 | 'Switch %d was pressed.' % pressed_switch) 38 | 39 | ## bad test case, this re-queries the switch - need a way around this... 40 | # test the switch class 41 | #this_switch = pfio.Switch(switch_num) 42 | #self.assertEqual(this_switch.value, 1) 43 | 44 | print 'OK!' 45 | 46 | sleep(0.3) 47 | 48 | # before moving on, wait until no switches are pressed 49 | switch_values = self.get_switch_values() 50 | while switch_values != 0: 51 | switch_values = self.get_switch_values() 52 | 53 | def get_switch_values(self): 54 | '''Returns the on/off states of the switches. 1 is on 0 is off''' 55 | return pfio.read_input() & 0x0f 56 | 57 | def test_output_objects(self): 58 | OUTPUT_SLEEP_DELAY = 0.01 59 | # test there are no outputs 60 | self.assertEqual(0, pfio.read_output()) 61 | 62 | for led_num in range(1, 5): 63 | this_led = pfio.LED(led_num) 64 | this_led.turn_on() 65 | sleep(OUTPUT_SLEEP_DELAY) 66 | expected_output_bpat = 1 << (led_num-1) 67 | self.assertEqual(expected_output_bpat, pfio.read_output()) 68 | this_led.turn_off() 69 | sleep(OUTPUT_SLEEP_DELAY) 70 | self.assertEqual(0, pfio.read_output()) 71 | 72 | for relay_num in range(1, 3): 73 | this_relay = pfio.Relay(relay_num) 74 | this_relay.turn_on() 75 | sleep(OUTPUT_SLEEP_DELAY) 76 | expected_output_bpat = 1 << (relay_num-1) 77 | self.assertEqual(expected_output_bpat, pfio.read_output()) 78 | this_relay.turn_off() 79 | sleep(OUTPUT_SLEEP_DELAY) 80 | self.assertEqual(0, pfio.read_output()) 81 | 82 | if __name__ == '__main__': 83 | pfio.init() 84 | unittest.main() 85 | pfio.deinit() 86 | -------------------------------------------------------------------------------- /python/demos/racingpi/gui.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | RacingPi gui initialisation 4 | """ 5 | import pygtk 6 | pygtk.require("2.0") 7 | import gtk 8 | 9 | import game 10 | import sys 11 | 12 | 13 | VERBOSE_MODE = True 14 | 15 | TITLE = "RacingPi" 16 | TITLE_SIZE = 40000 17 | DEFAULT_QUESTION = "What... is the air-speed velocity of an unladen swallow?" 18 | QUESTION_SIZE = 12000 19 | DEFAULT_SPACING = 10 20 | 21 | RACING_PI_IMAGE = "racingpi/racingPi.png" 22 | 23 | 24 | class RacingPiGUI(object): 25 | def __init__(self): 26 | self.the_game = None 27 | 28 | self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) 29 | self.window.connect("delete_event", self.delete_event) 30 | self.window.connect("destroy", self.destroy) 31 | self.window.set_border_width(10) 32 | self.window.set_title(TITLE) 33 | self.window.set_icon_from_file(RACING_PI_IMAGE) 34 | self.generate_contents() 35 | self.window.show() 36 | 37 | def delete_event(self, widget, data=None): 38 | return False # call the destroy event after this 39 | 40 | def destroy(self, widget, data=None): 41 | if self.the_game: 42 | self.the_game.stop() 43 | gtk.main_quit() 44 | 45 | def main(self): 46 | gtk.main() 47 | 48 | 49 | def generate_contents(self): 50 | """Generates the contents of the window""" 51 | # label 52 | main_title = gtk.Label() 53 | main_title.set_use_markup(True) 54 | main_title.set_markup("%s"%(TITLE_SIZE, TITLE)) 55 | main_title.show() 56 | 57 | image = gtk.Image() 58 | image.set_from_file(RACING_PI_IMAGE) 59 | image.show() 60 | 61 | 62 | # question space 63 | self.question_label = gtk.Label() 64 | self.question_label.set_use_markup(True) 65 | self.update_question(DEFAULT_QUESTION) 66 | self.question_label.show() 67 | 68 | main_box = make_vbox(elements=[main_title, self.question_label]) 69 | main_box.add(image) 70 | self.window.add(main_box) 71 | """ 72 | try: 73 | self.set_icon_from_file("racingPi.png") 74 | except Exception, e: 75 | print e.message 76 | sys.exit(1) 77 | """ 78 | 79 | 80 | def update_question(self, new_question): 81 | # clean up question 82 | new_question = new_question.replace("<", "\<").replace(">", "/>") 83 | gtk.gdk.threads_enter() 84 | self.question_label.set_markup("%s"%(QUESTION_SIZE, new_question)) 85 | gtk.gdk.threads_leave() 86 | 87 | 88 | def make_vbox(homogeneous=False, spacing=DEFAULT_SPACING, elements=(), expand=False): 89 | return make_box(gtk.VBox, homogeneous, spacing, elements, expand) 90 | 91 | def make_hbox(homogeneous=False, spacing=DEFAULT_SPACING, elements=(), expand=False): 92 | return make_box(gtk.HBox, homogeneous, spacing, elements, expand) 93 | 94 | def make_box(box_type, homogeneous, spacing, elements, expand): 95 | box = box_type(False, spacing) 96 | 97 | for element in elements: 98 | box.pack_start(element, expand) 99 | element.show() 100 | 101 | box.show() 102 | return box 103 | -------------------------------------------------------------------------------- /django/projects/httpi/httpiface/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render_to_response 2 | from django.http import HttpResponse, HttpResponseBadRequest 3 | from django.template import RequestContext 4 | import simplejson 5 | 6 | import piface.pfio as pfio 7 | 8 | """ 9 | # fake pfio stuff for testing 10 | outpins = 0 11 | inpins = 0 12 | def fakepfioinit(): 13 | pass 14 | def fakepfiowrite(something): 15 | global outpins 16 | outpins = something 17 | def fakepfioreadin(): 18 | return 0b10101010 19 | def fakepfioreadout(): 20 | global outpins 21 | return outpins 22 | pfio.init = fakepfioinit 23 | pfio.write_output = fakepfiowrite 24 | pfio.read_input = fakepfioreadin 25 | pfio.read_output = fakepfioreadout 26 | """ 27 | 28 | 29 | def index(request): 30 | piface_detected = True 31 | piface_error_msg = "" 32 | 33 | try: 34 | pfio.init() 35 | except pfio.InitError as error: 36 | piface_detected = False 37 | piface_error_msg = error 38 | 39 | return render_to_response("httpiface/index.html", 40 | {'button_range' : range(8), 41 | 'led_range' : range(4), 42 | 'piface_detected' : piface_detected, 43 | 'piface_error_msg' : piface_error_msg}, 44 | context_instance=RequestContext(request)) 45 | 46 | def ajax(request): 47 | data = request.GET.dict() 48 | return_values = dict() 49 | 50 | if 'init' in data: 51 | try: 52 | pfio.init() 53 | except pfio.InitError as error: 54 | return_values.update({'status' : 'init failed'}) 55 | return_values.update({'error' : str(error)}) 56 | return HttpResponseBadRequest(simplejson.dumps(return_values)) 57 | 58 | if 'read_input' in data: 59 | try: 60 | input_bitp = pfio.read_input() 61 | except Exception as e: 62 | return_values.update({'status' : 'read_input failed'}) 63 | return_values.update({'error' : str(e)}) 64 | return HttpResponseBadRequest(simplejson.dumps(return_values)) 65 | else: 66 | return_values.update({'input_bitp' : input_bitp}) 67 | 68 | if 'read_output' in data: 69 | try: 70 | output_bitp = pfio.read_output() 71 | except Exception as e: 72 | return_values.update({'status' : 'read_output failed'}) 73 | return_values.update({'error' : str(e)}) 74 | return HttpResponseBadRequest(simplejson.dumps(return_values)) 75 | else: 76 | return_values.update({'output_bitp' : output_bitp}) 77 | 78 | if 'write_output' in data: 79 | try: 80 | output_bitp = int(data['write_output']) 81 | except ValueError: 82 | return_values.update({'status' : 'write_output failed'}) 83 | return_values.update({'error' : "write_output needs an integer bit pattern."}) 84 | return HttpResponseBadRequest(simplejson.dumps(return_values)) 85 | 86 | try: 87 | pfio.write_output(output_bitp) 88 | except Exception as e: 89 | return_values.update({'status' : "write_output failed"}) 90 | return_values.update({'error' : str(e)}) 91 | return HttpResponseBadRequest(simplejson.dumps(return_values)) 92 | 93 | return_values.update({'status' : 'success'}) 94 | return HttpResponse(simplejson.dumps(return_values)) 95 | -------------------------------------------------------------------------------- /c/unitytest/test/tests.c: -------------------------------------------------------------------------------- 1 | #include "unity.h" 2 | #include "pfio.h" 3 | #include 4 | 5 | void setUp(void) 6 | { 7 | uint8_t result = pfio_init(); 8 | TEST_ASSERT_EQUAL_INT(0,result); 9 | } 10 | 11 | void tearDown(void) 12 | { 13 | uint8_t result = pfio_deinit(); 14 | TEST_ASSERT_EQUAL_INT(0,result); 15 | } 16 | 17 | void testInit(void) 18 | { 19 | uint8_t result = pfio_read_output(); 20 | TEST_ASSERT_BITS_LOW_MESSAGE(0xFF, result, "default outputs not all low"); 21 | } 22 | 23 | void testDigitalWrite0(void) 24 | { 25 | pfio_digital_write(0, 1); 26 | uint8_t result = pfio_read_output(); 27 | TEST_ASSERT_BIT_HIGH_MESSAGE(0, result, "pin 0 output not set"); 28 | pfio_digital_write(0, 0); 29 | result = pfio_read_output(); 30 | TEST_ASSERT_BIT_LOW_MESSAGE(0, result, "pin 0 output not cleared"); 31 | } 32 | 33 | void testDigitalWriteAll(void) 34 | { 35 | for(uint8_t pin = 0; pin < 8; ++pin) { 36 | pfio_digital_write(pin, 1); 37 | uint8_t result = pfio_read_output(); 38 | TEST_ASSERT_BIT_HIGH_MESSAGE(pin, result, "output not set"); 39 | pfio_digital_write(pin, 0); 40 | result = pfio_read_output(); 41 | TEST_ASSERT_BIT_LOW_MESSAGE(pin, result, "output not cleared"); 42 | } 43 | } 44 | 45 | void testWriteOutputAll(void) 46 | { 47 | pfio_write_output(0xFF); 48 | uint8_t result = pfio_read_output(); 49 | TEST_ASSERT_BITS_HIGH_MESSAGE(0xFF, result, "outputs not set"); 50 | pfio_write_output(0); 51 | result = pfio_read_output(); 52 | TEST_ASSERT_BITS_LOW_MESSAGE(0xFF, result, "outputs not cleared"); 53 | } 54 | 55 | void testWriteOutputByBit(void) 56 | { 57 | for(uint8_t pin = 0; pin < 8; ++pin) { 58 | pfio_write_output(1 << pin); 59 | uint8_t result = pfio_read_output(); 60 | TEST_ASSERT_BIT_HIGH_MESSAGE(pin, result, "output not set"); 61 | pfio_write_output(0); 62 | } 63 | } 64 | 65 | void testDigitalRead0(void) 66 | { 67 | pfio_digital_write(0, 1); 68 | uint8_t result = pfio_digital_read(0); 69 | TEST_ASSERT_EQUAL_INT(1,result); 70 | pfio_digital_write(0, 0); 71 | result = pfio_digital_read(0); 72 | TEST_ASSERT_EQUAL_INT(0,result); 73 | } 74 | 75 | void testDigitalReadByBit(void) 76 | { 77 | for(uint8_t pin = 0; pin < 8; ++pin) { 78 | pfio_digital_write(pin, 1); 79 | uint8_t result = pfio_digital_read(pin); 80 | TEST_ASSERT_EQUAL_INT(1,result); 81 | pfio_digital_write(pin, 0); 82 | result = pfio_digital_read(pin); 83 | TEST_ASSERT_EQUAL_INT(0,result); 84 | } 85 | } 86 | 87 | void testDigitalReadInput(void) 88 | { 89 | pfio_write_output(0xFF); 90 | uint8_t result = pfio_read_input(); 91 | TEST_ASSERT_BITS_HIGH_MESSAGE(0xFF, result, "outputs not set"); 92 | pfio_write_output(0); 93 | result = pfio_read_input(); 94 | TEST_ASSERT_BITS_LOW_MESSAGE(0xFF, result, "outputs not cleared"); 95 | } 96 | 97 | 98 | /* 99 | extern char pfio_init(void); 100 | - pfio_init twice 101 | ? Interface requirements - if init called twice then call should return failure (-1) but should still be able to perform I/O 102 | */ 103 | /* 104 | void testInitTwice(void) 105 | { 106 | uint8_t result = pfio_init(); 107 | TEST_ASSERT_EQUAL_INT(-1,result); 108 | testWriteOutputAll(); 109 | } 110 | */ 111 | 112 | /* 113 | extern char pfio_deinit(void); 114 | - pfio_deinit twice 115 | 116 | extern char pfio_digital_read(char pin_number); 117 | - pin_number > 7 118 | - -ve pin_number 119 | - 120 | 121 | extern void pfio_digital_write(char pin_number, char value); 122 | - pin_number > 7 123 | - -ve pin_number 124 | - value > 1 125 | - value < 0 126 | 127 | extern char pfio_read_input(void); 128 | extern char pfio_read_output(void); 129 | extern void pfio_write_output(char value); 130 | */ 131 | -------------------------------------------------------------------------------- /python/demos/whackAMole.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | whackAMole.py 4 | Simple whack a mole game for use with pfio and the RaspberryPi interface (piface) 5 | 6 | Objective of game: A random LED will light up and you must hit the corresponding button as quickly as possible. 7 | The amount of time you have to hit the button will get shorter as the game progresses. 8 | """ 9 | 10 | from time import sleep # for delays 11 | import random # for generating the next random button flash 12 | 13 | import piface.pfio as pfio # piface library 14 | 15 | 16 | pfio.init() # initialise pfio (sets up the spi transfers) 17 | 18 | 19 | def next_colour(): 20 | """ choses a random number between 1 and 5 to represent the coloured leds and their corresponding buttons""" 21 | return random.randint(1,5) 22 | 23 | 24 | 25 | current = next_colour() # create first random colour to be lit 26 | pfio.digital_write(current+2,1) # turn colour on 27 | set_time = 2000 # time allowed to hit each light (starts off large and reduced after each hit) 28 | time_left = set_time # countdown timer for hitting the light 29 | hit = 0 # the input value 30 | score = 0 # keep track of the player's score 31 | misses = 0 # keep track of how many the player misses 32 | 33 | colours = ["Red","Green","Blue","Yellow","White"] # colour list for printing to screen 34 | previous_pressed = 255 35 | 36 | 37 | print "Time left is: %s" %time_left # notify the player how long they have to hit each flash 38 | 39 | 40 | while True: 41 | 42 | in_bit_pattern = pfio.read_input() # see if any buttons have been hit 43 | 44 | if in_bit_pattern != previous_pressed: # check this is a new button press 45 | previous_pressed = in_bit_pattern # record button press for next time's check 46 | 47 | if in_bit_pattern > 0: 48 | 49 | if in_bit_pattern == pfio.get_pin_bit_mask(current): # check that only the correct button was hit 50 | 51 | pfio.digital_write(current+2, 0) # turn off hit light 52 | previous = current 53 | current = next_colour() # get next colour 54 | 55 | while current == previous: # ensure differnt colour each time 56 | current = next_colour() # get next colour 57 | 58 | if ((score + misses) %30) ==29: 59 | if set_time > 125: 60 | set_time /= 2 # reduce the time allowed to hit the light 61 | print "Time left is: %s" %set_time 62 | 63 | time_left = set_time # set the countdown time 64 | 65 | score += 1 66 | print "Your score %d" %score 67 | pfio.digital_write(current+2,1) # turn the new light on 68 | 69 | 70 | else: # wrong button pressed 71 | print "Wrong one!" 72 | print "Your score %d" %score 73 | score -= 1 74 | 75 | 76 | elif time_left==0: 77 | pfio.digital_write(current+2, 0) # turn off hit light 78 | misses +=1 # increment misses 79 | print "Missed one!" 80 | 81 | if misses == 10: # too many misses = Game Over! 82 | break 83 | 84 | previous = current # 85 | current = next_colour() # get next colour 86 | 87 | while current == previous: # ensure differnt colour each time 88 | current = next_colour() # get next colour 89 | 90 | if ((score + misses) %30)==29: 91 | if set_time > 125: 92 | set_time /= 2 # reduce the allowed time 93 | print "Time left is: %s" %set_time 94 | 95 | time_left = set_time # set the countdown time 96 | 97 | pfio.digital_write(current+2,1) # turn the new light on 98 | 99 | time_left -=1 # decrement the time left to hit the current light 100 | 101 | 102 | 103 | pfio.write_output(0) # turn all lights off 104 | print "\nGame over!\n" 105 | print "Your score was: %s" %score # print the player's final score 106 | #pfio.deinit() # close the pfio 107 | 108 | 109 | -------------------------------------------------------------------------------- /python/demos/racingpi/racingpi_db_helper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | racingpi_db_helper.py 4 | A database wrapper for the RacingPi question database 5 | 6 | TODO 7 | Make it so that connections can be passed in for quicker database access 8 | """ 9 | import sqlite3 10 | 11 | 12 | VERBOSE_MODE = True 13 | DATABASE_NAME = "racingpi_db" 14 | 15 | 16 | class Question(object): 17 | def __init__(self, question_text, correct_answer, incorrect_answer, 18 | difficulty, category): 19 | self.text = question_text 20 | self.correct_answer = correct_answer 21 | self.incorrect_answer = incorrect_answer 22 | self.difficulty = difficulty 23 | self.category = category 24 | 25 | def write_to_db(self): 26 | """Writes the question to the database""" 27 | connection = get_connection() 28 | cursor = connection.cursor() 29 | self.category.write_to_db() 30 | sql = """ 31 | INSERT INTO question 32 | (question_text, correct_answer, incorrect_answer, difficulty, 33 | category_id) 34 | VALUES (?,?,?,?,?) 35 | """ 36 | 37 | cursor.execute(sql, ( 38 | self.text, 39 | self.correct_answer, 40 | self.incorrect_answer, 41 | self.difficulty, 42 | self.category.category_id) 43 | ) 44 | 45 | self.question_id = cursor.lastrowid 46 | 47 | commit_connection(connection) 48 | 49 | class Category(object): 50 | def __init__(self, name): 51 | self.cetegory_id = None 52 | self.name = name 53 | 54 | def write_to_db(self): 55 | """Writes the category to the database""" 56 | connection = get_connection() 57 | cursor = connection.cursor() 58 | 59 | # check the category doesn't already exist 60 | sql = "SELECT id FROM category WHERE name=? LIMIT 1" 61 | cursor.execute(sql, (self.name,)) 62 | print cursor.fetchone()[0] 63 | 64 | # if it doesnt then insert the category 65 | if count < 1: 66 | sql = "INSERT INTO category (name) VALUES (?)" 67 | cursor.execute(sql, (self.name,)) 68 | self.category_id = cursor.lastrowid 69 | commit_connection(connection) 70 | 71 | 72 | def get_connection(): 73 | """Returns a databse connection""" 74 | return sqlite3.connect(DATABASE_NAME) 75 | 76 | def commit_connection(connection): 77 | """Saves all changes to the database""" 78 | connection.commit() 79 | 80 | def init_db(): 81 | """Initialises the RacingPi database""" 82 | connection = get_connection() 83 | cursor = connection.cursor() 84 | 85 | sql = """CREATE TABLE IF NOT EXISTS category ( 86 | id integer, 87 | name text, 88 | PRIMARY KEY (id) 89 | )""" 90 | cursor.execute(sql) 91 | 92 | sql = """CREATE TABLE IF NOT EXISTS question ( 93 | id integer, 94 | question_text text, 95 | correct_answer text, 96 | incorrect_answer text, 97 | difficulty integer, 98 | category_id integer, 99 | deleted integer DEFAULT 0, 100 | PRIMARY KEY (id) 101 | FOREIGN KEY (category_id) REFERENCES category(id) 102 | )""" 103 | cursor.execute(sql) 104 | 105 | commit_connection(connection) 106 | 107 | def add_question(question=None): 108 | """Adds a question to the database""" 109 | if question: 110 | question.write_to_db() 111 | else: 112 | question_text = raw_input("Question: ") 113 | correct_answer = raw_input("Correct answer: ") 114 | incorrect_answer = raw_input("Incorrect answer: ") 115 | difficulty = raw_input("Difficulty (number): ") 116 | category_name = raw_input("Category: ") 117 | 118 | question = Question( 119 | question_text, 120 | correct_answer, 121 | incorrect_answer, 122 | difficulty, 123 | Category(category_name)) 124 | question.write_to_db() 125 | 126 | def delete_question(question_id): 127 | """Sets the delete flag high on a question""" 128 | connection = get_connection() 129 | cursor = connection.cursor() 130 | sql = """ 131 | UPDATE question 132 | SET deleted = 1 133 | WHERE id = ? 134 | """ 135 | cursor.execute(sql, (question_id,)) 136 | commit_connection(connection) 137 | 138 | def get_question(question_id): 139 | """Return a single question""" 140 | connection = get_connection() 141 | cursor = connection.cursor() 142 | sql = """ 143 | SELECT question_text, correct_answer, incorrect_answer, 144 | difficulty, category_id 145 | FROM question 146 | WHERE id = ? 147 | AND deleted = 0 148 | LIMIT 1 149 | """ 150 | cursor.execute(sql, (question_id,)) 151 | row = cursor.fetchone() 152 | print row 153 | 154 | def get_all_questions(category=None): 155 | pass 156 | 157 | def get_all_categories(): 158 | pass 159 | -------------------------------------------------------------------------------- /python/demos/simon.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | simon.py 4 | Simple simon game for use with pfio and the RaspberryPi interface (piface) 5 | 6 | Objective of the game: You must remember an ever increasing sequence of flashes and input them correctly* 7 | 8 | """ 9 | 10 | from time import sleep # for delays 11 | import random # for random sequence generation 12 | import piface.pfio as pfio # piface library 13 | 14 | 15 | 16 | 17 | pfio.init() # initialise pfio (sets up the spi transfers) 18 | 19 | colours = ["Red","Green","Blue","Yellow","White"] # colour names for printing to screen 20 | 21 | 22 | 23 | def next_colour(): 24 | """ choses a random number between 1 and 5 to represent the coloured leds and their corresponding buttons""" 25 | return random.randint(1,5) 26 | 27 | 28 | 29 | first_in_sequence = next_colour() # create the first colour in the sequence 30 | 31 | array = [first_in_sequence] # add the first colour to the array 32 | 33 | game = 1 # keep track of game active (1 for active, 0 for game over) 34 | score = 0 # keep track of player's score 35 | screen_output = False # choice to write colours and cues to the screen 36 | 37 | 38 | sleep(1) # let them get their bearings 39 | 40 | while game: # while game in play 41 | 42 | game_round = score+1 43 | 44 | if screen_output: # print the round number 45 | print "\nRound %s!" %game_round 46 | 47 | for i in array: # for each colour in current sequence (flash the sequence) 48 | 49 | pfio.digital_write(i+2,1) # turn the colour on 50 | 51 | 52 | if screen_output: # print the colour to the screen 53 | print colours[i-1] 54 | 55 | sleep(0.5) # wait to keep the colour showing 56 | pfio.digital_write(i+2,0) # turn the colour off 57 | sleep(0.2) # small break between colours 58 | 59 | 60 | sleep(0.4) 61 | pfio.write_output(0xFF) # signify it is their turn by turning all the LEDs on then off 62 | sleep(0.3) 63 | pfio.write_output(0x0) 64 | 65 | if screen_output: 66 | print "\nYour turn!" 67 | 68 | 69 | for i in array: # for each colour in current sequence (check against inputted sequence) 70 | event = pfio.read_input() # read the button port state 71 | 72 | while event != 0: # wait till no buttons pressed 73 | event = pfio.read_input() # so a single button press is not read as 2 74 | sleep(0.001) # delay 75 | 76 | while event == 0: # wait for any input 77 | event = pfio.read_input() 78 | 79 | sleep(0.001) # delay 80 | pin_number = pfio.get_pin_number(event) # calculate the input pin 81 | 82 | if screen_output: 83 | print colours[pin_number -1] # print the colour in sequence to the screen 84 | 85 | pfio.digital_write(pin_number+2,1) # light up the buttons pressed 86 | 87 | if event != pfio.get_pin_bit_mask(i): 88 | game = 0 # if any wrong buttons were pressed end the game 89 | break 90 | 91 | else: # otherwise the correct button was pressed 92 | previous = event 93 | event = pfio.read_input() 94 | 95 | while previous == event: # while the button is held down, wait 96 | previous = event 97 | event = pfio.read_input() 98 | 99 | pfio.digital_write(i+2,0) # turn the button's LED off 100 | 101 | 102 | sleep(0.4) 103 | pfio.write_output(0xFF) # signify their turn is over 104 | sleep(0.3) 105 | pfio.write_output(0x0) 106 | 107 | if game: 108 | next = next_colour() # set next colour 109 | while next == array[-1]: # ensure the same colour isn't chosen twice in a row 110 | next = next_colour() 111 | 112 | array.append(next) # add another colour to the sequence 113 | score +=1 # increment the score counter 114 | sleep(0.4) # small break before flashing the new extended sequence 115 | 116 | 117 | 118 | pfio.write_output(0x00) # if the game has been lost, set all the button leds off 119 | 120 | print "Your score was %s" %score # print the players score 121 | 122 | """ 123 | f = open('high_scores.txt','r+') 124 | 125 | high_scores = f.readlines() 126 | 127 | 128 | high_score = 0 129 | index = 0 130 | 131 | for indx, line in enumerate(high_scores): 132 | if "simon" in line: 133 | line = line.split(",") 134 | high_score = int(line[1]) 135 | index = indx 136 | break 137 | 138 | f.close() 139 | 140 | print "The high score was %d" %high_score 141 | 142 | 143 | if score > high_score: 144 | print "Congratulations! You have the new high score" 145 | f = open('high_scores.txt','r+') 146 | f.write(replace(str(high_score),str(score))) 147 | f.close() 148 | else: 149 | print "You haven't beaten the high score, keep trying!" 150 | 151 | """ 152 | pfio.deinit() # close the pfio 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **New PiFace Digital Documentation: http://piface.github.io/pifacedigitalio/** 2 | 3 | **New PiFace GitHub: https://github.com/piface** 4 | 5 | News 6 | ==== 7 | 2013/02/15 8 | ---------- 9 | We're making the project more modular and so future development 10 | on the indvidual components will take place in component specific repositories. 11 | This repo will remain maintained but no new major features will be added. 12 | 13 | If you would like to use the most up-to-date software, use the following links: 14 | 15 | [piface](https://github.com/piface/) 16 | 17 | About 18 | ===== 19 | This repository contains code relating to piface projects. 20 | 21 | *The software in this repository uses Python 2 and is incompatible with Python 3* 22 | 23 | [Farnell Documentation](http://www.farnell.com/datasheets/1684425.pdf) 24 | 25 | [Getting Started](https://docs.google.com/document/d/145TkSMwnPAJaqKMLxdvD8aGULQ8UgIIU3hg-JAKwAa0/edit) 26 | 27 | [Documentation](https://docs.google.com/folder/d/0B-UAZ9CyJCLGQjJ3RDlqa2pqaDg/edit) 28 | 29 | [Downloads](http://pi.cs.man.ac.uk/download) 30 | 31 | Installation and Setup 32 | ====================== 33 | Please refer to the [Farnell Documentation](http://www.farnell.com/datasheets/1684425.pdf) 34 | for simple instructions. 35 | 36 | If you'd like to do things by yourself then the following might be of some use. 37 | 38 | \# is the root user prompt, $ is the normal user (pi) prompt. You can prefix user 39 | commands with *sudo* to run them with root user privileges. 40 | 41 | ### Enabling the SPI module 42 | PiFace Digital communicates with the Raspberry Pi using the SPI interface. 43 | The SPI interface driver is included in the later Raspbian distributions 44 | but is not enabled by default. 45 | 46 | To load the SPI driver manually, type: 47 | 48 | # modprobe spi-bcm2708 49 | 50 | *This will not persist after a reboot.* To permanently enable the SPI module 51 | comment out the spi module blacklist line in /etc/modprobe.d/raspi-blacklist.conf 52 | (you will have to be root). 53 | 54 | ### Dependencies 55 | Everything (if you're unsure, just run this one) 56 | 57 | # apt-get install python-dev python-gtk2-dev git automake libtool espeak python-django python-simplejson 58 | 59 | Just Python 60 | 61 | # apt-get install python-dev python-gtk2-dev git 62 | 63 | Just C 64 | 65 | # apt-get install automake libtool git 66 | 67 | Easyteach: 68 | 69 | # apt-get install espeak 70 | 71 | Web Interface 72 | 73 | # apt-get install python-django python-simplejson 74 | 75 | ### Getting the source 76 | To download all of the source files simply run the following command: 77 | 78 | $ git clone https://github.com/thomasmacpherson/piface.git 79 | 80 | This will create a directory called *piface*, which contains the entire 81 | project tree stored in this Git repository. 82 | 83 | ### Python 84 | To install the piface python package you must first download the source, 85 | move into the piface directory and then run the setup script as root (ignore 86 | the compiler warnings about data types not matching up, it's just being 87 | picky!): 88 | 89 | $ cd piface/python/ 90 | $ sudo python setup.py install 91 | 92 | Now whenever you enter a python shell you can access the piface's 93 | input/output module or the emulator by importing them like so: 94 | 95 | $ python 96 | >>> import piface.pfio 97 | >>> piface.pfio.init() 98 | >>> piface.pfio.digital_write(1, 1) 99 | >>> led1 = piface.pfio.LED(1) 100 | >>> led1.turn_off() 101 | >>> import piface.emulator 102 | >>> piface.emulator.init() 103 | 104 | *Note: Make sure you have left the python source directory before importing 105 | any modules, otherwise Python may get confused* 106 | 107 | If you prefer, you can refer to the pfio and emulator modules directly 108 | using the following Python syntax: 109 | 110 | $ python 111 | >>> import piface.pfio as pfio 112 | >>> import piface.emulator as emulator 113 | >>> pfio.digital_write(4, 0) 114 | >>> emulator.digital_write(3, 1) 115 | 116 | The emulator can be used in the same way as the pfio. Upon initialisation, 117 | an image of the Pi Face will be drawn to a window and its inputs/outputs 118 | can be seen. 119 | 120 | You can find some example python scripts in python/demos. 121 | 122 | If you would like to remove the PiFace Python libraries, issue the following command: 123 | 124 | $ sudo rm -r /usr/local/lib/python2.7/dist-packages/{piface,piface-1.0.egg-info} 125 | 126 | ### C 127 | To install the C pfio library download the source, move into the C directory, 128 | call the setup scripts and then (as root) run the install command: 129 | 130 | $ cd piface/c/ 131 | $ ./autogen.sh && ./configure && make && sudo make install 132 | 133 | You may also need to run ldconfig to reconfigure the libraries: 134 | 135 | $ sudo ldconfig 136 | 137 | To use the C libraries you will need to include the pfio header file from 138 | the piface library and then compile with the correct flags: 139 | 140 | $ cat piface_program.c 141 | #include 142 | 143 | int main(void) 144 | { 145 | pfio_init(); 146 | pfio_digital_write(0, 1); 147 | pfio_deinit(); 148 | } 149 | $ gcc -L/usr/local/lib/ -lpiface-1.0 -o piface_program piface_program.c 150 | $ ./piface_program 151 | 152 | Testing 153 | ======= 154 | ### Python 155 | To test the installed piface package run the tests in the tests/ directory. 156 | 157 | $ cd python/tests/ 158 | $ python piface_test.py 159 | -------------------------------------------------------------------------------- /django/projects/httpi/httpiface/static/js/piface.js: -------------------------------------------------------------------------------- 1 | PIN_IN_X = [6.0, 19.0, 31.0, 44.0, 56.0, 68.0, 80.0, 92.0 ]; 2 | PIN_IN_Y = [186.0, 186.0, 186.0, 186.0, 186.0, 186.0, 186.0, 186.0]; 3 | PIN_OUT_X = [266.0, 254.0, 242.0, 230.0, 218.0, 206.0, 194.0, 181.0]; 4 | PIN_OUT_Y = [8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0 ]; 5 | PIN_R = 5; 6 | 7 | SWITCH_X = [14.3, 39.3, 64.3, 89.3]; 8 | SWITCH_Y = [157.5, 157.5, 157.5, 157.5]; 9 | SWITCH_R = 5; 10 | 11 | RELAY_PINS_X = [[285.0, 285.0, 285.0], [285.0, 285.0, 285.0]] 12 | RELAY_PINS_Y = [[124.0, 136.0, 148.0], [ 73.0, 86.0, 98.0]] 13 | 14 | update_interval_id = 0; 15 | 16 | var error_handler = function(jqXHR, text_status, error_thrown) 17 | { 18 | // stop auto updating 19 | window.clearInterval(update_interval_id) 20 | alert(text_status + ": " + error_thrown + "\n" + jqXHR.responseText); 21 | }; 22 | 23 | var send_ajax = function(datatosend, success_func) 24 | { 25 | $.ajax({url: '/piface/ajax', 26 | data: datatosend, 27 | success: success_func, 28 | error: error_handler}); 29 | }; 30 | 31 | var write_completed = function(data, output_status, jqXHR) 32 | { 33 | }; 34 | 35 | var output_checkbox_clicked = function(the_event) 36 | { 37 | // generate binary 38 | var output_bitp = 0; 39 | for (var i=7; i >= 0; i--) // first output is on rhs 40 | { 41 | output_bitp = output_bitp << 1; 42 | if ($("#pifaceoutputcheckbox"+i).prop('checked')) 43 | output_bitp ^= 1; 44 | } 45 | 46 | send_ajax("write_output="+output_bitp, write_completed) 47 | }; 48 | 49 | var draw_circle = function(context, x, y, r, colour) 50 | { 51 | colour = typeof colour !== 'undefined' ? colour : "#8ed6ff"; 52 | context.beginPath(); 53 | context.arc(x, y, r, 0, 2 * Math.PI, false); 54 | context.fillStyle = colour; 55 | context.fill(); 56 | context.lineWidth = 1; 57 | context.strokeStyle = "black"; 58 | context.stroke(); 59 | }; 60 | 61 | var draw_in_pin = function(context, pin_number) 62 | { 63 | draw_circle(context, 64 | PIN_IN_X[pin_number], 65 | PIN_IN_Y[pin_number], 66 | PIN_R); 67 | }; 68 | 69 | var draw_out_pin = function(context, pin_number) 70 | { 71 | draw_circle(context, 72 | PIN_OUT_X[pin_number], 73 | PIN_OUT_Y[pin_number], 74 | PIN_R); 75 | }; 76 | 77 | var draw_switch = function(context, switch_number) 78 | { 79 | draw_circle(context, 80 | SWITCH_X[switch_number], 81 | SWITCH_Y[switch_number], 82 | SWITCH_R); 83 | }; 84 | 85 | var draw_led_on = function(context, led_number) 86 | { 87 | $("#pifaceled"+led_number).show(); 88 | }; 89 | 90 | var draw_led_off = function(context, led_number) 91 | { 92 | $("#pifaceled"+led_number).hide(); 93 | }; 94 | 95 | var draw_relay_on = function(context, relay_number) 96 | { 97 | draw_circle(context, 98 | RELAY_PINS_X[relay_number][1], 99 | RELAY_PINS_Y[relay_number][1], 100 | PIN_R); 101 | draw_circle(context, 102 | RELAY_PINS_X[relay_number][2], 103 | RELAY_PINS_Y[relay_number][2], 104 | PIN_R); 105 | }; 106 | 107 | var draw_relay_off = function(context, relay_number) 108 | { 109 | draw_circle(context, 110 | RELAY_PINS_X[relay_number][0], 111 | RELAY_PINS_Y[relay_number][0], 112 | PIN_R); 113 | draw_circle(context, 114 | RELAY_PINS_X[relay_number][1], 115 | RELAY_PINS_Y[relay_number][1], 116 | PIN_R); 117 | }; 118 | 119 | var set_in_pin = function(context, pin_number, set_pin) 120 | { 121 | if (set_pin) 122 | { 123 | draw_in_pin(context, pin_number); 124 | if (pin_number < 4) 125 | draw_switch(context, pin_number); 126 | } 127 | }; 128 | 129 | var set_out_pin = function(context, pin_number, set_pin) 130 | { 131 | if (set_pin) 132 | { 133 | draw_out_pin(context, pin_number); 134 | if (pin_number < 4) 135 | draw_led_on(context, pin_number); 136 | if (pin_number < 2) 137 | draw_relay_on(context, pin_number); 138 | } 139 | else if (pin_number < 4) 140 | { 141 | draw_led_off(context, pin_number); 142 | if (pin_number < 2) // relay is off 143 | draw_relay_off(context, pin_number); 144 | } 145 | }; 146 | 147 | var update_piface = function(data, output_status, jqXHR) 148 | { 149 | send_ajax("read_input&read_output", function(data, output_status, jqXHR) 150 | { 151 | var data = eval("("+data+")"); // convert text to a json object 152 | 153 | // once we have the I/O stuff, then draw everything 154 | var canvas = document.getElementById("pifacecanvas"); 155 | var context = canvas.getContext("2d"); 156 | 157 | // reset the canvas 158 | canvas.width = canvas.width; 159 | 160 | // draw the pins 161 | for (var i = 0; i <= 7; i++) 162 | { 163 | set_in_pin(context, i, (data.input_bitp >> i) & 1); 164 | set_out_pin(context, i, (data.output_bitp >> i) & 1); 165 | } 166 | }); // ajax callback 167 | }; 168 | 169 | /* sets up the page */ 170 | var setup = function() 171 | { 172 | // set some event listeners 173 | for (var i = 0; i <= 7; i++) 174 | $("#pifaceoutputcheckbox"+i).click(output_checkbox_clicked); 175 | 176 | update_piface(); // update now 177 | // update the board every second 178 | update_interval_id = window.setInterval(update_piface, 1000); 179 | }; 180 | 181 | $(document).ready(setup); 182 | -------------------------------------------------------------------------------- /django/projects/httpi/httpi/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for httpi project. 2 | #dir_prefix = "/home/X09/prestotx/raspberry_pi/piface/django/" 3 | dir_prefix = "/home/pi/piface/django/" 4 | 5 | DEBUG = True 6 | 7 | TEMPLATE_DEBUG = DEBUG 8 | 9 | ADMINS = ( 10 | # ('Your Name', 'your_email@example.com'), 11 | ('Thomas Preston', 'thomasmarkpreston@gmail.com'), 12 | ) 13 | 14 | MANAGERS = ADMINS 15 | 16 | DATABASES = { 17 | 'default': { 18 | 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 19 | 'NAME': dir_prefix + 'projects/httpi/database.db', # Or path to database file if using sqlite3. 20 | 'USER': '', # Not used with sqlite3. 21 | 'PASSWORD': '', # Not used with sqlite3. 22 | 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 23 | 'PORT': '', # Set to empty string for default. Not used with sqlite3. 24 | } 25 | } 26 | 27 | # Local time zone for this installation. Choices can be found here: 28 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 29 | # although not all choices may be available on all operating systems. 30 | # On Unix systems, a value of None will cause Django to use the same 31 | # timezone as the operating system. 32 | # If running in a Windows environment this must be set to the same as your 33 | # system time zone. 34 | TIME_ZONE = 'Europe/London' 35 | 36 | # Language code for this installation. All choices can be found here: 37 | # http://www.i18nguy.com/unicode/language-identifiers.html 38 | LANGUAGE_CODE = 'en-gb' 39 | 40 | SITE_ID = 1 41 | 42 | # If you set this to False, Django will make some optimizations so as not 43 | # to load the internationalization machinery. 44 | USE_I18N = True 45 | 46 | # If you set this to False, Django will not format dates, numbers and 47 | # calendars according to the current locale. 48 | USE_L10N = True 49 | 50 | # If you set this to False, Django will not use timezone-aware datetimes. 51 | USE_TZ = True 52 | 53 | # Absolute filesystem path to the directory that will hold user-uploaded files. 54 | # Example: "/home/media/media.lawrence.com/media/" 55 | MEDIA_ROOT = '' 56 | 57 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 58 | # trailing slash. 59 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" 60 | MEDIA_URL = '' 61 | 62 | # Absolute path to the directory static files should be collected to. 63 | # Don't put anything in this directory yourself; store your static files 64 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 65 | # Example: "/home/media/media.lawrence.com/static/" 66 | STATIC_ROOT = dir_prefix + 'projects/httpi/static/' 67 | 68 | # URL prefix for static files. 69 | # Example: "http://media.lawrence.com/static/" 70 | STATIC_URL = '/static/' 71 | 72 | # Additional locations of static files 73 | STATICFILES_DIRS = ( 74 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 75 | # Always use forward slashes, even on Windows. 76 | # Don't forget to use absolute paths, not relative paths. 77 | dir_prefix + 'projects/httpi/httpi/static', 78 | dir_prefix + 'projects/httpi/httpiface/static', 79 | ) 80 | 81 | # List of finder classes that know how to find static files in 82 | # various locations. 83 | STATICFILES_FINDERS = ( 84 | 'django.contrib.staticfiles.finders.FileSystemFinder', 85 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 86 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 87 | ) 88 | 89 | # Make this unique, and don't share it with anybody. 90 | SECRET_KEY = 'dsl64*0nv^&d_c&uv#8#)yj-5kg5q=$%0^ar^(ip6tl7oh*vj8' 91 | 92 | # List of callables that know how to import templates from various sources. 93 | TEMPLATE_LOADERS = ( 94 | 'django.template.loaders.filesystem.Loader', 95 | 'django.template.loaders.app_directories.Loader', 96 | # 'django.template.loaders.eggs.Loader', 97 | ) 98 | 99 | MIDDLEWARE_CLASSES = ( 100 | 'django.middleware.common.CommonMiddleware', 101 | 'django.contrib.sessions.middleware.SessionMiddleware', 102 | 'django.middleware.csrf.CsrfViewMiddleware', 103 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 104 | 'django.contrib.messages.middleware.MessageMiddleware', 105 | # Uncomment the next line for simple clickjacking protection: 106 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 107 | ) 108 | 109 | ROOT_URLCONF = 'httpi.urls' 110 | 111 | # Python dotted path to the WSGI application used by Django's runserver. 112 | WSGI_APPLICATION = 'httpi.wsgi.application' 113 | 114 | TEMPLATE_DIRS = ( 115 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 116 | # Always use forward slashes, even on Windows. 117 | # Don't forget to use absolute paths, not relative paths. 118 | dir_prefix + "templates/" 119 | ) 120 | 121 | INSTALLED_APPS = ( 122 | 'django.contrib.auth', 123 | 'django.contrib.contenttypes', 124 | 'django.contrib.sessions', 125 | 'django.contrib.sites', 126 | 'django.contrib.messages', 127 | 'django.contrib.staticfiles', 128 | # Uncomment the next line to enable the admin: 129 | # 'django.contrib.admin', 130 | # Uncomment the next line to enable admin documentation: 131 | # 'django.contrib.admindocs', 132 | ) 133 | 134 | # A sample logging configuration. The only tangible logging 135 | # performed by this configuration is to send an email to 136 | # the site admins on every HTTP 500 error when DEBUG=False. 137 | # See http://docs.djangoproject.com/en/dev/topics/logging for 138 | # more details on how to customize your logging configuration. 139 | LOGGING = { 140 | 'version': 1, 141 | 'disable_existing_loggers': False, 142 | 'filters': { 143 | 'require_debug_false': { 144 | '()': 'django.utils.log.RequireDebugFalse' 145 | } 146 | }, 147 | 'handlers': { 148 | 'mail_admins': { 149 | 'level': 'ERROR', 150 | 'filters': ['require_debug_false'], 151 | 'class': 'django.utils.log.AdminEmailHandler' 152 | } 153 | }, 154 | 'loggers': { 155 | 'django.request': { 156 | 'handlers': ['mail_admins'], 157 | 'level': 'ERROR', 158 | 'propagate': True, 159 | }, 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /c/src/piface/pfio.c: -------------------------------------------------------------------------------- 1 | /** 2 | * pfio.c 3 | * functions for accessing the PiFace add-on for the Raspberry Pi 4 | */ 5 | #include "pfio.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // /dev/spidev. 16 | #define SPI_BUS 0 17 | #define SPI_DEVICE 0 18 | #define MAXPATH 16 19 | 20 | #define TRANSFER_LEN 3 21 | #define TRANSFER_DELAY 5 22 | #define TRANSFER_SPEED 1000000 23 | #define TRANSFER_BPW 8 24 | 25 | #define SPI_WRITE_CMD 0x40 26 | #define SPI_READ_CMD 0x41 27 | 28 | // Port configuration 29 | #define IODIRA 0x00 // I/O direction A 30 | #define IODIRB 0x01 // I/O direction B 31 | #define IOCON 0x0A // I/O config 32 | #define GPIOA 0x12 // port A 33 | #define GPIOB 0x13 // port B 34 | #define GPPUA 0x0C // port A pullups 35 | #define GPPUB 0x0D // port B pullups 36 | #define OUTPUT_PORT GPIOA 37 | #define INPUT_PORT GPIOB 38 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 39 | 40 | typedef struct 41 | { 42 | int fd; // open file descriptor: /dev/spi-X.Y 43 | int mode; // current SPI mode 44 | int bitsperword; // current SPI bits per word setting 45 | int maxspeed; // current SPI max speed setting in Hz 46 | } Spi; 47 | 48 | #undef VERBOSE_MODE 49 | 50 | static Spi * spi; 51 | 52 | static void spi_transfer(uint8_t * txbuffer, uint8_t * rxbuffer); 53 | static void spi_write(uint8_t port, uint8_t value); 54 | static uint8_t spi_read(uint8_t port); 55 | 56 | 57 | int pfio_init(void) 58 | { 59 | if ((spi = malloc(sizeof(Spi))) == NULL) 60 | return -1; 61 | 62 | // initialise the spi with some values 63 | // create the path string 64 | char path[MAXPATH]; 65 | if (snprintf(path, MAXPATH, "/dev/spidev%d.%d", SPI_BUS, SPI_DEVICE) >= MAXPATH) 66 | { 67 | fprintf(stderr, "ERROR: Bus and/or device number is invalid."); 68 | return -1; 69 | } 70 | 71 | // try to open the device 72 | if ((spi->fd = open(path, O_RDWR, 0)) < 0) 73 | { 74 | fprintf(stderr, "ERROR: Can not open device"); 75 | return -1; 76 | } 77 | 78 | // try to control the device 79 | uint8_t temp; 80 | if (ioctl(spi->fd, SPI_IOC_RD_MODE, &temp) < 0) 81 | { 82 | fprintf(stderr, "ERROR: Can not get spi mode"); 83 | return -1; 84 | } 85 | spi->mode = temp; 86 | 87 | // try to get the bits per word 88 | if (ioctl(spi->fd, SPI_IOC_RD_BITS_PER_WORD, &temp) < 0) 89 | { 90 | fprintf(stderr, "ERROR: Can not get bits per word"); 91 | return -1; 92 | } 93 | spi->bitsperword = temp; 94 | 95 | // try to get the max speed 96 | int maxspeed; 97 | if (ioctl(spi->fd, SPI_IOC_RD_MAX_SPEED_HZ, &maxspeed) < 0) 98 | { 99 | fprintf(stderr, "ERROR: Can not get max speed hz"); 100 | return -1; 101 | } 102 | spi->maxspeed = maxspeed; 103 | 104 | // set up the ports 105 | // fixed SPI addresses so that we don't have that annoying 106 | // LED flashing when initializing pfio. 107 | spi_write(IOCON, 8); // enable hardware addressing 108 | spi_write(GPIOA, 0x00); // turn on port A 109 | spi_write(IODIRA, 0); // set port A as an output 110 | spi_write(IODIRB, 0xFF); // set port B as an input 111 | spi_write(GPPUB, 0xFF); // turn on port B pullups 112 | 113 | // initialise all outputs to 0 114 | int i; 115 | for (i = 1; i <= 8; i++) 116 | pfio_digital_write(i, 0); 117 | 118 | return 0; 119 | } 120 | 121 | int pfio_deinit(void) 122 | { 123 | close(spi->fd); 124 | free(spi); 125 | return 0; 126 | } 127 | 128 | uint8_t pfio_digital_read(uint8_t pin_number) 129 | { 130 | uint8_t current_pin_values = pfio_read_input(); 131 | uint8_t pin_bit_mask = pfio_get_pin_bit_mask(pin_number); 132 | // note: when using bitwise operators and checking if a mask is 133 | // in there it is always better to check if the result equals 134 | // to the desidered mask, in this case pin_bit_mask. 135 | return ( current_pin_values & pin_bit_mask ) == pin_bit_mask; 136 | } 137 | 138 | void pfio_digital_write(uint8_t pin_number, uint8_t value) 139 | { 140 | uint8_t pin_bit_mask = pfio_get_pin_bit_mask(pin_number); 141 | uint8_t old_pin_values = pfio_read_output(); 142 | 143 | uint8_t new_pin_values; 144 | if (value > 0) 145 | new_pin_values = old_pin_values | pin_bit_mask; 146 | else 147 | new_pin_values = old_pin_values & ~pin_bit_mask; 148 | 149 | #ifdef VERBOSE_MODE 150 | printf("digital_write: pin number %d, value %d\n", pin_number, value); 151 | printf("pin bit mask: 0x%x\n", pin_bit_mask); 152 | printf("old pin values: 0x%x\n", old_pin_values); 153 | printf("new pin values: 0x%x\n", new_pin_values); 154 | printf("\n"); 155 | #endif 156 | 157 | pfio_write_output(new_pin_values); 158 | } 159 | 160 | uint8_t pfio_read_input(void) 161 | { 162 | // XOR by 0xFF so we get the right outputs. 163 | // before a turned off input would read as 1, 164 | // confusing developers. 165 | return spi_read(INPUT_PORT) ^ 0xFF; 166 | } 167 | 168 | uint8_t pfio_read_output(void) 169 | { 170 | return spi_read(OUTPUT_PORT); 171 | } 172 | 173 | void pfio_write_output(uint8_t value) 174 | { 175 | spi_write(OUTPUT_PORT, value); 176 | } 177 | 178 | uint8_t pfio_get_pin_bit_mask(uint8_t pin_number) 179 | { 180 | // removed - 1 to reflect pin numbering of 181 | // the python interface (0, 1, ...) instead 182 | // of (1, 2, ...) 183 | return 1 << pin_number; 184 | } 185 | 186 | uint8_t pfio_get_pin_number(uint8_t bit_pattern) 187 | { 188 | uint8_t pin_number = 0; // assume pin 0 189 | while ((bit_pattern & 1) == 0) 190 | { 191 | bit_pattern >>= 1; 192 | if (++pin_number > 7) 193 | { 194 | pin_number = 0; 195 | break; 196 | } 197 | } 198 | return pin_number; 199 | } 200 | 201 | 202 | static void spi_transfer(uint8_t * txbuffer, uint8_t * rxbuffer) 203 | { 204 | // set up some transfer information 205 | struct spi_ioc_transfer transfer_buffer = 206 | { 207 | .tx_buf = (unsigned long) txbuffer, 208 | .rx_buf = (unsigned long) rxbuffer, 209 | .len = TRANSFER_LEN, 210 | .delay_usecs = TRANSFER_DELAY, 211 | .speed_hz = TRANSFER_SPEED, 212 | .bits_per_word = TRANSFER_BPW, 213 | }; 214 | 215 | // actually do the transfer 216 | if (ioctl(spi->fd, SPI_IOC_MESSAGE(1), &transfer_buffer) < 1) 217 | { 218 | fprintf(stderr, "ERROR: Can not send SPI message"); 219 | perror(0); 220 | } 221 | } 222 | 223 | static void spi_write(uint8_t port, uint8_t value) 224 | { 225 | uint8_t txbuffer[] = {SPI_WRITE_CMD, port, value}; 226 | uint8_t rxbuffer[ARRAY_SIZE(txbuffer)]; 227 | spi_transfer(txbuffer, rxbuffer); 228 | } 229 | 230 | static uint8_t spi_read(uint8_t port) 231 | { 232 | uint8_t txbuffer[] = {SPI_READ_CMD, port, 0xff}; 233 | uint8_t rxbuffer[ARRAY_SIZE(txbuffer)]; 234 | spi_transfer(txbuffer, rxbuffer); 235 | return rxbuffer[2]; 236 | } 237 | -------------------------------------------------------------------------------- /scratch/scratch_handler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from array import array 4 | from time import sleep 5 | import threading 6 | import socket 7 | import sys 8 | import struct 9 | 10 | if "-e" in sys.argv: 11 | import piface.emulator as pfio 12 | sys.argv.remove("-e") 13 | else: 14 | import piface.pfio as pfio 15 | 16 | PORT = 42001 17 | DEFAULT_HOST = '127.0.0.1' 18 | BUFFER_SIZE = 100 19 | SOCKET_TIMEOUT = 1 20 | SENDER_DELAY = 0.02 # poll the Pi Face every 20ms 21 | 22 | SCRATCH_SENSOR_NAME_INPUT = ( 23 | 'piface-input1', 24 | 'piface-input2', 25 | 'piface-input3', 26 | 'piface-input4', 27 | 'piface-input5', 28 | 'piface-input6', 29 | 'piface-input7', 30 | 'piface-input8') 31 | 32 | SCRATCH_SENSOR_NAME_OUTPUT = ( 33 | 'piface-output1', 34 | 'piface-output2', 35 | 'piface-output3', 36 | 'piface-output4', 37 | 'piface-output5', 38 | 'piface-output6', 39 | 'piface-output7', 40 | 'piface-output8') 41 | 42 | 43 | class ScratchSender(threading.Thread): 44 | def __init__(self, socket): 45 | threading.Thread.__init__(self) 46 | self.scratch_socket = socket 47 | self._stop = threading.Event() 48 | 49 | # make scratch aware of the pins 50 | for i in range(len(SCRATCH_SENSOR_NAME_INPUT)): 51 | self.broadcast_pin_update(i, 0) 52 | 53 | def stop(self): 54 | self._stop.set() 55 | 56 | def stopped(self): 57 | return self._stop.isSet() 58 | 59 | def run(self): 60 | last_bit_pattern = 0 61 | while not self.stopped(): 62 | sleep(SENDER_DELAY) 63 | pin_bit_pattern = pfio.read_input() 64 | 65 | # if there is a change in the input pins 66 | changed_pins = pin_bit_pattern ^ last_bit_pattern 67 | if changed_pins: 68 | try: 69 | self.broadcast_changed_pins(changed_pins, pin_bit_pattern) 70 | except Exception as e: 71 | print e 72 | break 73 | 74 | last_bit_pattern = pin_bit_pattern 75 | 76 | def broadcast_changed_pins(self, changed_pin_map, pin_value_map): 77 | for i in range(8): 78 | # if we care about this pin's value 79 | if (changed_pin_map >> i) & 0b1: 80 | pin_value = (pin_value_map >> i) & 0b1 81 | self.broadcast_pin_update(i, pin_value) 82 | 83 | def broadcast_pin_update(self, pin_index, value): 84 | sensor_name = SCRATCH_SENSOR_NAME_INPUT[pin_index] 85 | bcast_str = 'sensor-update "%s" %d' % (sensor_name, value) 86 | print 'sending: %s' % bcast_str 87 | self.send_scratch_command(bcast_str) 88 | 89 | def send_scratch_command(self, cmd): 90 | n = len(cmd) 91 | a = array('c') 92 | a.append(chr((n >> 24) & 0xFF)) 93 | a.append(chr((n >> 16) & 0xFF)) 94 | a.append(chr((n >> 8) & 0xFF)) 95 | a.append(chr(n & 0xFF)) 96 | self.scratch_socket.send(a.tostring() + cmd) 97 | 98 | class ScratchListener(threading.Thread): 99 | def __init__(self, socket): 100 | threading.Thread.__init__(self) 101 | self.scratch_socket = socket 102 | self._stop = threading.Event() 103 | 104 | self.last_zero_bit_mask = 0 105 | self.last_one_bit_mask = 0 106 | 107 | def stop(self): 108 | self._stop.set() 109 | 110 | def stopped(self): 111 | return self._stop.isSet() 112 | 113 | def run(self): 114 | while not self.stopped(): 115 | try: 116 | data = self.scratch_socket.recv(BUFFER_SIZE) 117 | #length = struct.unpack( 118 | # '>i', 119 | # '%c%c%c%c' % (data[0], data[1], data[2], data[3]) 120 | # )[0] 121 | data = data[4:] # get rid of the length info 122 | #print 'Length: %d, Data: %s' % (length, data) 123 | 124 | except socket.timeout: # if we timeout, re-loop 125 | continue 126 | except: # exit on any other errrors 127 | break 128 | 129 | data = data.split(" ") 130 | 131 | if data[0] == 'sensor-update': 132 | data = data[1:] 133 | print 'received sensor-update:', data 134 | self.sensor_update(data) 135 | 136 | elif data[0] == 'broadcast': 137 | data = data[1:] 138 | print 'received broadcast:', data 139 | 140 | else: 141 | print 'received something:', data 142 | 143 | def sensor_update(self, data): 144 | index_is_data = False # ignore the loop contents if not sensor 145 | zero_bit_mask = 0 # bit mask showing where zeros should be written 146 | one_bit_mask = 0 # bit mask showing where ones should be written 147 | we_should_update_piface = False 148 | 149 | # go through all of the sensors that have been updated 150 | for i in range(len(data)): 151 | 152 | if index_is_data: 153 | index_is_data = False 154 | continue 155 | 156 | sensor_name = data[i].strip('"') 157 | 158 | # if this sensor is a piface output then reflect 159 | # that update on the board 160 | if sensor_name in SCRATCH_SENSOR_NAME_OUTPUT: 161 | we_should_update_piface = True 162 | pin_index = SCRATCH_SENSOR_NAME_OUTPUT.index(sensor_name) 163 | sensor_value = int(data[i+1]) 164 | index_is_data = True 165 | 166 | # could this be made more efficient by sending a single write 167 | if sensor_value == 0: 168 | zero_bit_mask ^= (1 << pin_index) 169 | 170 | else: 171 | one_bit_mask ^= (1 << pin_index) 172 | 173 | if we_should_update_piface: 174 | old_pin_bitp = pfio.read_output() # grab the old values 175 | new_pin_bitp = old_pin_bitp & ~zero_bit_mask # set the zeros 176 | new_pin_bitp |= one_bit_mask # set the ones 177 | 178 | if new_pin_bitp != old_pin_bitp: 179 | pfio.write_output(new_pin_bitp) # write the new bit pattern 180 | 181 | 182 | def create_socket(host, port): 183 | try: 184 | scratch_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 185 | scratch_sock.connect((host, port)) 186 | except socket.error: 187 | print "There was an error connecting to Scratch!" 188 | print "I couldn't find a Mesh session at host: %s, port: %s" % (host, port) 189 | sys.exit(1) 190 | 191 | return scratch_sock 192 | 193 | def cleanup_threads(threads): 194 | for thread in threads: 195 | thread.stop() 196 | 197 | for thread in threads: 198 | thread.join() 199 | 200 | if __name__ == '__main__': 201 | if len(sys.argv) > 1: 202 | host = sys.argv[1] 203 | else: 204 | host = DEFAULT_HOST 205 | 206 | # open the socket 207 | print 'Connecting...' , 208 | the_socket = create_socket(host, PORT) 209 | print 'Connected!' 210 | 211 | the_socket.settimeout(SOCKET_TIMEOUT) 212 | 213 | pfio.init() 214 | 215 | listener = ScratchListener(the_socket) 216 | sender = ScratchSender(the_socket) 217 | listener.start() 218 | sender.start() 219 | 220 | # wait for ctrl+c 221 | try: 222 | while True: 223 | pass 224 | except KeyboardInterrupt: 225 | cleanup_threads((listener, sender)) 226 | pfio.deinit() 227 | sys.exit() 228 | -------------------------------------------------------------------------------- /python/demos/racingpi/game.py: -------------------------------------------------------------------------------- 1 | """ 2 | RacingPi Game 3 | Contains the code for running the actual game 4 | """ 5 | import time 6 | import threading 7 | import random 8 | 9 | import piface.pfio as pfio 10 | #import piface.emulator as pfio 11 | 12 | 13 | VERBOSE_MODE = True 14 | 15 | DEFAULT_QUESTION_FILE = "racingpi/questions.txt" 16 | 17 | 18 | class UnknownButtonError(Exception): 19 | pass 20 | 21 | 22 | class RacingPiGame(threading.Thread): 23 | def __init__(self, gui, question_file_name=None): 24 | threading.Thread.__init__(self) 25 | self.gui = gui 26 | 27 | self.question_file_name = question_file_name 28 | # set up the hardware interface 29 | pfio.init() 30 | 31 | # set up the buttons 32 | self.buttons = list() 33 | self.buttons.append(Button(ButtonSwitch(1), ButtonLight(3))) 34 | self.buttons.append(Button(ButtonSwitch(2), ButtonLight(4))) 35 | self.buttons.append(Button(ButtonSwitch(3), ButtonLight(5))) 36 | self.buttons.append(Button(ButtonSwitch(4), ButtonLight(6))) 37 | self.buttons.append(Button(ButtonSwitch(5), ButtonLight(7))) 38 | 39 | # set up the players 40 | self.player1 = Player("Adam", RacingCar(1), (self.buttons[0], self.buttons[1])) 41 | self.player2 = Player("Eve", RacingCar(2), (self.buttons[2], self.buttons[3])) 42 | 43 | """ 44 | Threading stopper idea from stack overflow 45 | http://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python 46 | """ 47 | self._stop = threading.Event() # a stopper to know when to end the game 48 | 49 | def stop(self): 50 | self._stop.set() 51 | 52 | def stopped(self): 53 | return self._stop.isSet() 54 | 55 | 56 | def run(self): 57 | """The main game stuff goes here""" 58 | while True: 59 | # set up the questions 60 | if self.question_file_name: 61 | question_file = open(question_file_name, "r") 62 | else: 63 | question_file = open(DEFAULT_QUESTION_FILE, "r") 64 | 65 | self.questions = list() 66 | for line in question_file.readlines(): 67 | q_parts = line.split(",") # this can be moved into db later... 68 | self.questions.append(Question(q_parts[0], q_parts[1], q_parts[2])) 69 | 70 | random.shuffle(self.questions) 71 | 72 | self.ask_questions() 73 | if self.stopped(): 74 | break 75 | 76 | self.stop() 77 | pfio.deinit() 78 | 79 | def ask_questions(self): 80 | for question in self.questions: 81 | # ask a question 82 | correct_answer_index = int(2 * random.random()) 83 | wrong_answer_index = correct_answer_index ^ 1 84 | answers = ["", ""] 85 | answers[correct_answer_index] = question.correct_answer 86 | answers[wrong_answer_index] = question.wrong_answer 87 | 88 | values = [question.text] 89 | values.extend(answers) 90 | self.gui.update_question("%s\nA: %s\nB: %s" % tuple(values)) 91 | 92 | # wait for a button press 93 | pin_bit_pattern = pfio.read_input() 94 | while pin_bit_pattern == 0 and not self.stopped(): 95 | pin_bit_pattern = pfio.read_input() 96 | 97 | # since we can't have multi-leveled break statements... 98 | if self.stopped(): 99 | break 100 | 101 | # find out which button was pressed 102 | pin_number = pfio.get_pin_number(pin_bit_pattern) 103 | 104 | #print "pin number: %d" % pin_number 105 | #print self.player1.buttons[correct_answer_index].switch.pin_number 106 | 107 | if pin_number == self.player1.buttons[correct_answer_index].switch.pin_number: 108 | self.player1.buttons[correct_answer_index].light.turn_on() 109 | print "Player 1 got the correct answer!" 110 | #print "The answer was: {}".format(question.correct_answer) 111 | self.gui.update_question("%s\n\nThe correct answer was: %s\n\nPlayer 1 has 3 seconds to race!" % (question.text, question.correct_answer)) 112 | self.player1.car.drive(3) 113 | self.player1.buttons[correct_answer_index].light.turn_off() 114 | 115 | elif pin_number == self.player1.buttons[wrong_answer_index].switch.pin_number: 116 | self.player1.buttons[wrong_answer_index].light.turn_on() 117 | print "Player 1 got the WRONG answer!" 118 | #print "The answer was: {}".format(question.correct_answer) 119 | self.gui.update_question("%s\n\nThe correct answer was: %s\n\nPlayer 2 has 3 seconds to race!" % (question.text, question.correct_answer)) 120 | self.player2.car.drive(3) 121 | self.player1.buttons[wrong_answer_index].light.turn_off() 122 | 123 | elif pin_number == self.player2.buttons[correct_answer_index].switch.pin_number: 124 | self.player2.buttons[correct_answer_index].light.turn_on() 125 | print "Player 2 got the correct answer!" 126 | #print "The answer was: {}".format(question.correct_answer) 127 | self.gui.update_question("%s\n\nThe correct answer was: %s\n\nPlayer 2 has 3 seconds to race!" % (question.text, question.correct_answer)) 128 | self.player2.car.drive(3) 129 | self.player2.buttons[correct_answer_index].light.turn_off() 130 | 131 | elif pin_number == self.player2.buttons[wrong_answer_index].switch.pin_number: 132 | self.player2.buttons[wrong_answer_index].light.turn_on() 133 | print "Player 2 got the WRONG answer!" 134 | #print "The answer was: {}".format(question.correct_answer) 135 | self.gui.update_question("%s\n\nThe correct answer was: %s\n\nPlayer 1 has 3 seconds to race!" % (question.text, question.correct_answer)) 136 | self.player1.car.drive(3) 137 | self.player2.buttons[wrong_answer_index].light.turn_off() 138 | 139 | elif pin_number == self.buttons[4].switch.pin_number: 140 | self.buttons[4].light.turn_on() 141 | print "PASS" 142 | #print "The answer was: {}".format(question.correct_answer) 143 | time.sleep(1) 144 | self.buttons[4].light.turn_off() 145 | 146 | else: 147 | raise UnknownButtonError("detected change on pin: %d" % pin_number) 148 | 149 | # wait until nothing is pressed 150 | pin_bit_pattern = pfio.read_input() 151 | while pin_bit_pattern != 0: 152 | pin_bit_pattern = pfio.read_input() 153 | 154 | # should we keep playing? 155 | if self.stopped(): 156 | break 157 | 158 | class RacingCar(pfio.Relay): 159 | def __init__(self, racing_car_number): 160 | # racing car number directly translates to the relay number 161 | pfio.Relay.__init__(self, racing_car_number) 162 | 163 | def drive(self, drive_period): 164 | """Move the car for the specified amount of seconds""" 165 | self.turn_on() 166 | time.sleep(drive_period) 167 | self.turn_off() 168 | 169 | class ButtonLight(pfio.OutputItem): 170 | def __init__(self, button_number): 171 | # button lights are connected directly to pins 172 | pfio.OutputItem.__init__(self, button_number) 173 | 174 | class ButtonSwitch(pfio.InputItem): 175 | def __init__(self, button_number): 176 | # button switches are connected directly to pins 177 | pfio.InputItem.__init__(self, button_number, True) # input 178 | 179 | class Button(object): 180 | def __init__(self, button_switch, button_light): 181 | self.switch = button_switch 182 | self.light = button_light 183 | 184 | class Player(object): 185 | def __init__(self, name, car, buttons): 186 | self.name = name 187 | self.car = car 188 | self.buttons = buttons 189 | self.points = 0 190 | 191 | class Question(object): 192 | def __init__(self, question_text, correct_answer, wrong_answer): 193 | self.text = question_text 194 | self.correct_answer = correct_answer 195 | self.wrong_answer = wrong_answer 196 | -------------------------------------------------------------------------------- /python/piface/spivisualiser.py: -------------------------------------------------------------------------------- 1 | """ 2 | spivisualiser.py 3 | An SPI visualiser for sending SPI packets to the SPI port 4 | """ 5 | import pygtk 6 | pygtk.require("2.0") 7 | import gtk 8 | 9 | import pfio 10 | 11 | 12 | MAX_SPI_LOGS = 50 13 | 14 | 15 | class SpiVisualiserSection(gtk.ScrolledWindow): 16 | def __init__(self, rpi_emulator=None): 17 | gtk.ScrolledWindow.__init__(self) 18 | self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) 19 | 20 | self.rpi_emulator = rpi_emulator 21 | 22 | # create a liststore with three string columns to use as the model 23 | self.liststore = gtk.ListStore(str, str, str, str, str) 24 | self.liststoresize = 0 25 | 26 | # create the TreeView using liststore 27 | self.treeview = gtk.TreeView(self.liststore) 28 | self.treeview.connect('size-allocate', self.treeview_changed) 29 | 30 | # create the TreeViewColumns to display the data 31 | self.tvcolumn = (gtk.TreeViewColumn('Time'), 32 | gtk.TreeViewColumn('In'), 33 | gtk.TreeViewColumn('In Breakdown'), 34 | gtk.TreeViewColumn('Out'), 35 | gtk.TreeViewColumn('Out Breakdown')) 36 | 37 | # add columns to treeview 38 | for column in self.tvcolumn: 39 | self.treeview.append_column(column) 40 | 41 | # create a CellRenderers to render the data 42 | self.cell = [gtk.CellRendererText() for i in range(5)] 43 | 44 | # set background color property 45 | self.cell[0].set_property('cell-background', 'cyan') 46 | self.cell[1].set_property('cell-background', '#87ea87') 47 | self.cell[2].set_property('cell-background', '#98fb98') 48 | self.cell[3].set_property('cell-background', '#ffccbb') 49 | self.cell[4].set_property('cell-background', '#ffddcc') 50 | 51 | # add the cells to the columns 52 | for i in range(len(self.tvcolumn)): 53 | self.tvcolumn[i].pack_start(self.cell[i], True) 54 | 55 | for i in range(len(self.tvcolumn)): 56 | self.tvcolumn[i].set_attributes(self.cell[i], text=i) 57 | 58 | # make treeview searchable 59 | self.treeview.set_search_column(0) 60 | 61 | # Allow sorting on the column 62 | self.tvcolumn[0].set_sort_column_id(0) 63 | 64 | # Allow drag and drop reordering of rows 65 | self.treeview.set_reorderable(True) 66 | 67 | self.add(self.treeview) 68 | self.treeview.show() 69 | 70 | def treeview_changed(self, widget, event, data=None): 71 | adjustment = self.get_vadjustment() 72 | adjustment.set_value(adjustment.upper - adjustment.page_size) 73 | 74 | def add_spi_log(self, time, data_tx, data_rx, custom_spi=False): 75 | if self.liststoresize >= MAX_SPI_LOGS: 76 | #remove the first item 77 | first_row_iter = self.treeview.get_model()[0].iter 78 | self.liststore.remove(first_row_iter) 79 | else: 80 | self.liststoresize += 1 81 | 82 | data_tx_breakdown = self.get_data_breakdown(data_tx) 83 | data_rx_breakdown = self.get_data_breakdown(data_rx) 84 | 85 | if custom_spi: 86 | in_fmt = "[0x%06x]" # use a special format 87 | else: 88 | in_fmt = "0x%06x" 89 | 90 | out_fmt = "0x%06x" 91 | 92 | data_tx_str = in_fmt % data_tx 93 | data_rx_str = out_fmt % data_rx 94 | 95 | if self.rpi_emulator: 96 | self.rpi_emulator.spi_liststore_lock.acquire() 97 | 98 | self.liststore.append((time, data_tx_str, data_tx_breakdown, data_rx_str, data_rx_breakdown)) 99 | 100 | if self.rpi_emulator: 101 | self.rpi_emulator.spi_liststore_lock.release() 102 | 103 | def get_data_breakdown(self, raw_data): 104 | cmd = (raw_data >> 16) & 0xff 105 | if cmd == pfio.WRITE_CMD: 106 | cmd = "WRITE" 107 | elif cmd == pfio.READ_CMD: 108 | cmd = "READ" 109 | else: 110 | cmd = hex(cmd) 111 | 112 | port = (raw_data >> 8) & 0xff 113 | if port == pfio.IODIRA: 114 | port = "IODIRA" 115 | elif port == pfio.IODIRB: 116 | port = "IODIRB" 117 | elif port == pfio.IOCON: 118 | port = "IOCON" 119 | elif port == pfio.GPIOA: 120 | port = "GPIOA" 121 | elif port == pfio.GPIOB: 122 | port = "GPIOB" 123 | elif port == pfio.GPPUA: 124 | port = "GPPUA" 125 | elif port == pfio.GPPUB: 126 | port = "GPPUB" 127 | else: 128 | port = hex(port) 129 | 130 | data = hex(raw_data & 0xff) 131 | 132 | data_breakdown = "cmd: %s, port: %s, data: %s" % (cmd, port, data) 133 | return data_breakdown 134 | 135 | class SpiSenderSection(gtk.HBox): 136 | def __init__(self, rpi_emulator=None): 137 | gtk.HBox.__init__(self, False) 138 | 139 | self.rpi_emulator = rpi_emulator 140 | 141 | label = gtk.Label("SPI Input: ") 142 | label.show() 143 | 144 | self.spi_input = gtk.Entry() 145 | self.spi_input.set_text("0x0") 146 | self.spi_input.show() 147 | 148 | button = gtk.Button("Send") 149 | button.connect("clicked", self.send_spi_message) 150 | button.show() 151 | 152 | self.error_label = gtk.Label() 153 | self.error_label.show() 154 | 155 | if self.rpi_emulator: 156 | self.update_emu_button = gtk.Button("Update Emulator") 157 | self.update_emu_button.connect("clicked", self.update_emu_button_pressed) 158 | self.update_emu_button.show() 159 | else: 160 | self.pfio_init_button = gtk.Button("Initialise PFIO") 161 | self.pfio_init_button.connect("clicked", self.init_pfio) 162 | self.pfio_init_button.show() 163 | 164 | self.pack_start(child=label, expand=False) 165 | self.pack_start(child=self.spi_input, expand=False) 166 | self.pack_start(child=button, expand=False) 167 | self.pack_start(child=self.error_label, expand=False) 168 | 169 | if self.rpi_emulator: 170 | self.pack_end(child=self.update_emu_button, expand=False) 171 | else: 172 | self.pack_end(child=self.pfio_init_button, expand=False) 173 | 174 | def __set_error_label_text(self, text): 175 | self.__error_text = text 176 | self.error_label.set_markup(" %s" % self.__error_text) 177 | 178 | def __get_error_label_text(self): 179 | return self.__error_text 180 | 181 | error_text = property(__get_error_label_text, __set_error_label_text) 182 | 183 | def send_spi_message(self, widget, data=None): 184 | self.error_text = "" 185 | spi_message = 0 186 | user_input = self.spi_input.get_text() 187 | try: 188 | if "0x" == user_input[:2]: 189 | spi_message = int(user_input, 16) 190 | elif "0b"== user_input[:2]: 191 | spi_message = int(user_input, 2) 192 | else: 193 | spi_message = int(user_input) 194 | 195 | # check we are three bytes long 196 | if len(hex(spi_message)[2:]) > 6: 197 | raise ValueError() 198 | 199 | except ValueError: 200 | msg = "Invalid SPI message" 201 | self.error_text = msg 202 | print msg 203 | return 204 | 205 | 206 | cmd = (spi_message >> 16) & 0xff 207 | port = (spi_message >> 8) & 0xff 208 | data = (spi_message) & 0xff 209 | pfio.send([(cmd, port, data)], True) 210 | 211 | def update_emu_button_pressed(self, widget, data=None): 212 | self.rpi_emulator.output_override_section.reset_buttons() 213 | self.rpi_emulator.emu_screen.update_voutput_pins() 214 | 215 | def init_pfio(self, widget, data=None): 216 | pfio.init() 217 | 218 | 219 | def init(): 220 | window = gtk.Window() 221 | window.connect("delete-event", gtk.main_quit) 222 | window.set_title("SPI Visualiser") 223 | window.set_size_request(500, 200) 224 | 225 | visualiser = SpiVisualiserSection() 226 | sender = SpiSenderSection() 227 | 228 | pfio.spi_handler = pfio.get_spi_handler() 229 | pfio.spi_visualiser_section = visualiser 230 | 231 | visualiser.show() 232 | sender.show() 233 | 234 | container = gtk.VBox() 235 | container.pack_start(child=visualiser, expand=True, fill=True) 236 | container.pack_start(child=sender, expand=False) 237 | container.show() 238 | window.add(container) 239 | window.show() 240 | gtk.main() 241 | -------------------------------------------------------------------------------- /python/piface/pfion.py: -------------------------------------------------------------------------------- 1 | """ 2 | pfion.py 3 | A network version of the pfio - can talk to Pi Face's over a network 4 | """ 5 | import socket 6 | import threading 7 | import struct 8 | import pfio 9 | 10 | 11 | DEFAULT_PORT = 15432 12 | BUFFER_SIZE = 100 13 | 14 | UNKNOWN_CMD = 0 15 | WRITE_OUT_CMD = 1 16 | WRITE_OUT_ACK = 2 17 | READ_OUT_CMD = 3 18 | READ_OUT_ACK = 4 19 | READ_IN_CMD = 5 20 | READ_IN_ACK = 6 21 | DIGITAL_WRITE_CMD = 7 22 | DIGITAL_WRITE_ACK = 8 23 | DIGITAL_READ_CMD = 9 24 | DIGITAL_READ_ACK = 10 25 | 26 | STRUCT_UNIT_TYPE = "B" 27 | 28 | """ 29 | # testing without pfio 30 | outpins = 0 31 | inpins = 0 32 | def fakepfioinit(): 33 | pass 34 | def fakepfiowrite(something): 35 | print "writing ", something 36 | global outpins 37 | outpins = something 38 | def fakepfioreadin(): 39 | print "read in" 40 | return 0b10101010 41 | def fakepfioreadout(): 42 | print "read out" 43 | global outpins 44 | return outpins 45 | pfio.init = fakepfioinit 46 | pfio.write_output = fakepfiowrite 47 | pfio.read_input = fakepfioreadin 48 | pfio.read_output = fakepfioreadout 49 | """ 50 | 51 | 52 | class UnknownPacketReceivedError(Exception): 53 | pass 54 | 55 | 56 | class PfionPacket(object): 57 | """Models a Pfio network packet""" 58 | def __init__(self, command=UNKNOWN_CMD): 59 | self.command = command 60 | self.cmd_data = 0 # 1 byte of data associated with the cmd 61 | self.data = "" # extra data as a string 62 | 63 | def for_network(self): 64 | """Returns this pfion packet as a struct+data""" 65 | pcmddata = struct.pack(STRUCT_UNIT_TYPE*2, self.command, self.cmd_data) 66 | return pcmddata + self.data 67 | 68 | def from_network(self, raw_struct): 69 | """Returns this pfion packet with new values interpereted from 70 | the struct+data given in""" 71 | self.command, = struct.unpack(STRUCT_UNIT_TYPE, raw_struct[0]) 72 | self.cmd_data, = struct.unpack(STRUCT_UNIT_TYPE, raw_struct[1]) 73 | self.data = raw_struct[2:] 74 | return self 75 | 76 | """Pin number and pin value are stored in the upper and lower 77 | nibbles of the first data byte respectively. These are for digital 78 | read and digital write operations""" 79 | def _get_pin_number(self): 80 | return self.cmd_data >> 4 81 | 82 | def _set_pin_number(self, new_pin_number): 83 | self.cmd_data = (new_pin_number << 4) ^ (self.cmd_data & 0xf) 84 | 85 | pin_number = property(_get_pin_number, _set_pin_number) 86 | 87 | def _get_pin_value(self): 88 | return self.cmd_data & 0xf 89 | 90 | def _set_pin_value(self, new_pin_value): 91 | self.cmd_data = (new_pin_value & 0xf) ^ (self.cmd_data & 0xf0) 92 | 93 | pin_value = property(_get_pin_value, _set_pin_value) 94 | 95 | def _get_bit_pattern(self): 96 | return self.cmd_data 97 | 98 | def _set_bit_pattern(self, new_bit_pattern): 99 | self.cmd_data = new_bit_pattern & 0xff 100 | 101 | bit_pattern = property(_get_bit_pattern, _set_bit_pattern) 102 | 103 | 104 | def start_pfio_server(callback=None, verbose=False, port=DEFAULT_PORT): 105 | """Starts listening for pfio packets over the network""" 106 | pfio.init() 107 | try: 108 | # this returns the loopback ip on the RPi :-( 109 | #hostname = socket.gethostname() 110 | 111 | ################################################### 112 | # this is pretty hacky, if anyone can find a better 113 | # solution, then please change this! 114 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 115 | s.connect(("8.8.8.8", 80)) # try to connect to google's dns 116 | hostname = s.getsockname()[0] # get this device's hostname 117 | s.close() 118 | # blergh, nasty stuff 119 | ################################################### 120 | 121 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 122 | sock.bind((hostname, port)) 123 | 124 | except socket.error as e: 125 | print "There was an error setting up the server socket!" 126 | print e 127 | return 128 | 129 | else: 130 | if verbose: 131 | print "Listening at %s on port %d" % (hostname, port) 132 | 133 | while True: 134 | # get the packet 135 | packet, sender = sock.recvfrom(BUFFER_SIZE) 136 | if verbose: 137 | print "Recieved packet from", sender 138 | # make it something sensible 139 | packet = PfionPacket().from_network(packet) 140 | 141 | if packet.command == WRITE_OUT_CMD: 142 | pfio.write_output(packet.bit_pattern) 143 | p = PfionPacket(WRITE_OUT_ACK) 144 | sock.sendto(p.for_network(), sender) 145 | 146 | elif packet.command == READ_OUT_CMD: 147 | output_bitp = pfio.read_output() 148 | p = PfionPacket(READ_OUT_ACK) 149 | p.bit_pattern = output_bitp 150 | sock.sendto(p.for_network(), sender) 151 | 152 | elif packet.command == READ_IN_CMD: 153 | input_bitp = pfio.read_input() 154 | p = PfionPacket(READ_IN_ACK) 155 | p.bit_pattern = input_bitp 156 | sock.sendto(p.for_network(), sender) 157 | 158 | elif packet.command == DIGITAL_WRITE_CMD: 159 | pfio.digital_write(packet.pin_number, packet.pin_value) 160 | p = PfionPacket(DIGITAL_WRITE_ACK) 161 | sock.sendto(p.for_network(), sender) 162 | 163 | elif packet.command == DIGITAL_READ_CMD: 164 | pin_value = pfio.digital_read(packet.pin_number) 165 | p = PfionPacket(DIGITAL_READ_ACK) 166 | p.pin_number = packet.pin_number 167 | p.pin_value = pin_value 168 | sock.sendto(p.for_network(), sender) 169 | 170 | elif callback != None: 171 | callback(packet, sender) 172 | 173 | elif verbose: 174 | print "Unkown packet command (%d). Ignoring." % packet.command 175 | 176 | # sending functions 177 | def send_packet(packet, hostname, port=DEFAULT_PORT): 178 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 179 | sock.sendto(packet.for_network(), (hostname, port)) 180 | return sock 181 | 182 | def send_write_output(output_bitp, hostname, port=DEFAULT_PORT): 183 | packet = PfionPacket(WRITE_OUT_CMD) 184 | packet.bit_pattern = output_bitp 185 | sock = send_packet(packet, hostname) 186 | p, sender = sock.recvfrom(BUFFER_SIZE) 187 | packet = PfionPacket().from_network(p) 188 | if packet.command != WRITE_OUT_ACK: 189 | raise UnknownPacketReceivedError( 190 | "Received packet command (%d) was not WRITE_OUT_ACK" % 191 | packet.command) 192 | 193 | def send_read_output(hostname, port=DEFAULT_PORT): 194 | packet = PfionPacket(READ_OUT_CMD) 195 | sock = send_packet(packet, hostname) 196 | p, sender = sock.recvfrom(BUFFER_SIZE) 197 | packet = PfionPacket().from_network(p) 198 | if packet.command == READ_OUT_ACK: 199 | return packet.bit_pattern 200 | else: 201 | raise UnknownPacketReceivedError( 202 | "Received packet command (%d) was not READ_OUT_ACK" % 203 | packet.command) 204 | 205 | def send_read_input(hostname, port=DEFAULT_PORT): 206 | packet = PfionPacket(READ_IN_CMD) 207 | sock = send_packet(packet, hostname) 208 | p, sender = sock.recvfrom(BUFFER_SIZE) 209 | packet = PfionPacket().from_network(p) 210 | if packet.command == READ_IN_ACK: 211 | return packet.bit_pattern 212 | else: 213 | raise UnknownPacketReceivedError( 214 | "Received packet command (%d) was not READ_IN_ACK" % 215 | packet.command) 216 | 217 | def send_digital_write(pin_number, pin_value, hostname, port=DEFAULT_PORT): 218 | packet = PfionPacket(DIGITAL_WRITE_CMD) 219 | packet.pin_number = pin_number 220 | packet.pin_value = pin_value 221 | sock = send_packet(packet, hostname) 222 | p, sender = sock.recvfrom(BUFFER_SIZE) 223 | packet = PfionPacket().from_network(p) 224 | if packet.command != DIGITAL_WRITE_ACK: 225 | raise UnknownPacketReceivedError( 226 | "Received packet command (%d) was not DIGITAL_WRITE_ACK" % 227 | packet.command) 228 | 229 | def send_digital_read(pin_number, hostname, port=DEFAULT_PORT): 230 | packet = PfionPacket(DIGITAL_READ_CMD) 231 | packet.pin_number = pin_number 232 | sock = send_packet(packet, hostname) 233 | p, sender = sock.recvfrom(BUFFER_SIZE) 234 | packet = PfionPacket().from_network(p) 235 | if packet.command == DIGITAL_READ_ACK: 236 | return packet.pin_value 237 | else: 238 | raise UnknownPacketReceivedError( 239 | "Received packet command (%d) was not DIGITAL_READ_ACK" % 240 | packet.command) 241 | -------------------------------------------------------------------------------- /python/piface/spimodule.c: -------------------------------------------------------------------------------- 1 | /* 2 | * spimodule.c - Python bindings for Linux SPI access through spidev 3 | * Copyright (C) 2009 Volker Thoms 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; version 2 of the License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | */ 18 | 19 | #include 20 | #include "structmember.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | //#define VERBOSE_MODE // comment out to turn off debugging 30 | 31 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 32 | #define MAXPATH 16 33 | 34 | PyDoc_STRVAR(SPI_module_doc, 35 | "This module defines an object type that allows SPI transactions\n" 36 | "on hosts running the Linux kernel. The host kernel must have SPI\n" 37 | "support and SPI device interface support.\n" 38 | "All of these can be either built-in to the kernel, or loaded from\n" 39 | "modules.\n" 40 | "\n" 41 | "Because the SPI device interface is opened R/W, users of this\n" 42 | "module usually must have root permissions.\n"); 43 | 44 | typedef struct { 45 | PyObject_HEAD 46 | 47 | int fd; /* open file descriptor: /dev/spi-X.Y */ 48 | uint8_t mode; /* current SPI mode */ 49 | uint8_t bpw; /* current SPI bits per word setting */ 50 | uint32_t msh; /* current SPI max speed setting in Hz */ 51 | } SPI; 52 | 53 | static PyObject * SpiError; // special exception 54 | 55 | static PyObject * 56 | SPI_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 57 | { 58 | SPI *self; 59 | if ((self = (SPI *)type->tp_alloc(type, 0)) == NULL) 60 | return NULL; 61 | 62 | self->fd = -1; 63 | self->mode = 0; 64 | self->bpw = 0; 65 | self->msh = 0; 66 | 67 | Py_INCREF(self); 68 | return (PyObject *)self; 69 | } 70 | 71 | PyDoc_STRVAR(SPI_close_doc, 72 | "close()\n\n" 73 | "Disconnects the object from the interface.\n"); 74 | 75 | 76 | static PyObject *SPI_close(SPI *self) 77 | { 78 | if ((self->fd != -1) && (close(self->fd) == -1)) { 79 | PyErr_SetFromErrno(PyExc_IOError); 80 | return NULL; 81 | } 82 | 83 | self->fd = -1; 84 | self->mode = 0; 85 | self->bpw = 0; 86 | self->msh = 0; 87 | 88 | Py_INCREF(Py_None); 89 | return Py_None; 90 | } 91 | 92 | PyDoc_STRVAR(SPI_transfer_doc, 93 | "transfer([values]) -> [values]\n\n" 94 | "Perform SPI transaction.\n" 95 | "CS will be released and reactivated between blocks.\n" 96 | "delay specifies delay in usec between blocks.\n"); 97 | 98 | 99 | 100 | static PyObject* SPI_transfer(SPI *self, PyObject *args) 101 | { 102 | uint8_t bits = 8; 103 | int ret = 0; 104 | char* list; 105 | int length_list = 1; 106 | uint16_t delay = 5; 107 | uint32_t speed = 1000000; 108 | int i=0; 109 | 110 | PyArg_ParseTuple(args, "s|i:transfer", &list, &length_list); 111 | #ifdef VERBOSE_MODE 112 | printf ("Length of String List from Python: %d\n", length_list); 113 | printf ("Read in String List from Python: %s\n", list); 114 | #endif 115 | 116 | char hexbyte[3] = {0}; 117 | uint8_t tx[length_list]; 118 | for (i=0; i < (length_list); i++){ 119 | 120 | //should grab first two characters 121 | //printf("Should grab %c%c\n",list[2*i], list[(2*i)+1]); 122 | 123 | //Data Transfer from String list to 2 byte string 124 | hexbyte[0] = list[2*i]; 125 | hexbyte[1] = list[(2*i)+1]; 126 | 127 | //Passing the 2 byte string into a Hex unsigned int 8-bit and then printing result 128 | sscanf(hexbyte, "%X", &tx[i]); 129 | #ifdef VERBOSE_MODE 130 | printf("Got HEX: 0x%2.2X\n\n",tx[i]); 131 | #endif 132 | } 133 | 134 | #ifdef VERBOSE_MODE 135 | //printf("TX array size after conversion: %d\n",ARRAY_SIZE(tx)); 136 | 137 | printf("Data for SPI to Transmit!! TX: "); 138 | for (ret=0; retfd, SPI_IOC_MESSAGE(1), &tr); 159 | if (ret < 1){ 160 | printf("ERROR: Can't send spi message"); 161 | perror(0); 162 | } 163 | 164 | 165 | #ifdef VERBOSE_MODE 166 | //This part prints the Received data of the SPI transmission of equal size to TX 167 | //printf("Data that was received from SPI!! RX: "); 168 | 169 | for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { 170 | if (!(ret % 6)) 171 | puts(""); 172 | printf("%.2X ", rx[ret]); 173 | 174 | 175 | } 176 | puts(""); // newline 177 | #endif 178 | 179 | Py_INCREF(list); 180 | 181 | //return tuple = (operation, port, data) 182 | return Py_BuildValue("(i,i,i)", rx[0],rx[1],rx[2]); 183 | 184 | } 185 | 186 | PyDoc_STRVAR(SPI_open_doc, 187 | "open(bus, device)\n\n" 188 | "Connects the object to the specified SPI device.\n" 189 | "open(X,Y) will open /dev/spidev-X.Y\n"); 190 | 191 | 192 | static PyObject *SPI_open(SPI *self, PyObject *args, PyObject *kwds) 193 | { 194 | int bus, device; 195 | char path[MAXPATH]; 196 | uint8_t tmp8; 197 | uint32_t tmp32; 198 | static char *kwlist[] = {"bus", "device", NULL}; 199 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii:open", kwlist, &bus, &device)) 200 | return NULL; 201 | if (snprintf(path, MAXPATH, "/dev/spidev%d.%d", bus, device) >= MAXPATH) { 202 | PyErr_SetString(PyExc_OverflowError, 203 | "Bus and/or device number is invalid."); 204 | return NULL; 205 | } 206 | if ((self->fd = open(path, O_RDWR, 0)) < 0) { 207 | /* changed to exceptions - thomas preston 29/06/2012 208 | printf("can't open device"); 209 | abort(); 210 | */ 211 | char err_str[20+MAXPATH]; 212 | sprintf(err_str, "can't open device: %s", path); 213 | PyErr_SetString(SpiError, err_str); 214 | return 0; // trigger exception 215 | } 216 | if (ioctl(self->fd, SPI_IOC_RD_MODE, &tmp8) == -1) { 217 | /* 218 | printf("can't get spi mode"); 219 | abort(); 220 | */ 221 | PyErr_SetString(SpiError, "can't get spi mode"); 222 | return 0; // trigger exception 223 | } 224 | self->mode = tmp8; 225 | if (ioctl(self->fd, SPI_IOC_RD_BITS_PER_WORD, &tmp8) == -1) { 226 | /* 227 | printf("can't get bits per word"); 228 | abort(); 229 | */ 230 | PyErr_SetString(SpiError, "can't get bits per word"); 231 | return 0; // trigger exception 232 | } 233 | self->bpw = tmp8; 234 | if (ioctl(self->fd, SPI_IOC_RD_MAX_SPEED_HZ, &tmp32) == -1) { 235 | /* 236 | printf("can't get max speed hz"); 237 | abort(); 238 | */ 239 | PyErr_SetString(SpiError, "can't get max speed hz"); 240 | return 0; // trigger exception 241 | } 242 | self->msh = tmp32; 243 | 244 | Py_INCREF(Py_None); 245 | return Py_None; 246 | } 247 | 248 | static int SPI_init(SPI *self, PyObject *args, PyObject *kwds) 249 | { 250 | int bus = -1; 251 | int client = -1; 252 | static char *kwlist[] = {"bus", "client", NULL}; 253 | 254 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:__init__", 255 | kwlist, &bus, &client)) 256 | return -1; 257 | 258 | if (bus >= 0) { 259 | SPI_open(self, args, kwds); 260 | if (PyErr_Occurred()) 261 | return -1; 262 | } 263 | return 0; 264 | } 265 | 266 | 267 | static PyMethodDef SPI_module_methods[] = { 268 | { NULL }, 269 | }; 270 | 271 | PyDoc_STRVAR(SPI_type_doc, 272 | "SPI([bus],[client]) -> SPI\n\n" 273 | "Return a new SPI object that is (optionally) connected to the\n" 274 | "specified SPI device interface.\n"); 275 | 276 | static PyMethodDef SPI_methods[] = { 277 | {"open", (PyCFunction)SPI_open, METH_VARARGS | METH_KEYWORDS, 278 | SPI_open_doc}, 279 | {"close", (PyCFunction)SPI_close, METH_NOARGS, 280 | SPI_close_doc}, 281 | {"transfer", (PyCFunction)SPI_transfer, METH_VARARGS, 282 | SPI_transfer_doc}, 283 | {NULL}, 284 | }; 285 | 286 | static PyTypeObject SPI_type = { 287 | PyObject_HEAD_INIT(NULL) 288 | 0, /* ob_size */ 289 | "SPI", /* tp_name */ 290 | sizeof(SPI), /* tp_basicsize */ 291 | 0, /* tp_itemsize */ 292 | 0, /* tp_dealloc */ 293 | 0, /* tp_print */ 294 | 0, /* tp_getattr */ 295 | 0, /* tp_setattr */ 296 | 0, /* tp_compare */ 297 | 0, /* tp_repr */ 298 | 0, /* tp_as_number */ 299 | 0, /* tp_as_sequence */ 300 | 0, /* tp_as_mapping */ 301 | 0, /* tp_hash */ 302 | 0, /* tp_call */ 303 | 0, /* tp_str */ 304 | 0, /* tp_getattro */ 305 | 0, /* tp_setattro */ 306 | 0, /* tp_as_buffer */ 307 | Py_TPFLAGS_DEFAULT, /* tp_flags */ 308 | SPI_type_doc, /* tp_doc */ 309 | 0, /* tp_traverse */ 310 | 0, /* tp_clear */ 311 | 0, /* tp_richcompare */ 312 | 0, /* tp_weaklistoffset */ 313 | 0, /* tp_iter */ 314 | 0, /* tp_iternext */ 315 | SPI_methods, /* tp_methods */ 316 | 0, /* tp_members */ 317 | 0, /* tp_getset */ 318 | 0, /* tp_base */ 319 | 0, /* tp_dict */ 320 | 0, /* tp_descr_get */ 321 | 0, /* tp_descr_set */ 322 | 0, /* tp_dictoffset */ 323 | (initproc)SPI_init, /* tp_init */ 324 | 0, /* tp_alloc */ 325 | SPI_new, /* tp_new */ 326 | }; 327 | 328 | #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ 329 | #define PyMODINIT_FUNC void 330 | #endif 331 | 332 | PyMODINIT_FUNC initspi(void) 333 | { 334 | PyObject* m; 335 | 336 | if (PyType_Ready(&SPI_type) < 0) 337 | return; 338 | 339 | m = Py_InitModule3("spi", SPI_module_methods, SPI_module_doc); 340 | Py_INCREF(&SPI_type); 341 | PyModule_AddObject(m, "SPI", (PyObject *)&SPI_type); 342 | 343 | // make a new exception 344 | SpiError = PyErr_NewException("spi.error", NULL, NULL); 345 | Py_INCREF(SpiError); 346 | PyModule_AddObject(m, "error", SpiError); 347 | 348 | 349 | } 350 | -------------------------------------------------------------------------------- /python/piface/emulator.py: -------------------------------------------------------------------------------- 1 | import pygtk 2 | import gtk, gobject, cairo 3 | import threading 4 | from gtk import gdk 5 | from math import pi 6 | from time import sleep 7 | import warnings 8 | 9 | import emulator_parts 10 | 11 | import pfio 12 | import sys 13 | 14 | VERBOSE_MODE = False 15 | DEFAULT_SPACING = 10 16 | 17 | EMU_WIDTH = 302 18 | EMU_HEIGHT = 201 19 | 20 | #EMU_WIDTH = 292 21 | #EMU_HEIGHT = 193 22 | 23 | EMU_SPEED = 20 24 | WINDOW_TITLE = "PiFace Emulator" 25 | 26 | # global variables are bad, AND YOU SHOULD FEEL BAD! 27 | rpi_emulator = None 28 | pfio_connect = False 29 | 30 | class EmulatorItem: 31 | def _get_handler(self): 32 | return sys.modules[__name__] 33 | 34 | handler = property(_get_handler, None) 35 | 36 | class LED(EmulatorItem, pfio.LED): 37 | pass 38 | 39 | class Relay(EmulatorItem, pfio.Relay): 40 | pass 41 | 42 | class Switch(EmulatorItem, pfio.Switch): 43 | pass 44 | 45 | class Emulator(threading.Thread): 46 | def __init__(self, spi_liststore_lock): 47 | gtk.gdk.threads_init() # init the gdk threads 48 | threading.Thread.__init__(self) 49 | 50 | self.spi_liststore_lock = spi_liststore_lock 51 | 52 | # a bit of spaghetti set up 53 | emulator_parts.pfio = pfio 54 | emulator_parts.rpi_emulator = self 55 | self.spi_visualiser_section = emulator_parts.SpiVisualiserFrame(self) 56 | global pfio_connect 57 | try: 58 | pfio.init() 59 | pfio_connect = True 60 | except pfio.InitError: 61 | print "Could not connect to the SPI module (check privileges). Starting emulator assuming that the PiFace is not connected." 62 | pfio_connect = False 63 | emulator_parts.pfio = None 64 | 65 | self.emu_window = gtk.Window() 66 | self.emu_window.connect("delete-event", gtk.main_quit) 67 | self.emu_window.set_title(WINDOW_TITLE) 68 | 69 | # emu screen 70 | self.emu_screen = emulator_parts.EmulatorScreen(EMU_WIDTH, EMU_HEIGHT, EMU_SPEED) 71 | self.emu_screen.show() 72 | 73 | # board connected msg 74 | if pfio_connect: 75 | msg = "Pi Face detected!" 76 | else: 77 | msg = "Pi Face not detected" 78 | self.board_con_msg = gtk.Label(msg) 79 | self.board_con_msg.show() 80 | 81 | if pfio_connect: 82 | # keep inputs updated 83 | self.update_input_check = gtk.CheckButton("Keep inputs updated") 84 | self.update_input_check.show() 85 | self.update_interval = gtk.Entry(5) 86 | self.update_interval.set_width_chars(5) 87 | self.update_interval.set_text("500") 88 | self.update_interval.show() 89 | update_interval_label = gtk.Label("ms interval") 90 | update_interval_label.show() 91 | 92 | self.update_input_check.connect("clicked", self.update_inputs) 93 | 94 | update_inputs_containter = gtk.HBox(False) 95 | update_inputs_containter.pack_start(self.update_input_check) 96 | update_inputs_containter.pack_start(self.update_interval, False, False) 97 | update_inputs_containter.pack_start(update_interval_label, False, False) 98 | update_inputs_containter.show() 99 | 100 | # spi visualiser checkbox 101 | self.spi_vis_check = gtk.CheckButton("SPI Visualiser") 102 | self.spi_vis_check.connect("clicked", self.toggle_spi_visualiser) 103 | self.spi_vis_check.show() 104 | 105 | # enable pullups checkbox 106 | self.en_pull_check = gtk.CheckButton("Enable pullups") 107 | self.en_pull_check.set_active(True) 108 | self.en_pull_check.connect("clicked", self.toggle_en_pullups) 109 | self.en_pull_check.show() 110 | 111 | # output override section 112 | self.output_override_section = \ 113 | emulator_parts.OutputOverrideSection(self.emu_screen.output_pins) 114 | self.output_override_section.show() 115 | 116 | # spi visualiser 117 | if pfio_connect: 118 | #spi_visualiser_section = emulator_parts.SpiVisualiserFrame() 119 | self.spi_visualiser_section.set_size_request(50, 200) 120 | self.spi_visualiser_section.set_border_width(DEFAULT_SPACING) 121 | #self.spi_visualiser_section.show() 122 | self.spi_visualiser_section.hide() 123 | 124 | # vertically pack together the emu_screen and the board connected msg 125 | container0 = gtk.VBox(homogeneous=False, spacing=DEFAULT_SPACING) 126 | container0.pack_start(self.emu_screen) 127 | container0.pack_start(self.board_con_msg) 128 | 129 | if pfio_connect: 130 | container0.pack_start(update_inputs_containter) 131 | container0.pack_start(self.spi_vis_check) 132 | container0.pack_start(self.en_pull_check) 133 | 134 | container0.show() 135 | 136 | # horizontally pack together the emu screen+msg and the button overide 137 | container1 = gtk.HBox(homogeneous=True, spacing=DEFAULT_SPACING) 138 | container1.pack_start(container0) 139 | container1.pack_start(self.output_override_section) 140 | container1.set_border_width(DEFAULT_SPACING) 141 | container1.show() 142 | top_containter = container1 143 | 144 | if pfio_connect: 145 | # now, verticaly pack that container and the spi visualiser 146 | container2 = gtk.VBox(homogeneous=True, spacing=DEFAULT_SPACING) 147 | container2.pack_start(child=container1, expand=False, fill=False, padding=0) 148 | container2.pack_start(self.spi_visualiser_section) 149 | container2.show() 150 | top_containter = container2 151 | 152 | self.emu_window.add(top_containter) 153 | self.emu_window.present() 154 | 155 | self.input_updater = None 156 | 157 | def run(self): 158 | gtk.main() 159 | 160 | def update_inputs(self, widget, data=None): 161 | """ 162 | If the checkbox has been pressed then schedule the virtual inputs 163 | to be updated, live 164 | """ 165 | if widget.get_active(): 166 | self.input_updater = InputUpdater(self.update_interval, self) 167 | self.input_updater.start() 168 | else: 169 | if self.input_updater: 170 | self.input_updater.stop() 171 | self.input_updater.join() 172 | 173 | def toggle_spi_visualiser(self, widget, data=None): 174 | if widget.get_active(): 175 | self.spi_visualiser_section.show() 176 | else: 177 | self.spi_visualiser_section.hide() 178 | self.emu_window.resize(10, 10) 179 | 180 | def toggle_en_pullups(self, widget, data=None): 181 | if widget.get_active(): 182 | pfio.write_pullups(0xff) 183 | else: 184 | pfio.write_pullups(0) 185 | 186 | class InputUpdater(threading.Thread): 187 | def __init__(self, update_interval_entry, rpi_emulator): 188 | threading.Thread.__init__(self) 189 | self.update_interval_entry = update_interval_entry 190 | self.emu = rpi_emulator 191 | self._stop = threading.Event() 192 | 193 | def stop(self): 194 | self._stop.set() 195 | 196 | def stopped(self): 197 | return self._stop.isSet() 198 | 199 | def run(self): 200 | while not self.stopped(): 201 | # get the input pin values 202 | input_pin_pattern = pfio.read_input() 203 | 204 | # set the virt input pin values 205 | for i in range(len(self.emu.emu_screen.input_pins)): 206 | if (input_pin_pattern >> i) & 1 == 1: 207 | self.emu.emu_screen.input_pins[i].turn_on(True) 208 | else: 209 | self.emu.emu_screen.input_pins[i].turn_off(True) 210 | 211 | 212 | self.emu.emu_screen.queue_draw() 213 | 214 | # sleep 215 | update_interval = int(self.update_interval_entry.get_text()) / 1000.0 216 | sleep(update_interval) 217 | 218 | 219 | """Input/Output functions mimicing the pfio module""" 220 | def init(): 221 | """Initialises the RaspberryPi emulator""" 222 | spi_liststore_lock = threading.Semaphore() 223 | 224 | global rpi_emulator 225 | rpi_emulator = Emulator(spi_liststore_lock) 226 | rpi_emulator.start() 227 | 228 | def deinit(): 229 | """Deinitialises the PiFace""" 230 | global rpi_emulator 231 | rpi_emulator.emu_window.destroy() 232 | 233 | gtk.main_quit() 234 | 235 | rpi_emulator.emu_screen = None 236 | 237 | def get_pin_bit_mask(pin_number): 238 | """Translates a pin number to pin bit mask.""" 239 | return pfio.get_pin_bit_mask(pin_number) 240 | 241 | def get_pin_number(bit_pattern): 242 | """Returns the lowest pin number from a given bit pattern""" 243 | return pfio.get_pin_number(bit_pattern) 244 | 245 | def hex_cat(items): 246 | return pfio.hex_cat(items) 247 | 248 | def digital_write(pin_number, value): 249 | """Writes the value given to the pin specified""" 250 | if VERBOSE_MODE: 251 | emulator_parts.emu_print("digital write start") 252 | 253 | global rpi_emulator 254 | if value >= 1: 255 | rpi_emulator.emu_screen.output_pins[pin_number-1].turn_on() 256 | else: 257 | rpi_emulator.emu_screen.output_pins[pin_number-1].turn_off() 258 | 259 | rpi_emulator.emu_screen.queue_draw() 260 | 261 | if VERBOSE_MODE: 262 | emulator_parts.emu_print("digital write end") 263 | 264 | def digital_read(pin_number): 265 | """Returns the value of the pin specified""" 266 | emulator_parts.request_digtial_read = True 267 | global rpi_emulator 268 | value = rpi_emulator.emu_screen.input_pins[pin_number-1].value 269 | emulator_parts.request_digtial_read = False 270 | 271 | rpi_emulator.emu_screen.queue_draw() 272 | return value 273 | 274 | """ 275 | Some wrapper functions so the user doesn't have to deal with 276 | ugly port variables 277 | """ 278 | def read_output(): 279 | """Returns the values of the output pins""" 280 | global rpi_emulator 281 | data = __read_pins(rpi_emulator.emu_screen.output_pins) 282 | 283 | global pfio_connect 284 | if pfio_connect: 285 | data |= pfio.read_output() 286 | 287 | return data 288 | 289 | def read_input(): 290 | """Returns the values of the input pins""" 291 | global rpi_emulator 292 | data = __read_pins(rpi_emulator.emu_screen.input_pins) 293 | 294 | global pfio_connect 295 | if pfio_connect: 296 | data |= pfio.read_input() 297 | print "data: %s" % data 298 | return data 299 | 300 | def __read_pins(pins): 301 | vpin_values = [pin._value for pin in pins] 302 | data = 0 303 | for i in range(len(vpin_values)): 304 | data ^= (vpin_values[i] & 1) << i 305 | 306 | #global rpi_emulator 307 | #rpi_emulator.emu_screen.queue_draw() 308 | 309 | return data 310 | 311 | def write_output(data): 312 | """Writes the values of the output pins""" 313 | global rpi_emulator 314 | for i in range(8): 315 | if ((data >> i) & 1) == 1: 316 | rpi_emulator.emu_screen.output_pins[i].turn_on() 317 | else: 318 | rpi_emulator.emu_screen.output_pins[i].turn_off() 319 | 320 | rpi_emulator.emu_screen.queue_draw() 321 | 322 | 323 | if __name__ == "__main__": 324 | init() 325 | -------------------------------------------------------------------------------- /python/piface/pfio.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | pfio.py 4 | Provides I/O methods for interfacing with the RaspberryPi interface (piface) 5 | 6 | piface has two ports (input/output) each with eight pins with several 7 | peripherals connected for interacting with the raspberry pi 8 | """ 9 | from time import sleep 10 | from datetime import datetime 11 | 12 | import sys 13 | import spi 14 | 15 | 16 | VERBOSE_MODE = False # toggle verbosity 17 | __pfio_print_PREFIX = "PFIO: " # prefix for pfio messages 18 | 19 | # SPI operations 20 | WRITE_CMD = 0x40 21 | READ_CMD = 0x41 22 | 23 | # Port configuration 24 | IODIRA = 0x00 # I/O direction A 25 | IODIRB = 0x01 # I/O direction B 26 | IOCON = 0x0A # I/O config 27 | GPIOA = 0x12 # port A 28 | GPIOB = 0x13 # port B 29 | GPPUA = 0x0C # port A pullups 30 | GPPUB = 0x0D # port B pullups 31 | OUTPUT_PORT = GPIOA 32 | INPUT_PORT = GPIOB 33 | INPUT_PULLUP = GPPUB 34 | 35 | spi_handler = None 36 | 37 | spi_visualiser_section = None # for the emulator spi visualiser 38 | 39 | 40 | # custom exceptions 41 | class InitError(Exception): 42 | pass 43 | 44 | class InputDeviceError(Exception): 45 | pass 46 | 47 | class PinRangeError(Exception): 48 | pass 49 | 50 | class LEDRangeError(Exception): 51 | pass 52 | 53 | class RelayRangeError(Exception): 54 | pass 55 | 56 | class SwitchRangeError(Exception): 57 | pass 58 | 59 | 60 | # classes 61 | class Item(object): 62 | """An item connected to a pin on the RaspberryPi""" 63 | def __init__(self, pin_number, handler=None): 64 | self.pin_number = pin_number 65 | if handler: 66 | self.handler = handler 67 | 68 | def _get_handler(self): 69 | return sys.modules[__name__] 70 | 71 | handler = property(_get_handler, None) 72 | 73 | class InputItem(Item): 74 | """An input connected to a pin on the RaspberryPi""" 75 | def __init__(self, pin_number, handler=None): 76 | Item.__init__(self, pin_number, handler) 77 | 78 | def _get_value(self): 79 | return self.handler.digital_read(self.pin_number) 80 | 81 | def _set_value(self, data): 82 | raise InputDeviceError("You cannot set an input's values!") 83 | 84 | value = property(_get_value, _set_value) 85 | 86 | class OutputItem(Item): 87 | """An output connected to a pin on the RaspberryPi""" 88 | def __init__(self, pin_number, handler=None): 89 | self.current = 0 90 | Item.__init__(self, pin_number, handler) 91 | 92 | def _get_value(self): 93 | return self.current 94 | 95 | def _set_value(self, data): 96 | self.current = data 97 | return self.handler.digital_write(self.pin_number, data) 98 | 99 | value = property(_get_value, _set_value) 100 | 101 | def turn_on(self): 102 | self.value = 1 103 | 104 | def turn_off(self): 105 | self.value = 0 106 | 107 | def toggle(self): 108 | self.value = not self.value 109 | 110 | class LED(OutputItem): 111 | """An LED on the RaspberryPi""" 112 | def __init__(self, led_number, handler=None): 113 | if led_number < 0 or led_number > 7: 114 | raise LEDRangeError( 115 | "Specified LED index (%d) out of range." % led_number) 116 | else: 117 | OutputItem.__init__(self, led_number, handler) 118 | 119 | class Relay(OutputItem): 120 | """A relay on the RaspberryPi""" 121 | def __init__(self, relay_number, handler=None): 122 | if relay_number < 0 or relay_number > 1: 123 | raise RelayRangeError( 124 | "Specified relay index (%d) out of range." % relay_number) 125 | else: 126 | OutputItem.__init__(self, relay_number, handler) 127 | 128 | class Switch(InputItem): 129 | """A switch on the RaspberryPi""" 130 | def __init__(self, switch_number, handler=None): 131 | if switch_number < 0 or switch_number > 3: 132 | raise SwitchRangeError( 133 | "Specified switch index (%d) out of range." % switch_number) 134 | else: 135 | InputItem.__init__(self, switch_number, handler) 136 | 137 | 138 | # functions 139 | def get_spi_handler(): 140 | return spi.SPI(0,0) # spi.SPI(X,Y) is /dev/spidevX.Y 141 | 142 | def init(init_ports=True): 143 | """Initialises the PiFace""" 144 | if VERBOSE_MODE: 145 | __pfio_print("initialising SPI") 146 | 147 | global spi_handler 148 | try: 149 | spi_handler = get_spi_handler() 150 | except spi.error as error: 151 | raise InitError(error) 152 | 153 | if init_ports: 154 | # set up the ports 155 | write(IOCON, 8) # enable hardware addressing 156 | write(GPIOA, 0x00) # set port A on 157 | write(IODIRA, 0) # set port A as outputs 158 | write(IODIRB, 0xFF) # set port B as inputs 159 | #write(GPIOA, 0xFF) # set port A on 160 | #write(GPIOB, 0xFF) # set port B on 161 | #write(GPPUA, 0xFF) # set port A pullups on 162 | write(GPPUB, 0xFF) # set port B pullups on 163 | 164 | # check the outputs are being set (primitive board detection) 165 | # AR removed this test as it lead to flashing of outputs which 166 | # could surprise users! 167 | #test_value = 0b10101010 168 | #write_output(test_value) 169 | #if read_output() != test_value: 170 | # spi_handler = None 171 | # raise InitError("The PiFace board could not be detected") 172 | 173 | # initialise all outputs to 0 174 | write_output(0) 175 | 176 | def deinit(): 177 | """Deinitialises the PiFace""" 178 | global spi_handler 179 | if spi_handler: 180 | spi_handler.close() 181 | spi_handler = None 182 | 183 | def __pfio_print(text): 184 | """Prints a string with the pfio print prefix""" 185 | print "%s %s" % (__pfio_print_PREFIX, text) 186 | 187 | def get_pin_bit_mask(pin_number): 188 | """Translates a pin number to pin bit mask. First pin is pin0.""" 189 | if pin_number > 7 or pin_number < 0: 190 | raise PinRangeError("Specified pin number (%d) out of range." % pin_number) 191 | else: 192 | return 1 << (pin_number) 193 | 194 | def get_pin_number(bit_pattern): 195 | """Returns the lowest pin number from a given bit pattern""" 196 | pin_number = 0 # assume pin 0 197 | while (bit_pattern & 1) == 0: 198 | bit_pattern = bit_pattern >> 1 199 | pin_number += 1 200 | if pin_number > 7: 201 | pin_number = 0 202 | break 203 | 204 | return pin_number 205 | 206 | def byte_cat(items): 207 | """ 208 | Returns a value comprised of the concatenation of the given hex values 209 | Example: (0x41, 0x16, 0x01) -> 0x411601 210 | """ 211 | items = list(items) 212 | items.reverse() 213 | cauldron = 0 214 | for i in range(len(items)): 215 | cauldron ^= items[i] << (i * 8) 216 | return cauldron 217 | 218 | def digital_write(pin_number, value): 219 | """Writes the value given to the pin specified""" 220 | if VERBOSE_MODE: 221 | __pfio_print("digital write start") 222 | 223 | pin_bit_mask = get_pin_bit_mask(pin_number) 224 | 225 | if VERBOSE_MODE: 226 | __pfio_print("pin bit mask: %s" % bin(pin_bit_mask)) 227 | 228 | old_pin_values = read_output() 229 | 230 | if VERBOSE_MODE: 231 | __pfio_print("old pin values: %s" % bin(old_pin_values)) 232 | 233 | # generate the 234 | if value: 235 | new_pin_values = old_pin_values | pin_bit_mask 236 | else: 237 | new_pin_values = old_pin_values & ~pin_bit_mask 238 | 239 | if VERBOSE_MODE: 240 | __pfio_print("new pin values: %s" % bin(new_pin_values)) 241 | 242 | write_output(new_pin_values) 243 | 244 | if VERBOSE_MODE: 245 | __pfio_print("digital write end") 246 | 247 | def digital_read(pin_number): 248 | """Returns the value of the pin specified""" 249 | current_pin_values = read_input() 250 | pin_bit_mask = get_pin_bit_mask(pin_number) 251 | 252 | result = current_pin_values & pin_bit_mask 253 | 254 | # is this correct? -thomas preston 255 | if result: 256 | return 1 257 | else: 258 | return 0 259 | 260 | def digital_write_pullup(pin_number, value): 261 | """Writes the pullup value given to the pin specified""" 262 | if VERBOSE_MODE: 263 | __pfio_print("digital write pullup start") 264 | 265 | pin_bit_mask = get_pin_bit_mask(pin_number) 266 | 267 | if VERBOSE_MODE: 268 | __pfio_print("pin bit mask: %s" % bin(pin_bit_mask)) 269 | 270 | old_pin_values = read_pullup() 271 | 272 | if VERBOSE_MODE: 273 | __pfio_print("old pin values: %s" % bin(old_pin_values)) 274 | 275 | # generate the 276 | if value: 277 | new_pin_values = old_pin_values | pin_bit_mask 278 | else: 279 | new_pin_values = old_pin_values & ~pin_bit_mask 280 | 281 | if VERBOSE_MODE: 282 | __pfio_print("new pin values: %s" % bin(new_pin_values)) 283 | 284 | write_pullup(new_pin_values) 285 | 286 | if VERBOSE_MODE: 287 | __pfio_print("digital write end") 288 | 289 | def digital_read_pullup(pin_number): 290 | """Returns the value of the pin specified""" 291 | current_pin_values = read_pullup() 292 | pin_bit_mask = get_pin_bit_mask(pin_number) 293 | 294 | result = current_pin_values & pin_bit_mask 295 | 296 | # works with true/false 297 | if result: 298 | return 1 299 | else: 300 | return 0 301 | 302 | """ 303 | Some wrapper functions so the user doesn't have to deal with 304 | ugly port variables 305 | """ 306 | def read_output(): 307 | """Returns the values of the output pins""" 308 | port, data = read(OUTPUT_PORT) 309 | return data 310 | 311 | def read_input(): 312 | """Returns the values of the input pins""" 313 | port, data = read(INPUT_PORT) 314 | # inputs are active low, but the user doesn't need to know this... 315 | return data ^ 0xff 316 | 317 | def read_pullup(): 318 | """Reads value of pullup registers""" 319 | port, data = read(INPUT_PULLUP) 320 | return data 321 | 322 | def write_pullup(data): 323 | port, data = write(INPUT_PULLUP, data) 324 | return data 325 | 326 | def write_output(data): 327 | """Writed the values of the output pins""" 328 | port, data = write(OUTPUT_PORT, data) 329 | return data 330 | 331 | """ 332 | def write_input(data): 333 | " ""Writes the values of the input pins"" " 334 | port, data = write(INPUT_PORT, data) 335 | return data 336 | """ 337 | 338 | def read(port): 339 | """Reads from the port specified""" 340 | # data byte is padded with 1's since it isn't going to be used 341 | operation, port, data = send([(READ_CMD, port, 0xff)])[0] # send is expecting and returns a list 342 | return (port, data) 343 | 344 | def write(port, data): 345 | """Writes data to the port specified""" 346 | #print "writing" 347 | operation, port, data = send([(WRITE_CMD, port, data)])[0] # send is expecting and returns a list 348 | return (port, data) 349 | 350 | 351 | def send(spi_commands, custom_spi=False): 352 | """Sends a list of spi commands to the PiFace""" 353 | if spi_handler == None: 354 | raise InitError("The pfio module has not yet been initialised. Before send(), call init().") 355 | # a place to store the returned values for each transfer 356 | returned_values_list = list() 357 | 358 | # datum is an array of three bytes 359 | for cmd, port, data in spi_commands: 360 | datum_tx = byte_cat((cmd, port, data)) 361 | if VERBOSE_MODE: 362 | __pfio_print("transfering data: 0x%06x" % datum_tx) 363 | 364 | # transfer the data string 365 | returned_values = spi_handler.transfer("%06x" % datum_tx, 3) 366 | datum_rx = byte_cat(returned_values) 367 | 368 | returned_values_list.append(returned_values) 369 | 370 | if VERBOSE_MODE: 371 | __pfio_print("SPI module returned: 0x%06x" % datum_rx) 372 | 373 | # if we are visualising, add the data to the emulator visualiser 374 | global spi_visualiser_section 375 | if spi_visualiser_section: 376 | time = datetime.now() 377 | timestr = "%d:%d:%d.%d" % (time.hour, time.minute, time.second, time.microsecond) 378 | datum_tx = byte_cat((cmd, port, data)) # recalculate since the transfer changes it 379 | #print "writing to spi_liststore: %s" % str((timestr, hex(datum_tx), hex(datum_rx))) 380 | spi_visualiser_section.add_spi_log(timestr, datum_tx, datum_rx, custom_spi) 381 | 382 | return returned_values_list 383 | 384 | 385 | def test_method(): 386 | digital_write(1,1) # write pin 1 high 387 | sleep(2) 388 | digital_write(1,0) # write pin 1 low 389 | 390 | if __name__ == "__main__": 391 | init() 392 | test_method() 393 | deinit() 394 | -------------------------------------------------------------------------------- /misc/icons/piface.xpm: -------------------------------------------------------------------------------- 1 | /* XPM */ 2 | static char * pifaceiconsmall_xpm[] = { 3 | "36 50 425 2", 4 | " c None", 5 | ". c #4E9F4A", 6 | "+ c #4C9E49", 7 | "@ c #4A9D48", 8 | "# c #499B49", 9 | "$ c #419744", 10 | "% c #55A34C", 11 | "& c #56A44D", 12 | "* c #55A44E", 13 | "= c #54A34D", 14 | "- c #51A14B", 15 | "; c #4E9F49", 16 | "> c #479A46", 17 | ", c #449844", 18 | "' c #3E9542", 19 | ") c #52A14B", 20 | "! c #55A34D", 21 | "~ c #58A64F", 22 | "{ c #5BA850", 23 | "] c #5CA951", 24 | "^ c #5AA850", 25 | "/ c #57A54E", 26 | "( c #53A24C", 27 | "_ c #4A9C48", 28 | ": c #469A45", 29 | "< c #419643", 30 | "[ c #3A9341", 31 | "} c #35903F", 32 | "| c #2E8D3E", 33 | "1 c #4B9D48", 34 | "2 c #4FA04A", 35 | "3 c #59A750", 36 | "4 c #5DA951", 37 | "5 c #60AC54", 38 | "6 c #61AC54", 39 | "7 c #5FAA52", 40 | "8 c #52A24C", 41 | "9 c #489B46", 42 | "0 c #3D9442", 43 | "a c #369240", 44 | "b c #318E3E", 45 | "c c #298A3B", 46 | "d c #228739", 47 | "e c #479B46", 48 | "f c #65B056", 49 | "g c #69B158", 50 | "h c #67B157", 51 | "i c #63AE55", 52 | "j c #5FAB53", 53 | "k c #4FA14A", 54 | "l c #459945", 55 | "m c #3F9642", 56 | "n c #389240", 57 | "o c #328F3E", 58 | "p c #2C8B3D", 59 | "q c #23883A", 60 | "r c #1F8638", 61 | "s c #3C9442", 62 | "t c #439845", 63 | "u c #489C47", 64 | "v c #54A44D", 65 | "w c #5AA750", 66 | "x c #64B056", 67 | "y c #6BB359", 68 | "z c #6FB55A", 69 | "A c #6EB55A", 70 | "B c #68B157", 71 | "C c #62AC54", 72 | "D c #5DAA52", 73 | "E c #3A9340", 74 | "F c #338F3F", 75 | "G c #2D8C3D", 76 | "H c #208638", 77 | "I c #1E863A", 78 | "J c #36913F", 79 | "K c #3D9542", 80 | "L c #449845", 81 | "M c #499C47", 82 | "N c #56A44E", 83 | "O c #66B057", 84 | "P c #6DB55A", 85 | "Q c #72B85D", 86 | "R c #70B75C", 87 | "S c #6AB358", 88 | "T c #63AF56", 89 | "U c #5DAA53", 90 | "V c #479A45", 91 | "W c #33903F", 92 | "X c #25883A", 93 | "Y c #208639", 94 | "Z c #1F8738", 95 | "` c #208738", 96 | " . c #318E3D", 97 | ".. c #3C9441", 98 | "+. c #439844", 99 | "@. c #489B47", 100 | "#. c #4D9F4A", 101 | "$. c #60AB53", 102 | "%. c #64AF56", 103 | "&. c #6EB55B", 104 | "*. c #6DB459", 105 | "=. c #62AD55", 106 | "-. c #57A54F", 107 | ";. c #4B9D49", 108 | ">. c #469A46", 109 | ",. c #409743", 110 | "'. c #348F3F", 111 | "). c #24893A", 112 | "!. c #208739", 113 | "~. c #288A3B", 114 | "{. c #2F8D3D", 115 | "]. c #35913F", 116 | "^. c #3B9341", 117 | "/. c #429744", 118 | "(. c #58A54E", 119 | "_. c #66B157", 120 | ":. c #66B156", 121 | "<. c #5BA750", 122 | "[. c #4FA04B", 123 | "}. c #459944", 124 | "|. c #3F9643", 125 | "1. c #338E3E", 126 | "2. c #2C8B3C", 127 | "3. c #23883B", 128 | "4. c #1F8739", 129 | "5. c #24883A", 130 | "6. c #409642", 131 | "7. c #55A44D", 132 | "8. c #59A64F", 133 | "9. c #5EAA52", 134 | "0. c #4D9E48", 135 | "a. c #479B47", 136 | "b. c #3C9542", 137 | "c. c #37913F", 138 | "d. c #308E3E", 139 | "e. c #2A8A3C", 140 | "f. c #218839", 141 | "g. c #1F873A", 142 | "h. c #238839", 143 | "i. c #2B8A3C", 144 | "j. c #37923F", 145 | "k. c #439744", 146 | "l. c #51A04B", 147 | "m. c #58A64E", 148 | "n. c #5BA851", 149 | "o. c #409643", 150 | "p. c #34903F", 151 | "q. c #2E8D3D", 152 | "r. c #27893B", 153 | "s. c #1F8639", 154 | "t. c #358F3F", 155 | "u. c #399340", 156 | "v. c #3F9542", 157 | "w. c #4D9F49", 158 | "x. c #4A9D47", 159 | "y. c #429743", 160 | "z. c #379140", 161 | "A. c #2B8B3C", 162 | "B. c #36903F", 163 | "C. c #3A9441", 164 | "D. c #4EA04A", 165 | "E. c #50A04A", 166 | "F. c #33903E", 167 | "G. c #26883A", 168 | "H. c #459A45", 169 | "I. c #489C48", 170 | "J. c #439B49", 171 | "K. c #429A49", 172 | "L. c #429A47", 173 | "M. c #3D9541", 174 | "N. c #399240", 175 | "O. c #34903E", 176 | "P. c #298A3C", 177 | "Q. c #218739", 178 | "R. c #2D8C3C", 179 | "S. c #3F9746", 180 | "T. c #4F9940", 181 | "U. c #869E2C", 182 | "V. c #929F26", 183 | "W. c #729B31", 184 | "X. c #3D9544", 185 | "Y. c #399341", 186 | "Z. c #379240", 187 | "`. c #338F3E", 188 | " + c #248739", 189 | ".+ c #308D3E", 190 | "++ c #47953E", 191 | "@+ c #A49F1D", 192 | "#+ c #F3A600", 193 | "$+ c #F0A600", 194 | "%+ c #EFA500", 195 | "&+ c #F2A500", 196 | "*+ c #DFA405", 197 | "=+ c #72972B", 198 | "-+ c #2E8C3D", 199 | ";+ c #2A8B3C", 200 | ">+ c #318D3E", 201 | ",+ c #368F3D", 202 | "'+ c #B49F14", 203 | ")+ c #EDA500", 204 | "!+ c #EAA400", 205 | "~+ c #EAA500", 206 | "{+ c #E9A400", 207 | "]+ c #E7A301", 208 | "^+ c #6D9329", 209 | "/+ c #24893C", 210 | "(+ c #238739", 211 | "_+ c #22883A", 212 | ":+ c #26893B", 213 | "<+ c #268A3C", 214 | "[+ c #6B942A", 215 | "}+ c #E6A300", 216 | "|+ c #E5A200", 217 | "1+ c #E3A100", 218 | "2+ c #E29F00", 219 | "3+ c #E09E01", 220 | "4+ c #DD9C04", 221 | "5+ c #19863C", 222 | "6+ c #BA9D10", 223 | "7+ c #EAA300", 224 | "8+ c #E4A200", 225 | "9+ c #E2A001", 226 | "0+ c #E09F01", 227 | "a+ c #DE9D02", 228 | "b+ c #DD9B02", 229 | "c+ c #DB9A04", 230 | "d+ c #D99906", 231 | "e+ c #DC9806", 232 | "f+ c #638D28", 233 | "g+ c #1A863A", 234 | "h+ c #16853B", 235 | "i+ c #D29D06", 236 | "j+ c #E19E00", 237 | "k+ c #DE9C03", 238 | "l+ c #DB9B03", 239 | "m+ c #DA9A05", 240 | "n+ c #D89807", 241 | "o+ c #D69608", 242 | "p+ c #D49509", 243 | "q+ c #D3940B", 244 | "r+ c #D4930C", 245 | "s+ c #7B8D23", 246 | "t+ c #18863A", 247 | "u+ c #17863B", 248 | "v+ c #BE970F", 249 | "w+ c #DC9805", 250 | "x+ c #D79707", 251 | "y+ c #D59608", 252 | "z+ c #D2930C", 253 | "A+ c #D1930C", 254 | "B+ c #CE910D", 255 | "C+ c #CC900D", 256 | "D+ c #CF8F0D", 257 | "E+ c #698A28", 258 | "F+ c #1B863A", 259 | "G+ c #768D24", 260 | "H+ c #DB9509", 261 | "I+ c #D0930C", 262 | "J+ c #CF920C", 263 | "K+ c #CD900E", 264 | "L+ c #CC900E", 265 | "M+ c #CA8F0F", 266 | "N+ c #C88E10", 267 | "O+ c #C78C11", 268 | "P+ c #318735", 269 | "Q+ c #1E8639", 270 | "R+ c #2D8736", 271 | "S+ c #B49015", 272 | "T+ c #CE8F0E", 273 | "U+ c #C98D10", 274 | "V+ c #C88D10", 275 | "W+ c #C68C11", 276 | "X+ c #C58B12", 277 | "Y+ c #C38A12", 278 | "Z+ c #CB8A12", 279 | "`+ c #6E8828", 280 | " @ c #3F8832", 281 | ".@ c #B58B16", 282 | "+@ c #C48B12", 283 | "@@ c #C28A13", 284 | "#@ c #C08A13", 285 | "$@ c #BF8814", 286 | "%@ c #BD8715", 287 | "&@ c #788625", 288 | "*@ c #238738", 289 | "=@ c #1C8639", 290 | "-@ c #268738", 291 | ";@ c #6B8828", 292 | ">@ c #908720", 293 | ",@ c #93861F", 294 | "'@ c #828623", 295 | ")@ c #498630", 296 | "!@ c #1A873A", 297 | "~@ c #1B8639", 298 | "{@ c #1C863A", 299 | "]@ c #1E8739", 300 | "^@ c #1D8639", 301 | "/@ c #1C8739", 302 | "(@ c #19883A", 303 | "_@ c #1C883A", 304 | ":@ c #1D8739", 305 | "<@ c #1B8739", 306 | "[@ c #218638", 307 | "}@ c #537C2D", 308 | "|@ c #797324", 309 | "1@ c #5E782A", 310 | "2@ c #507C2D", 311 | "3@ c #4B7D2E", 312 | "4@ c #497E2F", 313 | "5@ c #4C7D2E", 314 | "6@ c #597C2C", 315 | "7@ c #6C7927", 316 | "8@ c #867621", 317 | "9@ c #A4731A", 318 | "0@ c #A36717", 319 | "a@ c #9E6818", 320 | "b@ c #9F6818", 321 | "c@ c #A06818", 322 | "d@ c #A16A18", 323 | "e@ c #A56C19", 324 | "f@ c #A76F18", 325 | "g@ c #A97218", 326 | "h@ c #AB7518", 327 | "i@ c #AD7717", 328 | "j@ c #2E8435", 329 | "k@ c #9E691A", 330 | "l@ c #9A6A19", 331 | "m@ c #9B6C1A", 332 | "n@ c #9F6E1A", 333 | "o@ c #A27019", 334 | "p@ c #A67319", 335 | "q@ c #A97518", 336 | "r@ c #AD7817", 337 | "s@ c #B07A17", 338 | "t@ c #B37D16", 339 | "u@ c #248537", 340 | "v@ c #817222", 341 | "w@ c #9F6E19", 342 | "x@ c #A57218", 343 | "y@ c #B07A16", 344 | "z@ c #B77F15", 345 | "A@ c #BB8214", 346 | "B@ c #597D2B", 347 | "C@ c #A67218", 348 | "D@ c #AC7717", 349 | "E@ c #AF7A16", 350 | "F@ c #BE8513", 351 | "G@ c #C28712", 352 | "H@ c #2F8535", 353 | "I@ c #9D791B", 354 | "J@ c #B37C16", 355 | "K@ c #B67F15", 356 | "L@ c #BA8214", 357 | "M@ c #C28711", 358 | "N@ c #C58A10", 359 | "O@ c #CA8D0F", 360 | "P@ c #CC8F0E", 361 | "Q@ c #6C8127", 362 | "R@ c #B87F15", 363 | "S@ c #BA8114", 364 | "T@ c #C68910", 365 | "U@ c #CD900D", 366 | "V@ c #D0920B", 367 | "W@ c #D4940A", 368 | "X@ c #A8841A", 369 | "Y@ c #C48712", 370 | "Z@ c #C58910", 371 | "`@ c #C98C0F", 372 | " # c #CD8F0D", 373 | ".# c #D0920C", 374 | "+# c #D4950A", 375 | "@# c #D79608", 376 | "## c #DA9805", 377 | "$# c #3A8733", 378 | "%# c #CC8C10", 379 | "&# c #D0910B", 380 | "*# c #D99805", 381 | "=# c #DC9803", 382 | "-# c #DF9901", 383 | ";# c #E19A01", 384 | "># c #738C25", 385 | ",# c #D89409", 386 | "'# c #D99706", 387 | ")# c #DC9904", 388 | "!# c #E19B01", 389 | "~# c #E39B00", 390 | "{# c #E69C00", 391 | "]# c #2A8836", 392 | "^# c #AC9414", 393 | "/# c #DD9903", 394 | "(# c #DF9A02", 395 | "_# c #E09B01", 396 | ":# c #E89E00", 397 | "<# c #E99E00", 398 | "[# c #E99E01", 399 | "}# c #378933", 400 | "|# c #DD9A03", 401 | "1# c #E59C00", 402 | "2# c #E89D01", 403 | "3# c #EA9E00", 404 | "4# c #EA9D00", 405 | "5# c #508C2D", 406 | "6# c #EC9D00", 407 | "7# c #E99D00", 408 | "8# c #749023", 409 | "9# c #EA9D01", 410 | "0# c #218738", 411 | "a# c #959419", 412 | "b# c #E99D01", 413 | "c# c #1D863B", 414 | "d# c #B89810", 415 | "e# c #EC9E00", 416 | "f# c #248738", 417 | "g# c #B29712", 418 | "h# c #F19F00", 419 | "i# c #E99E02", 420 | "j# c #2F8835", 421 | "k# c #B79810", 422 | "l# c #338934", 423 | "m# c #C99A0B", 424 | "n# c #EB9E00", 425 | "o# c #348934", 426 | "p# c #B8980F", 427 | "q# c #ED9E00", 428 | "r# c #EA9E01", 429 | " . + @ # $ ", 430 | " % & & * = - ; @ > , ' ", 431 | " ) ! ~ { ] ] ^ / ( . _ : < [ } | ", 432 | " 1 2 % 3 4 5 6 6 7 { / 8 + 9 , 0 a b c d ", 433 | " e + 8 ~ 4 6 f g h i j { & k @ l m n o p q r ", 434 | " s t u . v w j x y z A B C D ~ - 1 : $ E F G q r H I ", 435 | " J K L M . N { 5 O P Q R S T U ~ 8 + V $ [ W G X Y Z ` r ", 436 | " .J ..+.@.#.v ^ $.%.y &.*.B =.4 -.- ;.>.,.E '.G ).r !.` Z ", 437 | " ~.{.].^./.> + 8 (.] 6 %._.:.i j <.* [.@ }.|.n 1.2.3.r !.!.` 4. ", 438 | " 5.G F [ 6.l @ 2 7.8.] j 6 5 9.{ / ) 0.a.+.b.c.d.e.f.r !.!.4.!. ", 439 | " g.h.i.d.j.0 k.e 1 l.! m.^ n.n.3 / 8 . M l o.[ p.q.r.!.r !.!.!.4.H ", 440 | " g.s.!.~.| t.u.v., @.;.2 8 * N & = - w.x.>.y.s z.b A.5.r !.!.!.!.H Z ", 441 | " H Z s.5.i.b B.C.6., e x.+ D.E.2 w.1 M >.y.' n F.G r.!.!.!.!.!.!.4.!.", 442 | " s.!.r !.G.2.b J [ m k.H.> @.I.J.K.L., y.M.N.O.{.P.h.!.!.!.!.!.!.!.!.", 443 | " r ` !.4.r Q.r.R.b J u...|.$ S.T.U.V.W.X.Y.Z.`.{.A. +H r !.!.!.!.!.!.!.", 444 | " 4.` !.!.!.4.Q.r.A..+F c.n ++@+#+$+%+&+*+=+o -+e. +H 4.!.!.!.!.!.!.4.` ", 445 | " !.Z !.!.!.!.r Q.X ;+-+>+,+'+)+!+~+~+{+!+]+^+/+(+H 4.!.!.!.!.!.!.!.` 4.", 446 | " r !.!.!.!.!.4.H H _+:+<+[+#+~+~+}+|+1+2+3+4+(+s.H !.!.!.!.!.!.!.!.` 4.", 447 | "!.r !.!.!.!.!.!.!.!.r !.5+6+7+8+9+0+a+b+c+d+e+f+g+!.!.!.!.!.!.!.!.4.` s.", 448 | "!.r !.!.!.!.!.!.!.!.!.r h+i+j+k+l+m+n+o+p+q+r+s+t+!.!.!.!.!.!.!.!.!.Z ", 449 | "4.` !.!.!.!.!.!.!.!.!.4.u+v+w+x+y+q+z+A+B+C+D+E+g+!.!.!.!.!.!.!.!.` s. ", 450 | "` 4.!.!.!.!.!.!.!.!.!.!.F+G+H+I+J+K+L+M+N+O+O+P+Q+!.!.!.!.!.!.!.Z s. ", 451 | "!.4.!.!.!.!.!.!.!.!.!.!.s.R+S+T+U+V+W+X+Y+Z+`+g+` !.!.!.!.!.!.4.H s. ", 452 | "s.!.!.!.!.!.!.!.!.!.!.!.` s. @.@+@@@#@$@%@&@*@s.!.!.!.!.!.!.!.Y 4. ", 453 | "` 4.!.!.!.!.!.!.!.!.!.!.!.` =@-@;@>@,@'@)@!@4.!.!.!.!.!.!.4.!.` ", 454 | "` 4.!.!.!.!.!.!.!.!.!.!.!.!.` s.~@{@]@!@^@4.` !.!.!.!.!.!.4.r ", 455 | "s.` !.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.H 4.!.s.r ", 456 | " s.!.!.!.!.!.!.!.!.!.!.!.4.4.4.4.4.4.4.!.!.4.4.4.H 4.!. ", 457 | " ` 4.!.!.!.!.!.!.!.!.!.H /@(@_@:@:@:@/@<@!@(@(@[@ ", 458 | " s.H !.!.!.!.!.!.!.!.4.]@}@|@1@2@3@4@5@6@7@8@9@ ", 459 | " ` 4.!.!.!.!.!.!.!.!.4.]@3@0@a@b@c@d@e@f@g@h@i@ ", 460 | " H !.!.!.!.!.!.!.!.!.4.j@k@l@m@n@o@p@q@r@s@t@ ", 461 | " Y 4.!.!.!.!.!.!.!.!.!.u@v@w@o@x@q@r@y@t@z@A@ ", 462 | " 4.H !.!.!.!.!.!.!.!.!.r B@C@q@D@E@t@z@A@F@G@ ", 463 | " 4.Z !.!.!.!.!.!.!.4.4.H@I@s@J@K@L@F@M@N@O@P@ ", 464 | " ` !.4.!.!.!.!.!.!.!.H !@Q@R@S@F@M@T@O@U@V@W@ ", 465 | " s.` !.!.!.!.!.!.!.!.4.s.X@Y@Z@`@ #.#+#@### ", 466 | " H ` !.!.!.!.!.!.!.H :@$#%# #&#W@x+*#=#-#;# ", 467 | " 4.Z Y !.!.!.!.!.!.!.` ` >#,#x+'#)#-#!#~#{# ", 468 | " !.Z Y !.!.!.!.!.!.!.s.]#^#/#(#_#~#{#:#<#[# ", 469 | " Z !.!.!.!.!.!.!.!.H ^@}#|#~#1#2#<#<#3#4#[# ", 470 | " Y Z ` !.!.!.!.!.!.!.` F+5#6#3#3#7#3#3#3#4# ", 471 | " !.4.` !.!.!.!.!.!.!.` g+8#7#3#3#3#3#3#3#9# ", 472 | " s.` !.!.!.!.!.!.!.!.` 0#a#3#7#3#3#3#3#3#b# ", 473 | " 4.!.!.!.!.!.!.!.!.!.s.c#d#e#4#<#3#3#3#<#4# ", 474 | " !.!.4.!.!.!.!.!.!.` Q+f#g#h#7#3#3#3#<#4#i# ", 475 | " r !.!.!.!.!.!.!.!.` s.j#k#e#<#3#3#3#<#4# ", 476 | " Z !.4.!.!.!.!.!.!.!.Q+l#m#n#7#<#3#4#<# ", 477 | " r H 4.4.4.4.!.!.4.` F+o#p#q#4#b#r# ", 478 | " s.!.!.!.!.4.4.!.!.` {@ "}; 479 | -------------------------------------------------------------------------------- /django/projects/httpi/httpi/static/css/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | * HTML5 Boilerplate 3 | * 4 | * What follows is the result of much research on cross-browser styling. 5 | * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal, 6 | * Kroc Camen, and the H5BP dev community and team. 7 | * 8 | * Detailed information about this CSS: h5bp.com/css 9 | * 10 | * ==|== normalize ========================================================== 11 | */ 12 | 13 | 14 | /* ============================================================================= 15 | HTML5 display definitions 16 | ========================================================================== */ 17 | 18 | article, 19 | aside, 20 | details, 21 | figcaption, 22 | figure, 23 | footer, 24 | header, 25 | hgroup, 26 | nav, 27 | section, 28 | summary { 29 | display: block; 30 | } 31 | 32 | audio, 33 | canvas, 34 | video { 35 | display: inline-block; 36 | *display: inline; 37 | *zoom: 1; 38 | } 39 | 40 | audio:not([controls]) { 41 | display: none; 42 | } 43 | 44 | [hidden] { 45 | display: none; 46 | } 47 | 48 | 49 | /* ============================================================================= 50 | Base 51 | ========================================================================== */ 52 | 53 | /* 54 | * 1. Correct text resizing oddly in IE6/7 when body font-size is set using em units 55 | * 2. Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g 56 | */ 57 | 58 | html { 59 | font-size: 100%; 60 | -webkit-text-size-adjust: 100%; 61 | -ms-text-size-adjust: 100%; 62 | } 63 | 64 | html, 65 | button, 66 | input, 67 | select, 68 | textarea { 69 | font-family: sans-serif; 70 | color: #222; 71 | } 72 | 73 | body { 74 | margin: 0; 75 | font-size: 1em; 76 | line-height: 1.4; 77 | background-color: #eeeeee; 78 | } 79 | 80 | /* 81 | * Remove text-shadow in selection highlight: h5bp.com/i 82 | * These selection declarations have to be separate. 83 | * Customize the background color to match your design. 84 | */ 85 | 86 | ::-moz-selection { 87 | background: #b3d4fc; 88 | text-shadow: none; 89 | } 90 | 91 | ::selection { 92 | background: #b3d4fc; 93 | text-shadow: none; 94 | } 95 | 96 | 97 | /* ============================================================================= 98 | Links 99 | ========================================================================== */ 100 | 101 | a { 102 | color: #00e; 103 | } 104 | 105 | a:visited { 106 | color: #551a8b; 107 | } 108 | 109 | a:hover { 110 | color: #06e; 111 | } 112 | 113 | a:focus { 114 | outline: thin dotted; 115 | } 116 | 117 | /* 118 | * Improve readability when focused and hovered in all browsers: h5bp.com/h 119 | */ 120 | 121 | a:hover, 122 | a:active { 123 | outline: 0; 124 | } 125 | 126 | 127 | /* ============================================================================= 128 | Typography 129 | ========================================================================== */ 130 | 131 | abbr[title] { 132 | border-bottom: 1px dotted; 133 | } 134 | 135 | b, 136 | strong { 137 | font-weight: bold; 138 | } 139 | 140 | blockquote { 141 | margin: 1em 40px; 142 | } 143 | 144 | dfn { 145 | font-style: italic; 146 | } 147 | 148 | hr { 149 | display: block; 150 | height: 1px; 151 | border: 0; 152 | border-top: 1px solid #ccc; 153 | margin: 1em 0; 154 | padding: 0; 155 | } 156 | 157 | ins { 158 | background: #ff9; 159 | color: #000; 160 | text-decoration: none; 161 | } 162 | 163 | mark { 164 | background: #ff0; 165 | color: #000; 166 | font-style: italic; 167 | font-weight: bold; 168 | } 169 | 170 | /* 171 | * Redeclare monospace font family: h5bp.com/j 172 | */ 173 | 174 | pre, 175 | code, 176 | kbd, 177 | samp { 178 | font-family: monospace, serif; 179 | _font-family: 'courier new', monospace; 180 | font-size: 1em; 181 | } 182 | 183 | /* 184 | * Improve readability of pre-formatted text 185 | */ 186 | 187 | pre { 188 | white-space: pre; 189 | white-space: pre-wrap; 190 | word-wrap: break-word; 191 | } 192 | 193 | q { 194 | quotes: none; 195 | } 196 | 197 | q:before, 198 | q:after { 199 | content: ""; 200 | content: none; 201 | } 202 | 203 | small { 204 | font-size: 85%; 205 | } 206 | 207 | /* 208 | * Position subscript and superscript content without affecting line-height: h5bp.com/k 209 | */ 210 | 211 | sub, 212 | sup { 213 | font-size: 75%; 214 | line-height: 0; 215 | position: relative; 216 | vertical-align: baseline; 217 | } 218 | 219 | sup { 220 | top: -0.5em; 221 | } 222 | 223 | sub { 224 | bottom: -0.25em; 225 | } 226 | 227 | 228 | /* ============================================================================= 229 | Lists 230 | ========================================================================== */ 231 | 232 | ul, 233 | ol { 234 | margin: 1em 0; 235 | padding: 0 0 0 40px; 236 | } 237 | 238 | dd { 239 | margin: 0 0 0 40px; 240 | } 241 | 242 | nav ul, 243 | nav ol { 244 | list-style: none; 245 | list-style-image: none; 246 | margin: 0; 247 | padding: 0; 248 | } 249 | 250 | 251 | /* ============================================================================= 252 | Embedded content 253 | ========================================================================== */ 254 | 255 | /* 256 | * 1. Improve image quality when scaled in IE7: h5bp.com/d 257 | * 2. Remove the gap between images and borders on image containers: h5bp.com/i/440 258 | */ 259 | 260 | img { 261 | border: 0; 262 | vertical-align: middle; 263 | -ms-interpolation-mode: bicubic; 264 | } 265 | 266 | /* 267 | * Correct overflow not hidden in IE9 268 | */ 269 | 270 | svg:not(:root) { 271 | overflow: hidden; 272 | } 273 | 274 | 275 | /* ============================================================================= 276 | Figures 277 | ========================================================================== */ 278 | 279 | figure { 280 | margin: 0; 281 | } 282 | 283 | 284 | /* ============================================================================= 285 | Forms 286 | ========================================================================== */ 287 | 288 | form { 289 | margin: 0; 290 | } 291 | 292 | fieldset { 293 | border: 0; 294 | margin: 0; 295 | padding: 0; 296 | } 297 | 298 | /* 299 | * Indicate that 'label' will shift focus to the associated form element 300 | */ 301 | 302 | label { 303 | cursor: pointer; 304 | } 305 | 306 | /* 307 | * 1. Correct color not inheriting in IE6/7/8/9 308 | * 2. Correct alignment displayed oddly in IE6/7 309 | */ 310 | 311 | legend { 312 | border: 0; 313 | padding: 0; 314 | white-space: normal; 315 | *margin-left: -7px; 316 | } 317 | 318 | /* 319 | * 1. Correct font-size not inheriting in all browsers 320 | * 2. Remove margins in FF3/4 S5 Chrome 321 | * 3. Define consistent vertical alignment display in all browsers 322 | */ 323 | 324 | button, 325 | input, 326 | select, 327 | textarea { 328 | font-size: 100%; 329 | margin: 0; 330 | vertical-align: baseline; 331 | *vertical-align: middle; 332 | } 333 | 334 | /* 335 | * 1. Define line-height as normal to match FF3/4 (set using !important in the UA stylesheet) 336 | */ 337 | 338 | button, 339 | input { 340 | line-height: normal; 341 | } 342 | 343 | /* 344 | * 1. Display hand cursor for clickable form elements 345 | * 2. Allow styling of clickable form elements in iOS 346 | * 3. Correct inner spacing displayed oddly in IE7 (doesn't effect IE6) 347 | */ 348 | 349 | button, 350 | input[type="button"], 351 | input[type="reset"], 352 | input[type="submit"] { 353 | cursor: pointer; 354 | -webkit-appearance: button; 355 | *overflow: visible; 356 | } 357 | 358 | /* 359 | * Re-set default cursor for disabled elements 360 | */ 361 | 362 | button[disabled], 363 | input[disabled] { 364 | cursor: default; 365 | } 366 | 367 | /* 368 | * Consistent box sizing and appearance 369 | */ 370 | 371 | input[type="checkbox"], 372 | input[type="radio"] { 373 | box-sizing: border-box; 374 | padding: 0; 375 | *width: 13px; 376 | *height: 13px; 377 | } 378 | 379 | input[type="search"] { 380 | -webkit-appearance: textfield; 381 | -moz-box-sizing: content-box; 382 | -webkit-box-sizing: content-box; 383 | box-sizing: content-box; 384 | } 385 | 386 | input[type="search"]::-webkit-search-decoration, 387 | input[type="search"]::-webkit-search-cancel-button { 388 | -webkit-appearance: none; 389 | } 390 | 391 | /* 392 | * Remove inner padding and border in FF3/4: h5bp.com/l 393 | */ 394 | 395 | button::-moz-focus-inner, 396 | input::-moz-focus-inner { 397 | border: 0; 398 | padding: 0; 399 | } 400 | 401 | /* 402 | * 1. Remove default vertical scrollbar in IE6/7/8/9 403 | * 2. Allow only vertical resizing 404 | */ 405 | 406 | textarea { 407 | overflow: auto; 408 | vertical-align: top; 409 | resize: vertical; 410 | } 411 | 412 | 413 | /* ============================================================================= 414 | Tables 415 | ========================================================================== */ 416 | 417 | table { 418 | border-collapse: collapse; 419 | border-spacing: 0; 420 | } 421 | 422 | td { 423 | vertical-align: top; 424 | } 425 | 426 | 427 | /* ============================================================================= 428 | Chrome Frame Prompt 429 | ========================================================================== */ 430 | 431 | .chromeframe { 432 | margin: 0.2em 0; 433 | background: #ccc; 434 | color: #000; 435 | padding: 0.2em 0; 436 | } 437 | 438 | 439 | /* ==|== primary styles ===================================================== 440 | Author: 441 | ========================================================================== */ 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | /* ==|== media queries ====================================================== 459 | EXAMPLE Media Query for Responsive Design. 460 | This example overrides the primary ('mobile first') styles 461 | Modify as content requires. 462 | ========================================================================== */ 463 | 464 | @media only screen and (min-width: 35em) { 465 | /* Style adjustments for viewports that meet the condition */ 466 | } 467 | 468 | 469 | 470 | /* ==|== non-semantic helper classes ======================================== 471 | Please define your styles before this section. 472 | ========================================================================== */ 473 | 474 | /* 475 | * Image replacement 476 | */ 477 | 478 | .ir { 479 | border: 0; 480 | font: 0/0 a; 481 | text-shadow: none; 482 | color: transparent; 483 | background-color: transparent; 484 | } 485 | 486 | /* 487 | * Hide from both screenreaders and browsers: h5bp.com/u 488 | */ 489 | 490 | .hidden { 491 | display: none !important; 492 | visibility: hidden; 493 | } 494 | 495 | /* 496 | * Hide only visually, but have it available for screenreaders: h5bp.com/v 497 | */ 498 | 499 | .visuallyhidden { 500 | border: 0; 501 | clip: rect(0 0 0 0); 502 | height: 1px; 503 | margin: -1px; 504 | overflow: hidden; 505 | padding: 0; 506 | position: absolute; 507 | width: 1px; 508 | } 509 | 510 | /* 511 | * Extends the .visuallyhidden class to allow the element to be focusable 512 | * when navigated to via the keyboard: h5bp.com/p 513 | */ 514 | 515 | .visuallyhidden.focusable:active, 516 | .visuallyhidden.focusable:focus { 517 | clip: auto; 518 | height: auto; 519 | margin: 0; 520 | overflow: visible; 521 | position: static; 522 | width: auto; 523 | } 524 | 525 | /* 526 | * Hide visually and from screenreaders, but maintain layout 527 | */ 528 | 529 | .invisible { 530 | visibility: hidden; 531 | } 532 | 533 | /* 534 | * Contain floats: h5bp.com/q 535 | */ 536 | 537 | .clearfix:before, 538 | .clearfix:after { 539 | content: ""; 540 | display: table; 541 | } 542 | 543 | .clearfix:after { 544 | clear: both; 545 | } 546 | 547 | .clearfix { 548 | *zoom: 1; 549 | } 550 | 551 | 552 | 553 | /* ==|== print styles ======================================================= 554 | Print styles. 555 | Inlined to avoid required HTTP connection: h5bp.com/r 556 | ========================================================================== */ 557 | 558 | @media print { 559 | * { 560 | background: transparent !important; 561 | color: #000 !important; /* Black prints faster: h5bp.com/s */ 562 | box-shadow:none !important; 563 | text-shadow: none !important; 564 | } 565 | 566 | a, 567 | a:visited { 568 | text-decoration: underline; 569 | } 570 | 571 | a[href]:after { 572 | content: " (" attr(href) ")"; 573 | } 574 | 575 | abbr[title]:after { 576 | content: " (" attr(title) ")"; 577 | } 578 | 579 | /* 580 | * Don't show links for images, or javascript/internal links 581 | */ 582 | 583 | .ir a:after, 584 | a[href^="javascript:"]:after, 585 | a[href^="#"]:after { 586 | content: ""; 587 | } 588 | 589 | pre, 590 | blockquote { 591 | border: 1px solid #999; 592 | page-break-inside: avoid; 593 | } 594 | 595 | thead { 596 | display: table-header-group; /* h5bp.com/t */ 597 | } 598 | 599 | tr, 600 | img { 601 | page-break-inside: avoid; 602 | } 603 | 604 | img { 605 | max-width: 100% !important; 606 | } 607 | 608 | @page { 609 | margin: 0.5cm; 610 | } 611 | 612 | p, 613 | h2, 614 | h3 { 615 | orphans: 3; 616 | widows: 3; 617 | } 618 | 619 | h2, 620 | h3 { 621 | page-break-after: avoid; 622 | } 623 | } 624 | -------------------------------------------------------------------------------- /django/projects/httpi/httpi/static/js/vendor/modernizr-2.6.1.min.js: -------------------------------------------------------------------------------- 1 | /* Modernizr 2.6.1 (Custom Build) | MIT & BSD 2 | * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load 3 | */ 4 | ;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),k.id=h,(l?k:m).innerHTML+=f,m.appendChild(k),l||(m.style.background="",g.appendChild(m)),i=c(k,a),l?k.parentNode.removeChild(k):m.parentNode.removeChild(m),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(['#modernizr:after{content:"',l,'";visibility:hidden}'].join(""),function(b){a=b.offsetHeight>=1}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return o.call(a)=="[object Function]"}function e(a){return typeof a=="string"}function f(){}function g(a){return!a||a=="loaded"||a=="complete"||a=="uninitialized"}function h(){var a=p.shift();q=1,a?a.t?m(function(){(a.t=="c"?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){a!="img"&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l={},o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};y[c]===1&&(r=1,y[c]=[],l=b.createElement(a)),a=="object"?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),a!="img"&&(r||y[c]===2?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i(b=="c"?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),p.length==1&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&o.call(a.opera)=="[object Opera]",l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return o.call(a)=="[object Array]"},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f