diff options
| author | Jeffrey Armstrong <jeffrey.armstrong@approximatrix.com> | 2015-10-09 10:34:49 -0400 |
|---|---|---|
| committer | Jeffrey Armstrong <jeffrey.armstrong@approximatrix.com> | 2015-10-09 10:34:49 -0400 |
| commit | 8b756e368a33a02d7783053b84bc1e5b50419ff0 (patch) | |
| tree | 658a81b96d4522fe3b7e0b33661dc265dbc968e8 /server/rback.py | |
| download | rback-master.tar.gz rback-master.zip | |
Diffstat (limited to 'server/rback.py')
| -rw-r--r-- | server/rback.py | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/server/rback.py b/server/rback.py new file mode 100644 index 0000000..5a21669 --- /dev/null +++ b/server/rback.py @@ -0,0 +1,179 @@ + # Serial Backup Server + # Copyright © 2015 Jeffrey Armstrong <jeff@rainbow-100.com> + # http://jeff.rainbow-100.com/ + # + # 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, either version 3 of the License, or + # (at your option) any later version. + # + # 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, see <http://www.gnu.org/licenses/>. + +import time +import serial +import argparse +import os +import os.path + +DEFAULT_PORT = 19200 +DEFAULT_DEV = '/dev/ttyUSB0' + +OK = "OK" +RETRY = "RETRY" +ABORT = "ABORT" + +def respond(ser, msg): + """Writes a response message to the client""" + ser.write(msg) + ser.write(";") + +def fletcher16(data): + """Computes the Fletcher 16 checksum of a data stream""" + c0 = 0 + c1 = 0 + + for b in data: + c0 = (c0 + ord(b)) + c1 = (c1 + c0) + + cb0 = 255 - ((c0+c1) % 255) + cb1 = 255 - ((c0 + cb0) % 255) + + return cb0, cb1 + +def receive_file(ser, fp): + """Receives a file block from the client, determines its validity, + and responds accordingly.""" + + file_contents = b'' + + length = ord(ser.read()) + err = 0 + + while length > 0: + #print(" receiving {0} bytes".format(length)) + bytes = b'' + for i in range(0, length): + bytes = bytes + ser.read() + + fl1 = ser.read() + fl2 = ser.read() + + v1, v2 = fletcher16(bytes) + + # print("Fletcher16 - Rainbow({0}, {1}) Python({2}, {3})".format(ord(fl1), ord(fl2), v1, v2)) + + if (v1 == ord(fl1) and v2 == ord(fl2)): + fp.write(bytes) + respond(ser, OK) + elif err < 10: + respond(ser, RETRY) + err = err + 1 + if err == 1: + fp.write(bytes) + print(" block retry {0}...".format(err)) + else: + respond(ser, ABORT) + print(" block abort") + break + + length = ord(ser.read()) + +def readtext(ser, bytes=1): + """Reads a string of bytes from the serial port and converts + them to a string if necessary (i.e. Python 3)""" + b = ser.read(bytes) + try: + return str(b,'ascii') + except TypeError: + return b + +def init(ser): + """Waits for an initialization message from the client""" + print("Waiting for 'ONLINE'...") + while ser.inWaiting() < 6: + time.sleep(1) + + x = readtext(ser, 6) + if x == 'ONLINE': + print("Received 'ONLINE' message. Awaiting files...") + return True + + return False + +def readfilename(ser): + """Reads the next filename from the client""" + fname = b'' + + b = ser.read() + while b != b';': + fname = fname + b + b = ser.read() + + try: + return str(fname, 'ascii') + except TypeError: + return fname + +def prepfile(filename): + """Returns an open file for writing based on the + reported DOS name""" + + newfile = filename.replace(':', '') + if os.sep != '\\': + newfile = newfile.replace('\\', os.sep) + + dirs = newfile.split(os.sep) + fullpath = '' + for d in dirs[:-1]: + fullpath = os.path.join(fullpath,d) + if not os.path.exists(fullpath): + os.mkdir(fullpath) + + return open(newfile, "w") + +def main_transfer(ser): + """Main program loop""" + + # First wait for the online signal + if not init(ser): + print("Initialize failed. Quitting.") + return + + while True: + fname = readfilename(ser) + fp = prepfile(fname) + if fp is None: + break + + print("Receiving {0}".format(fname)) + respond(ser, OK) + receive_file(ser, fp) + fp.close() + +def main(port='/dev/ttyUSB0', speed=19200): + """Opens the serial port and starts the transfer""" + + ser = serial.Serial(port, speed) + + main_transfer(ser) + + ser.close() + +if __name__ == '__main__': + + parser = argparse.ArgumentParser() + + parser.add_argument('-p', '--port', dest='port', default='/dev/ttyUSB0') + parser.add_argument('-s', '--speed', dest='speed', type=int, default=19200) + + res = parser.parse_args() + + main(port=res.port, speed=res.speed) + |
