Renamed Service into ServiceIn
[ais.git] / bin / inputs / serialin.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 '''
5 Module for receiving AIVDM data from serial port.
6 '''
7
8 from __future__ import division
9 import serial
10 import logging
11
12 from ais.inputs.common import get_source_by_id4
13 from ais.inputs.virtual import Channel, ServiceIn
14
15 DEFAULT_SPEED = 38400
16
17 class SerialChannel(Channel):
18     '''
19     Simple channel bound to a ttyS device like /dev/ttyUSB0
20     '''
21     def __init__(self, id4, serialname, speed=DEFAULT_SPEED):
22         Channel.__init__(self)
23         self.id4 = id4
24         self.source = get_source_by_id4(id4)
25         self.name = serialname
26         self.serial = serial.Serial(serialname, speed)
27         bytesize = self.serial.getByteSize()
28         parity = self.serial.getParity()
29         stopbits = self.serial.getStopbits()
30         self.rawbytesize = bytesize + stopbits
31         if parity == 'O' or parity == 'E':
32             self.rawbytesize += 1
33         else:
34             assert parity == 'N', 'Illegal parity settings "%s"' % parity
35         logging.info('Listening on %s speed %s settings %s%s%s (%s bits)',
36                      self.serial.portstr, speed,
37                      bytesize, parity, stopbits,
38                      self.rawbytesize)
39
40     def fill_buffer(self):
41         '''
42         Grab more bytes into self.data internal buffer.
43         '''
44         try:
45             waiting = self.serial.inWaiting()
46         except IOError, err:
47             logging.critical('%s: %s', self.name, err)
48             return
49         if waiting:
50             data = self.serial.read(waiting)
51         else:
52             logging.critical('Signaled but no data waiting. Device disapeared?')
53             # TODO: go back to device creation wait loop?
54             return
55         stats = self.source.stats
56         stats.npackets += 1
57         stats.nbytes += len(data)
58         stats.nbytes_ethernet += len(data) * self.rawbytesize // 8
59         logging.debug('IN %s %s', self.name, repr(data))
60         self.data += data
61     
62         
63 class SerialServiceIn(ServiceIn):
64     '''
65     Service that listen to a ttyS device like /dev/ttyUSB0
66     '''
67     def __init__(self, id4, serialname, speed=DEFAULT_SPEED):
68         # TODO: wait for the request device to be available
69         #ServiceIn.__init__(self, stdout)
70         self.channel = SerialChannel(id4, serialname, speed)
71
72     def __repr__(self):
73         return 'SerialServiceIn<%s>' % self.channel.name
74
75     def fileno(self):
76         '''
77         Returns file descriptor of underlying socket, for os.select().
78         '''
79         return self.channel.serial.fileno()
80
81     def get_activity(self):
82         '''
83         Pool the serial channel and returns when ready.
84         '''
85         channel = self.channel
86         channel.fill_buffer()
87         return channel.name, channel