Exemple #1
0
//ImportInternalLog imports any locally saved internal orders to the active queue. Called at init.
func ImportInternalLog() {
	intSlice := ReadLog()

	for i := 0; i < len(intSlice); i++ {
		shouldStop[driver.DirectionNone][intSlice[i]] = true
		driver.ButtonLightOn(driver.Floor(intSlice[i]), driver.DirectionNone)
	}
}
Exemple #2
0
func strToOrder(str string) OrderMessage {
	// Check for CRC mismatch. Not tamper-proof, but should be corruption-proof.
	calculatedCrc := crc16.Crc16([]byte(str[:6]))
	receivedCrc := (uint16(str[6]) << 8) + uint16(str[7])

	if calculatedCrc != receivedCrc {
		log.Error("CRC mismatch in " + str[:4] + " message!")
		return OrderMessage{Type: InvalidOrder} // Probably corrupted
	}

	senderID, _ := strconv.Atoi(string(str[3]))
	floorNum, _ := strconv.Atoi(string(str[4]))
	dirNum, _ := strconv.Atoi(string(str[5]))

	return OrderMessage{Type: OrderType(str[:2]), SenderID: uint(senderID), Floor: driver.Floor(floorNum), Direction: driver.Direction(dirNum)}

}
Exemple #3
0
// NextDirection gives and sets next direction
func NextDirection() driver.Direction {
	// BOOOOOOILERPLATE
	if currentDir == driver.DirectionUp {
		for i := currentFloor + 1; i < driver.NumFloors; i++ {
			if shouldStop[driver.DirectionUp][i] || shouldStop[driver.DirectionNone][i] {
				currentDir = gotoDir(driver.Floor(i))
				return currentDir
			}
		}
		// then the other way
		for i := driver.NumFloors - 1; i >= 0; i-- {
			if shouldStop[driver.DirectionDown][i] || shouldStop[driver.DirectionNone][i] {
				currentDir = gotoDir(driver.Floor(i))
				return currentDir
			}
		}
		for i := 0; i < int(currentFloor); i++ {
			if shouldStop[driver.DirectionUp][i] || shouldStop[driver.DirectionNone][i] {
				currentDir = gotoDir(driver.Floor(i))
				return currentDir
			}
		}
	} else {
		for i := currentFloor - 1; i >= 0; i-- {
			if shouldStop[driver.DirectionDown][i] || shouldStop[driver.DirectionNone][i] {
				currentDir = gotoDir(driver.Floor(i))
				return currentDir
			}
		}
		// then the other way
		for i := 0; i < driver.NumFloors; i++ {
			if shouldStop[driver.DirectionUp][i] || shouldStop[driver.DirectionNone][i] {
				currentDir = gotoDir(driver.Floor(i))
				return currentDir
			}
		}
		for i := driver.NumFloors - 1; i > int(currentFloor); i-- {
			if shouldStop[driver.DirectionDown][i] || shouldStop[driver.DirectionNone][i] {
				currentDir = gotoDir(driver.Floor(i))
				return currentDir
			}
		}
	}
	currentDir = driver.DirectionNone
	return currentDir
}
Exemple #4
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)
			}
		}
	}
}