Elias Bakken avatar Elias Bakken committed 92de50f Merge

Comments (0)

Files changed (12)

 *.s#*
 stl/
 *~
+*.pyc

firmware/firmware_pru_0.p

 .entrypoint START
 
 #define PRU0_ARM_INTERRUPT 	19
-#define GPIO1 				0x4804c000		// The adress of the GPIO1 
-#define GPIO_DATAOUT 		0x13c			// This is the register for setting data
-#define CONST_DDR 			0x80001000
-#define DDR_END				0x80002000
-#define CTPPR_1         	0x2202C 	
-#define DDR_MAGIC			0xbabe7175		// Magic number used to reset the DDR counter 
+#define GPIO_DATAOUT 		0x13c				// This is the register for setting data
+#define DDR_MAGIC			0xbabe7175			// Magic number used to reset the DDR counter 
+#define GPIO1 				0x4804C000			// The adress of the GPIO1 bank
+#define GPIO2 				0x481AC000	 		// The adress of the GPIO2 bank
+#define GPIO3 				0x481AE000 			// The adress of the GPIO3 bank 
+#define GPIO1_MASK			(1<<13)|(1<<12)|(1<<30)|(1<<31)|(1<<1)	// Only these two pins are togglable
+#define GPIO2_MASK			(1<<2)
+#define GPIO3_MASK			(1<<19)|(1<<21)		// Only these two pins are togglable
 
 START:
-    LBCO r0, C4, 4, 4					// Load Bytes Constant Offset (?)
-    CLR  r0, r0, 4						// Clear bit 4 in reg 0
-    SBCO r0, C4, 4, 4					// Store Bytes Constant Offset
-
-    MOV r0, 0x00100000					// Configure the programmable pointer register for PRU0 by setting c31_pointer[15:0]
-    MOV r1, CTPPR_1    					// field to 0x0010. This will make C31 point to 0x80001000 (DDR memory).
-    SBBO r0, r1, 0, 4
+    LBCO r0, C4, 4, 4							// Load Bytes Constant Offset (?)
+    CLR  r0, r0, 4								// Clear bit 4 in reg 0
+    SBCO r0, C4, 4, 4							// Store Bytes Constant Offset
 
+	MOV  r10, GPIO1_MASK						// Make the mask
+    MOV  r11, GPIO1 | GPIO_DATAOUT				// Load address
+    MOV  r12, 0xFFFFFFFF ^ (GPIO1_MASK)			// Invert the mask
+	MOV  r13, GPIO2_MASK						// Make the mask
+    MOV  r14, GPIO2 | GPIO_DATAOUT				// Load address 
+    MOV  r15, 0xFFFFFFFF ^ (GPIO2_MASK)			// Invert mask
+	MOV  r16, GPIO3_MASK						// Make the mask
+    MOV  r17, GPIO3 | GPIO_DATAOUT				// Load address
+    MOV  r18, 0xFFFFFFFF ^ (GPIO3_MASK)			// Invert mask
+	
+	MOV  r0, 4									// Load the address of the events_counter 
+	LBBO r6, r0, 0, 4							// Put it in R6
+	MOV  r5, 0									// Make r5 the nr of events counter
+	SBBO r5, r6, 0, 4							// store the number of interrupts that have occured in the second reg of DRAM
+	
 RESET_R4:
-	MOV  r4, CONST_DDR
-	QBA WAIT
+	MOV  r0, 0
+	LBBO r4, r0, 0, 4							// Load the ddr_addr from the first adress in the PRU0 DRAM
+	QBA WAIT									// Check if the end of DDR is reached
 
 BLINK:
-	ADD  r4, r4, 4						// Increment r4
-    LBBO r2, r4, 0, 4					// Load pin data into r2
-    MOV r3, GPIO1 | GPIO_DATAOUT
-    SBBO r2, r3, 0, 4
+	ADD  r4, r4, 4								// Increment r4
+
+    LBBO r2, r4, 0, 4							// Load pin data into r2
+	AND  r2, r2, r10							// Mask the pins to GPIO1
+	LBBO r3, r11, 0, 4							// Load the data currently in addr r3
+	AND	 r3, r3, r12							// Mask the data so only the necessary pins can change
+	OR   r3, r3, r2 							// Add the GPIO1-mask to hinder toggling PRU1's pins
+    SBBO r3, r11, 0, 4							// Ok, set the pins
+
+    LBBO r2, r4, 0, 4							// Load pin data into r2
+	AND  r2, r2, r13							// Mask the pins to GPIO2
+	LBBO r3, r14, 0, 4							// Load the data currently in addr r3
+	AND	 r3, r3, r15							// Mask the data so only the necessary pins can change
+	OR   r3, r3, r2 							// Add the GPIO2-mask to hinder toggling PRU1's pins
+    SBBO r3, r14, 0, 4							// Ok, set the pins
+
+    LBBO r2, r4, 0, 4							// Load pin data into r2
+	AND  r2, r2, r16							// Mask the pins to GPIO3
+	LBBO r3, r17, 0, 4							// Load the data currently in addr r3
+	AND	 r3, r3, r18							// Mask the data so only the necessary pins can change
+	OR   r3, r3, r2 							// Add the GPIO1-mask to hinder toggling PRU1's pins
+    SBBO r3, r17, 0, 4							// Ok, set the pins
 
 	ADD  r4, r4, 4
-    LBBO r0, r4, 0, 4					// Load delay data into r0
+    LBBO r0, r4, 0, 4							// Load delay data into r0
 DELAY:
     SUB r0, r0, 1
     QBNE DELAY, r0, 0
 
     SUB r1, r1, 1
-    QBNE BLINK, r1, 0					// Still more pins to go, jump back
+    QBNE BLINK, r1, 0							// Still more pins to go, jump back
 	ADD  r4, r4, 4			
 
-    MOV R31.b0, PRU0_ARM_INTERRUPT+16   // Send notification to Host that the instructions are done
+	ADD r5, r5, 1								// r5++
+	SBBO r5, r6, 0, 4							// store the number of interrupts that have occured in the second reg of DRAM
+    MOV R31.b0, PRU0_ARM_INTERRUPT+16   		// Send notification to Host that the instructions are done
 
-	MOV  r3, DDR_MAGIC					// Load the fancy word into r3
-	LBBO r2, r4, 0, 4					// Load the next data into r2
-	QBEQ RESET_R4, r2, r3				// Check if the end of DDR is reached
+	MOV  r3, DDR_MAGIC							// Load the fancy word into r3
+	LBBO r2, r4, 0, 4							// Load the next data into r2
+	QBEQ RESET_R4, r2, r3						// Check if the end of DDR is reached
 
 
 WAIT:
-    LBBO r1, r4, 0, 4     				// Load values from external DDR Memory into R1
+    LBBO r1, r4, 0, 4     						// Load values from external DDR Memory into R1
     QBNE BLINK, r1, 0
-	QBA WAIT							// Loop back to wait for new data
+	QBA WAIT									// Loop back to wait for new data
 
-	
-DEBUG:
-    MOV r2, (7<<22)						// Load pin data into r2
-    MOV r3, GPIO1 | GPIO_DATAOUT
-    SBBO r2, r3, 0, 4
-	QBA DEBUG

firmware/firmware_test.py

-''' ddr_write.py - test script for writing to DDR memory using the PyPRUSS library'''
-
-import pypruss
-import mmap
-import struct
-import numpy as np
-
-DDR_BASEADDR        = 0x70000000					# The actual baseaddr is 0x80000000, but due to a bug(?), 
-DDR_HACK            = 0x10001000					# Python accept unsigned int as offset argument.
-DDR_FILELEN         = DDR_HACK+0x1000				# The amount of memory to make available
-DDR_OFFSET          = DDR_HACK						# Add the hack to the offset as well. 
-DDR_MAGIC           = 0xbabe7175
-
-#with open("/dev/mem", "r+b") as f:					# Open the memory device
-#	ddr_mem = mmap.mmap(f.fileno(), DDR_FILELEN, offset=DDR_BASEADDR) # 
-
-ddr_mem = mmap.mmap(0, 0x40000, offset=0x8c080000) # 
-
-
-steps = [(3<<22), 0]*2								# 10 blinks, this control the GPIO1 pins
-delays = [0xFFFFFF]*4								# number of delays. Each delay adds 2 instructions, so ~10ns
-
-data = np.array([steps, delays])					# Make a 2D matrix combining the ticks and delays
-data = data.transpose().flatten()					# Braid the data so every other item is a 
-data = [4]+list(data)+[DDR_MAGIC]						# Make the data into a list and add the number of ticks total
-
-str_data = ""										# Data in string form
-for reg in data:									
-	str_data += struct.pack('L', reg) 				# Make the data, it needs to be a string
-
-print str_data.encode("hex")
-ddr_mem[DDR_OFFSET:DDR_OFFSET+len(str_data)] = str_data	# Write the data to the DDR memory, four bytes should suffice
-ddr_mem.close()										# Close the memory 
-f.close()											# Close the file
-
-pypruss.modprobe()							       	# This only has to be called once pr boot
-pypruss.init()										# Init the PRU
-pypruss.open(0)										# Open PRU event 0 which is PRU0_ARM_INTERRUPT
-pypruss.pruintc_init()								# Init the interrupt controller
-pypruss.exec_program(0, "./firmware_pru_0.bin")			# Load firmware "ddr_write.bin" on PRU 0
-pypruss.wait_for_event(0)							# Wait for event 0 which is connected to PRU0_ARM_INTERRUPT
-pypruss.clear_event(0)								# Clear the event
-pypruss.pru_disable(0)								# Disable PRU 0, this is already done by the firmware
-pypruss.exit()										# Exit, don't know what this does. 
-
-
-

libs/spi/setup.py

+#!/usr/bin/env python
+
+from distutils.core import setup, Extension
+
+from distutils import sysconfig
+import re
+
+vars  = sysconfig.get_config_vars()
+for v in vars:
+	if str(vars[v]).find("--sysroot") > 0:
+		vars[v] =  re.sub("--sysroot=[^\s]+", " ", vars[v])
+
+setup(	name="spi",
+	version="1.1",
+	description="Python bindings for Linux SPI access through spi-dev",
+	author="Volker Thoms",
+	author_email="unconnected@gmx.de",
+	maintainer="Volker Thoms",
+	maintainer_email="unconnected@gmx.de",
+	license="GPLv2",
+	url="http://www.hs-augsburg.de/~vthoms",
+	include_dirs=["/usr/include"],
+	ext_modules=[Extension("spi", ["spimodule.c"])])
+

libs/spi/spimodule.c

+/*
+ * spimodule.c - Python bindings for Linux SPI access through spidev
+ * Copyright (C) 2009 Volker Thoms <unconnected@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <Python.h>
+#include "structmember.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <linux/spi/spidev.h>
+#include <linux/types.h>
+#include <sys/ioctl.h>
+
+PyDoc_STRVAR(SPI_module_doc,
+	"This module defines an object type that allows SPI transactions\n"
+	"on hosts running the Linux kernel. The host kernel must have SPI\n"
+	"support and SPI device interface support.\n"
+	"All of these can be either built-in to the kernel, or loaded from\n"
+	"modules.\n"
+	"\n"
+	"Because the SPI device interface is opened R/W, users of this\n"
+	"module usually must have root permissions.\n");
+
+typedef struct {
+	PyObject_HEAD
+
+	int fd;	/* open file descriptor: /dev/spi-X.Y */
+	uint8_t mode;	/* current SPI mode */
+	uint8_t bpw;	/* current SPI bits per word setting */
+	uint32_t msh;	/* current SPI max speed setting in Hz */
+} SPI;
+
+static PyObject *
+SPI_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+	SPI *self;
+	if ((self = (SPI *)type->tp_alloc(type, 0)) == NULL)
+		return NULL;
+
+	self->fd = -1;
+	self->mode = 0;
+	self->bpw = 0;
+	self->msh = 0;
+
+	Py_INCREF(self);
+	return (PyObject *)self;
+}
+
+PyDoc_STRVAR(SPI_close_doc,
+	"close()\n\n"
+	"Disconnects the object from the interface.\n");
+
+static PyObject *
+SPI_close(SPI *self)
+{
+	if ((self->fd != -1) && (close(self->fd) == -1)) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	self->fd = -1;
+	self->mode = 0;
+	self->bpw = 0;
+	self->msh = 0;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static void
+SPI_dealloc(SPI *self)
+{
+	PyObject *ref = SPI_close(self);
+	Py_XDECREF(ref);
+
+	self->ob_type->tp_free((PyObject *)self);
+}
+
+#define MAXPATH 16
+// DAW - 8/12/12 - increased buffer size from 32 to 1024 bytes
+#define MAXMSGLEN 1024
+
+static char *wrmsg = "Argument must be a list of at least one, "
+				"but not more than 1024 integers";
+
+PyDoc_STRVAR(SPI_write_doc,
+	"write([values]) -> None\n\n"
+	"Write bytes to SPI device.\n");
+
+static PyObject *
+SPI_writebytes(SPI *self, PyObject *args)
+{
+	int		status;
+	uint8_t	ii, len;
+	uint8_t	buf[MAXMSGLEN];
+	PyObject	*list;
+
+	if (!PyArg_ParseTuple(args, "O:write", &list))
+		return NULL;
+
+	if (!PyList_Check(list)) {
+		PyErr_SetString(PyExc_TypeError, wrmsg);
+		return NULL;
+	}
+
+	if ((len = PyList_GET_SIZE(list)) >  MAXMSGLEN) {
+		PyErr_SetString(PyExc_OverflowError, wrmsg);
+		return NULL;
+	}
+
+	for (ii = 0; ii < len; ii++) {
+		PyObject *val = PyList_GET_ITEM(list, ii);
+		if (!PyInt_Check(val)) {
+			PyErr_SetString(PyExc_TypeError, wrmsg);
+			return NULL;
+		}
+		buf[ii] = (__u8)PyInt_AS_LONG(val);
+	}
+
+	status = write(self->fd, &buf[0], len);
+
+	if (status < 0) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	if (status != len) {
+		perror("short write");
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyDoc_STRVAR(SPI_read_doc,
+	"read(len) -> [values]\n\n"
+	"Read len bytes from SPI device.\n");
+
+static PyObject *
+SPI_readbytes(SPI *self, PyObject *args)
+{
+	uint8_t	rxbuf[MAXMSGLEN];
+	int		status, len, ii;
+	PyObject	*list;
+
+	if (!PyArg_ParseTuple(args, "i:read", &len))
+		return NULL;
+
+	/* read at least 1 byte, no more than 1024 */
+	if (len < 1)
+		len = 1;
+	else if (len > sizeof(rxbuf))
+		len = sizeof(rxbuf);
+
+	memset(rxbuf, 0, sizeof rxbuf);
+	status = read(self->fd, &rxbuf[0], len);
+
+	if (status < 0) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	if (status != len) {
+		perror("short read");
+		return NULL;
+	}
+
+	list = PyList_New(len);
+
+	for (ii = 0; ii < len; ii++) {
+		PyObject *val = Py_BuildValue("l", (long)rxbuf[ii]);
+		PyList_SET_ITEM(list, ii, val);
+	}
+
+	Py_INCREF(list);
+	return list;
+}
+
+PyDoc_STRVAR(SPI_xfer_doc,
+	"xfer([values]) -> [values]\n\n"
+	"Perform SPI transaction.\n"
+	"CS will be released and reactivated between blocks.\n"
+	"delay specifies delay in usec between blocks.\n");
+
+static PyObject *
+SPI_xfer(SPI *self, PyObject *args)
+{
+	uint8_t ii, len;
+	int status;
+	int delay = -1;
+	//uint8_t ret = 0;
+	PyObject *list;
+	struct spi_ioc_transfer *xferptr;
+	uint8_t *txbuf, *rxbuf;
+
+	if (!PyArg_ParseTuple(args, "O|i:msg", &list, &delay))
+		return NULL;
+
+	if (!PyList_Check(list)) {
+		PyErr_SetString(PyExc_TypeError, wrmsg);
+		return NULL;
+	}
+
+	if ((len = PyList_GET_SIZE(list)) > MAXMSGLEN) {
+		PyErr_SetString(PyExc_OverflowError, wrmsg);
+		return NULL;
+	}
+
+	if (delay == -1) {
+		delay = 0;
+	}
+
+	xferptr = (struct spi_ioc_transfer*) malloc(sizeof(struct spi_ioc_transfer) * len);
+	txbuf = malloc(sizeof(__u8) * len);
+	rxbuf = malloc(sizeof(__u8) * len);
+
+	for (ii = 0; ii < len; ii++) {
+		PyObject *val = PyList_GET_ITEM(list, ii);
+		if (!PyInt_Check(val)) {
+			PyErr_SetString(PyExc_TypeError, wrmsg);
+			return NULL;
+		}
+		txbuf[ii] = (__u8)PyInt_AS_LONG(val);
+		xferptr[ii].tx_buf = (unsigned long)&txbuf[ii];
+		xferptr[ii].rx_buf = (unsigned long)&rxbuf[ii];
+		xferptr[ii].len = 1;
+		xferptr[ii].delay_usecs = delay;
+		xferptr[ii].speed_hz = 0;      
+		xferptr[ii].bits_per_word = 0;
+	}
+
+	status = ioctl(self->fd, SPI_IOC_MESSAGE(len), xferptr);
+	if (status < 0) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	for (ii = 0; ii < len; ii++) {
+		PyObject *val = Py_BuildValue("l", (long)rxbuf[ii]);
+		PyList_SET_ITEM(list, ii, val);
+	}
+
+	// WA:
+	// in CS_HIGH mode CS isn't pulled to low after transfer, but after read
+	// reading 0 bytes doesnt matter but brings cs down
+	status = read(self->fd, &rxbuf[0], 0);
+
+	free(txbuf);
+	free(rxbuf);
+	free(xferptr);
+
+	Py_INCREF(list);
+	return list;
+}
+
+
+PyDoc_STRVAR(SPI_xfer2_doc,
+	"xfer2([values]) -> [values]\n\n"
+	"Perform SPI transaction.\n"
+	"CS will be held active between blocks.\n");
+
+static PyObject *
+SPI_xfer2(SPI *self, PyObject *args)
+{
+	static char *msg = "Argument must be a list of at least one, "
+				"but not more than 1024 integers";
+	int status;	
+	uint8_t ii, len;
+	PyObject *list;
+	struct spi_ioc_transfer	xfer;
+	uint8_t *txbuf, *rxbuf;
+
+	if (!PyArg_ParseTuple(args, "O:xfer2", &list))
+		return NULL;
+
+	if (!PyList_Check(list)) {
+		PyErr_SetString(PyExc_TypeError, wrmsg);
+		return NULL;
+	}
+
+	if ((len = PyList_GET_SIZE(list)) > MAXMSGLEN) {
+		PyErr_SetString(PyExc_OverflowError, wrmsg);
+		return NULL;
+	}
+
+	txbuf = malloc(sizeof(__u8) * len);
+	rxbuf = malloc(sizeof(__u8) * len);
+
+	for (ii = 0; ii < len; ii++) {
+		PyObject *val = PyList_GET_ITEM(list, ii);
+		if (!PyInt_Check(val)) {
+			PyErr_SetString(PyExc_TypeError, msg);
+			return NULL;
+		}
+		txbuf[ii] = (__u8)PyInt_AS_LONG(val);
+	}
+
+	xfer.tx_buf = (unsigned long)txbuf;
+	xfer.rx_buf = (unsigned long)rxbuf;
+	xfer.len = len;
+	xfer.delay_usecs = 0;
+	xfer.speed_hz = 0;      
+	xfer.bits_per_word = 0;
+	
+	status = ioctl(self->fd, SPI_IOC_MESSAGE(1), &xfer);
+	if (status < 0) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	for (ii = 0; ii < len; ii++) {
+		PyObject *val = Py_BuildValue("l", (long)rxbuf[ii]);
+		PyList_SET_ITEM(list, ii, val);
+	}
+	// WA:
+	// in CS_HIGH mode CS isnt pulled to low after transfer
+	// reading 0 bytes doesn't really matter but brings CS down
+	status = read(self->fd, &rxbuf[0], 0);
+
+	free(txbuf);
+	free(rxbuf);
+
+	Py_INCREF(list);
+	return list;
+}
+
+static int __SPI_set_mode( int fd, __u8 mode) {
+	__u8 test;
+	printf("setmode called with mode = %x\n", mode);
+	if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return -1;
+	}
+	if (ioctl(fd, SPI_IOC_RD_MODE, &test) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return -1;
+	}
+	if (test != mode) {
+		return -1;
+	}
+	return 0;
+}
+
+static PyObject *
+SPI_get_mode(SPI *self, void *closure)
+{
+	PyObject *result = Py_BuildValue("i", (self->mode & (SPI_CPHA | SPI_CPOL) ) );
+	Py_INCREF(result);
+	return result;
+}
+
+static PyObject *
+SPI_get_cshigh(SPI *self, void *closure)
+{
+	PyObject *result;
+
+	if (self->mode & SPI_CS_HIGH)
+		result = Py_True;
+	else
+		result = Py_False;
+
+	Py_INCREF(result);
+	return result;
+}
+
+static PyObject *
+SPI_get_lsbfirst(SPI *self, void *closure)
+{
+	PyObject *result;
+
+	if (self->mode & SPI_LSB_FIRST)
+		result = Py_True;
+	else
+		result = Py_False;
+
+	Py_INCREF(result);
+	return result;
+}
+
+static PyObject *
+SPI_get_3wire(SPI *self, void *closure)
+{
+	PyObject *result;
+
+	if (self->mode & SPI_3WIRE)
+		result = Py_True;
+	else
+		result = Py_False;
+
+	Py_INCREF(result);
+	return result;
+}
+
+static PyObject *
+SPI_get_loop(SPI *self, void *closure)
+{
+	PyObject *result;
+
+	if (self->mode & SPI_LOOP)
+		result = Py_True;
+	else
+		result = Py_False;
+
+	Py_INCREF(result);
+	return result;
+}
+
+
+static int
+SPI_set_mode(SPI *self, PyObject *val, void *closure)
+{
+	uint8_t mode, tmp;
+
+	if (val == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+			"Cannot delete attribute");
+		return -1;
+	}
+	else if (!PyInt_Check(val)) {
+		PyErr_SetString(PyExc_TypeError,
+			"The mode attribute must be an integer");
+		return -1;
+	}
+
+	mode = PyInt_AsLong(val);
+
+	if ( mode > 3 ) {
+		PyErr_SetString(PyExc_TypeError,
+			"The mode attribute must be an integer"
+				 "between 0 and 3.");
+		return -1;
+	}
+
+	// clean and set CPHA and CPOL bits
+	tmp = ( self->mode & ~(SPI_CPHA | SPI_CPOL) ) | mode ;
+
+	__SPI_set_mode(self->fd, tmp);
+
+	self->mode = tmp;
+	printf("mode now: %x\n", self->mode);
+	return 0;
+}
+
+static int
+SPI_set_cshigh(SPI *self, PyObject *val, void *closure)
+{
+	uint8_t tmp;
+
+	if (val == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+			"Cannot delete attribute");
+		return -1;
+	}
+	else if (!PyBool_Check(val)) {
+		PyErr_SetString(PyExc_TypeError,
+			"The cshigh attribute must be boolean");
+		return -1;
+	}
+
+	if (val == Py_True)
+		tmp = self->mode | SPI_CS_HIGH;
+	else
+		tmp = self->mode & ~SPI_CS_HIGH;
+
+	__SPI_set_mode(self->fd, tmp);
+
+	self->mode = tmp;
+	printf("mode now: %x\n", self->mode);
+	return 0;
+}
+
+static int
+SPI_set_lsbfirst(SPI *self, PyObject *val, void *closure)
+{
+	uint8_t tmp;
+
+	if (val == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+			"Cannot delete attribute");
+		return -1;
+	}
+	else if (!PyBool_Check(val)) {
+		PyErr_SetString(PyExc_TypeError,
+			"The lsbfirst attribute must be boolean");
+		return -1;
+	}
+
+	if (val == Py_True)
+		tmp = self->mode | SPI_LSB_FIRST;
+	else
+		tmp = self->mode & ~SPI_LSB_FIRST;
+
+	__SPI_set_mode(self->fd, tmp);
+
+	self->mode = tmp;
+	printf("mode now: %x\n", self->mode);
+	return 0;
+}
+
+static int
+SPI_set_3wire(SPI *self, PyObject *val, void *closure)
+{
+	uint8_t tmp;
+
+	if (val == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+			"Cannot delete attribute");
+		return -1;
+	}
+	else if (!PyBool_Check(val)) {
+		PyErr_SetString(PyExc_TypeError,
+			"The 3wire attribute must be boolean");
+		return -1;
+	}
+
+	if (val == Py_True)
+		tmp = self->mode | SPI_3WIRE;
+	else
+		tmp = self->mode & ~SPI_3WIRE;
+
+	__SPI_set_mode(self->fd, tmp);
+
+	self->mode = tmp;
+	printf("mode now: %x\n", self->mode);
+	return 0;
+}
+
+static int
+SPI_set_loop(SPI *self, PyObject *val, void *closure)
+{
+	uint8_t tmp;
+
+	if (val == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+			"Cannot delete attribute");
+		return -1;
+	}
+	else if (!PyBool_Check(val)) {
+		PyErr_SetString(PyExc_TypeError,
+			"The loop attribute must be boolean");
+		return -1;
+	}
+
+	if (val == Py_True)
+		tmp = self->mode | SPI_LOOP;
+	else
+		tmp = self->mode & ~SPI_LOOP;
+
+	__SPI_set_mode(self->fd, tmp);
+
+	self->mode = tmp;
+	printf("mode now: %x\n", self->mode);
+	return 0;
+}
+
+static PyObject *
+SPI_get_bpw(SPI *self, void *closure)
+{
+	PyObject *result = Py_BuildValue("i", self->bpw);
+	Py_INCREF(result);
+	return result;
+}
+
+static int
+SPI_set_bpw(SPI *self, PyObject *val, void *closure)
+{
+	uint8_t bits;
+
+	if (val == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+			"Cannot delete attribute");
+		return -1;
+	}
+	else if (!PyInt_Check(val)) {
+		PyErr_SetString(PyExc_TypeError,
+			"The bpw attribute must be an integer");
+		return -1;
+	}
+
+	bits = PyInt_AsLong(val);
+
+        if (bits < 8 || bits > 16) {
+		PyErr_SetString(PyExc_TypeError,
+                                "invalid bits_per_word (8 to 16)");
+		return -1;
+	}
+
+	if (self->bpw != bits) {
+		if (ioctl(self->fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) {
+			PyErr_SetFromErrno(PyExc_IOError);
+			return -1;
+		}
+		self->bpw = bits;
+	}
+	return 0;
+}
+
+static PyObject *
+SPI_get_msh(SPI *self, void *closure)
+{
+	PyObject *result = Py_BuildValue("i", self->msh);
+	Py_INCREF(result);
+	return result;
+}
+
+static int
+SPI_set_msh(SPI *self, PyObject *val, void *closure)
+{
+	uint32_t msh;
+
+	if (val == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+			"Cannot delete attribute");
+		return -1;
+	}
+	else if (!PyInt_Check(val)) {
+		PyErr_SetString(PyExc_TypeError,
+			"The msh attribute must be an integer");
+		return -1;
+	}
+
+	msh = PyInt_AsLong(val);
+	// DAW - 8/12/12 - removed limitation on SPI speed
+	// if (8000000 < msh) {
+		// PyErr_SetString(PyExc_TypeError,
+			// "The mode attribute must be an integer < 8000000.");
+		// return -1;
+	// }
+
+	if (self->msh != msh) {
+		if (ioctl(self->fd, SPI_IOC_WR_MAX_SPEED_HZ, &msh) == -1) {
+			PyErr_SetFromErrno(PyExc_IOError);
+			return -1;
+		}
+		self->msh = msh;
+	}
+	return 0;
+}
+
+static PyGetSetDef SPI_getset[] = {
+	{"mode", (getter)SPI_get_mode, (setter)SPI_set_mode,
+			"SPI mode as two bit pattern of \n"
+			"Clock Polarity  and Phase [CPOL|CPHA]\n"
+			"min: 0b00 = 0 max: 0b11 = 3\n"},
+	{"cshigh", (getter)SPI_get_cshigh, (setter)SPI_set_cshigh,
+			"CS active high\n"},
+	{"threewire", (getter)SPI_get_3wire, (setter)SPI_set_3wire,
+			"SI/SO signals shared\n"},
+	{"lsbfirst", (getter)SPI_get_lsbfirst, (setter)SPI_set_lsbfirst,
+			"LSB first\n"},
+	{"loop", (getter)SPI_get_loop, (setter)SPI_set_loop,
+			"loopback configuration\n"},
+	{"bpw", (getter)SPI_get_bpw, (setter)SPI_set_bpw,
+			"bits per word\n"},
+	{"msh", (getter)SPI_get_msh, (setter)SPI_set_msh,
+			"maximum speed in Hz\n"},
+	{NULL},
+};
+
+PyDoc_STRVAR(SPI_open_doc,
+	"open(bus, device)\n\n"
+	"Connects the object to the specified SPI device.\n"
+	"open(X,Y) will open /dev/spidev-X.Y\n");
+
+static PyObject *
+SPI_open(SPI *self, PyObject *args, PyObject *kwds)
+{
+	int bus, device;
+	char path[MAXPATH];
+	uint8_t tmp8;
+	uint32_t tmp32;
+	static char *kwlist[] = {"bus", "device", NULL};
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii:open", kwlist, &bus, &device))
+		return NULL;
+	if (snprintf(path, MAXPATH, "/dev/spidev%d.%d", bus, device) >= MAXPATH) {
+		PyErr_SetString(PyExc_OverflowError,
+			"Bus and/or device number is invalid.");
+		return NULL;
+	}
+	if ((self->fd = open(path, O_RDWR, 0)) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+	if (ioctl(self->fd, SPI_IOC_RD_MODE, &tmp8) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+	self->mode = tmp8;
+	if (ioctl(self->fd, SPI_IOC_RD_BITS_PER_WORD, &tmp8) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+	self->bpw = tmp8;
+	if (ioctl(self->fd, SPI_IOC_RD_MAX_SPEED_HZ, &tmp32) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+	self->msh = tmp32;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static int
+SPI_init(SPI *self, PyObject *args, PyObject *kwds)
+{
+	int bus = -1;
+	int client = -1;
+	static char *kwlist[] = {"bus", "client", NULL};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:__init__",
+			kwlist, &bus, &client))
+		return -1;
+
+	if (bus >= 0) {
+		SPI_open(self, args, kwds);
+		if (PyErr_Occurred())
+			return -1;
+	}
+
+	return 0;
+}
+
+
+PyDoc_STRVAR(SPI_type_doc,
+	"SPI([bus],[client]) -> SPI\n\n"
+	"Return a new SPI object that is (optionally) connected to the\n"
+	"specified SPI device interface.\n");
+
+static PyMethodDef SPI_methods[] = {
+	{"open", (PyCFunction)SPI_open, METH_VARARGS | METH_KEYWORDS,
+		SPI_open_doc},
+	{"close", (PyCFunction)SPI_close, METH_NOARGS,
+		SPI_close_doc},
+	{"readbytes", (PyCFunction)SPI_readbytes, METH_VARARGS,
+		SPI_read_doc},
+	{"writebytes", (PyCFunction)SPI_writebytes, METH_VARARGS,
+		SPI_write_doc},
+	{"xfer", (PyCFunction)SPI_xfer, METH_VARARGS,
+		SPI_xfer_doc},
+	{"xfer2", (PyCFunction)SPI_xfer2, METH_VARARGS,
+		SPI_xfer2_doc},
+	{NULL},
+};
+
+static PyTypeObject SPI_type = {
+	PyObject_HEAD_INIT(NULL)
+	0,				/* ob_size */
+	"SPI",			/* tp_name */
+	sizeof(SPI),			/* tp_basicsize */
+	0,				/* tp_itemsize */
+	(destructor)SPI_dealloc,	/* tp_dealloc */
+	0,				/* tp_print */
+	0,				/* tp_getattr */
+	0,				/* tp_setattr */
+	0,				/* tp_compare */
+	0,				/* tp_repr */
+	0,				/* tp_as_number */
+	0,				/* tp_as_sequence */
+	0,				/* tp_as_mapping */
+	0,				/* tp_hash */
+	0,				/* tp_call */
+	0,				/* tp_str */
+	0,				/* tp_getattro */
+	0,				/* tp_setattro */
+	0,				/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,		/* tp_flags */
+	SPI_type_doc,			/* tp_doc */
+	0,				/* tp_traverse */
+	0,				/* tp_clear */
+	0,				/* tp_richcompare */
+	0,				/* tp_weaklistoffset */
+	0,				/* tp_iter */
+	0,				/* tp_iternext */
+	SPI_methods,			/* tp_methods */
+	0,				/* tp_members */
+	SPI_getset,			/* tp_getset */
+	0,				/* tp_base */
+	0,				/* tp_dict */
+	0,				/* tp_descr_get */
+	0,				/* tp_descr_set */
+	0,				/* tp_dictoffset */
+	(initproc)SPI_init,		/* tp_init */
+	0,				/* tp_alloc */
+	SPI_new,			/* tp_new */
+};
+
+static PyMethodDef SPI_module_methods[] = {
+	{NULL}
+};
+
+#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+initspi(void)
+{
+	PyObject* m;
+
+	if (PyType_Ready(&SPI_type) < 0)
+		return;
+
+	m = Py_InitModule3("spi", SPI_module_methods, SPI_module_doc);
+	Py_INCREF(&SPI_type);
+	PyModule_AddObject(m, "SPI", (PyObject *)&SPI_type);
+}
+

software/Gcode.py

     def removeTokenByLetter(self, letter):
          for i, token in enumerate(self.tokens):
             if token[0] == letter:
-                print token+" "+str(i)  
                 self.tokens.pop(i)
 
     def numTokens(self):
 
     ''' Get the result of the execution '''
     def getAnswer(self):
-        print self.message + " = " +self.answer
+        #print self.message + " = " +self.answer
         return self.answer
     
     ''' Set a new answer other than 'ok'  '''
         
     ''' Get the length of this path segment '''
     def get_length(self):      
-        if not "X" in self.axes or not "Y" in self.axes:
-            return 0.0
-        x = self.axes["X"]/1000.0
-        y = self.axes["Y"]/1000.0
+        if "X" in self.axes:
+            x = self.axes["X"]/1000.0
+            if self.movement == "ABSOLUTE":
+                x -= self.global_pos["X"]
+        else:
+            x = 0
+        if "Y" in self.axes:
+            y = self.axes["Y"]/1000.0
+            if self.movement == "ABSOLUTE":        
+                y -= self.global_pos["Y"]
+        else:
+            y = 0
 
-        if self.movement == "ABSOLUTE":
-            x -= self.global_pos["X"]
-            y -= self.global_pos["Y"]
         self.length = np.sqrt(x**2+y**2)                             # calculate the hypotenuse to the X-Y vectors, 
 
         if "Z" in self.axes:
     def get_max_speed(self):
         return (self.feed_rate/60.0)/1000.0
 
+    ''' Get the ratio for this axis '''
+    def get_axis_ratio(self, axis):
+        hyp     = self.get_length()    	                                # Calculate the ratio               
+        if hyp == 0.0:
+            return 1.0
+        return abs(self.get_axis_length(axis))/hyp
+
     ''' Get the lowest speed along this segment '''
     def get_min_speed(self):
         return 0
 
+
     ''' Return the list of axes '''
     def get_axes(self):
         return self.axes

software/Path_planner.py

 '''
 
 import time
+import logging
 import numpy as np  
 from threading import Thread
 from Pru import Pru
+import Queue
 
 class Path_planner:
     ''' Init the planner '''
-    def __init__(self, steppers):
-        self.steppers = steppers
-        self.pru = Pru()                                        # Make the PRU
-        self.paths = list()                                     # Make a list of paths
-        self.current_pos = {"X":0.0, "Y":0.0, "Z":0.0, "E":0.0} # Current position in (x, y, z, e)
-        self.running = True                                     # Yes, we are running
-        self.t = Thread(target=self._do_work)                   # Make the thread
+    def __init__(self, steppers, current_pos):
+        self.steppers    = steppers
+        self.pru         = Pru()                                # Make the PRU
+        self.paths       = Queue.Queue(100)                      # Make a queue of paths
+        self.current_pos = current_pos                          # Current position in (x, y, z, e)
+        self.running     = True                                 # Yes, we are running
+        self.t           = Thread(target=self._do_work)         # Make the thread
         self.t.start()		                
 
     ''' Set the acceleration used '''
 
     ''' Add a path segment to the path planner '''        
     def add_path(self, new):        
-        self.paths.append(new)
-        if len(self.paths) > 1:
-            prev = self.paths[0]
-            new.set_prev(prev)
-            prev.set_next(new)
+        self.paths.put(new)
         
     ''' Return the number of paths currently on queue '''
     def nr_of_paths(self):
-        return len(self.paths)
+        return self.paths.qsize()
 
+    ''' Set position for an axis '''
+    def set_pos(self, axis, val):
+        self.current_pos[axis] = val
+ 
+    ''' This loop pops a path, sends it to the PRU 
+    and waits for an event '''
+    def _do_work(self):
+        events_waiting = 0
+        while self.running:       
+            try: 
+                path = self.paths.get(timeout = 1)                            # Get the last path added
+                path.set_global_pos(self.current_pos.copy())       # Set the global position of the printer
+                axes_added = 0
+                all_data = {}
+                slowest =  0
+                for axis in path.get_axes():                       # Run through all the axes in the path    
+                    stepper = self.steppers[axis]                  # Get a handle of  the stepper                    
+                    data = self._make_data(path, axis)
+                    if len(data[0]) > 0:
+                        all_data[axis] = data                      # Generate the timing and pin data                         
+                        slowest = max(slowest, sum(data[1]))   
+                                
+
+                for axis in all_data:                         
+                    packet = all_data[axis]                           
+                    delays = np.array(packet[1])
+                    #print "Axis "+axis+" uses "+str(sum(delays))
+                    diff = (slowest-sum(delays))/len(delays)
+                    for j, delay in enumerate(delays):
+                        delays[j] = max(delay+diff, 1.0/10000.0)    # min 0.2ms                     
+                    data = (packet[0], delays)  
+                    #print "Axis "+axis+" uses "+str(sum(delays))
+                
+                if "Z" in all_data:     # HACK! The Z-axis cannot be combined with the other data
+                    packet = all_data["Z"]      
+                    while not self.pru.has_capacity_for(len(packet[0])*8):# Wait until the PRU has capacity for this chunk of data
+                        print "PRU does not have capacity for "+str(len(packet[0])*8),
+                        print "only has "+str(self.pru.get_capacity())
+                        time.sleep(1)                   
+                    if self.pru.add_data(packet) > 0:                        
+                        self.pru.commit_data() 
+                    del all_data["Z"]
+                    
+                for axis in all_data:   # Commit the other axes    
+                    packet = all_data[axis]
+                    while not self.pru.has_capacity_for(len(packet[0])*8):# Wait until the PRU has capacity for this chunk of data
+                        print "PRU does not have capacity for "+str(len(packet[0])*8),
+                        print "only has "+str(self.pru.get_capacity())
+                        time.sleep(1)                   
+                    axes_added += self.pru.add_data(packet)
+                    
+                if axes_added > 0:
+                    self.pru.commit_data()                            # Commit data to ddr
+                                     
+                self.paths.task_done()
+               
+            except Queue.Empty:
+                pass
     ''' Join the thread '''
     def exit(self):
         self.running = False
+        self.pru.join()
+        logging.debug("pru joined")
         self.t.join()
+        logging.debug("path planner joined")
 
-    def set_pos(self, axis, pos):
-        self.current_pos[axis] = pos
-    
-    def get_pos(self, axis):
-        return self.current_pos[axis]
-
-    def reset_pos(self):
-        self.current_pos = {"X":0.0, "Y":0.0, "Z":0.0, "E":0.0}
-        print "Path planner: pos reset"
-    
-    ''' Add a certain length to a vector '''
-    def add_to_pos(axis, vec):
-        self.current_pos[axis] += vec
-
-    ''' This loop pops a path, sends it to the PRU 
-    and waits for an event '''
-    def _do_work(self):
-        while self.running:
-            if len(self.paths) > 0:
-                path = self.paths.pop(0)                            # Get the last path added
-                path.set_global_pos(self.current_pos.copy())               # Set the global position of the printer
-                for axis in path.get_axes():                        # Run through all the axes in the path
-                    if path.get_axis_length(axis) == 0:
-                        continue
-                    stepper = self.steppers[axis]                   # Get a handle of  the stepper
-                    data = self._make_data(path, axis)              # Generate the timing and pin data                         
-                    if stepper.has_pru():                           # If this stepper has a PRU associated with it
-                        pru_num = stepper.get_pru()
-                        self.pru.add_data(data, pru_num) 
-                    else:               
-                        stepper.add_data(data)                      # If not, let the stepper fix this.     
-
-                for axis in path.get_axes():                        
-                    self.steppers[axis].prepare_move()              # Make them start performing
-                for axis in path.get_axes():                        
-                    self.steppers[axis].start_move()                # Make them start performing
-
-                self.pru.commit_data()                              # Commit data to ddr 
-                self.pru.wait_for_event()                           # Wait for the PRU to finish execution 
-                for axis in path.get_axes():                        
-                    self.steppers[axis].end_move()                  # Join threads
-                print "_do_work done"
-            else:
-                time.sleep(0.1)                                     # If there is no paths to execute, sleep. 
 
     ''' Make the data for the PRU or steppers '''
-    def _make_data(self, path, axis):        
-        vec         = path.get_axis_length(axis)                        # Total travel distance
-        stepper     = self.steppers[axis]
-        num_steps   = int(abs(vec) * stepper.get_steps_pr_meter())      # Number of steps to tick
+    def _make_data(self, path, axis):     
+        stepper         = self.steppers[axis]
+        steps_pr_meter  = stepper.get_steps_pr_meter()
+        vec             = path.get_axis_length(axis)                        # Total travel distance
+        num_steps       = int(abs(vec) * steps_pr_meter)                    # Number of steps to tick
+        if num_steps == 0:
+            return ([], [])
         step_pin    = stepper.get_step_pin()                            # Get the step pin
         dir_pin     = stepper.get_dir_pin()                             # Get the direction pin
         dir_pin     = 0 if vec < 0 else dir_pin                         # Disable the dir-pin if we are going backwards               
-        delays      = self._calculate_delays(path, axis)                # Make the delays
         pins        = [step_pin | dir_pin, dir_pin]*num_steps           # Make the pin states
 
-        if len(delays) > num_steps:                                     # If the delays is longer than the steps, something is wrong
-            delays = []
-        if num_steps == 1:
-            delays = [0]            
+        s           = abs(path.get_axis_length(axis))                   # Get the length of the vector
+        ratio       = path.get_axis_ratio(axis)
+
+        Vm = path.get_max_speed()*ratio				                    # The travelling speed in m/s
+        a  = self.acceleration*ratio    		                        # Accelleration in m/s/s
+        ds = 1.0/steps_pr_meter                                         # Delta S, distance in meters travelled pr step. 
+        u  = ratio*path.get_min_speed()                 	            # Minimum speed in m/s
+        tm = (Vm-u)/a					                                # Calculate the time for when max speed is met. 
+        sm = min(u*tm + 0.5*a*tm*tm, s/2.0)			                    # Calculate the distance traveled when max speed is met
+
+        distances       = list(np.arange(0, sm, ds))		            # Table of distances                       
+        timestamps      = [(-u+np.sqrt(2.0*a*ss+u*u))/a for ss in distances]# Make a table of times when a tick occurs   
+        delays          = np.diff(timestamps)/2.0			                # We are more interested in the delays pr second.         
+        #logging.info(axis+" Ramp single uses "+str(sum(delays)))
+        delays = list(np.array([delays, delays]).transpose().flatten()) # Double the array so we have timings for up and down  
+        #logging.info(axis+" Ramp uses "+str(sum(delays)))
+
+        #logging.info("ratio: "+str(ratio))
+        #logging.info("ds: "+str(ds))
+        #logging.info("Vm: "+str(Vm))
+
         i_steps     = num_steps-len(delays)		                        # Find out how many delays are missing
-        i_delays    = delays[-1::]*i_steps*2		                    # Make the intermediate steps
+        i_delays    = [(ds/Vm)/2.0]*i_steps*2		                    # Make the intermediate steps
         delays      += i_delays+delays[::-1]                            # Add the missing delays. These are max_speed
-
-        td          = num_steps/stepper.get_steps_pr_meter()            # Calculate the actual travelled distance        
+        td          = num_steps/steps_pr_meter                          # Calculate the actual travelled distance        
         if vec < 0:                                                     # If the vector is negative, negate it.      
             td     *= -1.0
 
         path.set_travelled_distance(axis, td)                           # Set the travelled distance back in the path 
         self.current_pos[axis] += td                                    # Update the global position vector
-        #print "Axis: "+axis+",  Vector: "+str(vec)+",  Num_steps: "+str(num_steps)
-        #print "Global position: "+str(self.current_pos)
 
+        #logging.info(axis+" uses "+str(sum(delays)))
         return (pins, delays)                                           # return the pin states and the data
 
-    ''' Caluclate the delays for a path vector '''
-    def _calculate_delays(self, path, axis):
-        s       = abs(path.get_axis_length(axis))                             # Get the length of the vector
-        hyp     = path.get_length()    	                                # Calculate the ratio               
-        if hyp == 0.0:
-            ratio = 1
-        else:
-            ratio = s/hyp
-        Vm = path.get_max_speed()*ratio				                    # The travelling speed in m/s
-        a  = self.acceleration*ratio    		                        # Accelleration in m/s/s
-        ds = 1.0/self.steppers[axis].get_steps_pr_meter()               # Delta S, distance in meters travelled pr step. 
-        u  = ratio*path.get_min_speed()                 	            # Minimum speed in m/s
 
-        #print "Axis: "+str(axis)+", vec: "+str(s)+", len: "+str(path.get_length())+", ratio: "+str(ratio)
-        tm = (Vm-u)/a					                                # Calculate the time for when max speed is met. 
-        sm = u*tm + 0.5*a*tm*tm			                                # Calculate the distace travelled when max speed is met
-        if sm > s/2.0:                                                  # If the distance is too short, we do not reach full speed 
-            sm = s/2.0            
-        if ds > sm:                                                     # If the delta-step is too small, force it to become 2*ds
-            sm = 2.0*ds
-        
-        distances   = np.arange(0, sm, ds)		                        # Table of distances
-        timestamps  = [(-u+np.sqrt(2.0*a*s+u*u))/a for s in distances]  # Make a table of times, the time at which a tick occurs
-        delays      = np.diff(timestamps)/2.0			                # We are more interested in the delays pr second. 
-        delays      = np.array([delays, delays]).transpose().flatten()	# Double the array so we have timings for up and down
-        
-        return list(delays)
 
 
-  
+'''
+for axis in all_data: 
+    packet = all_data[axis]                           
+    delays = np.array(packet[1])
+    diff = (slowest-sum(delays))/len(delays)
+    for j, delay in enumerate(delays):
+        delays[j] = max(delay+diff, 2.0/10000)                     
+    data = (packet[0], delays)                    
+    self.steppers[axis].add_data(data)
+
+for axis in all_data:                            
+    self.steppers[axis].prepare_move()
+for axis in all_data:                            
+    self.steppers[axis].start_move()
+for axis in all_data:                            
+    self.steppers[axis].end_move()               
+'''                         
+
+
 
 import os
 os.system("export LD_LIBRARY_PATH=/usr/local/lib")
+import logging
 import pypruss      					                            # The Programmable Realtime Unit Library
 import numpy as np						                            # Needed for braiding the pins with the delays
-from threading import Thread
+from threading import Thread, Lock
+import Queue
 import time 
 import mmap
 import struct 
 
-DDR_BASEADDR		= 0x70000000					# The actual baseaddr is 0x80001000, but due to a bug(?), 
-DDR_HACK			= 0x10001000					# Python accept unsigned int as offset argument.
-DDR_END			    = DDR_HACK+0x4000 				# The amount of memory to make available
-DDR_START			= DDR_HACK						# Add the hack to the offset as well. 
-DDR_LEN             = DDR_END-DDR_START
 DDR_MAGIC			= 0xbabe7175
 
 class Pru:
     def __init__(self):
-        pru_hz 			    = 200*1000*1000		            # The PRU has a speed of 200 MHz
-        self.s_pr_inst 		= 1.0/pru_hz		            # I take it every instruction is a single cycle instruction
-        self.inst_pr_loop 	= 16				            # This is the minimum number of instructions needed to step. 
-        self.inst_pr_delay 	= 2					            # Every loop adds two instructions: i-- and i != 0            
-        self.pru_data       = [[], []]                      
-        self.ddr_start      = DDR_START
-        with open("/dev/mem", "r+b") as f:					# Open the memory device
-            self.ddr_mem = mmap.mmap(f.fileno(), DDR_HACK+DDR_LEN, offset=DDR_BASEADDR) # 
-            self.ddr_mem[DDR_START:DDR_START+4] = struct.pack('L', 0) 
+        pru_hz 			    = 200*1000*1000             # The PRU has a speed of 200 MHz
+        self.s_pr_inst 		= 1.0/pru_hz                # I take it every instruction is a single cycle instruction
+        self.inst_pr_loop 	= 16                        # This is the minimum number of instructions needed to step. 
+        self.inst_pr_delay 	= 2                         # Every loop adds two instructions: i-- and i != 0            
+        self.pru_data       = []      	    	        # This holds all data for one move (x,y,z,e1,e2)
+        self.ddr_used       = Queue.Queue(100)           # List of data lengths currently in DDR for execution
+        self.ddr_reserved   = 0      
+        self.ddr_mem_used   = 0  
+        self.clear_events   = []       
+        self.ddr_lock       = Lock() 
 
-        pypruss.modprobe()							       	# This only has to be called once pr boot
-        pypruss.init()										# Init the PRU
-        pypruss.open(0)										# Open PRU event 0 which is PRU0_ARM_INTERRUPT
-        pypruss.pruintc_init()								# Init the interrupt controller
-        pypruss.exec_program(0, "../firmware/firmware_pru_0.bin")			# Load firmware "ddr_write.bin" on PRU 0
-        print "PRU initialized"
+        self.i = 0
+        pypruss.modprobe(0x40000)    			        # This only has to be called once pr boot
+        self.ddr_addr = pypruss.ddr_addr()
+        self.ddr_size = pypruss.ddr_size() 
+        print "The DDR memory reserved for the PRU is "+hex(self.ddr_size)+" and has addr "+hex(self.ddr_addr)
 
+        ddr_offset     		= self.ddr_addr-0x10000000  # The Python mmap function cannot accept unsigned longs. 
+        ddr_filelen    		= self.ddr_size+0x10000000
+        self.DDR_START      = 0x10000000
+        self.DDR_END        = 0x10000000+self.ddr_size
+        self.ddr_start      = self.DDR_START
+        self.ddr_nr_events  = self.ddr_addr+self.ddr_size-4
 
 
+        with open("/dev/mem", "r+b") as f:	            # Open the memory device
+            self.ddr_mem = mmap.mmap(f.fileno(), ddr_filelen, offset=ddr_offset) # mmap the right area            
+            self.ddr_mem[self.ddr_start:self.ddr_start+4] = struct.pack('L', 0)  # Add a zero to the first reg to make it wait
+       
+        pypruss.init()						            # Init the PRU
+        pypruss.open(0)						            # Open PRU event 0 which is PRU0_ARM_INTERRUPT
+        pypruss.pruintc_init()					        # Init the interrupt controller
+        pypruss.pru_write_memory(0, 0, [self.ddr_addr, self.ddr_nr_events])		# Put the ddr address in the first region 
+        pypruss.exec_program(0, "../firmware/firmware_pru_0.bin")	# Load firmware "ddr_write.bin" on PRU 0
+        self.t = Thread(target=self._wait_for_events)         # Make the thread
+        self.running = True
+        self.t.start()		                
+
+        logging.debug("PRU initialized")
+
     ''' Add some data to one of the PRUs '''
-    def add_data(self, data, pru_num):
+    def add_data(self, data):
         (pins, delays) = data                       	    # Get the data
         if len(pins) == 0:
-            return 
-        print "Adding data len for "+str(pru_num)+": "+str(len(pins))
+            return 0
         delays = map(self._sec_to_inst, delays)     	    # Convert the delays in secs to delays in instructions
         data = np.array([pins, delays])		        	    # Make a 2D matrix combining the ticks and delays
         data = list(data.transpose().flatten())     	    # Braid the data so every other item is a pin and delay
         
-        if len(self.pru_data[pru_num]) > 0:
-            self.pru_data[pru_num] = self._braid_data(data, self.pru_data[pru_num])
+        self.ddr_reserved += len(data)*4		            # This amount is now reserved, waiting to be committed       
+
+        if len(self.pru_data) > 0:
+            self.pru_data = self._braid_data(data, self.pru_data)
         else:
-            self.pru_data[pru_num] = data
+            self.pru_data = data
+        return 1
+
+    ''' Check if the PRU has capacity for a chunk of data '''
+    def has_capacity_for(self, data_len):
+        with self.ddr_lock:
+            cap = self.ddr_size-self.ddr_mem_used
+        return (cap > data_len) 
+
+    ''' Check if the PRU has capacity for a chunk of data '''
+    def get_capacity(self):
+        with self.ddr_lock:
+            cap = self.ddr_size-self.ddr_mem_used
+        return cap
 
     ''' Commit the data to the DDR memory '''
     def commit_data(self):
-        data = struct.pack('L', len(self.pru_data[0])/2)	    # Data in string form
-        for reg in self.pru_data[0]:									
+        data = struct.pack('L', len(self.pru_data)/2)	    	# Data in string form
+        for reg in self.pru_data:									
             data += struct.pack('L', reg) 				        # Make the data, it needs to be a string
-        data += struct.pack('L', 0)                             # Add a terminating 0, this keeps it looping.
+        data += struct.pack('L', 0)                             # Add a terminating 0, this keeps the fw waiting for a new command.
 
         self.ddr_end = self.ddr_start+len(data)       
-        if self.ddr_end > DDR_END:                              # If the data is too long, wrap it around to the start
-            multiple = (DDR_END-self.ddr_start)%8               # Find a multiple of 8
-            cut = DDR_END-self.ddr_start-multiple-4             # The cut must be done after a delay, so a multiple of 8 bytes +/-4
-            first = struct.pack('L', cut/8)+data[4:cut]         # Update the loop count
-            first += struct.pack('L', DDR_MAGIC)                # Add the magic number to force a reset of DDR memory counter
+        if self.ddr_end >= self.DDR_END-16:                        # If the data is too long, wrap it around to the start
+            multiple = (self.DDR_END-self.ddr_start)%8          # Find a multiple of 8
+            cut = self.DDR_END-self.ddr_start-multiple-4-8      # The cut must be done after a delay, so a multiple of 8 bytes +/-4
+        
+            first = struct.pack('L', len(data[4:cut])/8)+data[4:cut]    # Update the loop count
+            first += struct.pack('L', DDR_MAGIC)            # Add the magic number to force a reset of DDR memory counter
+            print "Laying out from "+hex(self.ddr_start)+" to "+hex(self.ddr_start+len(first))
             self.ddr_mem[self.ddr_start:self.ddr_start+len(first)] = first  # Write the first part of the data to the DDR memory.
-            second = struct.pack('L', (len(data[cut:-4])/8))+data[cut:]     # Add the number of steps in this iteration
-            self.ddr_end = DDR_START+len(second)                # Update the end counter
-            self.ddr_mem[DDR_START:self.ddr_end] = second       # Write the second half of data to the DDR memory.
-            self.wait_for_event()                               # Must wait for event here
+
+            with self.ddr_lock:
+                self.ddr_mem_used += len(first)
+            self.ddr_used.put(len(first))
+            self.ddr_reserved -= len(first)
+
+            if len(data[cut:-4]) > 0:                                 # If len(data) == 4, only the terminating zero is present..
+                second = struct.pack('L', (len(data[cut:-4])/8))+data[cut:]     # Add the number of steps in this iteration
+                self.ddr_end = self.DDR_START+len(second)           # Update the end counter
+                print "Second batch starts from "+hex(self.DDR_START)+" to "+hex(self.ddr_end)
+                print "First register is "+hex(struct.unpack("L", second[0:4])[0])
+                print "Last register is "+hex(struct.unpack("L", second[-4::])[0])
+                self.ddr_mem[self.DDR_START:self.ddr_end] = second  # Write the second half of data to the DDR memory.
+            else:
+                 self.ddr_end = self.DDR_START
+                 self.ddr_mem[self.DDR_START:4] = struct.pack('L', 0) # Terminate the first word
+                print "Second batch skipped, 0 length"
+            
+            print "Wrapped. Capacity is now "+str(self.get_capacity())
         else:
             self.ddr_mem[self.ddr_start:self.ddr_end] = data    # Write the data to the DDR memory.
-            if DDR_END-self.ddr_end < 16:                       # There is no room for a complete  step, add the magic number to wrap
-                self.ddr_mem[self.ddr_end-4:self.ddr_end] = struct.pack('L', DDR_MAGIC)
-                self.ddr_mem[DDR_START:DDR_START+4] = struct.pack('L', 0) # Terminate the next instruction
-                self.ddr_end = DDR_START+4                
-                print "wrapped due to insufficient DDR"
 
-        self.ddr_start = self.ddr_end-4                         # Update the start of ddr for next time 
-        self.pru_data = [[],[]]                                 # Reset the pru_data list since it has been commited         
+        self.ddr_start 		= self.ddr_end-4                    # Update the start of ddr for next time 
+        with self.ddr_lock:
+            self.ddr_mem_used += self.ddr_reserved
+            #print "Pushed "+str(self.ddr_reserved)+ "\tnow "+str(self.ddr_used.qsize())
+        self.ddr_used.put(self.ddr_reserved) 		            # update the amount of memory used 
+        self.ddr_reserved   = 0        
+        self.pru_data 		= []                                # Reset the pru_data list since it has been commited         
 
 
-    ''' Wait for the PRU to finish '''                
-    def wait_for_event(self):
-        pypruss.wait_for_event(PRU_EVTOUT_0)				    # Wait a while for it to finish.
-        pypruss.clear_event(PRU0_ARM_INTERRUPT)				    # Clear the event 
-        pypruss.wait_for_event(PRU_EVTOUT_0)				    # Wait a while for it to finish.
-        pypruss.clear_event(PRU0_ARM_INTERRUPT)				    # Clear the event 
+    ''' Catch events coming from the PRU '''                
+    def _wait_for_events(self):
+        events_caught = 0
+        self.dev = os.open("/dev/uio0", os.O_RDONLY)
+        self.new_events = 0
+        self.old_events = 0
+        nr_interrupts = 0
+        while self.running:                    
+                self._wait_for_event()
+                pypruss.clear_event(PRU0_ARM_INTERRUPT)			# Clear the event        
+                nr_interrupts += 1
+                nr_events = struct.unpack("L", self.ddr_mem[self.DDR_END-4:self.DDR_END])[0]            
+                if nr_interrupts != nr_events:
+                    print "Error, nr of interrupts ("+str(nr_interrupt)+") != nr of events ("+str(nr_events)+")"
+                #print "Events: "+str(nr_events)+" nr of interrupts: "+str(nr_interrupts)
+                ddr = self.ddr_used.get()                       # Pop the first ddr memory amount           
+                with self.ddr_lock:
+                    self.ddr_mem_used -= ddr
+                    #print "Popped "+str(ddr)+"\tnow "+str(self.ddr_used.qsize())
+                self.ddr_used.task_done()
+
+    ''' Wait for an event. The resturn is the number of events that have occured since last check '''
+    def _wait_for_event(self):
+        self.new_events =  struct.unpack("L", os.read(self.dev, 4))[0]
+        ret = self.new_events-self.old_events
+        self.old_events = self.new_events
+        return ret
 
     ''' Close shit up '''
-    def close(self):
-        ddr_mem.close()                                         # Close the memory 
-        f.close()                                               # Close the file
+    def join(self):
+        logging.debug("joining")
+        self.running = False
+        self.t.join()        
+        self.ddr_mem.close()                                         # Close the memory        
         pypruss.pru_disable(0)                                  # Disable PRU 0, this is already done by the firmware
-        #pypruss.pru_disable(1)                                 # Disable PRU 0, this is already done by the firmware
         pypruss.exit()                                          # Exit, don't know what this does. 
         
-
     ''' Convert delay in seconds to number of instructions for the PRU '''
     def _sec_to_inst(self, s):					    # Shit, I'm missing MGP for this??
         inst_pr_step  = s/self.s_pr_inst  		    # Calculate the number of instructions of delay pr step. 
         return int(inst_pr_step)			        # Make it an int
 
 
-    ''' Braid together the data from the two data sets'''
+    ''' Braid/merge together the data from the two data sets'''
     def _braid_data(self, data1, data2):
         braids = [data1[0] | data2[0]]
         del data1[0]

software/Replicape.py

 
 import bbio as io
 from math import sqrt
+import time
+import Queue 
+import logging
 
 from Mosfet import Mosfet
 from Smd import SMD
 from Path import Path
 from Path_planner import Path_planner
     
+logging.basicConfig(level=logging.INFO)
+
 class Replicape:
     ''' Init '''
     def __init__(self):
         self.steppers["Z"]  = SMD(io.GPIO1_1,  io.GPIO2_2,  io.GPIO0_27, 2, "Z")  
         self.steppers["E"]  = SMD(io.GPIO3_21, io.GPIO3_19, io.GPIO2_3,  4, "Ext1")
 
-        # Enable the steppers and set current,  
+        # Enable the steppers and set the current, steps pr mm and microstepping  
         self.steppers["X"].setCurrentValue(2.0) # 2A
         self.steppers["X"].setEnabled() 
         self.steppers["X"].set_steps_pr_mm(6.105)         
         self.steppers["X"].set_microstepping(2) 
-        self.steppers["X"].set_pru(0)
 
         self.steppers["Y"].setCurrentValue(2.0) # 2A
         self.steppers["Y"].setEnabled() 
         self.steppers["Y"].set_steps_pr_mm(5.95)
         self.steppers["Y"].set_microstepping(2) 
-        self.steppers["Y"].set_pru(1)
 
         self.steppers["Z"].setCurrentValue(1.0) # 2A
         self.steppers["Z"].setEnabled() 
-        self.steppers["Z"].set_steps_pr_mm(149.25)
-        self.steppers["Z"].set_microstepping(0) 
+        self.steppers["Z"].set_steps_pr_mm(155)
+        self.steppers["Z"].set_microstepping(2) 
 
-        self.steppers["E"].setCurrentValue(1.0) # 2A        
+        self.steppers["E"].setCurrentValue(1.8) # 2A        
         self.steppers["E"].setEnabled()
         self.steppers["E"].set_steps_pr_mm(5.0)
         self.steppers["E"].set_microstepping(2)
-        self.steppers["E"].set_pru(0)
 
         # init the 3 thermistors
         self.therm_ext1 = Thermistor(io.AIN4, "Ext_1", chart_name="QU-BD")
         self.ext1.setPvalue(0.5)
         self.ext1.setDvalue(0.1)     
         self.ext1.setIvalue(0.001)
-     
-        self.hbp = HBP( self.therm_hbp, self.mosfet_hbp)        # Make Heated Build platform 
-        #self.hbp.debugLevel(1)
+
+        # Make Heated Build platform 
+        self.hbp = HBP( self.therm_hbp, self.mosfet_hbp)       
 
         # Init the three fans
         self.fan_1 = Fan(1)
         self.fan_3 = Fan(3)
 
         # Make a queue of commands
-        self.queue = list()
+        self.commands = Queue.Queue()
 
         # Set up USB, this receives messages and pushes them on the queue
-        self.usb = USB(self.queue)		
+        self.usb = USB(self.commands)		
 
         # Get all options 
         self.options = Options()
 
-        # Make the positioning vector
-        self.position = {"x": 0, "y": 0, "z": 0}
-        
+        # Init the path planner
         self.movement = "RELATIVE"
         self.feed_rate = 3000.0
+        self.current_pos = {"X":0.0, "Y":0.0, "Z":0.0, "E":0.0}
+        self.acceleration = 300.0/1000.0
 
-        # Init the path planner
-        self.path_planner = Path_planner(self.steppers)         
-        self.path_planner.set_acceleration(300.0/1000.0) 
+        self.path_planner = Path_planner(self.steppers, self.current_pos)         
+        self.path_planner.set_acceleration(self.acceleration) 
+        logging.debug("Debug prints to console")
 	
     ''' When a new gcode comes in, excute it '''
     def loop(self):
         try:
-            while True:
-                if len(self.queue) > 0:
-                    gcode = Gcode(self.queue.pop(0), self)
-                    self._execute(gcode)
-                    self.usb.send_message(gcode.getAnswer())
-                else:
-                    io.delay(10)
+            while True:                
+                gcode = Gcode(self.commands.get(), self)
+                self._execute(gcode)
+                self.usb.send_message(gcode.getAnswer())
+                self.commands.task_done()
         except KeyboardInterrupt:
             print "Caught signal, exiting" 
             return
         finally:
-            self.cleanUp()  
+            self.ext1.disable()
+            self.hbp.disable()
+            self.usb.close() 
+            self.path_planner.exit()   
+        logging.debug("Done")
 		
     ''' Execute a G-code '''
     def _execute(self, g):
             for i in range(g.numTokens()):                          # Run through all tokens
                 axis = g.tokenLetter(i)                             # Get the axis, X, Y, Z or E
                 smds[axis] = float(g.tokenValue(i))                 # Get tha value, new position or vector             
-            path = Path(smds, feed_rate, self.movement)             # Make a path segment from the axes
-            while self.path_planner.nr_of_paths() > 4:              # If the queue is full, wait. 
-                io.delay(100)                                       # This is the waiting part
-            self.path_planner.add_path(path)                        # Ok, add the path to the planner queue
+            path = Path(smds, feed_rate, self.movement)             # Make a path segment from the axes            
+            self.path_planner.add_path(path)                        # Add the path. This blocks until the path planner has capacity
         elif g.code() == "G21":                                     # Set units to mm
             self.factor = 1.0
         elif g.code() == "G28":                                     # Home the steppers
             if g.numTokens() == 0:                                  # If no token is given, home all
-                g.setTokens(["X", "Y", "Z"])
+                g.setTokens(["X0", "Y0", "Z0"])                
+            smds = {}                                               # All steppers 
             for i in range(g.numTokens()):                          # Run through all tokens
                 axis = g.tokenLetter(i)                             # Get the axis, X, Y, Z or E
-                val = -self.path_planner.get_pos(axis)*1000.0
-                self.steppers[axis].move(val, self.movement)        # Get tha value, new position or vector             
-            self.path_planner.reset_pos()
+                smds[axis] = float(g.tokenValue(i))                 # Get tha value, new position or vector             
+            path = Path(smds, self.feed_rate, "ABSOLUTE")           # Make a path segment from the axes
+            self.path_planner.add_path(path)                        # Add the path. This blocks until the path planner has capacity
+        elif g.code() == "G29": 
+            print self.current_pos
         elif g.code() == "G90":                                     # Absolute positioning
             self.movement = "ABSOLUTE"
         elif g.code() == "G91":                                     # Relative positioning 
                 val = float(g.tokenValue(i))
                 self.path_planner.set_pos(axis, val)
         elif g.code() == "M17":                                     # Enable all steppers
-            self.enableAllSteppers()
+            for name, stepper in self.steppers.iteritems():
+                stepper.setEnabled()
         elif g.code() == "M30":                                     # Set microstepping (Propietary to Replicape)
             for i in range(g.numTokens()):
                 self.steppers[g.tokenLetter(i)].set_microstepping(int(g.tokenValue(i)))            
         elif g.code() == "M84":                                     # Disable all steppers
-            self.disableAllSteppers()
+            for name, stepper in self.steppers.iteritems():
+            	stepper.setDisabled()
+        elif g.code() == "M101":									# Deprecated 
+            pass 													
+        elif g.code() == "M103":									# Deprecated
+            pass 													
         elif g.code() == "M104":                                    # Set extruder temperature
             self.ext1.setTargetTemperature(float(g.tokenValue(0)))
         elif g.code() == "M105":                                    # Get Temperature
         elif g.code() == "M106":                                    # Fan on
             self.fan_1.setPWMFrequency(100)
             self.fan_1.setValue(float(g.tokenValue(0)))	
+        elif g.code() == "M108":									# Deprecated
+            pass 													
         elif g.code() == "M110":                                    # Reset the line number counter 
             Gcode.line_number = 0       
         elif g.code() == "M130":                                    # Set PID P-value, Format (M130 P0 S8.0)
             self.hbp.setTargetTemperature(float(g.tokenValue(0)))
         else:
             print "Unknown command: "+g.message	
-
-    ''' Stop all threads '''
-    def cleanUp(self):
-        self.ext1.disable()
-        self.hbp.disable()
-        self.usb.close() 
-        self.path_planner.exit()
-
-    ''' Move the stepper motors '''
-    def moveTo(self, stepper, pos):
-        print "Moving "+stepper+" to "+str(pos)
-        self.steppers[stepper].moveTo(pos)
-
-    ''' Move the stepper motors '''
-    def move(self, stepper, amount, feed_rate):
-        print "Moving "+stepper+" "+str(amount)+"mm @ F:"+str(feed_rate)
-        self.steppers[stepper].setFeedRate(feed_rate)
-        self.steppers[stepper].move(amount)
-
-    ''' Set the current position of each of the steppers is '''
-    def setCurrentPosition(self, stepper, pos):
-        self.steppers[stepper].setCurrentPosition(pos)
-
-    ''' Disable all steppers '''
-    def disableAllSteppers(self):
-        for name, stepper in self.steppers.iteritems():
-            stepper.setDisabled()
-
-    ''' Enable all steppers '''
-    def enableAllSteppers(self):		
-        for name, stepper in self.steppers.iteritems():
-            stepper.setEnabled()
-		
-    ''' Given an X and Y vector and a feed_rate, 
-    calculate the feed_rates of the two vectors.''' 
-    def decompose_vector(self, x, y, e, feed_rate_hyp):
-        hyp = sqrt(x**2+y**2)
-        feed_rate_ratio = feed_rate_hyp/hyp        
-        feed_rate_y = feed_rate_ratio*abs(y)
-        feed_rate_x = feed_rate_ratio*abs(x)
-        feed_rate_e = feed_rate_ratio*abs(e)
-        
-        return (feed_rate_x, feed_rate_y, feed_rate_e)
-          
-
+   
 r = Replicape()
 r.loop()
 
         bytes = []
         for smd in SMD.all_smds:	   
             bytes.append(smd.getState())
-        print "Updating registers with: "+str(bytes[::-1])
         spi2_1.writebytes(bytes[::-1])
 
     ''' Init'''
     def setEnabled(self):
         if not self.enabled:
             self.state &= ~(1<<6)
-            self.update()
             self.enabled = True
-	
+            self.update()
+            	
     ''' Sets the SMD disabled '''
     def setDisabled(self):
-        print "setDisabled called"
         if self.enabled:
             self.state |= (1<<6)
-            self.update()
             self.enabled = False
-            print "smd disabled, state = "+bin(self.state)
+            self.update()           
 
     '''Logic high to enable device, logic low to enter
     low-power sleep mode. Internal pulldown.'''
         (pins, delays) = data
         self.pins = pins
         self.delays = delays
-        print "steps: "+str(len(self.pins))+" delays "+str(len(self.delays))
+        #print "steps: "+str(len(self.pins))+" delays "+str(len(self.delays))
     
     ''' Prepare a move. But do not start the thread yet. '''
     def prepare_move(self):
 #from Gcode import Gcode
 from threading import Thread
 import select
+import logging
 
 class USB:
     def __init__(self, queue):
             ret = select.select( [self.tty],[],[], 1.0 )
     	    if ret[0] == [self.tty]:
                 message = self.tty.readline().strip("\n")          
-                if self.debug > 1:
-                    print "Message: "+message+" ("+message.encode("hex")+")"	
-                self.queue.append(message)
+                logging.debug("Message: "+message+" ("+message.encode("hex")+")")
+                self.queue.put(message)
             
 
     # Send a message		
     def send_message(self, message):
-        if self.debug > 1:           
-            print "USB: writing '"+message+"'"
+        logging.debug("USB: writing '"+message+"'")
         if message[-1] != "\n":
             message += "\n"
         self.tty.write(message)
     # Stop receiving mesassages
     def close(self):
         self.running = False
-        self.t.join(1.5)
+        self.t.join()
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.