Tag: python

May 14th 2011

Embedded development setup with Macbook

Tags: python howto embedded Written by Dave Barker

I’ve been put onto an interesting project recently, doing some embedded Python development for a Telit GM862-GPS unit. Being new to this type of thing it took me a while to get a development environment set up that I was happy with. In an effort to share what I’ve learned, here’s my setup:

(To be clear I’m using the Roundsolutions development starter kit for the Telit GM862-GPS with my Macbook pro.)

Roundsolutions dev board

First of all I had to install the usb-serial driver (PL2303_1.2.1r2.dmg) to get the serial port working. Once that’s installed and it’s connected the serial device /dev/tty.usbserial appeared for use.

Next I followed this guide and connected to the device using the GNU Screen command that’s included with Snowleopard. This command worked nicely: screen -S telit -T vt100 /dev/tty.usbserial 115200,crtcts,-parity,-cstopb

Typing AT returned OK and I knew I was in business!

I soon found that deploying code over serial manually was pretty tedious, it’s easy to mess up the AT commands. I wrote this script to automate the process, making deployment as easy as telit-send-python.py telit example.py.

The next issue I hit was that my code was sometimes being crapped up during transfer. I eventually figured out I was using the wrong line terminators for my files, Unix style just uses \n where as the Telit module demands \n\r (DOS style). To convert my files in Emacs I used the buffer-file-coding-system command, so M-x set buffer-file-coding-system undecided dos.

Next I realised backspace wasn’t being transmitted properly across Screen, there’s an option in the Advanced section of Terminal preferences “Delete sends Cntrl-H” which resolved it for me. Unfortunately I found it messed up my normal SSH sessions, a better solution is to have this fixed in GNU Screen, add these lines to your ~/.screenrc:

bindkey -d ^? stuff ^H
bindkey -d ^@ stuff ^H

Another annoyance with Screen was that I wasn’t able to scroll up like normal in my Terminal windows. Luckily fixing that was pretty easy, I added this to my ~/.screenrc : termcapinfo xterm* ti@:te@

Messing with SMS at commands I realised that the body of a SMS needs to be terminated with 0x1a, it bit tricky to type but there’s a solution, Screen’s “digraph” feature. To send 0x1a here’s what I did: C-a C-v 0x1a.

So the next thing I really wanted to was to get the Telit version of Python running locally, allowing me to test things interactively at a ‘REPL’. The units run a modified version of Python 1.5.2 and unfortunately I had no luck compiling or installing a version that old under Snowleopard. My solution in the end was to install the Windows version TelitPy1.5.2+_V4.1.exe using Wine. I then set up a little shell-script shortcut to launch it easily. (It installs to ~/.wine/drive_c/Program\ Files/Python/python.exe )

Now I’ve got a pretty sweet set up, but having the PCB dangling off the side of my Macbook in Starbucks isn’t really an option. So I plugged it into my Linux server at home and then I can SSH in and deploy code / interact with the Terminal. (Using Emacs’ tramp feature I can edit the code directly over SSH too.)

Only thing worth noting is that the naming convention for serial devices seems different in Linux. Also I found that sometimes the LANG environment variable ended up corrupting the binary transfer. Here’s the Screen command I ended up using: unset LANG && screen -S telit -T vt100 /dev/ttyUSB0 115200,crtcts,-parity,-cstopb.

Read the Stty man page for details about those serial options at the end.

I also sometimes needed to check what Screen’s really sending out, helpful for debugging problems with transmitting binary data. It’s not hard though, just start a Screen session and run this command inside it: stty raw; cat > binary-file-name.

(Just make sure to exit using the C-a :quit screen command rather, most special keys will be sent directly through into your file.)

Finaly while I’m waiting for the Python debugging board to arrive I needed to have some way of getting output through to the serial port. Otherwise it’s hard to know if your code even ran at all. Turns out it’s not too hard, here’s a (noddy) example:

import SER, MOD, MDM, GPS, sys

# Set the baud rate
SER.set_speed('115200', '8N1')

# Send stout and stderr over serial
# http://forum.sparkfun.com/viewtopic.php?t=6289
class SerWriter:
  def write(self, s):
    SER.send(s + '\r')
sys.stdout = sys.stderr = SerWriter()

# You get the idea...
print "Lovely stuff"

Thanks for reading, I’d be interested to hear how any tips you’ve got in the comments. Also if anyone knows a better support forum / community than the Roundsolutions one let me know.

Cheers, Dave.

Edit: I’ve just discovered Sparkfun’s evaluation board. The board looks a lot nicer, it’s cheaper and Sparkfun actually list prices and stock. I’ve just been browsing their forum and it’s way friendlier too, I would definitely go with Sparkfun over Roundsolutions if you get the choice.

Edit 2: I’ve had all sorts of problems uploading Python scripts larger than about 7kb to the Telit module. In the end I updated my script to send files in chunks with enough delay for the module to catch up. I also had problems deleting large files until I removed the quotes around a file name. Much much more details on this forum post.

Edit 3: I’ve just been shown this great guide about Telit Python development, well worth reading.

November 18th 2010

Syncing Google calendar with Facebook birthdays and events

Tags: howto project python Written by Dave Barker

Hi everyone,

I recently tried to get Facebook birthdays and events to show up in my Google calendar. Everything I tried was broken, I just couldn’t find something that worked properly.

Anyway I’ve made my own solution, it’s available here: http://apps.facebook.com/calenderp

You have to click two install buttons (one with Facebook and one with Google) and then your calendar will be synced. It gets timezones right, has been translated into 3 languages so far and is starting to build up a fair following of users.

If you’re interested in the technical side of things I’ve shared the source on GitHub https://github.com/kzar/CalenDerp. It uses Python, Google appengine, Facebook’s graph API and the Google calendar API to sync everything.

Anyway let me know if you have feedback!

Cheers, Dave.

Edit: Also I’m looking for translators, get in touch if you can translate about 20 phrases into your language for me.

July 14th 2009

web.py captcha form

Tags: web.py python code Written by Dave Barker

I coded a basic captcha for my web.py form, here’s how:

First I made a function that generates an image and returns it + the code (yea yea it’s a mess).

import Image, ImageDraw, ImageFont, cStringIO, random

def getCaptcha():
    im = Image.new("RGB", (100, 60))
    draw = ImageDraw.Draw(im)

    for x in range(0, 100):
        for y in range(0, 60):
            draw.point((x, y), (135, 191, 107))

    font = ImageFont.truetype('cracked.ttf', 50)

    alphabet = 'abcdefghijklmnopqrstuvwxyz'

    word = ''
    for i in range(5):
        word = word + alphabet[random.randint(0, len(alphabet) -1)]

    draw.text((5, 5), word, font=font, fill=(0, 0, 0))

    f = cStringIO.StringIO()
    im.save(f, "GIF")
    f.seek(0)
    return word, f

Now here’s snippets of web.py code:

urls = (
    ...
    '/captcha.gif', 'captcha'
)

if web.config.get('_session') is None:
    session = web.session.Session(app, web.session.DiskStore('sessions'), initializer={'captcha': ''})
    web.config._session = session
else:
    session = web.config._session

vcaptcha = form.Validator('Please enter the code',  lambda x:x == session.captcha)

enquiry_form = form.Form(
    ...
    form.Textbox("captcha", vcaptcha, description="Validation Code", pre="<img src='/captcha.gif' valign=center><br>", class_="standard", style="width:70px;"),
)

class captcha:
    def GET(self):
        web.header("Content-Type", "image/gif")
        captcha = getCaptcha()
        session.captcha = captcha[0]
        return captcha[1].read()

Also to make the form look prettier I modified web.py to give the table rows an id and then used css to alter their padding etc.

Sorry I didn’t take much time over this post, hopefully the code will get you started though, Dave.

January 06th 2012

Telit GM862-GPS hex() bug

Tags: code news python embedded Written by Dave Barker

My SHA1 code was returning a different hex digest when run on my Telit GM862 GPS. I eventually tracked the problem down to the hex() function. Simply put hex(3181490320L) does not return the right result!

Run this test script and post your results below.

import sys, SER, MDM

# Set up printing to serial
SER.set_speed('115200', '8N1')
class SerWriter:
  def write(self, s):
    SER.send(s + "\r")
sys.stdout = sys.stderr = SerWriter()

# Simplistic AT command function
def at_command(command):
  # Clear the command interface buffer
  MDM.read()
  # Send the command
  MDM.send(command + '\r', 0)
  # Create a buffer
  buffer = ''
  while 1:
    # Listen to serial port for click
    incoming = MDM.receive(1)
    # If we got some data handle it
    if incoming:
      buffer = buffer + incoming
      if buffer.find("OK") > -1:
        return buffer
      elif buffer.find("ERROR") > -1:
        return ''

# Run the tests
print at_command("AT+CGMM")
print at_command("AT+CGMR")
i = 3181490320L
print i
print long(hex(i), 16)

# Restore standard out
sys.stdout = sys.stderr = sys.__stdout__

My output was:

OK

GM862-GPS

OK


07.03.402

OK

3181490320
2376183952

Cheers, Dave.

Edit: In case anyone’s interested here’s my hex() replacement. It’s probably much slower but it works and can pad the hex string to x bytes.

def write_hex(x, bytes=1):
  h = ['0'] * bytes * 2
  i = 0
  while x > 0:
    if i < bytes * 2:
      h[i] = '0123456789abcdef'[x & 0xf]
    else:
      h.append('0123456789abcdef'[x & 0xf])
    x = x >> 4
    i = i + 1
  h.reverse()
  return ''.join(h)

July 10th 2009

I like Python

Tags: python thoughts Written by Dave Barker

So I decided to learn Python and Django in the hopes it would be a half way house between PHP and Lisp, letting me actually get stuff done whilst not being PHP.

My first impression of Django has been pretty bad, I bought the ‘definitive guide’ book only to find it was not so much definitive as obsolete. Also the amount of arbitrary seeming magic didn’t impress. Having said that I have passed through that and I’m beginning to get the hang of it.

Python on the other hand was different, to start with I HATED the look of the code compared to Lisp but after a few hours hacking it doesn’t seem that bad. For my first program I decided to solve this little puzzle. This great guide got me going quickly and along with a few small pointers from verte in the friendly seeming #python I came to a solution.

def draw_diamond(letter):
    alphabet = 'abcdefghijklmnopqrstuvqxyz'
    size = alphabet.find(letter)

    for x in range(size) + range(size, -1, -1):
        line = [' '] * ((2 * size) + 1)
        line[size + x] = alphabet[x]
        line[size - x] = alphabet[x]
        print "".join(line)

draw_diamond('d')

It didn’t take long, the code looks nice and most importantly I enjoyed writing it. I’m pretty impressed!

July 10th 2009

web.py tutorial + sqlite

Tags: python web.py howto Written by Dave Barker

If you want to follow the web.py tutorial using sqlite here’s how:

Line for your python to connect to DB

db = web.database(dbn='sqlite', db='testdb')

To create the database type sqlite3 testdb and input this SQL:

CREATE TABLE todo (id integer primary key, title text, created date, done boolean default 'f');
CREATE TRIGGER insert_todo_created after insert on todo
begin
update todo set created = datetime('now')
where rowid = new.rowid;
end;

Now create an entry with this SQL

insert into todo (title) values ('Learn web.py');

Finally quit sqlite3 when your ready by typing .quit

October 01st 2010

Web.py checkboxes

Tags: web.py python howto code Written by Dave Barker

Checkboxes are a bit tricky with web.py, here’s how to get them working:

import web
from web import form

example_form = form.Form(
    form.Checkbox("lovelycheckbox", description="lovelycheckbox", class_="standard", value="something.. Anything!"),
    form.Button("Update checkbox", type="submit", description="Send"),
    )

class grabresults:
    def GET(self):
        f = example_form()
        return f.render()
    def POST(self):
        f = example_form()
        theresult = f['lovelycheckbox'].checked

OK, so that’s a dumb (and untested) example, but it gives you an idea. The ‘theresult’ variable is going to be true or false depending on if the ‘thelovelycheckbox’ was ticked or not.

Things to note:

  1. The checkbox has to be given a value, it’s a bug with web.py.
  2. To get the result you use .checked instead of the normal .value

Cheers, Dave.