vw.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 """
00003 This module provides a 313MHz/434MHz radio interface compatible
00004 with the Virtual Wire library used on Arduinos.
00005 
00006 It has been tested between a Pi, TI Launchpad, and Arduino Pro Mini.
00007 """
00008 # 2014-08-14
00009 # vw.py
00010 
00011 import time
00012 
00013 import pigpio
00014 
00015 MAX_MESSAGE_BYTES=77
00016 
00017 MIN_BPS=50
00018 MAX_BPS=10000
00019 
00020 _HEADER=[0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x38, 0x2c]
00021 
00022 _CTL=3
00023 
00024 _SYMBOL=[
00025    0x0d, 0x0e, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 
00026    0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x32, 0x34]
00027 
00028 
00029 def _sym2nibble(symbol):
00030    for nibble in range(16):
00031       if symbol == _SYMBOL[nibble]:
00032          return nibble
00033    return 0
00034 
00035 def _crc_ccitt_update(crc, data):
00036 
00037    data = data ^ (crc & 0xFF);
00038 
00039    data = (data ^ (data << 4)) & 0xFF;
00040 
00041    return (
00042              (((data << 8) & 0xFFFF) | (crc >> 8)) ^
00043               ((data >> 4) & 0x00FF) ^ ((data << 3) & 0xFFFF)
00044           )
00045 
00046 class tx():
00047 
00048    def __init__(self, pi, txgpio, bps=2000):
00049       """
00050       Instantiate a transmitter with the Pi, the transmit gpio,
00051       and the bits per second (bps).  The bps defaults to 2000.
00052       The bps is constrained to be within MIN_BPS to MAX_BPS.
00053       """
00054       self.pi = pi
00055 
00056       self.txbit = (1<<txgpio)
00057 
00058       if bps < MIN_BPS:
00059          bps = MIN_BPS
00060       elif bps > MAX_BPS:
00061          bps = MAX_BPS
00062 
00063       self.mics = int(1000000 / bps)
00064 
00065       self.wave_id = None
00066 
00067       pi.wave_add_new()
00068 
00069       pi.set_mode(txgpio, pigpio.OUTPUT)
00070 
00071 
00072    def _nibble(self, nibble):
00073 
00074       for i in range(6):
00075          if nibble & (1<<i):
00076             self.wf.append(pigpio.pulse(self.txbit, 0, self.mics))
00077          else:
00078             self.wf.append(pigpio.pulse(0, self.txbit, self.mics))
00079 
00080    def _byte(self, crc, byte):
00081       self._nibble(_SYMBOL[byte>>4])
00082       self._nibble(_SYMBOL[byte&0x0F])
00083       return _crc_ccitt_update(crc, byte)
00084 
00085    def put(self, data):
00086       """
00087       Transmit a message.  If the message is more than
00088       MAX_MESSAGE_BYTES in size it is discarded.  If a message
00089       is currently being transmitted it is aborted and replaced
00090       with the new message.  True is returned if message
00091       transmission has successfully started.  False indicates
00092       an error.
00093       """
00094       if len(data) > MAX_MESSAGE_BYTES:
00095          return False
00096 
00097       self.wf = []
00098 
00099       self.cancel()
00100 
00101       for i in _HEADER:
00102          self._nibble(i)
00103 
00104       crc = self._byte(0xFFFF, len(data)+_CTL)
00105 
00106       for i in data:
00107 
00108          if type(i) == type(""):
00109             v = ord(i)
00110          else:
00111             v = i
00112 
00113          crc = self._byte(crc, v)
00114 
00115       crc = ~crc
00116 
00117       self._byte(0, crc&0xFF)
00118       self._byte(0, crc>>8)
00119 
00120       self.pi.wave_add_generic(self.wf)
00121 
00122       self.wave_id = self.pi.wave_create()
00123 
00124       if self.wave_id >= 0:
00125          self.pi.wave_send_once(self.wave_id)
00126          return True
00127       else:
00128          return False
00129 
00130 
00131    def ready(self):
00132       """
00133       Returns True if a new message may be transmitted.
00134       """
00135       return not self.pi.wave_tx_busy()
00136 
00137    def cancel(self):
00138       """
00139       Cancels the wireless transmitter, aborting any message
00140       in progress.
00141       """
00142       if self.wave_id is not None:
00143          self.pi.wave_tx_stop()
00144          self.pi.wave_delete(self.wave_id)
00145          self.pi.wave_add_new()
00146 
00147       self.wave_id = None
00148 
00149 class rx():
00150 
00151    def __init__(self, pi, rxgpio, bps=2000):
00152       """
00153       Instantiate a receiver with the Pi, the receive gpio, and
00154       the bits per second (bps).  The bps defaults to 2000.
00155       The bps is constrained to be within MIN_BPS to MAX_BPS.
00156       """
00157       self.pi = pi
00158       self.rxgpio = rxgpio
00159 
00160       self.messages = []
00161       self.bad_CRC = 0
00162 
00163       if bps < MIN_BPS:
00164          bps = MIN_BPS
00165       elif bps > MAX_BPS:
00166          bps = MAX_BPS
00167 
00168       slack = 0.20
00169       self.mics = int(1000000 / bps)
00170       slack_mics = int(slack * self.mics)
00171       self.min_mics = self.mics - slack_mics       # Shortest legal edge.
00172       self.max_mics = (self.mics + slack_mics) * 4 # Longest legal edge.
00173 
00174       self.timeout =  8 * self.mics / 1000 # 8 bits time in ms.
00175       if self.timeout < 8:
00176          self.timeout = 8
00177 
00178       self.last_tick = None
00179       self.good = 0
00180       self.bits = 0
00181       self.token = 0
00182       self.in_message = False
00183       self.message = [0]*(MAX_MESSAGE_BYTES+_CTL)
00184       self.message_len = 0
00185       self.byte = 0
00186 
00187       pi.set_mode(rxgpio, pigpio.INPUT)
00188 
00189       self.cb = pi.callback(rxgpio, pigpio.EITHER_EDGE, self._cb)
00190 
00191    def _calc_crc(self):
00192 
00193       crc = 0xFFFF
00194       for i in range(self.message_length):
00195          crc = _crc_ccitt_update(crc, self.message[i])
00196       return crc
00197 
00198    def _insert(self, bits, level):
00199 
00200       for i in range(bits):
00201 
00202          self.token >>= 1
00203 
00204          if level == 0:
00205             self.token |= 0x800
00206 
00207          if self.in_message:
00208 
00209             self.bits += 1
00210 
00211             if self.bits >= 12: # Complete token.
00212 
00213                byte = (
00214                   _sym2nibble(self.token & 0x3f) << 4 |
00215                   _sym2nibble(self.token >> 6))
00216 
00217                if self.byte == 0:
00218                   self.message_length = byte
00219 
00220                   if byte > (MAX_MESSAGE_BYTES+_CTL):
00221                      self.in_message = False # Abort message.
00222                      return
00223 
00224                self.message[self.byte] = byte
00225 
00226                self.byte += 1
00227                self.bits = 0
00228 
00229                if self.byte >= self.message_length:
00230                   self.in_message = False
00231                   self.pi.set_watchdog(self.rxgpio, 0)
00232 
00233                   crc = self._calc_crc()
00234 
00235                   if crc == 0xF0B8: # Valid CRC.
00236                      self.messages.append(
00237                         self.message[1:self.message_length-2])
00238                   else:
00239                      self.bad_CRC += 1
00240 
00241          else:
00242             if self.token == 0xB38: # Start message token.
00243                self.in_message = True
00244                self.pi.set_watchdog(self.rxgpio, self.timeout)
00245                self.bits = 0
00246                self.byte = 0
00247 
00248    def _cb(self, gpio, level, tick):
00249 
00250       if self.last_tick is not None:
00251 
00252          if level == pigpio.TIMEOUT:
00253 
00254             self.pi.set_watchdog(self.rxgpio, 0) # Switch watchdog off.
00255 
00256             if self.in_message:
00257                self._insert(4, not self.last_level)
00258 
00259             self.good = 0
00260             self.in_message = False
00261 
00262          else:
00263 
00264             edge = pigpio.tickDiff(self.last_tick, tick)
00265 
00266             if edge < self.min_mics:
00267 
00268                self.good = 0
00269                self.in_message = False
00270 
00271             elif edge > self.max_mics:
00272 
00273                if self.in_message:
00274                   self._insert(4, level)
00275 
00276                self.good = 0
00277                self.in_message = False
00278 
00279             else:
00280 
00281                self.good += 1
00282 
00283                if self.good > 8: 
00284 
00285                   bitlen = (100 * edge) / self.mics
00286 
00287                   if   bitlen < 140:
00288                      bits = 1
00289                   elif bitlen < 240:
00290                      bits = 2
00291                   elif bitlen < 340:
00292                      bits = 3
00293                   else:
00294                      bits = 4
00295 
00296                   self._insert(bits, level)
00297 
00298       self.last_tick = tick
00299       self.last_level = level
00300 
00301    def get(self):
00302       """
00303       Returns the next unread message, or None if none is avaiable.
00304       """
00305       if len(self.messages):
00306          return self.messages.pop(0)
00307       else:
00308          return None
00309 
00310    def ready(self):
00311       """
00312       Returns True if there is a message available to be read.
00313       """
00314       return len(self.messages)
00315 
00316    def cancel(self):
00317       """
00318       Cancels the wireless receiver.
00319       """
00320       if self.cb is not None:
00321          self.cb.cancel()
00322          self.pi.set_watchdog(self.rxgpio, 0)
00323       self.cb = None
00324 
00325 if __name__ == "__main__":
00326 
00327    import time
00328 
00329    import pigpio
00330 
00331    import vw
00332 
00333    RX=11
00334    TX=25
00335 
00336    BPS=2000
00337 
00338    pi = pigpio.pi() # Connect to local Pi.
00339 
00340    rx = vw.rx(pi, RX, BPS) # Specify Pi, rx gpio, and baud.
00341    tx = vw.tx(pi, TX, BPS) # Specify Pi, tx gpio, and baud.
00342 
00343    msg = 0
00344 
00345    start = time.time()
00346 
00347    while (time.time()-start) < 300:
00348 
00349       msg += 1
00350 
00351       while not tx.ready():
00352          time.sleep(0.1)
00353 
00354       time.sleep(0.2)
00355 
00356       tx.put([48, 49, 65, ((msg>>6)&0x3F)+32, (msg&0x3F)+32])
00357 
00358       while not tx.ready():
00359          time.sleep(0.1)
00360 
00361       time.sleep(0.2)
00362 
00363       tx.put("Hello World #{}!".format(msg))
00364 
00365       while rx.ready():
00366          print("".join(chr (c) for c in rx.get()))
00367 
00368    rx.cancel()
00369    tx.cancel()
00370 
00371    pi.stop()
00372 


cob_hand_bridge
Author(s): Mathias Lüdtke
autogenerated on Thu Jun 6 2019 20:43:57