Beispiel #1
0
// StopButtonListener should be spawned as a goroutine, and will trigger on press
func StopButtonListener(ch chan<- bool) {
	var stopButtonState bool

	for {
		mutex.Lock()
		newState := C.elev_get_stop_signal() != 0
		mutex.Unlock()
		if newState != stopButtonState {
			stopButtonState = newState

			if newState {
				log.Debug("Stop button pressed")
			} else {
				log.Debug("Stop button released")
			}
			ch <- newState
		}
	}
}
Beispiel #2
0
// SendOrder sends the parameter order struct to the network
func SendOrder(order OrderMessage) {
	if order.Direction == driver.DirectionNone {
		log.Warning("Transmitted order cannot have no direction")
		return
	}
	order.SenderID = elevatorID
	str := orderToStr(order)
	log.Debug("Sending message: ", str)
	udpSendCh <- udp.Udp_message{Raddr: "broadcast", Data: str}
}
Beispiel #3
0
//AddToLog adds a floor from the log file, if the floor is not already in the queue. If added, the file size increases by one character.
func AddToLog(floor int) {
	if isInLog(floor) {
		return
	}

	intSlice := append(ReadLog(), floor)

	writeLog(intSlice)

	log.Debug("Logged floor: ", floor)
}
Beispiel #4
0
//RemoveFromLog removes a floor from the log file, shortening the file by one character. If the floor is not present in the log, nothing happens.
func RemoveFromLog(floor int) {
	oldSlice := ReadLog()
	var newSlice []int

	for i := 0; i < len(oldSlice); i++ {
		if oldSlice[i] != floor {
			newSlice = append(newSlice, oldSlice[i])
		}
	}
	writeLog(newSlice)

	log.Debug("Removed from log: ", floor)
}
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
// FloorButtonListener should be spawned as a goroutine
func FloorButtonListener(ch chan<- ButtonEvent) {
	var floorButtonState [3][NumFloors]bool

	for {
		for direction := DirectionUp; direction <= DirectionNone; direction++ {
			for floor := Floor(0); floor < NumFloors; floor++ {
				mutex.Lock()
				newState := C.elev_get_button_signal(C.elev_button_type_t(direction), C.int(floor)) != 0
				mutex.Unlock()
				if newState != floorButtonState[direction][floor] {
					floorButtonState[direction][floor] = newState

					// Only dispatch an event if it's pressed
					if newState {
						log.Debug("Button type ", direction, " floor ", floor, " pressed")
						ch <- ButtonEvent{Dir: direction, Floor: floor}
					} else {
						log.Bullshit("Button type ", direction, " floor ", floor, " released")
					}
				}
			}
		}
	}
}
Beispiel #7
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)
			}
		}
	}
}
Beispiel #8
0
// Init initializes the elevator, resets all lamps.
func Init() {
	log.Debug("Initializing driver")
	C.elev_init()
}