When I power an RF Transmitter attached to an aduino, I am successfully sending text messages via an RF Receiver connected to a Raspberry Pi that has a GSM module attached to it. The RF sniffing code on the Raspberry Pi waits for a transmission from the RF Transmitter before sending a text. However, once the sniffing code receives the first signal, it doesn't stop sending text messages even after the transmitter has been powered off. If I comment out the line
the code works as expected. In other words, when I power off the transmitter and have the above line commented out, the sniffing program does not enter the loop at
. However, when I uncomment
, run the program, and turn the transmitter on to send one text and immediately power it off , it continuously loops this section (line 369 - 382 of vw.py).
Somehow, when the transmitter is cycled on and off one time, the char "L" is re-appended to the string even though it is successfully removed after sending the text. I assume I have broken some sort of importing rule when I call
but I have tried numerous modifications and can't seem to figure it out. Any help solving this problem would be much appreciated.
Text Code (sendSMS1.py)
Sniffing Code (vw.py)
Code:
sendSMS1.sms()
Code:
while rx.ready():
Code:
sendSMS1.sms()
Code:
if (letter[len(letter) - 1]) == "L": #capture lastletter of list
print("The letter is L")
print(letter + "before send")
sendSMS1.sms() #send the text
i += 1
l = list(letter) #strings are immutable, convert to a list
del(l[len(letter) - 1]) #delete the last letter of the list
letter = "".join(l) #assign the list of chars to the string letter
print(letter)
print(i)
Somehow, when the transmitter is cycled on and off one time, the char "L" is re-appended to the string even though it is successfully removed after sending the text. I assume I have broken some sort of importing rule when I call
Code:
sendSMS1.sms()
Text Code (sendSMS1.py)
Code:
import os
import serial
from time import sleep, time
from string import replace
from globalParVar import *
from agsm2_064_hw_control import *
from agsm_Serial_Lib import *
from agsm_Basic_Lib import *
from agsm_SMS_Lib import *
def sms(): #when importing this module, the desired code must be in a definition
message="Hi!\r\nThis message has been sent from the a-gsm v2.064 shield connected with my RPi board."
destinationNumber="3185184930"#usually phone number with International prefix eg. +40 for Romania - in some networks you must use domestic numbers
usePoweringControl = 1#change it to 0 if you do not want to control powerUP/powerDown the a-gsm board. In this case, please be sure the a-gsm board is powered UP(..see a-gsm_kickstart_v_x-yz.pdf) before run this utility
print "Light example - just send a SMS to a destination number"
sleep(1)
if not os.getuid() == 0:
print("please use root privileges! try: \"sudo python yourPythonFileName.py\"")
exit(0)
if destinationNumber=="":
print("No destination number has been set for your SMS!")
print("Edit the file and set the destinationNumber in line 35\r\n")
exit(0)
# set SERIAL/USB communication section start
# bellow chose value bw [SER] Serial /dev/ttyAMA0 or [USB] /dev/ttyUSB0
# if module USB port maps to other port as /dev/ttyUSB1, just edit the moduleName_Serial_lib.py...
serialCommunicationVia = SERIALCON # OVERRIDE the default value loaded from globalParVar.py. here I use via SERIAL communication
setSerialCom(serialCommunicationVia) # set the current communication option
startSerialCom() # open serial communication bw. RPi and a-gsm shield
# set SERIAL/USB communication section end
# set HARDWARE CONTROL setup & POWER ON section start
if usePoweringControl==1:
hwControlSetup() # setup the RPi I/O ports
sleep(2)#some delay...
if usePoweringControl==1:
poweron()
sleep(1)
# set HARDWARE CONTROL setup & POWER ON section end
# set MODEM STARTUP SETUP section start
setupMODEM()
# set MODEM STARTUP SETUP section end
# MAIN PROGRAM section start
print "try to send a SMS...."
#check AT command pdf for proper 129/145 parameter/number format usage
res = sendSMS(destinationNumber, "129", message)#domestic format numbers
#res = sendSMS(destinationNumber, "145", message)#international format numbers
if res==0:
print "SMS has been sent with succes"
# MAIN PROGRAM section end
# stop SERIAL COMMUNICATION section start
stopSerialCom() # close modem communication
# stop SERIAL COMMUNICATION section end
# HARDWARE CONTROL release & POWER OFF section start
if usePoweringControl==1:
poweroff() #shutdown modem
if usePoweringControl==1:
hwControlRelease() # free GPIO
# HARDWARE CONTROL release & POWER OFF section end
print("\r\n\r\nThat's all folks!\r\n")
Sniffing Code (vw.py)
Code:
#!/usr/bin/env python
"""
This module provides a 313MHz/434MHz radio interface compatible
with the Virtual Wire library used on Arduinos.
It has been tested between a Pi, TI Launchpad, and Arduino Pro Mini.
"""
# 2014-08-14
# vw.py
import time
import pigpio
import sendSMS1
MAX_MESSAGE_BYTES=77
MIN_BPS=50
MAX_BPS=10000
_HEADER=[0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x38, 0x2c]
_CTL=3
_SYMBOL=[
0x0d, 0x0e, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x32, 0x34]
def _sym2nibble(symbol):
for nibble in range(16):
if symbol == _SYMBOL[nibble]:
return nibble
return 0
def _crc_ccitt_update(crc, data):
data = data ^ (crc & 0xFF);
data = (data ^ (data << 4)) & 0xFF;
return (
(((data << 8) & 0xFFFF) | (crc >> 8)) ^
((data >> 4) & 0x00FF) ^ ((data << 3) & 0xFFFF)
)
class tx():
def __init__(self, pi, txgpio, bps=2000):
"""
Instantiate a transmitter with the Pi, the transmit gpio,
and the bits per second (bps). The bps defaults to 2000.
The bps is constrained to be within MIN_BPS to MAX_BPS.
"""
self.pi = pi
self.txbit = (1<<txgpio)
if bps < MIN_BPS:
bps = MIN_BPS
elif bps > MAX_BPS:
bps = MAX_BPS
self.mics = int(1000000 / bps)
self.wave_id = None
pi.wave_add_new()
pi.set_mode(txgpio, pigpio.OUTPUT)
def _nibble(self, nibble):
for i in range(6):
if nibble & (1<<i):
self.wf.append(pigpio.pulse(self.txbit, 0, self.mics))
else:
self.wf.append(pigpio.pulse(0, self.txbit, self.mics))
def _byte(self, crc, byte):
self._nibble(_SYMBOL[byte>>4])
self._nibble(_SYMBOL[byte&0x0F])
return _crc_ccitt_update(crc, byte)
def put(self, data):
"""
Transmit a message. If the message is more than
MAX_MESSAGE_BYTES in size it is discarded. If a message
is currently being transmitted it is aborted and replaced
with the new message. True is returned if message
transmission has successfully started. False indicates
an error.
"""
if len(data) > MAX_MESSAGE_BYTES:
return False
self.wf = []
self.cancel()
for i in _HEADER:
self._nibble(i)
crc = self._byte(0xFFFF, len(data)+_CTL)
for i in data:
if type(i) == type(""):
v = ord(i)
else:
v = i
crc = self._byte(crc, v)
crc = ~crc
self._byte(0, crc&0xFF)
self._byte(0, crc>>8)
self.pi.wave_add_generic(self.wf)
self.wave_id = self.pi.wave_create()
if self.wave_id >= 0:
self.pi.wave_send_once(self.wave_id)
return True
else:
return False
def ready(self):
"""
Returns True if a new message may be transmitted.
"""
return not self.pi.wave_tx_busy()
def cancel(self):
"""
Cancels the wireless transmitter, aborting any message
in progress.
"""
if self.wave_id is not None:
self.pi.wave_tx_stop()
self.pi.wave_delete(self.wave_id)
self.pi.wave_add_new()
self.wave_id = None
class rx():
def __init__(self, pi, rxgpio, bps=2000):
"""
Instantiate a receiver with the Pi, the receive gpio, and
the bits per second (bps). The bps defaults to 2000.
The bps is constrained to be within MIN_BPS to MAX_BPS.
"""
self.pi = pi
self.rxgpio = rxgpio
self.messages = []
self.bad_CRC = 0
if bps < MIN_BPS:
bps = MIN_BPS
elif bps > MAX_BPS:
bps = MAX_BPS
slack = 0.20
self.mics = int(1000000 / bps)
slack_mics = int(slack * self.mics)
self.min_mics = self.mics - slack_mics # Shortest legal edge.
self.max_mics = (self.mics + slack_mics) * 4 # Longest legal edge.
self.timeout = 8 * self.mics / 1000 # 8 bits time in ms.
if self.timeout < 8:
self.timeout = 8
self.last_tick = None
self.good = 0
self.bits = 0
self.token = 0
self.in_message = False
self.message = [0]*(MAX_MESSAGE_BYTES+_CTL)
self.message_len = 0
self.byte = 0
pi.set_mode(rxgpio, pigpio.INPUT)
self.cb = pi.callback(rxgpio, pigpio.EITHER_EDGE, self._cb)
def _calc_crc(self):
crc = 0xFFFF
for i in range(self.message_length):
crc = _crc_ccitt_update(crc, self.message[i])
return crc
def _insert(self, bits, level):
for i in range(bits):
self.token >>= 1
if level == 0:
self.token |= 0x800
if self.in_message:
self.bits += 1
if self.bits >= 12: # Complete token.
byte = (
_sym2nibble(self.token & 0x3f) << 4 |
_sym2nibble(self.token >> 6))
if self.byte == 0:
self.message_length = byte
if byte > (MAX_MESSAGE_BYTES+_CTL):
self.in_message = False # Abort message.
return
self.message[self.byte] = byte
self.byte += 1
self.bits = 0
if self.byte >= self.message_length:
self.in_message = False
self.pi.set_watchdog(self.rxgpio, 0)
crc = self._calc_crc()
if crc == 0xF0B8: # Valid CRC.
self.messages.append(
self.message[1:self.message_length-2])
else:
self.bad_CRC += 1
else:
if self.token == 0xB38: # Start message token.
self.in_message = True
self.pi.set_watchdog(self.rxgpio, self.timeout)
self.bits = 0
self.byte = 0
def _cb(self, gpio, level, tick):
if self.last_tick is not None:
if level == pigpio.TIMEOUT:
self.pi.set_watchdog(self.rxgpio, 0) # Switch watchdog off.
if self.in_message:
self._insert(4, not self.last_level)
self.good = 0
self.in_message = False
else:
edge = pigpio.tickDiff(self.last_tick, tick)
if edge < self.min_mics:
self.good = 0
self.in_message = False
elif edge > self.max_mics:
if self.in_message:
self._insert(4, level)
self.good = 0
self.in_message = False
else:
self.good += 1
if self.good > 8:
bitlen = (100 * edge) / self.mics
if bitlen < 140:
bits = 1
elif bitlen < 240:
bits = 2
elif bitlen < 340:
bits = 3
else:
bits = 4
self._insert(bits, level)
self.last_tick = tick
self.last_level = level
def get(self):
"""
Returns the next unread message, or None if none is avaiable.
"""
if len(self.messages):
return self.messages.pop(0)
else:
return None
def ready(self):
"""
Returns True if there is a message available to be read.
"""
return len(self.messages)
def cancel(self):
"""
Cancels the wireless receiver.
"""
if self.cb is not None:
self.cb.cancel()
self.pi.set_watchdog(self.rxgpio, 0)
self.cb = None
if __name__ == "__main__":
import time
import pigpio
import vw
RX=27
TX=25
BPS=900
pi = pigpio.pi() # Connect to local Pi.
rx = vw.rx(pi, RX, BPS) # Specify Pi, rx gpio, and baud.
tx = vw.tx(pi, TX, BPS) # Specify Pi, tx gpio, and baud.
msg = 0
start = time.time()
while (time.time()-start) < 300:
# msg += 1
# while not tx.ready():
# time.sleep(0.1)
# time.sleep(0.2)
# tx.put([48, 49, 65, ((msg>>6)&0x3F)+32, (msg&0x3F)+32])
# while not tx.ready():
# time.sleep(0.1)
# time.sleep(0.2)
# tx.put("Hello World #{}!".format(msg))
i = 0
while rx.ready():
print("immediately after while before join")
letter = ("".join(chr (c) for c in rx.get())) #retrieve what was sent first 2 or 3 characters are preambles
if (letter[len(letter) - 1]) == "L": #capture lastletter of list
print("The letter is L")
print(letter + "before send")
sendSMS1.sms() #send the text
#time.sleep(60) this does not help. Line does not execute until previous is finished
#when executing sendSMS1.sms() this loop completes once the text is sent
#I unplug the battery but code does not exit while loop and it somehow restores the string to remember the L
#the code works as expected if I comment out the sendSMS1 command
i += 1
l = list(letter) #strings are immutable, convert to a list
del(l[len(letter) - 1]) #delete the last letter of the list
letter = "".join(l) #assign the list of chars to the string letter
print(letter)
print(i)
else:
print("failed")
rx.cancel()
tx.cancel()
pi.stop()