Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit of PyCSP

  • Loading branch information...
commit 11f6af9c6f5ea9fd6c3873c05acdc56e793c1de8 0 parents
@marshall authored
Showing with 564 additions and 0 deletions.
  1. +3 −0  .gitignore
  2. +5 −0 README.md
  3. +108 −0 csp.py
  4. +376 −0 libcsp.py
  5. +72 −0 simple.py
3  .gitignore
@@ -0,0 +1,3 @@
+*.pyc
+*.dylib
+*.so
5 README.md
@@ -0,0 +1,5 @@
+PyCSP
+----
+A higher level API and bug fixes for python bindings of the Cubesat Space Protocol: http://libcsp.org
+
+See simple.py for a python port of the libcsp simple.c
108 csp.py
@@ -0,0 +1,108 @@
+# A higher level wrapper around the native libcsp bindings
+import ctypes
+import time
+from libcsp import *
+
+def buffer_init(count, size):
+ return csp_buffer_init(count, size)
+
+def init(my_node_address):
+ return csp_init(my_node_address)
+
+def route_start_task(task_stack_size, priority):
+ return csp_route_start_task(task_stack_size, priority)
+
+def ping(node, timeout, size, options):
+ return csp_ping(node, timeout, size, options)
+
+def service_handler(conn, packet):
+ csp_service_handler(conn.conn, packet.packet)
+
+class CspSocket(object):
+ def __init__(self, options=CSP_SO_NONE, _sock=None):
+ self.sock = _sock or csp_socket(options)
+
+ def bind(self, port):
+ return csp_bind(self.sock, port)
+
+ def listen(self, max_clients):
+ return csp_listen(self.sock, max_clients)
+
+ def accept(self, timeout):
+ conn = csp_accept(self.sock, ctypes.c_uint(timeout))
+ return CspConnection(None, None, _conn=conn)
+
+class CspPacket(object):
+ def __init__(self, length=-1, data=None, _packet=None):
+ length += csp_packet_t.CSP_BUFFER_PACKET_OVERHEAD
+ self.packet = _packet or ctypes.cast(csp_buffer_get(length),
+ ctypes.POINTER(csp_packet_t))
+ if data:
+ self.data = data
+
+ @property
+ def id(self):
+ return self.packet.id.id
+
+ @property
+ def data(self):
+ return ctypes.cast(self.packet.contents.data, ctypes.c_char_p).value
+
+ @data.setter
+ def data(self, value):
+ self.packet.contents.data = ctypes.cast(ctypes.c_char_p(value),
+ ctypes.POINTER(ctypes.c_uint8))
+ self.packet.contents.length = len(value) if value else 0
+
+ def erase(self):
+ csp_buffer_free(self.packet)
+
+ def __getitem__(self, item):
+ return self.packet.contents.data[item]
+
+ def __len__(self):
+ return self.packet.contents.length
+
+ def __str__(self):
+ return ctypes.cast(self.packet.contents.data, ctypes.c_char_p).value
+
+class CspConnection(object):
+ def __init__(self, dest, port, timeout=-1, prio=CSP_PRIO_NORM,
+ options=CSP_O_NONE, _conn=None):
+ self.conn = _conn or csp_connect(prio, dest, port, timeout, options)
+
+ def close(self):
+ return csp_close(self.conn)
+
+ @property
+ def dport(self):
+ return csp_conn_dport(self.conn)
+
+ @property
+ def sport(self):
+ return csp_conn_sport(self.conn)
+
+ @property
+ def dst(self):
+ return csp_conn_dst(self.conn)
+
+ @property
+ def src(self):
+ return csp_conn_src(self.conn)
+
+ @property
+ def flags(self):
+ return csp_conn_flags(self.conn)
+
+ def read(self, n):
+ packet = csp_read(self.conn, n)
+ if packet:
+ return CspPacket(_packet=packet)
+ else: return None
+
+ def send(self, data, timeout):
+ packet = data
+ if not isinstance(data, CspPacket):
+ packet = CspPacket(length=len(data), data=data)
+
+ return csp_send(self.conn, packet.packet, timeout)
376 libcsp.py
@@ -0,0 +1,376 @@
+# Cubesat Space Protocol - A small network-layer protocol designed for Cubesats
+# Copyright (C) 2012 GomSpace ApS (http://www.gomspace.com)
+# Copyright (C) 2012 AAUSAT3 Project (http://aausat3.space.aau.dk)
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Python bindings for Cubesat Space Protocol
+#
+# Various bug fixes and modifications to better support cross platform embedding
+# for PyCSP
+
+import ctypes
+import ctypes.util
+import time
+import sys
+import os
+
+# CSP Configuration
+CSP_MAX_BIND_PORT = 31
+
+# NULL pointer Exception
+class NullPointerException(Exception):
+ pass
+
+# Generic CSP Exception
+class CspException(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return str(self.value)
+
+# Null pointer error function
+def null_pointer_err(result, func, args):
+ if bool(result) != True:
+ raise NullPointerException
+ else:
+ return result
+
+# Generic error function
+def csp_err(result, func, args):
+ if result != 1:
+ raise CspException(os.strerror(ctypes.get_errno()))
+ else:
+ return result
+
+def csp_err_negative(result, func, args):
+ if result != 0:
+ raise CspException(os.strerror(ctypes.get_errno()))
+ else:
+ return result
+
+# Reserved Ports (Services)
+CSP_PING = 1
+CSP_PS = 2
+CSP_MEMFREE = 3
+CSP_REBOOT = 4
+CSP_BUF_FREE= 5
+CSP_UPTIME = 6
+CSP_ANY = (CSP_MAX_BIND_PORT + 1)
+CSP_PROMISC = (CSP_MAX_BIND_PORT + 2)
+
+# Priorities
+CSP_PRIO_CRITICAL = 0
+CSP_PRIO_HIGH = 1
+CSP_PRIO_NORM = 2
+CSP_PRIO_LOW = 3
+
+# Define used to specify MAC_ADDR = NODE_ID
+CSP_NODE_MAC = 0xFF
+
+# Size of bit-fields in CSP header
+CSP_ID_PRIO_SIZE = 2
+CSP_ID_HOST_SIZE = 5
+CSP_ID_PORT_SIZE = 6
+CSP_ID_FLAGS_SIZE = 8
+
+if CSP_ID_PRIO_SIZE + 2 * CSP_ID_HOST_SIZE + 2 * CSP_ID_PORT_SIZE + CSP_ID_FLAGS_SIZE != 32:
+ print "CSP header lenght must be 32 bits"
+
+# Highest number to be entered in field
+CSP_ID_PRIO_MAX = (1 << CSP_ID_PRIO_SIZE) - 1
+CSP_ID_HOST_MAX = (1 << CSP_ID_HOST_SIZE) - 1
+CSP_ID_PORT_MAX = (1 << CSP_ID_PORT_SIZE) - 1
+CSP_ID_FLAGS_MAX = (1 << CSP_ID_FLAGS_SIZE) - 1
+
+# Identifier field masks
+CSP_ID_PRIO_MASK = CSP_ID_PRIO_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE + 2 * CSP_ID_HOST_SIZE)
+CSP_ID_SRC_MASK = CSP_ID_HOST_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE + 1 * CSP_ID_HOST_SIZE)
+CSP_ID_DST_MASK = CSP_ID_HOST_MAX << (CSP_ID_FLAGS_SIZE + 2 * CSP_ID_PORT_SIZE)
+CSP_ID_DPORT_MASK = CSP_ID_PORT_MAX << (CSP_ID_FLAGS_SIZE + 1 * CSP_ID_PORT_SIZE)
+CSP_ID_SPORT_MASK = CSP_ID_PORT_MAX << (CSP_ID_FLAGS_SIZE)
+CSP_ID_FLAGS_MASK = CSP_ID_FLAGS_MAX << (0)
+
+CSP_ID_CONN_MASK = CSP_ID_SRC_MASK | CSP_ID_DST_MASK | CSP_ID_DPORT_MASK | CSP_ID_SPORT_MASK
+
+# Broadcast address
+CSP_BROADCAST_ADDR = CSP_ID_HOST_MAX
+
+# Default routing address
+CSP_DEFAULT_ROUTE = CSP_ID_HOST_MAX + 1
+
+# CSP Flags
+CSP_FRES1 = 0x80 # Reserved for future use
+CSP_FRES2 = 0x40 # Reserved for future use
+CSP_FRES3 = 0x20 # Reserved for future use
+CSP_FRES4 = 0x10 # Reserved for future use
+CSP_FHMAC = 0x08 # Use HMAC verification/generation
+CSP_FXTEA = 0x04 # Use XTEA encryption/decryption
+CSP_FRDP = 0x02 # Use RDP protocol
+CSP_FCRC = 0x01 # Use CRC32 checksum (Not implemented)
+
+# CSP Socket options
+CSP_SO_NONE = 0x0000
+CSP_SO_RDPREQ = 0x0001
+CSP_SO_HMACREQ = 0x0002
+CSP_SO_XTEAREQ = 0x0004
+
+# CSP Connect options
+CSP_O_NONE = CSP_SO_NONE
+CSP_O_RDP = CSP_SO_RDPREQ
+CSP_O_HMAC = CSP_SO_HMACREQ
+CSP_O_XTEA = CSP_SO_XTEAREQ
+
+# CSP Packet Identifier
+if sys.byteorder == 'little':
+ class csp_id_fields_t (ctypes.Structure):
+ _pack_ = 1
+ _fields_ = [("flags", ctypes.c_uint, 8),
+ ("sport", ctypes.c_uint, 6),
+ ("dport", ctypes.c_uint, 6),
+ ("dst", ctypes.c_uint, 5),
+ ("src", ctypes.c_uint, 5),
+ ("pri", ctypes.c_uint, 2)]
+elif sys.byteorder == 'big':
+ class csp_id_fields_t (ctypes.Structure):
+ _pack_ = 1
+ _fields_ = [("pri", ctypes.c_uint, 2),
+ ("src", ctypes.c_uint, 5),
+ ("dst", ctypes.c_uint, 5),
+ ("dport", ctypes.c_uint, 6),
+ ("sport", ctypes.c_uint, 6),
+ ("flags", ctypes.c_uint, 8)]
+else:
+ raise Exception("sys.byteorder was neither little or big")
+
+class csp_id_t (ctypes.Union):
+ _pack_ = 1
+ _anonymous_ = ("id",)
+ _fields_ = [("ext", ctypes.c_uint32),
+ ("id", csp_id_fields_t)]
+
+class csp_packet_t (ctypes.Structure):
+ _pack_ = 1
+ _fields_ = [("padding", ctypes.c_uint8 * 46),
+ ("length", ctypes.c_uint16),
+ ("id", csp_id_t),
+ ("data", ctypes.POINTER(ctypes.c_uint8))]
+
+ CSP_BUFFER_PACKET_OVERHEAD = 46+2+4
+
+# typedef struct csp_socket_s csp_socket_t;
+class csp_socket_t (ctypes.Structure):
+ pass
+
+# typedef struct csp_conn_s csp_conn_t;
+class csp_conn_t (ctypes.Structure):
+ pass
+
+# typedef struct csp_l4data_s csp_l4data_t;
+class csp_l4data_t (ctypes.Structure):
+ pass
+
+# Load library
+libcsp = ctypes.CDLL("lib/libpycsp.dylib", use_errno=True)
+
+my_address = libcsp.my_address
+
+# Function prototypes
+
+# csp_io.c
+csp_init = libcsp.csp_init
+csp_init.argtypes = [ctypes.c_uint8]
+csp_init.restype = None
+
+csp_socket = libcsp.csp_socket
+csp_socket.argtypes = [ctypes.c_uint32]
+csp_socket.restype = ctypes.POINTER(csp_socket_t)
+csp_socket.errcheck = null_pointer_err
+
+csp_accept = libcsp.csp_accept
+csp_accept.argtypes = [ctypes.POINTER(csp_socket_t), ctypes.c_uint]
+csp_accept.restype = ctypes.POINTER(csp_conn_t)
+csp_accept.errcheck = null_pointer_err
+
+csp_read = libcsp.csp_read
+csp_read.argtypes = [ctypes.POINTER(csp_conn_t), ctypes.c_uint]
+csp_read.restype = ctypes.POINTER(csp_packet_t)
+csp_read.errcheck = null_pointer_err
+
+csp_send = libcsp.csp_send
+csp_send.argtypes = [ctypes.POINTER(csp_conn_t), ctypes.POINTER(csp_packet_t), ctypes.c_uint]
+csp_send.restype = ctypes.c_int
+csp_send.errcheck = csp_err
+
+csp_transaction = libcsp.csp_transaction
+csp_transaction.argtypes = [ctypes.c_uint8, ctypes.c_uint8, ctypes.c_uint8, ctypes.c_uint, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int]
+csp_transaction.restype = ctypes.c_int
+
+csp_transaction_persistent = libcsp.csp_transaction_persistent
+csp_transaction_persistent.argtypes = [ctypes.POINTER(csp_conn_t), ctypes.c_uint, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int]
+csp_transaction_persistent.restype = ctypes.c_int
+
+# csp_conn.c
+csp_connect = libcsp.csp_connect
+csp_connect.argtypes = [ctypes.c_uint8, ctypes.c_uint8, ctypes.c_uint8, ctypes.c_uint, ctypes.c_uint32]
+csp_connect.restype = ctypes.POINTER(csp_conn_t)
+csp_connect.errcheck = null_pointer_err
+
+csp_close = libcsp.csp_close
+csp_close.argtypes = [ctypes.POINTER(csp_conn_t)]
+csp_close.restype = None
+
+csp_conn_dport = libcsp.csp_conn_dport
+csp_conn_dport.argtypes = [ctypes.POINTER(csp_conn_t)]
+csp_conn_dport.restype = ctypes.c_int
+
+csp_conn_sport = libcsp.csp_conn_sport
+csp_conn_sport.argtypes = [ctypes.POINTER(csp_conn_t)]
+csp_conn_sport.restype = ctypes.c_int
+
+csp_conn_dst = libcsp.csp_conn_dst
+csp_conn_dst.argtypes = [ctypes.POINTER(csp_conn_t)]
+csp_conn_dst.restype = ctypes.c_int
+
+csp_conn_src = libcsp.csp_conn_src
+csp_conn_src.argtypes = [ctypes.POINTER(csp_conn_t)]
+csp_conn_src.restype = ctypes.c_int
+
+# Define csp_conn_print if libcsp was compiled with CSP_DEBUG
+try:
+ csp_conn_print_table = libcsp.csp_conn_print_table
+ csp_conn_print_table.argtypes = None
+ csp_conn_print_table.restype = None
+except:
+ pass
+
+# csp_port.c
+csp_listen = libcsp.csp_listen
+csp_listen.argtypes = [ctypes.POINTER(csp_socket_t), ctypes.c_size_t]
+csp_listen.restype = ctypes.c_int
+
+csp_bind = libcsp.csp_bind
+csp_bind.argtypes = [ctypes.POINTER(csp_socket_t), ctypes.c_uint8]
+csp_bind.restype = ctypes.c_int
+
+# csp_route.c
+#typedef int (*nexthop_t)(csp_id_t idout, csp_packet_t * packet, uint32_t timeout);
+
+csp_route_set = libcsp.csp_route_set
+# TODO, add argtypes (i.e. figure out how to define function pointer)
+csp_route_set.restype = None
+
+csp_route_start_task = libcsp.csp_route_start_task
+csp_route_start_task.argtypes = [ctypes.c_uint, ctypes.c_uint]
+csp_route_start_task.restype = None
+
+try:
+ csp_promisc_enable = libcsp.csp_promisc_enable
+ csp_promisc_enable.argtypes = [ctypes.c_uint]
+ csp_promisc_enable.restype = ctypes.c_int
+
+ csp_promisc_read = libcsp.csp_promisc_read
+ csp_promisc_read.argtypes = [ctypes.c_uint]
+ csp_promisc_read.restype = ctypes.POINTER(csp_packet_t)
+ csp_promisc_read.errcheck = null_pointer_err
+except:
+ # promiscuous mode is disabled
+ pass
+
+# csp_services.c
+csp_service_handler = libcsp.csp_service_handler
+csp_service_handler.argtypes = [ctypes.POINTER(csp_conn_t), ctypes.POINTER(csp_packet_t)]
+csp_service_handler.restype = None
+
+csp_ping = libcsp.csp_ping
+csp_ping.argtypes = [ctypes.c_uint8, ctypes.c_uint]
+csp_ping.restype = ctypes.c_int
+
+csp_ping_noreply = libcsp.csp_ping_noreply
+csp_ping_noreply.argtypes = [ctypes.c_uint8]
+csp_ping_noreply.restype = None
+
+csp_ps = libcsp.csp_ps
+csp_ps.argtypes = [ctypes.c_uint8, ctypes.c_uint]
+csp_ps.restype = None
+
+csp_memfree = libcsp.csp_memfree
+csp_memfree.argtypes = [ctypes.c_uint8, ctypes.c_uint]
+csp_memfree.restype = None
+
+csp_buf_free = libcsp.csp_buf_free
+csp_buf_free.argtypes = [ctypes.c_uint8, ctypes.c_uint]
+csp_buf_free.restype = None
+
+csp_reboot = libcsp.csp_reboot
+csp_reboot.argtypes = [ctypes.c_uint8, ctypes.c_uint]
+csp_reboot.restype = None
+
+csp_buffer_init = libcsp.csp_buffer_init
+csp_buffer_init.argtypes = [ctypes.c_int, ctypes.c_int]
+csp_buffer_init.restype = ctypes.c_int
+
+csp_buffer_get = libcsp.csp_buffer_get
+csp_buffer_get.argtypes = [ctypes.c_size_t]
+csp_buffer_get.restype = ctypes.c_void_p
+csp_buffer_get.errcheck = null_pointer_err
+
+csp_buffer_get_isr = libcsp.csp_buffer_get
+csp_buffer_get_isr.argtypes = [ctypes.c_size_t]
+csp_buffer_get_isr.restype = ctypes.c_void_p
+csp_buffer_get_isr.errcheck = null_pointer_err
+
+csp_buffer_free = libcsp.csp_buffer_free
+csp_buffer_free.argtypes = [ctypes.c_void_p]
+csp_buffer_free.restype = None
+
+csp_buffer_remaining = libcsp.csp_buffer_remaining
+csp_buffer_remaining.argtypes = None
+csp_buffer_remaining.restype = ctypes.c_int
+
+# Define csp_buffer_print if libcsp was compiled with CSP_DEBUG
+DEBUG_FUNC = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
+try:
+ csp_debug_hook_set = libcsp.csp_debug_hook_set
+ csp_debug_hook_set.argtypes = [DEBUG_FUNC]
+ csp_debug_hook_set.restype = None
+except:
+ pass
+
+# Debug hook
+CSP_INFO = 0
+CSP_ERROR = 1
+CSP_WARN = 2
+CSP_BUFFER = 3
+CSP_PACKET = 4
+CSP_PROTOCOL = 5
+CSP_LOCK = 6
+
+# CAN Interface - this should be moved to it's own bindings
+class can_socketcan_conf (ctypes.Structure):
+ _fields_ = [("ifc", ctypes.c_char_p)]
+
+try:
+ csp_if_can = libcsp.csp_if_can
+ csp_can_init = libcsp.csp_can_init
+ csp_can_init.argtypes = [ctypes.c_uint8, ctypes.c_void_p, ctypes.c_uint]
+ csp_can_init.restype = ctypes.c_int
+ csp_can_init.errcheck = csp_err_negative
+
+ csp_can_tx = libcsp.csp_can_tx
+ csp_can_tx.argtypes = [csp_id_t, ctypes.POINTER(csp_packet_t), ctypes.c_uint]
+ csp_can_tx.restype = ctypes.c_int
+except:
+ pass
72 simple.py
@@ -0,0 +1,72 @@
+import csp
+import ctypes
+import threading
+import time
+
+class SimpleServer(threading.Thread):
+ PORT = 10
+ def run(self):
+ self.sock = csp.CspSocket()
+ self.sock.bind(csp.CSP_ANY)
+ self.sock.listen(10)
+ self.running = True
+ while self.running:
+ self.iteration()
+
+ def iteration(self):
+ conn = self.sock.accept(1000)
+ if not conn:
+ return
+
+ packet = conn.read(100)
+ if packet:
+ self.handle_packet(conn, packet)
+ conn.close()
+
+ def handle_packet(self, conn, packet):
+ if conn.dport == self.PORT:
+ print "Packet received on PORT: %s" % packet
+ packet.erase()
+ csp.service_handler(conn, packet)
+
+class SimpleClient(threading.Thread):
+ ADDRESS = 1
+ def run(self):
+ self.running = True
+ while self.running:
+ self.iteration()
+
+ def iteration(self):
+ time.sleep(0.3)
+ result = csp.ping(self.ADDRESS, 100, 100, csp.CSP_O_NONE)
+ print "Ping result %d [ms]" % result
+
+ time.sleep(0.3)
+ conn = csp.CspConnection(dest=self.ADDRESS, port=SimpleServer.PORT, timeout=1000)
+ if not conn.send("Hello World", 1000):
+ print "Send failed"
+
+ conn.close()
+
+def main():
+ print "Initialising CSP"
+ csp.buffer_init(2, 300)
+ csp.init(SimpleClient.ADDRESS)
+ csp.route_start_task(500, 1)
+
+ print "Starting Server task"
+ server = SimpleServer()
+ server.start()
+
+ print "Starting Client task"
+ client = SimpleClient()
+ client.start()
+
+ try:
+ server.join(10)
+ except KeyboardInterrupt:
+ server.running = client.running = False
+ server.join()
+
+if __name__ == "__main__":
+ main()
Please sign in to comment.
Something went wrong with that request. Please try again.