def next(self, input):
     action = map(DriverAction.DriverAction, [input["action"]])[0]
     if action == DriverAction.recvLocReq:
         # TODO: response the current location
         # check if the rsn is my RSN, route matched?
         global ROUTE_NO, DIRECTION, RSN_ADDR, LOCAL_ADDR, BUS_ID, WATCHDOG
         LOGGER.info("received RSN location request: %s" % input)
         
         # pet the watch dog
         WATCHDOG.petWatchdog()
         
         loc_message = {
                        "SM" : "RSN_SM",
                        "action" : "recvDriverLoc",
                        "requestNo" : input["requestNo"],
                        "route" : ROUTE_NO,
                        "direction" : DIRECTION,
                        "busId" : BUS_ID,
                        "location" : Location.getLocation(), 
                        "busIP" : LOCAL_ADDR.ip,
                        "busPort" : LOCAL_ADDR.port
                        }
         # TODO: TEST ONLY; rsn should be modified
         MessagePasser.directSend(RSN_ADDR.ip, RSN_ADDR.port, loc_message)
         
         return DriverSM.Ready
     elif action == DriverAction.timeout:
         # don't hear from RSN for 15 secs
         # send re-elect message to GSN
         global ROUTE_NO, DIRECTION, GSN_ADDR, LOCAL_ADDR, BUS_ID, WATCHDOG
         LOGGER.info("send re-elect request to GSN")
         RSN_elect_message = {
                              "SM" : "GSN_SM",
                              "action" : "recvElecReq",
                              "busId" : BUS_ID,
                              "route" : ROUTE_NO,
                              "direction" : DIRECTION,
                              "location" : Location.getLocation(),
                              "busIP" : LOCAL_ADDR.ip,
                              "busPort" : LOCAL_ADDR.port
                              }
         MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, RSN_elect_message)
         WATCHDOG.petWatchdog()
         return DriverSM.Hold
     elif action == DriverAction.turnOff:
         # TODO: do something to shut-down
         RESEND_ELECT_NUM = 0
         WATCHDOG.StopWatchdog()
         return DriverSM.Off
     else:
         # for other illegal action
         # assert 0, "Ready: invalid action: %s" % str(input)
         pass
Beispiel #2
0
    def next(self, input):
        action = map(UserAction.UserAction, [input["action"]])[0]
        if action == UserAction.request:
            global LOCAL_ADDR, GSN_ADDR, USER_ID, REQUEST_SEQ, WAITING_REQ_LIST, LAST_REQ, WATCHDOG, LAST_RESPONSE, IS_REPORTED
            # TODO: send a request to GSN
            LOGGER.info("send user request: %s" % input)
            REQUEST_SEQ = REQUEST_SEQ + 1
            requestId = USER_ID + str(REQUEST_SEQ)

            request_message = {
                "SM": "GSN_SM",
                "action": "recvUserReq",
                "requestId": requestId,
                "userId": USER_ID,
                "route": input["route"],
                "direction": input["direction"],
                "destination": input["destination"],
                "location": input["location"],
                "userIP": LOCAL_ADDR.ip,
                "userPort": LOCAL_ADDR.port
            }

            LAST_REQ = request_message
            LAST_RESPONSE = None
            IS_REPORTED = False

            # TODO: TEST ONLY; gsn should be modified
            MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port,
                                     request_message)
            WAITING_REQ_LIST.append(requestId)

            WATCHDOG.startWatchdog()

            return UserSM.Req_Waiting
        elif action == UserAction.turnOff:
            # TODO: do something to shut-down
            global WATCHDOG
            WATCHDOG.stopWatchdog()
            return UserSM.Off
        else:
            # for other illegal action
            # assert 0, "Ready: invalid action: %s" % str(input)
            pass
    def next(self, input):
        action = map(UserAction.UserAction, [input["action"]])[0]
        if action == UserAction.request:
            global LOCAL_ADDR, GSN_ADDR, USER_ID, REQUEST_SEQ, WAITING_REQ_LIST, LAST_REQ, WATCHDOG, LAST_RESPONSE, IS_REPORTED
            # TODO: send a request to GSN
            LOGGER.info("send user request: %s" % input)
            REQUEST_SEQ = REQUEST_SEQ + 1
            requestId = USER_ID + str(REQUEST_SEQ)

            request_message = {
                "SM": "GSN_SM",
                "action": "recvUserReq",
                "requestId": requestId,
                "userId": USER_ID,
                "route": input["route"],
                "direction": input["direction"],
                "destination": input["destination"],
                "location": input["location"],
                "userIP": LOCAL_ADDR.ip,
                "userPort": LOCAL_ADDR.port,
            }

            LAST_REQ = request_message
            LAST_RESPONSE = None
            IS_REPORTED = False

            # TODO: TEST ONLY; gsn should be modified
            MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, request_message)
            WAITING_REQ_LIST.append(requestId)

            WATCHDOG.startWatchdog()

            return UserSM.Req_Waiting
        elif action == UserAction.turnOff:
            # TODO: do something to shut-down
            global WATCHDOG
            WATCHDOG.stopWatchdog()
            return UserSM.Off
        else:
            # for other illegal action
            # assert 0, "Ready: invalid action: %s" % str(input)
            pass
    def next(self, input):
        action = map(DriverAction.DriverAction, [input["action"]])[0]
        if action == DriverAction.start:
            global LOCAL_ADDR, RSN_ADDR, ROUTE_NO, DIRECTION, BUS_ID, WATCHDOG
            
            ROUTE_NO = input["route"]
            DIRECTION = input["direction"]
            Location.setLocation(int(input["location"]))
            
            # TODO: ping RSN to add into the group
            add_message = {
                           "SM" : "GSN_SM",
                           "action" : "recvBusReq",
                           "type" : "add",
                           "route" : ROUTE_NO,
                           "direction" : DIRECTION,
                           "busId" : BUS_ID,
                           "location" : Location.getLocation(), 
                           "busIP" : LOCAL_ADDR.ip,
                           "busPort" : LOCAL_ADDR.port
                           }
            # TODO: should use real gsn 
            MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, add_message)
            
            # start the watchdog
            WATCHDOG.startWatchdog()
            
            return DriverSM.Init_Waiting
        elif action == DriverAction.timeout:
            # TODO: re-ping
            return DriverSM.Idle
        elif action == DriverAction.turnOff:
            # TODO: do something to shut-down
            RESEND_ELECT_NUM = 0
            WATCHDOG.stopWatchdog()

            return DriverSM.Off
        else:
            # for other illegal action
            # assert 0, "Idle: invalid action: %s" % str(input)
            pass
Beispiel #5
0
    def next(self, input):
        action = map(UserAction.UserAction, [input["action"]])[0]
        if action == UserAction.recvRes:
            # TODO: return response to GUI
            global RESPONSE_QUE, WAITING_REQ_LIST, WATCHDOG, LAST_RESPONSE, LAST_REQ, ARRIVE_TIME
            LOGGER.info("receive response from RSN %s" % input)

            WATCHDOG.stopWatchdog()

            if str(input["original"]["requestId"]) in WAITING_REQ_LIST:
                RESPONSE_QUE.append(input)
                # if the last res is matched with last req, calculate arrive time
                if input["original"]["requestId"] == LAST_REQ["requestId"]:
                    if input["location"] == None:
                        diff = -1
                    else:
                        diff = int(LAST_REQ["location"]) - int(
                            input["location"])
                    ARRIVE_TIME = diff
                    LAST_RESPONSE = input
                    IS_REPORTED = False

            LOGGER.info("expected arrive time: %s" % str(ARRIVE_TIME))
            return UserSM.Ready
        elif action == UserAction.reqTimeout:
            # TODO: re-send request if over threshold
            global LAST_REQ, WATCHDOG

            MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, LAST_REQ)

            WATCHDOG.petWatchdog()
            return UserSM.Req_Waiting
        elif action == UserAction.turnOff:
            # TODO: do something to shut-down
            global WATCHDOG
            WATCHDOG.stopWatchdog()
            return UserSM.Off
        else:
            # for other illegal action
            # assert 0, "Req_Waiting: invalid action: %s" % str(input)
            pass
    def next(self, input):
        action = map(UserAction.UserAction, [input["action"]])[0]
        if action == UserAction.recvRes:
            # TODO: return response to GUI
            global RESPONSE_QUE, WAITING_REQ_LIST, WATCHDOG, LAST_RESPONSE, LAST_REQ, ARRIVE_TIME
            LOGGER.info("receive response from RSN %s" % input)

            WATCHDOG.stopWatchdog()

            if str(input["original"]["requestId"]) in WAITING_REQ_LIST:
                RESPONSE_QUE.append(input)
                # if the last res is matched with last req, calculate arrive time
                if input["original"]["requestId"] == LAST_REQ["requestId"]:
                    if input["location"] == None:
                        diff = -1
                    else:
                        diff = int(LAST_REQ["location"]) - int(input["location"])
                    ARRIVE_TIME = diff
                    LAST_RESPONSE = input
                    IS_REPORTED = False

            LOGGER.info("expected arrive time: %s" % str(ARRIVE_TIME))
            return UserSM.Ready
        elif action == UserAction.reqTimeout:
            # TODO: re-send request if over threshold
            global LAST_REQ, WATCHDOG

            MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, LAST_REQ)

            WATCHDOG.petWatchdog()
            return UserSM.Req_Waiting
        elif action == UserAction.turnOff:
            # TODO: do something to shut-down
            global WATCHDOG
            WATCHDOG.stopWatchdog()
            return UserSM.Off
        else:
            # for other illegal action
            # assert 0, "Req_Waiting: invalid action: %s" % str(input)
            pass
    def next(self, input):
        action = map(RSNAction.RSNAction, [input["action"]])[0]
        if action == RSNAction.recvLocReq:
            # TODO: lookup the queried bus location and
            # TODO: response to user directly
            global BUS_TABLE, LOC_REQ_NO
            LOGGER.info("received location request: %s" % input)
            
            # fetch the nearest bus available
            # TODO: this function should be polished
            nearest_bus = None;
            nearest_loc = None;
            nearest_dist = -1;
            for key in BUS_TABLE:
                bus = BUS_TABLE[key]
                if (int(bus["last_update"]) >= int(LOC_REQ_NO) - 1) and (int(bus["last_update"]) <= int(LOC_REQ_NO)):
                    distance = int(input["original"]["location"]) - int(bus["location"])
                    if (nearest_dist < 0 or distance < nearest_dist) and distance >= 0:
                        nearest_dist = distance
                        nearest_bus = key
                        nearest_loc = bus["location"]
            
            response_message = {
                                "SM" : "USER_SM",
                                "action" : "recvRes",
                                "location" : nearest_loc, 
                                "busId" : nearest_bus,
                                "original" : input["original"]
                               }

            MessagePasser.directSend(input["original"]["userIP"], input["original"]["userPort"], response_message)
            
            return RSNSM.Ready
        elif action == RSNAction.askBusLoc:
            # periodically ask each buses' location
            # TODO: triggered by host timer
            global GROUP_MEMBER, RSN_ID, ROUTE_NO, LOCAL_ADDR, LOC_REQ_NO
            LOGGER.info("asking each bus' location %s" % BUS_TABLE.keys())
            LOC_REQ_NO = LOC_REQ_NO + 1             # maybe overflow!!!
            
            req_loc_message = {
                               "SM" : "DRIVER_SM",
                               "action" : "recvLocReq",
                               "requestNo" : LOC_REQ_NO,
                               "rsnId" : RSN_ID,
                               "route" : ROUTE_NO,
                               "rsnIP" : LOCAL_ADDR.ip,
                               "rsnPort" : LOCAL_ADDR.port
                               }
            
            #MessagePasser.multicast(GROUP_MEMBER, req_loc_message)
            # TODO: replace the code below with a multicast version

            for member in BUS_TABLE:
                MessagePasser.directSend(BUS_TABLE[member]["addr"].ip, BUS_TABLE[member]["addr"].port, req_loc_message)
 
            return RSNSM.Ready
        elif action == RSNAction.recvDriverLoc:
            # TODO: update local cache
            global BUS_TABLE, ROUTE_NO

            if input["route"] == ROUTE_NO \
                and input["busId"] in BUS_TABLE \
                and input["requestNo"] > BUS_TABLE[input["busId"]]["last_update"]:
                
                BUS_TABLE[input["busId"]] = {
                                              "direction" : input["direction"],
                                              "location" : input["location"],
                                              "addr" : Addr(input["busIP"], input["busPort"]),
                                              "last_update" : input["requestNo"]    # TODO: use local time stamp
                                              }
            
            return RSNSM.Ready
        elif action == RSNAction.recvBusChange:
            # TODO: add or remove a bus from current group
            LOGGER.info("Receive bus change request: %s" % input)
            global GROUP_MEMBER, BUS_TABLE, ROUTE_NO, RSN_ID, LOCAL_ADDR, LOC_REQ_NO
            
            if input["route"] == ROUTE_NO:
                if input["type"] == "add":
                    #if not input["busId"] in BUS_TABLE:
                        #GROUP_MEMBER.append(input["busId"])
                        BUS_TABLE[input["busId"]] = {
                                                      "direction" : input["direction"],
                                                      "location" : input["location"],
                                                      "addr" : Addr(input["busIP"], input["busPort"]),
                                                      "last_update" : LOC_REQ_NO # TODO: use local time stamp
                                                      }
                        # send an ACK to driver
                        rsn_ack = {
                                   "SM" : "DRIVER_SM",
                                   "action" : "recvRSNAck",
                                   "route" : ROUTE_NO,
                                   "rsnId" : RSN_ID,
                                   "rsnIP" : LOCAL_ADDR.ip,
                                   "rsnPort" : LOCAL_ADDR.port
                                   }
                        MessagePasser.directSend(input["busIP"], input["busPort"], rsn_ack)
                elif input["type"] == "remove":
                    if input["busId"] in BUS_TABLE:
                        #GROUP_MEMBER.remove(input["busId"])
                        BUS_TABLE.pop(input["busId"])
            return RSNSM.Ready
        
        elif action == RSNAction.recvGSNHB:
            LOGGER.info("Receive GSN heart beat: %s" % input["HBNo"])
            
            global BUS_TABLE, RSN_ID, ROUTE_NO, LOCAL_ADDR, GSN_ADDR, LOC_REQ_NO
            
            # filter out some dead buses
            remove_list = []
            for bus in BUS_TABLE:
                if int(BUS_TABLE[bus]["last_update"]) + 1 < LOC_REQ_NO:
                    remove_list.append(bus)
            for bus in remove_list:
                BUS_TABLE.pop(bus)
                    
            # send current route table to GSN
            HB_res_message = {
                              "SM" : "GSN_SM",
                              "action" : "recvHBRes",
                              "HBNo" : input["HBNo"],
                              "rsnId" : RSN_ID,
                              "route" : ROUTE_NO,
                              "rsnIP" : LOCAL_ADDR.ip,
                              "rsnPort" : LOCAL_ADDR.port,
                              "busTable" : BUS_TABLE
                              }
            MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, HB_res_message)
            return  RSNSM.Ready
        elif action == RSNAction.recvRSNResign:
            LOGGER.info("Receive GSN resign")
            TIMER_OFF.set()
            TIMER_ON.clear()
            return RSNSM.Idle
        elif action == RSNAction.turnOff:
            # TODO: do something to shut-down
            TIMER_OFF.set()
            TIMER_ON.clear()
            return RSNSM.Off
        else:
            # for other illegal action
            # assert 0, "Ready: invalid action: %s" % str(input)
            pass
    def next(self, input):
        action = map(RSNAction.RSNAction, [input["action"]])[0]
        if action == RSNAction.recvRSNAssign:
            # TODO: received the group info from GSN
            # TODO: store the group info
            
            global LOCAL_ADDR, ROUTE_NO, BUS_TABLE, TIMER_ON, TIMER_OFF
            ROUTE_NO = input["route"]

            # if the RSN is the Driver itself, send a recvRSNAck to driver role
            if input["type"] == "self":
                BUS_TABLE[input["original"]["busId"]] = {
                                             "direction" : input["original"]["direction"],
                                             "location" : input["original"]["location"],
                                             "addr" : Addr(input["original"]["busIP"], input["original"]["busPort"]),
                                             "last_update" : 0 # TODO: use local time stamp
                                             }
                
                rsn_ack = {
                           "SM" : "DRIVER_SM",
                           "action" : "recvRSNAck",
                           "route" : ROUTE_NO,
                           "rsnId" : RSN_ID,
                           "rsnIP" : LOCAL_ADDR.ip,
                           "rsnPort" : LOCAL_ADDR.port
                           }
                MessagePasser.directSend(input["original"]["busIP"], input["original"]["busPort"], rsn_ack)
            elif input["type"] == "normal":
                BUS_TABLE = input["busTable"]
                
                if BUS_TABLE == None:
                    BUS_TABLE = {}
                # reset all time stampes
                for bus in BUS_TABLE:
                    BUS_TABLE[bus]["last_update"] = 0
                
                # notify each bus 
                global GROUP_MEMBER, RSN_ID, ROUTE_NO, LOCAL_ADDR, LOC_REQ_NO
                LOGGER.info("asking each bus' location %s" % BUS_TABLE.keys())
                LOC_REQ_NO = 0
                LOC_REQ_NO = LOC_REQ_NO + 1             # maybe overflow!!!
            
                req_loc_message = {
                                   "SM" : "DRIVER_SM",
                                   "action" : "recvLocReq",
                                   "requestNo" : LOC_REQ_NO,
                                   "rsnId" : RSN_ID,
                                   "route" : ROUTE_NO,
                                   "rsnIP" : LOCAL_ADDR.ip,
                                   "rsnPort" : LOCAL_ADDR.port
                                   }
                for member in BUS_TABLE:
                    MessagePasser.directSend(BUS_TABLE[member]["addr"].ip, BUS_TABLE[member]["addr"].port, req_loc_message)
                
                
            # unblock the timer thread
            TIMER_OFF.clear()
            TIMER_ON.set()
            
            return RSNSM.Ready
        elif action == RSNAction.timeout:
            # TODO: re-ping
            # Terry: seems no need to re-ping gsn
            return RSNSM.Idle
        elif action == RSNAction.turnOff:
            global TIMER_ON, TIMER_OFF
            # TODO: do something to shut-down
            TIMER_OFF.set()
            TIMER_ON.clear()
            return RSNSM.Off
        else:
            # for other illegal action
            # assert 0, "Idle: invalid action: %s" % str(input)
            pass
    def next(self, input):
        action = map(GSNAction.GSNAction, [input["action"]])[0]
        if action == GSNAction.recvUserReq:
            # TODO: forward user request to responding RSN
            LOGGER.info("receive user request")
            rsn = getRSNByName(input["route"])
            
            if rsn != None:
                LOGGER.info("forward user request to RSN")
                rsnAddr = rsn["rsnAddr"]
                request_message = {
                                   "SM" : "RSN_SM",
                                   "action" : "recvLocReq",
                                   "original" : input
                                   }
                MessagePasser.directSend(rsnAddr.ip, rsnAddr.port, request_message)
            else:
                LOGGER.info("no rsn running")
                response_message = {
                                    "SM" : "USER_SM",
                                    "action" : "recvRes",
                                    "location" : None, 
                                    "busId" : None,
                                    "original" : input
                                    }
                MessagePasser.directSend(input["userIP"], input["userPort"], response_message)
            
            return GSNSM.Ready
        
        elif action == GSNAction.heartBeat:
            LOGGER.info("send heart beat to each RSN")
            global HB_NO
            HB_NO = HB_NO + 1
            
            hb_message = {
                          "SM" : "RSN_SM",
                          "action" : "recvGSNHB",
                          "HBNo" : HB_NO
                          }

            for route in ROUTE_TABLE:
                MessagePasser.directSend(ROUTE_TABLE[route]["rsnAddr"].ip, ROUTE_TABLE[route]["rsnAddr"].port, hb_message)
            
            return GSNSM.Ready
        
        elif action == GSNAction.recvHBRes:
            LOGGER.info("receive HB response")
            
            global ROUTE_TABLE, HB_NO
            
            # update ROUTE_TABLE
            if input["route"] in ROUTE_TABLE:
                if input["rsnId"] == ROUTE_TABLE[input["route"]]["rsnId"]:
                    ROUTE_TABLE[input["route"]]["rsnAddr"] = Addr(input["rsnIP"], input["rsnPort"])
                    ROUTE_TABLE[input["route"]]["busTable"] = input["busTable"]
                    ROUTE_TABLE[input["route"]]["last_update"] = input["HBNo"]
                    ROUTE_TABLE[input["route"]]["isElect"] = False
                else:
                    # TODO: the rsnId is not recorded
                    pass
            else:
                # TODO: the route is not recorded.
                pass
            
            return GSNSM.Ready
        elif action == GSNAction.recvBusReq:
            # TODO: update route table and forward user request to responding RSN
            LOGGER.info("receive bus request")
            rsn = getRSNByName(input["route"])
            # if there is no RSN, assign the request bus as the RSN
            if rsn == None:
                # Qian: some checks: (1) if there is no rsn but receive a remove req
                LOGGER.info("assign new RSN")
                """
                routeTableElm = RouteTableElm(input["route"], 
                                              Addr(input["driverIp"], input["driverPort"]), 
                                              [])
                routeTableElm.busTable.append(BusTableElm(Addr(input["driverIp"], input["driverPort"])))
                """
                route_table_entry = {
                                     "rsnId" : input["busId"],
                                     "rsnAddr" : Addr(input["busIP"], input["busPort"]),
                                     "busTable" : None,
                                     "last_update" : HB_NO
                                     }
                
                ROUTE_TABLE[input["route"]] = route_table_entry
                assign_message = {
                                  "SM" : "RSN_SM",
                                  "action" : "recvRSNAssign",
                                  "type" : "self", 
                                  "route" : input["route"],
                                  "original" : input,
                                  "groupMember" : [input["busId"]]
                                  }
                
                MessagePasser.directSend(input["busIP"], input["busPort"], assign_message)
            else:
                # Qian: GSN will just forward it to rsn
                # may change this design
                request_message = {
                                   "SM" : "RSN_SM",
                                   "action" : "recvBusChange",
                                   "type" : input["type"],    # add or remove
                                   "route" : input["route"],
                                   "direction" : input["direction"],
                                   "location" : input["location"],
                                   "busId" : input["busId"],
                                   "busIP" : input["busIP"],
                                   "busPort" : input["busPort"]
                                   }
                MessagePasser.directSend(rsn["rsnAddr"].ip, rsn["rsnAddr"].port, request_message)
            return GSNSM.Ready
        elif action == GSNAction.recvElecReq:
            # receive election rsn request for a bus
            LOGGER.info("receive election request")
            global HB_NO
            
            rsn = getRSNByName(input["route"])
            
            # check if the rsn is live by checking the time stamp
            if rsn["last_update"] + 1 >= HB_NO:
                # means the RSN is alive, tell the driver to wait or reboot
                if rsn["isElect"] == True:
                    LOGGER.info("new RSN has been elected, ignore the elect request")
                else:
                    LOGGER.info("RSN is alive, ask the driver to reboot")
                    restart_message = {
                                       "SM" : "DRIVER_SM",
                                       "action" : "restart"
                                       }
                    MessagePasser.directSend(input["busIP"], input["busPort"], restart_message)
            else:
                # the RSN is dead, elect a new one, select the bus who sends the request, #with the longest potential running time
                
                
                bus_table = rsn["busTable"]
                '''
                rsn_candidate = None
                min_dist = -1
                min_bus_id = -1
                
                for bus in bus_table:
                    dist = int(bus_table[bus]["location"])
                    if min_dist < 0 or dist < min_dist:
                        min_dist = dist
                        rsn_candidate = bus_table[bus]
                        min_bus_id = bus
                '''
                LOGGER.info("RSN is dead, select a new RSN [%s] for route [%s]" % (input["busId"], input["route"]))
                

                
                # explicitly send a message to shut down the previous RSN
                resign_message = {
                                  "SM" : "RSN_SM",
                                  "action" : "recvRSNResign"
                                  }
                MessagePasser.directSend(rsn["rsnAddr"].ip, rsn["rsnAddr"].port, resign_message)

                
                # assign a new RSN
                assign_message = {
                                  "SM" : "RSN_SM",
                                  "action" : "recvRSNAssign",
                                  "type" : "normal", 
                                  "route" : input["route"],
                                  "original" : None,
                                  "busTable" : bus_table
                                  }
                
                ROUTE_TABLE[input["route"]] = {
                                               "rsnId" : input["busId"],
                                               "rsnAddr" : Addr(input["busIP"], input["busPort"]),
                                               "busTable" : bus_table,
                                               "last_update" : HB_NO,
                                               "isElect" : True,
                                               }
                
                MessagePasser.directSend(input["busIP"], input["busPort"], assign_message)
                
            
            # TODO: select a bus from the table to be the new rsn, below code just selects the first driver
            '''
            elm.rsnIP = elm.busTable[0]["rsnAddr"].ip
            elm.rsnPort = elm.busTable[0]["rsnAddr"].port
            
            LOGGER.info("send message to new rsn")
            assign_message = {
                              "SM" : "RSN_SM",
                              "action" : "recvRSNAssign",
                              "groupMember" : elm.busTable
                              }
            # TODO: TEST ONLY; gsn should be modified
            MessagePasser.directSend(elm.rsnIP, elm.rsnPort, request_message)
            '''
            return GSNSM.Ready
        elif action == GSNAction.turnOff:
            # TODO: do something to shut-down
            return GSNSM.Off
    def next(self, input):
        action = map(DriverAction.DriverAction, [input["action"]])[0]
        if action == DriverAction.recvLocReq:
            # TODO: response the current location
            # check if the rsn is my RSN, route matched?
            global ROUTE_NO, DIRECTION, RSN_ADDR, LOCAL_ADDR, BUS_ID, WATCHDOG
            LOGGER.info("received RSN location request: %s" % input)
            
            # pet the watch dog
            WATCHDOG.petWatchdog()
            
            # check if the RSN has changed
            if RSN_ADDR.ip != input["rsnIP"] or RSN_ADDR.port != input["rsnPort"]:
                LOGGER.info("RSN has changed")
                RSN_ADDR = Addr(input["rsnIP"], input["rsnPort"])
            
            loc_message = {
                           "SM" : "RSN_SM",
                           "action" : "recvDriverLoc",
                           "requestNo" : input["requestNo"],
                           "route" : ROUTE_NO,
                           "direction" : DIRECTION,
                           "busId" : BUS_ID,
                           "location" : Location.getLocation(), 
                           "busIP" : LOCAL_ADDR.ip,
                           "busPort" : LOCAL_ADDR.port
                           }
            # TODO: TEST ONLY; rsn should be modified
            MessagePasser.directSend(RSN_ADDR.ip, RSN_ADDR.port, loc_message)
            
            return DriverSM.Ready
        
        elif action == DriverAction.restart:
            # restart
            global LOCAL_ADDR, RSN_ADDR, ROUTE_NO, DIRECTION, BUS_ID, RESEND_ELECT_NUM

            LOGGER.info("Receive restart message from GSN. Restart now.")
                
                
            # TODO: ping RSN to add into the group
            add_message = {
                           "SM" : "GSN_SM",
                           "action" : "recvBusReq",
                           "type" : "add",
                           "route" : ROUTE_NO,
                           "direction" : DIRECTION,
                           "busId" : BUS_ID,
                           "location" : Location.getLocation(), 
                           "busIP" : LOCAL_ADDR.ip,
                           "busPort" : LOCAL_ADDR.port
                           }
            # TODO: should use real gsn 
            MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, add_message)

            RESEND_ELECT_NUM = 0
            
            # pet the watch dog
            WATCHDOG.petWatchdog()
            
            return DriverSM.Init_Waiting
        elif action == DriverAction.timeout:
            # if reaches the limit of re-elect, reboot
            global RESEND_ELECT_NUM
            if RESEND_ELECT_NUM >= 3:
                LOGGER.info("RESEND_ELECT_NUM reaches the limit, reboot now.")
                RESEND_ELECT_NUM = 0
                # restart
                global LOCAL_ADDR, RSN_ADDR, ROUTE_NO, DIRECTION, BUS_ID

                add_message = {
                               "SM" : "GSN_SM",
                               "action" : "recvBusReq",
                               "type" : "add",
                               "route" : ROUTE_NO,
                               "direction" : DIRECTION,
                               "busId" : BUS_ID,
                               "location" : Location.getLocation(), 
                               "busIP" : LOCAL_ADDR.ip,
                               "busPort" : LOCAL_ADDR.port
                               }
                # TODO: should use real gsn 
                MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, add_message)
                
                # pet the watch dog
                WATCHDOG.petWatchdog()
                
                return DriverSM.Init_Waiting
            else:
                # re-send re-elect msg
                LOGGER.info("send re-elect request to GSN, RESEND_ELECT_NUM: %s" % str(RESEND_ELECT_NUM))
                RESEND_ELECT_NUM = RESEND_ELECT_NUM + 1
                RSN_elect_message = {
                                     "SM" : "GSN_SM",
                                     "action" : "recvElecReq",
                                     "busId" : BUS_ID,
                                     "route" : ROUTE_NO,
                                     "direction" : DIRECTION,
                                     "location" : Location.getLocation(),
                                     "busIP" : LOCAL_ADDR.ip,
                                     "busPort" : LOCAL_ADDR.port
                                     }
                MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, RSN_elect_message)
                
                # pet the watch dog
                WATCHDOG.petWatchdog()
                
                return DriverSM.Hold
        elif action == DriverAction.turnOff:
            # TODO: do something to shut-down
            RESEND_ELECT_NUM = 0
            WATCHDOG.stopWatchdog()
            return DriverSM.Off
        else:
            # for other illegal action
            # assert 0, "Init_Waiting: invalid action: %s" % str(input)
            pass
    def next(self, input):
        action = map(DriverAction.DriverAction, [input["action"]])[0]
        if action == DriverAction.recvRSNAck:
            global MYSELF_ADDR, RSN_ADDR, ROUTE_NO, DIRECTION, BUS_ID

            # if the response route number doesn't match
            if input["route"] != ROUTE_NO:
                return DriverSM.Init_Waiting
            
            RSN_ADDR = Addr(input["rsnIP"], input["rsnPort"])
            
            # pet the watch dog
            WATCHDOG.petWatchdog()

            return DriverSM.Ready
        elif action == DriverAction.timeout:
            # not receive the reponse from RSN for 15 secs
            global RESEND_ELECT_NUM
            if RESEND_ELECT_NUM >= 3:
                LOGGER.info("RESEND_ELECT_NUM reaches the limit, reboot now.")
                RESEND_ELECT_NUM = 0
                # restart
                global LOCAL_ADDR, RSN_ADDR, ROUTE_NO, DIRECTION, BUS_ID

                add_message = {
                               "SM" : "GSN_SM",
                               "action" : "recvBusReq",
                               "type" : "add",
                               "route" : ROUTE_NO,
                               "direction" : DIRECTION,
                               "busId" : BUS_ID,
                               "location" : Location.getLocation(), 
                               "busIP" : LOCAL_ADDR.ip,
                               "busPort" : LOCAL_ADDR.port
                               }
                # TODO: should use real gsn 
                MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, add_message)
                
                # pet the watch dog
                WATCHDOG.petWatchdog()
                
                return DriverSM.Init_Waiting
            else:
                # re-send re-elect msg
                LOGGER.info("send re-elect request to GSN, RESEND_ELECT_NUM: %s" % str(RESEND_ELECT_NUM))
                RESEND_ELECT_NUM = RESEND_ELECT_NUM + 1
                RSN_elect_message = {
                                     "SM" : "GSN_SM",
                                     "action" : "recvElecReq",
                                     "busId" : BUS_ID,
                                     "route" : ROUTE_NO,
                                     "direction" : DIRECTION,
                                     "location" : Location.getLocation(),
                                     "busIP" : LOCAL_ADDR.ip,
                                     "busPort" : LOCAL_ADDR.port
                                     }
                MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, RSN_elect_message)
                
                # pet the watch dog
                WATCHDOG.petWatchdog()
                
                return DriverSM.Init_Waiting
            
            return DriverSM.Init_Waiting
        elif action == DriverAction.turnOff:
            # TODO: do something to shut-down
            RESEND_ELECT_NUM = 0
            WATCHDOG.stopWatchdog()
            return DriverSM.Off
        else:
            # for other illegal action
            # assert 0, "Init_Waiting: invalid action: %s" % str(input)
            pass
    def next(self, input):
        action = map(GSNAction.GSNAction, [input["action"]])[0]
        if action == GSNAction.recvUserReq:
            # TODO: forward user request to responding RSN
            LOGGER.info("receive user request")
            rsn = getRSNByName(input["route"])

            if rsn != None:
                LOGGER.info("forward user request to RSN")
                rsnAddr = rsn["rsnAddr"]
                request_message = {
                    "SM": "RSN_SM",
                    "action": "recvLocReq",
                    "original": input
                }
                MessagePasser.directSend(rsnAddr.ip, rsnAddr.port,
                                         request_message)
            else:
                LOGGER.info("no rsn running")
                response_message = {
                    "SM": "USER_SM",
                    "action": "recvRes",
                    "location": None,
                    "busId": None,
                    "original": input
                }
                MessagePasser.directSend(input["userIP"], input["userPort"],
                                         response_message)

            return GSNSM.Ready

        elif action == GSNAction.heartBeat:
            LOGGER.info("send heart beat to each RSN")
            global HB_NO
            HB_NO = HB_NO + 1

            hb_message = {"SM": "RSN_SM", "action": "recvGSNHB", "HBNo": HB_NO}

            for route in ROUTE_TABLE:
                MessagePasser.directSend(ROUTE_TABLE[route]["rsnAddr"].ip,
                                         ROUTE_TABLE[route]["rsnAddr"].port,
                                         hb_message)

            return GSNSM.Ready

        elif action == GSNAction.recvHBRes:
            LOGGER.info("receive HB response")

            global ROUTE_TABLE, HB_NO

            # update ROUTE_TABLE
            if input["route"] in ROUTE_TABLE:
                if input["rsnId"] == ROUTE_TABLE[input["route"]]["rsnId"]:
                    ROUTE_TABLE[input["route"]]["rsnAddr"] = Addr(
                        input["rsnIP"], input["rsnPort"])
                    ROUTE_TABLE[input["route"]]["busTable"] = input["busTable"]
                    ROUTE_TABLE[input["route"]]["last_update"] = input["HBNo"]
                    ROUTE_TABLE[input["route"]]["isElect"] = False
                else:
                    # TODO: the rsnId is not recorded
                    pass
            else:
                # TODO: the route is not recorded.
                pass

            return GSNSM.Ready
        elif action == GSNAction.recvBusReq:
            # TODO: update route table and forward user request to responding RSN
            LOGGER.info("receive bus request")
            rsn = getRSNByName(input["route"])
            # if there is no RSN, assign the request bus as the RSN
            if rsn == None:
                # Qian: some checks: (1) if there is no rsn but receive a remove req
                LOGGER.info("assign new RSN")
                """
                routeTableElm = RouteTableElm(input["route"], 
                                              Addr(input["driverIp"], input["driverPort"]), 
                                              [])
                routeTableElm.busTable.append(BusTableElm(Addr(input["driverIp"], input["driverPort"])))
                """
                route_table_entry = {
                    "rsnId": input["busId"],
                    "rsnAddr": Addr(input["busIP"], input["busPort"]),
                    "busTable": None,
                    "last_update": HB_NO
                }

                ROUTE_TABLE[input["route"]] = route_table_entry
                assign_message = {
                    "SM": "RSN_SM",
                    "action": "recvRSNAssign",
                    "type": "self",
                    "route": input["route"],
                    "original": input,
                    "groupMember": [input["busId"]]
                }

                MessagePasser.directSend(input["busIP"], input["busPort"],
                                         assign_message)
            else:
                # Qian: GSN will just forward it to rsn
                # may change this design
                request_message = {
                    "SM": "RSN_SM",
                    "action": "recvBusChange",
                    "type": input["type"],  # add or remove
                    "route": input["route"],
                    "direction": input["direction"],
                    "location": input["location"],
                    "busId": input["busId"],
                    "busIP": input["busIP"],
                    "busPort": input["busPort"]
                }
                MessagePasser.directSend(rsn["rsnAddr"].ip,
                                         rsn["rsnAddr"].port, request_message)
            return GSNSM.Ready
        elif action == GSNAction.recvElecReq:
            # receive election rsn request for a bus
            LOGGER.info("receive election request")
            global HB_NO

            rsn = getRSNByName(input["route"])

            # check if the rsn is live by checking the time stamp
            if rsn["last_update"] + 1 >= HB_NO:
                # means the RSN is alive, tell the driver to wait or reboot
                if rsn["isElect"] == True:
                    LOGGER.info(
                        "new RSN has been elected, ignore the elect request")
                else:
                    LOGGER.info("RSN is alive, ask the driver to reboot")
                    restart_message = {"SM": "DRIVER_SM", "action": "restart"}
                    MessagePasser.directSend(input["busIP"], input["busPort"],
                                             restart_message)
            else:
                # the RSN is dead, elect a new one, select the bus who sends the request, #with the longest potential running time

                bus_table = rsn["busTable"]
                '''
                rsn_candidate = None
                min_dist = -1
                min_bus_id = -1
                
                for bus in bus_table:
                    dist = int(bus_table[bus]["location"])
                    if min_dist < 0 or dist < min_dist:
                        min_dist = dist
                        rsn_candidate = bus_table[bus]
                        min_bus_id = bus
                '''
                LOGGER.info(
                    "RSN is dead, select a new RSN [%s] for route [%s]" %
                    (input["busId"], input["route"]))

                # explicitly send a message to shut down the previous RSN
                resign_message = {"SM": "RSN_SM", "action": "recvRSNResign"}
                MessagePasser.directSend(rsn["rsnAddr"].ip,
                                         rsn["rsnAddr"].port, resign_message)

                # assign a new RSN
                assign_message = {
                    "SM": "RSN_SM",
                    "action": "recvRSNAssign",
                    "type": "normal",
                    "route": input["route"],
                    "original": None,
                    "busTable": bus_table
                }

                ROUTE_TABLE[input["route"]] = {
                    "rsnId": input["busId"],
                    "rsnAddr": Addr(input["busIP"], input["busPort"]),
                    "busTable": bus_table,
                    "last_update": HB_NO,
                    "isElect": True,
                }

                MessagePasser.directSend(input["busIP"], input["busPort"],
                                         assign_message)

            # TODO: select a bus from the table to be the new rsn, below code just selects the first driver
            '''
            elm.rsnIP = elm.busTable[0]["rsnAddr"].ip
            elm.rsnPort = elm.busTable[0]["rsnAddr"].port
            
            LOGGER.info("send message to new rsn")
            assign_message = {
                              "SM" : "RSN_SM",
                              "action" : "recvRSNAssign",
                              "groupMember" : elm.busTable
                              }
            # TODO: TEST ONLY; gsn should be modified
            MessagePasser.directSend(elm.rsnIP, elm.rsnPort, request_message)
            '''
            return GSNSM.Ready
        elif action == GSNAction.turnOff:
            # TODO: do something to shut-down
            return GSNSM.Off
    def next(self, input):
        action = map(RSNAction.RSNAction, [input["action"]])[0]
        if action == RSNAction.recvLocReq:
            # TODO: lookup the queried bus location and
            # TODO: response to user directly
            global BUS_TABLE, LOC_REQ_NO
            LOGGER.info("received location request: %s" % input)

            # fetch the nearest bus available
            # TODO: this function should be polished
            nearest_bus = None
            nearest_loc = None
            nearest_dist = -1
            for key in BUS_TABLE:
                bus = BUS_TABLE[key]
                if (int(bus["last_update"]) >= int(LOC_REQ_NO) - 1) and (int(
                        bus["last_update"]) <= int(LOC_REQ_NO)):
                    distance = int(input["original"]["location"]) - int(
                        bus["location"])
                    if (nearest_dist < 0
                            or distance < nearest_dist) and distance >= 0:
                        nearest_dist = distance
                        nearest_bus = key
                        nearest_loc = bus["location"]

            response_message = {
                "SM": "USER_SM",
                "action": "recvRes",
                "location": nearest_loc,
                "busId": nearest_bus,
                "original": input["original"]
            }

            MessagePasser.directSend(input["original"]["userIP"],
                                     input["original"]["userPort"],
                                     response_message)

            return RSNSM.Ready
        elif action == RSNAction.askBusLoc:
            # periodically ask each buses' location
            # TODO: triggered by host timer
            global GROUP_MEMBER, RSN_ID, ROUTE_NO, LOCAL_ADDR, LOC_REQ_NO
            LOGGER.info("asking each bus' location %s" % BUS_TABLE.keys())
            LOC_REQ_NO = LOC_REQ_NO + 1  # maybe overflow!!!

            req_loc_message = {
                "SM": "DRIVER_SM",
                "action": "recvLocReq",
                "requestNo": LOC_REQ_NO,
                "rsnId": RSN_ID,
                "route": ROUTE_NO,
                "rsnIP": LOCAL_ADDR.ip,
                "rsnPort": LOCAL_ADDR.port
            }

            #MessagePasser.multicast(GROUP_MEMBER, req_loc_message)
            # TODO: replace the code below with a multicast version

            for member in BUS_TABLE:
                MessagePasser.directSend(BUS_TABLE[member]["addr"].ip,
                                         BUS_TABLE[member]["addr"].port,
                                         req_loc_message)

            return RSNSM.Ready
        elif action == RSNAction.recvDriverLoc:
            # TODO: update local cache
            global BUS_TABLE, ROUTE_NO

            if input["route"] == ROUTE_NO \
                and input["busId"] in BUS_TABLE \
                and input["requestNo"] > BUS_TABLE[input["busId"]]["last_update"]:

                BUS_TABLE[input["busId"]] = {
                    "direction": input["direction"],
                    "location": input["location"],
                    "addr": Addr(input["busIP"], input["busPort"]),
                    "last_update":
                    input["requestNo"]  # TODO: use local time stamp
                }

            return RSNSM.Ready
        elif action == RSNAction.recvBusChange:
            # TODO: add or remove a bus from current group
            LOGGER.info("Receive bus change request: %s" % input)
            global GROUP_MEMBER, BUS_TABLE, ROUTE_NO, RSN_ID, LOCAL_ADDR, LOC_REQ_NO

            if input["route"] == ROUTE_NO:
                if input["type"] == "add":
                    #if not input["busId"] in BUS_TABLE:
                    #GROUP_MEMBER.append(input["busId"])
                    BUS_TABLE[input["busId"]] = {
                        "direction": input["direction"],
                        "location": input["location"],
                        "addr": Addr(input["busIP"], input["busPort"]),
                        "last_update": LOC_REQ_NO  # TODO: use local time stamp
                    }
                    # send an ACK to driver
                    rsn_ack = {
                        "SM": "DRIVER_SM",
                        "action": "recvRSNAck",
                        "route": ROUTE_NO,
                        "rsnId": RSN_ID,
                        "rsnIP": LOCAL_ADDR.ip,
                        "rsnPort": LOCAL_ADDR.port
                    }
                    MessagePasser.directSend(input["busIP"], input["busPort"],
                                             rsn_ack)
                elif input["type"] == "remove":
                    if input["busId"] in BUS_TABLE:
                        #GROUP_MEMBER.remove(input["busId"])
                        BUS_TABLE.pop(input["busId"])
            return RSNSM.Ready

        elif action == RSNAction.recvGSNHB:
            LOGGER.info("Receive GSN heart beat: %s" % input["HBNo"])

            global BUS_TABLE, RSN_ID, ROUTE_NO, LOCAL_ADDR, GSN_ADDR, LOC_REQ_NO

            # filter out some dead buses
            remove_list = []
            for bus in BUS_TABLE:
                if int(BUS_TABLE[bus]["last_update"]) + 1 < LOC_REQ_NO:
                    remove_list.append(bus)
            for bus in remove_list:
                BUS_TABLE.pop(bus)

            # send current route table to GSN
            HB_res_message = {
                "SM": "GSN_SM",
                "action": "recvHBRes",
                "HBNo": input["HBNo"],
                "rsnId": RSN_ID,
                "route": ROUTE_NO,
                "rsnIP": LOCAL_ADDR.ip,
                "rsnPort": LOCAL_ADDR.port,
                "busTable": BUS_TABLE
            }
            MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port,
                                     HB_res_message)
            return RSNSM.Ready
        elif action == RSNAction.recvRSNResign:
            LOGGER.info("Receive GSN resign")
            TIMER_OFF.set()
            TIMER_ON.clear()
            return RSNSM.Idle
        elif action == RSNAction.turnOff:
            # TODO: do something to shut-down
            TIMER_OFF.set()
            TIMER_ON.clear()
            return RSNSM.Off
        else:
            # for other illegal action
            # assert 0, "Ready: invalid action: %s" % str(input)
            pass
    def next(self, input):
        action = map(RSNAction.RSNAction, [input["action"]])[0]
        if action == RSNAction.recvRSNAssign:
            # TODO: received the group info from GSN
            # TODO: store the group info

            global LOCAL_ADDR, ROUTE_NO, BUS_TABLE, TIMER_ON, TIMER_OFF
            ROUTE_NO = input["route"]

            # if the RSN is the Driver itself, send a recvRSNAck to driver role
            if input["type"] == "self":
                BUS_TABLE[input["original"]["busId"]] = {
                    "direction":
                    input["original"]["direction"],
                    "location":
                    input["original"]["location"],
                    "addr":
                    Addr(input["original"]["busIP"],
                         input["original"]["busPort"]),
                    "last_update":
                    0  # TODO: use local time stamp
                }

                rsn_ack = {
                    "SM": "DRIVER_SM",
                    "action": "recvRSNAck",
                    "route": ROUTE_NO,
                    "rsnId": RSN_ID,
                    "rsnIP": LOCAL_ADDR.ip,
                    "rsnPort": LOCAL_ADDR.port
                }
                MessagePasser.directSend(input["original"]["busIP"],
                                         input["original"]["busPort"], rsn_ack)
            elif input["type"] == "normal":
                BUS_TABLE = input["busTable"]

                if BUS_TABLE == None:
                    BUS_TABLE = {}
                # reset all time stampes
                for bus in BUS_TABLE:
                    BUS_TABLE[bus]["last_update"] = 0

                # notify each bus
                global GROUP_MEMBER, RSN_ID, ROUTE_NO, LOCAL_ADDR, LOC_REQ_NO
                LOGGER.info("asking each bus' location %s" % BUS_TABLE.keys())
                LOC_REQ_NO = 0
                LOC_REQ_NO = LOC_REQ_NO + 1  # maybe overflow!!!

                req_loc_message = {
                    "SM": "DRIVER_SM",
                    "action": "recvLocReq",
                    "requestNo": LOC_REQ_NO,
                    "rsnId": RSN_ID,
                    "route": ROUTE_NO,
                    "rsnIP": LOCAL_ADDR.ip,
                    "rsnPort": LOCAL_ADDR.port
                }
                for member in BUS_TABLE:
                    MessagePasser.directSend(BUS_TABLE[member]["addr"].ip,
                                             BUS_TABLE[member]["addr"].port,
                                             req_loc_message)

            # unblock the timer thread
            TIMER_OFF.clear()
            TIMER_ON.set()

            return RSNSM.Ready
        elif action == RSNAction.timeout:
            # TODO: re-ping
            # Terry: seems no need to re-ping gsn
            return RSNSM.Idle
        elif action == RSNAction.turnOff:
            global TIMER_ON, TIMER_OFF
            # TODO: do something to shut-down
            TIMER_OFF.set()
            TIMER_ON.clear()
            return RSNSM.Off
        else:
            # for other illegal action
            # assert 0, "Idle: invalid action: %s" % str(input)
            pass