From d93fcde0ae01b8c7fc06c7a7bc1813fbabd27b40 Mon Sep 17 00:00:00 2001
From: Robert Hartung <hartung@ibr.cs.tu-bs.de>
Date: Mon, 22 Jan 2018 11:29:11 +0100
Subject: [PATCH] latest software and coordinator version

---
 software/coordinator2.py | 121 ++++++++++++++++++++++++++++-----------
 software/main.c          |   2 +-
 2 files changed, 87 insertions(+), 36 deletions(-)

diff --git a/software/coordinator2.py b/software/coordinator2.py
index ad153f3..f15f9c9 100644
--- a/software/coordinator2.py
+++ b/software/coordinator2.py
@@ -1,24 +1,47 @@
-from time import sleep
+from time import sleep, time
 import re
 from clients.client import Client
 from common.logging import Logger
-from sqlalchemy import Column, Integer, String, Float
+from sqlalchemy import Column, Integer, String, Float, ForeignKey
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.orm import sessionmaker
 from sqlalchemy import create_engine
+from threading import Lock
 
-DATABASE = 'sqlite.db'
-NODES = ['serial-AE00EI9M', 'serial-ATML2127031800008867', 'serial-A502C3ZD']
+db_lock = Lock()
+
+# Middle: serial-A502C1P4
+#NODES = ['serial-A502C1OZ', 'serial-A502C1PH', 'serial-A502C1PV', 'serial-A502C1PE', 'serial-A502C1Q1', 'serial-A502C1QH', 'serial-A502C1P5', 'serial-A502C1PI', 'serial-A502C1P4']
+# node ids: 7, ..., 16
+NODES = ['serial-A502C1PO', 'serial-A502C1PV', 'serial-A502C1P4', 'serial-A502C1QH', 'serial-A502C1OZ', 'serial-A502C1PE', 'serial-A502C1PI', 'serial-A502C1P5', 'serial-A502C1PH', 'serial-A502C1Q1']
 CHANNELS = [11, 15, 26]
+ANGELS = [0,25,50,75,100,125,150,175]
+POWERS = [-17, -7, 3]
+PAYLOADS = ['short', 'loooooooooooooooooooooooooooooooooooooooong']
+
+if False:
+    CHANNELS = [11]
+    POWERS = [-17]
+    PAYLOADS = ['short']
 
 logger = Logger(__file__)
 Base = declarative_base()
 
+class Round(Base):
+    __tablename__ = 'round'
+    id = Column(Integer, nullable=False, primary_key=True, autoincrement=True)
+    channel = Column(Integer, nullable=False)
+    power = Column(Integer, nullable=False)
+    angle = Column(Integer, nullable=False)
+    payload = Column(String(250), nullable=False)
+    ts = Column(Float, nullable=False)
+
 class TX(Base):
     __tablename__ = 'tx'
     serial_id = Column(String(250), nullable=False, primary_key=True)
     ts = Column(Float, nullable=False, primary_key=True)
     seq_nr = Column(Integer, nullable=False)
+    round_id = Column(Integer)
 
 class RX(Base):
     __tablename__ = 'rx'
@@ -28,6 +51,7 @@ class RX(Base):
     lqi = Column(Integer, nullable=False)
     node_id = Column(Integer, nullable=False)
     seq_nr = Column(Integer, nullable=False)
+    round_id = Column(Integer)
 
 class Corrupt(Base):
     __tablename__ = 'corrupt'
@@ -36,9 +60,9 @@ class Corrupt(Base):
     rssi = Column(Integer, nullable=False)
     lqi = Column(Integer, nullable=False)
     payload = Column(String(255), nullable=False)
+    round_id = Column(Integer)
 
-engine = create_engine('sqlite:///test.db')
-
+engine = create_engine('sqlite:////data/row_2.db')
 Session = sessionmaker(bind=engine)
 Base.metadata.create_all(engine)
 
@@ -49,6 +73,7 @@ re_rx_corrupt = re.compile("^<(?P<rssi>-?[0-9]+)\|(?P<lqi>[0-9]+)\|(?P<length>[0
 
 re_ifconfig = re.compile("^success: set (.*?) o(n|f) interface [0-9]+ to (.*?)$")
 
+eval_round = None
 
 def calculate_checksum(*args):
     s = 0
@@ -62,9 +87,12 @@ def handle_match_tx( src_id, ts, match_tx ):
     
     expected_checksum = calculate_checksum( seq_nr )
     if expected_checksum == checksum:
+        db_lock.acquire()
         session = Session()
-        session.add(TX(serial_id = src_id, ts=ts, seq_nr = seq_nr ))
+        session.add(TX( round_id=eval_round, serial_id = src_id, ts=ts, seq_nr = seq_nr ))
         session.commit()
+        session.close()
+        db_lock.release()
         #logger.log("[{}] TX: #{}".format( src_id, seq_nr ))
         return True
     else:
@@ -80,10 +108,14 @@ def handle_match_rx( src_id, ts, match_rx ):
     expected_checksum = calculate_checksum( node_id, '|', seq_nr, '|', rssi, '|', lqi )
 
     if expected_checksum == checksum:
+        db_lock.acquire()
         session = Session()
-        session.add(RX(serial_id = src_id, ts=ts, seq_nr = seq_nr, node_id = node_id, rssi = rssi, lqi = lqi))
-        # TODO(rh): Add sqlite3.OperationalError
+        session.add(RX(round_id=eval_round, serial_id = src_id, ts=ts, seq_nr = seq_nr, node_id = node_id, rssi = rssi, lqi = lqi))
         session.commit()
+        session.close()
+        db_lock.release()
+        # TODO(rh): Add sqlite3.OperationalError
+        # TODO(rh): Add sqlalchemy.exc.OperationalError / sqlite3.OperationalError
         #logger.log("[{}] RX: #{} from {}".format( src_id, node_id, seq_nr ))
         return True
     else:
@@ -95,16 +127,23 @@ def handle_match_rx_corrupt( src_id, ts, match_rx_corrupt ):
     lqi = match_rx_corrupt.group('lqi')
     payload = match_rx_corrupt.group('payload').strip()
     logger.debug( "Corrupt: {}dBm, {}, {}".format( rssi, lqi, payload ) )
+    db_lock.acquire()
     session = Session()
-    session.add(Corrupt(serial_id = src_id, ts=ts, rssi = rssi, lqi = lqi, payload = payload))
+    session.add(Corrupt(round_id=eval_round, serial_id = src_id, ts=ts, rssi = rssi, lqi = lqi, payload = payload))
     session.commit()
+    session.close()
+    db_lock.release()
     return True
 
 def handle_serial_rx(d):
+    global eval_round
     src_id = d['src']['id'][0]
     ts = d['ts']
     line = d['line'].strip()
 
+    if eval_round is None:
+        return False
+
     match_ifconfig = re_ifconfig.match(line)
     if match_ifconfig is not None:
         return True
@@ -122,32 +161,38 @@ def handle_serial_rx(d):
 class PRREvalClient(Client):
     def __init__(self, args = None):
         super(PRREvalClient, self).__init__(args, logging = True)
+        self.session = Session()
 
     def eval(self):
-        for channel in [11, 15, 26]:
+        global eval_round
+#        for angle in [0,25,50,75,100,125,150,175]:
+#            self.set_angle(angle)
+#            sleep(0.5)
+        for channel in CHANNELS:
             logger.log( "CHANNEL={} ".format(channel) )
             self.set_channel( channel  )
-            sleep(0.25)
-			for angle in [0,25,50,75,100,125,150,175]
-			    self.set_angle(angle)
-				sleep(2)
-				for power in [-17, -7, 0, 3]:
-					logger.log( "POWER={} ".format(power) )
-					self.set_txpower( power  )
-					sleep( 0.5 )
-					for payload in ['short', 'miiiiiiiiiiiiiiiiidle', 'loooooooooooooooooooooooooooooooooooooooong']:
-						logger.log( "PAYLOAD={} ".format(payload) )
-						self.send_all( "payload {}\n".format( payload )  )
-						sleep( 0.5 )
-						# TODO(rh) START ROUND:
-						# round = Round( channel=channel, power=power, payload=payload )
-						# session.add( round )
-						# session.commit()
-						for sender in NODES:
-							self.send({'dst': {'id': sender}, 'type': 'serial_tx', 'line': 'tx 5 200000\n'})
-							# 5 packets, 200ms -> 1 second
-							sleep( 1.5 )
-							self.send({'dst': {'id': sender}, 'type': 'serial_tx', 'line': 'ifconfig 3 set state idle\n'})
+            sleep(0.5)
+            for power in POWERS:
+                logger.log( "POWER={} ".format(power) )
+                self.set_txpower( power  )
+                sleep( 0.5 )
+                for payload in PAYLOADS:
+                    logger.log( "PAYLOAD={} ".format(payload) )
+                    self.send_all( "payload {}\n".format( payload )  )
+                    sleep( 0.5 )
+                    db_lock.acquire()
+                    r = Round( angle=-1, channel=channel, power=power, payload=payload, ts=time() )
+                    self.session.add( r )
+                    self.session.commit()
+                    eval_round = r.id
+                    db_lock.release()
+                    for sender in NODES:
+                        self.send({'dst': {'id': sender}, 'type': 'serial_tx', 'line': 'tx 5 200000\n'})
+                        # 5 packets, 200ms -> 1 second
+                        sleep( 2 )
+                        self.send({'dst': {'id': sender}, 'type': 'serial_tx', 'line': 'ifconfig 3 set state idle\n'})
+                    # Delay after all sends
+                    time.sleep( 5.0 )
 
     def run(self):
         while True:
@@ -158,8 +203,10 @@ class PRREvalClient(Client):
                 break
 
     def set_angle(self, angle):
-        self.send({'dst': {'id': 'lctc-01-serialsteppermotormodule'}, 'type': 'serial_position', 'position': angle})
-	
+        logger.log("ANGLE={}".format( angle ))
+        # {'module': ['SerialStepperMotorModule']}
+        self.send({'dst': {'id': ['lctc-01-serialsteppermotormodule']}, 'type': 'set_position', 'position': angle})
+
     def set_channel(self, channel):
         #self.send_all("ifconfig 3 set state idle\n")
         self.send_all("ifconfig 3 set channel {}\n".format( channel ))
@@ -175,8 +222,12 @@ class PRREvalClient(Client):
             if data_dict['type'] == 'serial_rx':
                 if handle_serial_rx( data_dict ):
                     return True
+                else:
+                    logger.debug("[{}] {}".format( data_dict['src']['id'][0], data_dict['line'] ) )
+                    return True
+          
         logger.debug( data_dict )
 
 if __name__ == '__main__':
     client = PRREvalClient()
-    client.run()
\ No newline at end of file
+    client.run()
diff --git a/software/main.c b/software/main.c
index 8776e33..48cac77 100644
--- a/software/main.c
+++ b/software/main.c
@@ -35,7 +35,7 @@
 #include "net/gnrc/netif/ieee802154.h"
 
 #define SEND_INTERVAL (1)
-#define RCV_QUEUE_SIZE (4)
+#define RCV_QUEUE_SIZE (16)
 #define MAX_PAYLOAD_LENGTH (64)
 #define MAGIC_STRING "IBREVAL\0"
 
-- 
GitLab