Beispiel #1
0
// NewOrder locally or remotely
func NewOrder(floor driver.Floor, dir driver.Direction) {
	if dir == driver.DirectionNone { // From inside the elevator
		shouldStop[dir][floor] = true
		driver.ButtonLightOn(floor, dir)
		AddToLog(int(floor)) //Log internal order to file
	} else { // From external panel on this or some other elevator

		if floor == 0 {
			dir = driver.DirectionDown
		} else if floor == driver.NumFloors-1 {
			dir = driver.DirectionUp
		}

		o := order{
			floor: floor,
			dir:   dir,
			timer: time.AfterFunc(calculateTimeout(floor, dir), func() {
				shouldStop[dir][floor] = true
				if currentDir == driver.DirectionNone {
					// Ping
					timeoutCh <- true
				}
				// Send network message that we have accepted
				net.SendOrder(net.OrderMessage{Type: net.AcceptedOrder, Floor: floor, Direction: dir})
				log.Info("Accepted order for floor ", floor)
			}),
		}

		pendingOrders.PushBack(&o)
	}
	driver.ButtonLightOn(floor, dir)
}
Beispiel #2
0
// ReadLog reads the log and returns an int slice of floors
func ReadLog() []int {
	file, err := os.Open(filename)
	if err != nil {
		log.Info(err)
		ioutil.WriteFile(filename, []byte(""), 0666)
		file, _ = os.Open(filename)
	}

	defer file.Close()

	reader := bufio.NewReader(file)

	var nSlice []int

	for {
		s, err := reader.ReadString('\n')
		n, sErr := strconv.ParseInt(strings.Replace(strings.Replace(s, "\r", "", -1), "\n", "", -1), 10, 32) // removes \r\n and parses string
		if err != nil {
			break
		}
		log.Check(err)
		log.Check(sErr)
		nSlice = append(nSlice, int(n))
	}

	return nSlice
}
Beispiel #3
0
// FloorListener sends event on floor update
func FloorListener(ch chan<- Floor) {
	currentFloor := getFloor()
	for {
		newFloor := getFloor()
		if newFloor > -1 {
			if newFloor != currentFloor {
				currentFloor = newFloor
				setFloorIndicator(newFloor)
				log.Info("Now at floor ", newFloor)
				ch <- newFloor
			}
		}
	}
}
Beispiel #4
0
// InitAndHandle initializes network and handles receive
func InitAndHandle(receiveCh chan<- OrderMessage, id uint) {
	udpSendCh = make(chan udp.Udp_message, 8)
	udpRecvCh = make(chan udp.Udp_message, 8)

	elevatorID = id

	udp.Udp_init(LPORT, BPORT, MSGLEN, udpSendCh, udpRecvCh)

	for {
		msg := <-udpRecvCh
		if msg.Length != 8 { // Disregard messages not 8 in length
			log.Warning("Non-8-byte message received")
			continue
		}
		order := strToOrder(msg.Data)
		if order.SenderID != elevatorID { // Don't loop
			log.Info("Received order: ID: ", order.SenderID, ", type: ", order.Type, ", floor: ", order.Floor)
			receiveCh <- order
		}
	}
}
Beispiel #5
0
// Reset makes sure the elevator is at a safe floor on startup
// Blocking, should never be called when listeners are running
func Reset() Floor {
	log.Debug("Resetting floor")
	currentFloor := getFloor()

	if currentFloor == -1 {
		log.Warning("Unknown floor")
		// Move down until we hit something
		RunDown()
		for {
			currentFloor = getFloor()
			if currentFloor != -1 {
				break
			}
		}
		log.Info("At floor ", currentFloor, ", ready for service")
		setFloorIndicator(currentFloor)
		Stop()
		OpenDoor()
		time.Sleep(time.Second)
		CloseDoor()
	}
	return currentFloor
}
Beispiel #6
0
func main() {
	id := flag.Uint("id", 1337, "Elevator ID")
	flag.Parse()

	if *id > 9 {
		log.Error("Elevator ID must be between 0 and 9")
		os.Exit(1)
	}

	log.Info("Id: ", *id)
	queue.SetID(*id)

	currentDirection := driver.DirectionDown
	lastFloor := driver.Floor(0)

	doorOpen := false

	// Init driver and make sure elevator is at a floor
	driver.Init()

	queue.ImportInternalLog()

	lastFloor = driver.Reset()
	queue.Update(lastFloor)
	queue.ClearOrderLocal(lastFloor, currentDirection)

	floorCh := make(chan driver.Floor)
	go driver.FloorListener(floorCh)

	floorBtnCh := make(chan driver.ButtonEvent, 8)
	go driver.FloorButtonListener(floorBtnCh)

	orderReceiveCh := make(chan net.OrderMessage, 8)
	go net.InitAndHandle(orderReceiveCh, *id)

	timeoutCh := make(chan bool, 8)
	queue.SetTimeoutCh(timeoutCh)

	// Oh, God almighty, please spare our ears
	sigtermCh := make(chan os.Signal)
	signal.Notify(sigtermCh, os.Interrupt, syscall.SIGTERM)
	go func(ch <-chan os.Signal) {
		<-ch
		driver.Stop()
		os.Exit(0)
	}(sigtermCh)

	// Ping timeout so we start in case we have logged orders from a previous crash
	timeoutCh <- true

	// Main event loop
	for {
		select {
		// Elevator has arrived at a new floor
		case fl := <-floorCh:
			queue.Update(fl)
			if queue.ShouldStop(fl) {
				driver.Stop()
				queue.ClearOrderLocal(fl, currentDirection)
				log.Debug("Stopped at floor ", fl)
				net.SendOrder(net.OrderMessage{Type: net.CompletedOrder, Floor: fl, Direction: currentDirection})

				go func() {
					doorOpen = true
					driver.OpenDoor()
					time.Sleep(1 * time.Second)
					doorOpen = false
					driver.CloseDoor()
					timeoutCh <- true
				}()
			}

		// A floor button was pressed
		case btn := <-floorBtnCh:
			queue.NewOrder(btn.Floor, btn.Dir)
			if btn.Dir != driver.DirectionNone {
				net.SendOrder(net.OrderMessage{Type: net.NewOrder, Floor: btn.Floor, Direction: btn.Dir})
			}
			if !doorOpen {
				currentDirection = queue.NextDirection()
				driver.Run(currentDirection)
			}

		// A message came in from the network
		case o := <-orderReceiveCh:
			switch o.Type {
			case net.NewOrder:
				log.Debug("New order, floor: ", o.Floor, ", dir: ", o.Direction)
				queue.NewOrder(o.Floor, o.Direction)

			case net.AcceptedOrder:
				log.Debug("Remote accepted order, floor: ", o.Floor, ", dir: ", o.Direction)
				queue.OrderAcceptedRemotely(o.Floor, o.Direction)

			case net.CompletedOrder:
				log.Debug("Remote completed order, floor: ", o.Floor, ", dir: ", o.Direction)
				queue.ClearOrder(o.Floor, o.Direction)
			}

		// Something timed out. Wake if idle.
		case <-timeoutCh:
			currentDirection = queue.NextDirection()
			if !doorOpen {
				driver.Run(currentDirection)
			}
		}
	}
}