func (m *ManualDriver) Move(deckposition []string, wellcoords []string, reference []int, offsetX, offsetY, offsetZ []float64, plate_type []string, head int) driver.CommandStatus { params := make(map[string]string) params["deckposition"] = fmt.Sprintf("%v", deckposition[0]) params["wellcoords"] = fmt.Sprintf("%v", wellcoords[0]) params["reference"] = fmt.Sprintf("%v", reference) params["offsetX"] = fmt.Sprintf("%v", offsetX) params["offsetY"] = fmt.Sprintf("%v", offsetY) params["offsetZ"] = fmt.Sprintf("%v", offsetZ) params["plate_type"] = fmt.Sprintf("%v", plate_type) params["head"] = fmt.Sprintf("%v", head) desc := fmt.Sprintf("Deck Postition %v @well %v with reference %v", deckposition, wellcoords, reference) ad := *equipment.NewActionDescription(action.LH_MOVE, desc, params) m.sendActionToEquipment(ad) // go m.eq.Do(ad) // err := m.eq.Do(ad) // if err != nil { // return driver.CommandStatus{ // OK: false, // Errorcode: 1, // Msg: err.Error(), // } // } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *Manual) Message(message string) driver.CommandStatus { var act action.Action act = action.MESSAGE ret := new(driver.CommandStatus) var eq *equipment.Equipment params := make(map[string]string, 0) // fmt.Println(m.Manager) acd := equipment.NewActionDescription(act, message, params) // fmt.Println(*acd) eq = m.Manager.GetActionCandidate(*acd) if eq == nil { ret.Errorcode = driver.ERR ret.Msg = fmt.Sprintf("Could not find suitable equipment for action %v : %v.", act, message) ret.OK = false return *ret } var actionEq equipment.Equipment actionEq = *eq err := actionEq.Do(*acd) if err != nil { ret.Errorcode = driver.ERR ret.Msg = err.Error() ret.OK = false return *ret } ret.Errorcode = driver.OK ret.OK = true return *ret }
func (m *ManualDriver) Aspirate(volume []float64, overstroke []bool, head int, multi int, platetype []string, what []string, llf []bool) driver.CommandStatus { params := make(map[string]string) params["volume"] = fmt.Sprintf("%g", volume[0]) params["overstroke"] = fmt.Sprintf("%v", overstroke[0]) params["head"] = fmt.Sprintf("%v", head) params["multi"] = fmt.Sprintf("%v", multi) params["platetype"] = fmt.Sprintf("%v", platetype[0]) params["what"] = fmt.Sprintf("%v", what[0]) // params["llf"] = fmt.Sprintf("%v", llf[0]) desc := fmt.Sprintf("Aspirate volumes %v", volume) //TOOD make a meaning of the values ad := *equipment.NewActionDescription(action.LH_ASPIRATE, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) Dispense(volume []float64, blowout []bool, head int, multi int, platetype []string, what []string, llf []bool) driver.CommandStatus { params := make(map[string]string) params["volume"] = fmt.Sprintf("%g", volume[0]) params["blowout"] = fmt.Sprintf("%t", blowout[0]) params["head"] = fmt.Sprintf("%v", head) params["multi"] = fmt.Sprintf("%v", multi) params["platetype"] = fmt.Sprintf("%v", platetype[0]) params["what"] = fmt.Sprintf("%s", what[0]) params["llf"] = fmt.Sprintf("%t", llf) desc := fmt.Sprintf("Dispense volumes %v", volume) ad := *equipment.NewActionDescription(action.LH_DISPENSE, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
//NewManualDriver returns a new instance of a manual driver pointing to the right piece of equipment func NewManualDriver() *ManualDriver { ret := new(ManualDriver) eqm := *equipmentManager.GetEquipmentManager() params := make(map[string]string, 0) ret.eq = *eqm.GetActionCandidate(*equipment.NewActionDescription(action.LH_MIX, "", params)) //TODO make this into something more meaningful return ret }
//NewManualDriver returns a new instance of a manual driver pointing to the right piece of equipment func NewManualDriver() *ManualDriver { ret := new(ManualDriver) ret.ag = *NewAggregator() ret.plateLookup = *NewTranslateDictionary("Plate") ret.tipboxlookup = *NewTranslateDictionary("Tipbox") ret.tipwastelookup = *NewTranslateDictionary("Tipwaste") eqm := *equipmentManager.GetEquipmentManager() params := make(map[string]string, 0) ret.eq = *eqm.GetActionCandidate(*equipment.NewActionDescription(action.LH_MIX, "", params)) return ret }
func (m *ManualDriver) RemovePlateAt(position string) driver.CommandStatus { desc := fmt.Sprintf("Remove Plate at position %s", position) //TODO params := make(map[string]string) ad := *equipment.NewActionDescription(action.LH_REMOVE_PLATE, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) RemoveAllPlates() driver.CommandStatus { desc := fmt.Sprintf("Remove all Plates from the liquid handler") //TODO params := make(map[string]string) ad := *equipment.NewActionDescription(action.LH_REMOVE_ALL_PLATES, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) Mix(head int, volume []float64, fvolume []float64, platetype []string, cycles []int, multi int, prms map[string]interface{}) driver.CommandStatus { params := make(map[string]string) desc := fmt.Sprintf("Mix with head num %d", head) ad := *equipment.NewActionDescription(action.LH_MIX, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) SetPositionState(position string, state driver.PositionState) driver.CommandStatus { desc := fmt.Sprintf("Set position %s to state %v", position, state) params := make(map[string]string) ad := *equipment.NewActionDescription(action.LH_SET_POSITION_STATE, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) SetPipetteSpeed(head, channel int, rate float64) driver.CommandStatus { desc := fmt.Sprintf("Set pippete speed to %v for head num %d, channel num %d", rate, head, channel) params := make(map[string]string) ad := *equipment.NewActionDescription(action.LH_SET_PIPPETE_SPEED, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) UnloadTips(channels []int, head, multi int, platetype, position, well []string) driver.CommandStatus { params := make(map[string]string) desc := fmt.Sprintf("Unload tips for channels %v", channels) ad := *equipment.NewActionDescription(action.LH_UNLOAD_TIPS, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) MoveRaw(head int, x, y, z float64) driver.CommandStatus { desc := fmt.Sprintf("Move to coordinates %v, %v, %v", x, y, z) params := make(map[string]string) ad := *equipment.NewActionDescription(action.LH_MOVE_RAW, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) MoveExplicit(deckposition []string, wellcoords []string, reference []int, offsetX, offsetY, offsetZ []float64, plate_type []*wtype.LHPlate, head int) driver.CommandStatus { params := make(map[string]string) desc := fmt.Sprintf("Deck Postition %v @well %v with reference %v", deckposition, wellcoords, reference) ad := *equipment.NewActionDescription(action.LH_MOVE_EXPLICIT, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) SetDriveSpeed(drive string, rate float64) driver.CommandStatus { desc := fmt.Sprintf("Set drive %s to speed %v", drive, rate) params := make(map[string]string) ad := *equipment.NewActionDescription(action.LH_SET_DRIVE_SPEED, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) AddPlateTo(position string, plate interface{}, name string) driver.CommandStatus { //plate can be lhplate, lhtipbox or lhtipwaste params := make(map[string]string) var desc string var ad equipment.ActionDescription switch w := plate.(type) { case *wtype.LHPlate: desc = fmt.Sprintf("Get a %s of type %s and label it as %s. We will refer to it by that name", "Plate", w.Type, m.lookupPlateName(w.GetName())) case wtype.LHPlate: desc = fmt.Sprintf("Get a %s of type %s and label it as %s. We will refer to it by that name", "Plate", w.Type, m.lookupPlateName(w.GetName())) case *wtype.LHTipbox: desc = fmt.Sprintf("Get a %s of type %s and label it as %s. We will refer to it by that name", "Tipbox", w.Type, m.lookupTipboxName(w.GetName())) case wtype.LHTipbox: desc = fmt.Sprintf("Get a %s of type %s and label it as %s. We will refer to it by that name", "Tipbox", w.Type, m.lookupTipboxName(w.GetName())) case *wtype.LHTipwaste: desc = fmt.Sprintf("Get a %s of type %s and label it as %s. We will refer to it by that name", "Tipwaste", w.Type, m.lookupTipwasteName(w.GetName())) case wtype.LHTipwaste: desc = fmt.Sprintf("Get a %s of type %s and label it as %s. We will refer to it by that name", "Tipwaste", w.Type, m.lookupTipwasteName(w.GetName())) default: //panic(reflect.TypeOf(plate)) panic(errors.New("Unknow plate type")) } ad = *equipment.NewActionDescription(action.LH_ADD_PLATE, desc, params) err := m.sendActionToEquipment(ad) if err != nil { return driver.CommandStatus{ OK: false, Errorcode: 1, Msg: err.Error(), } } return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func (m *ManualDriver) Incubate(what *wtype.LHSolution, temp wunit.Temperature, time wunit.Time, shaking bool) driver.CommandStatus { params := make(map[string]string) params["what"] = fmt.Sprintf("%v", what) params["temp"] = fmt.Sprintf("%v", temp) params["time"] = fmt.Sprintf("%v", time) params["shaking"] = fmt.Sprintf("%v", shaking) var desc string var act action.Action if shaking { desc = fmt.Sprintf("Incubate shaking %s for %s at a temperature of %s.", params["what"], params["time"], params["temp"]) act = action.IN_INCUBATE_SHAKE } else { desc = fmt.Sprintf("Incubate %s for %s at a temperature of %s.", params["what"], params["time"], params["temp"]) act = action.IN_INCUBATE } ad := *equipment.NewActionDescription(act, desc, params) m.sendActionToEquipment(ad) return driver.CommandStatus{ OK: true, Errorcode: 0, Msg: "OK", } }
func TestCapabilities(t *testing.T) { anthaManual := NewAnthaManual("") expectedBehaviours := [...]equipment.ActionDescription{ *equipment.NewActionDescription(action.MESSAGE, "", nil), *equipment.NewActionDescription(action.LH_SETUP, "", nil), *equipment.NewActionDescription(action.LH_MOVE, "", nil), *equipment.NewActionDescription(action.LH_MOVE_EXPLICIT, "", nil), *equipment.NewActionDescription(action.LH_MOVE_RAW, "", nil), *equipment.NewActionDescription(action.LH_ASPIRATE, "", nil), *equipment.NewActionDescription(action.LH_DISPENSE, "", nil), *equipment.NewActionDescription(action.LH_LOAD_TIPS, "", nil), *equipment.NewActionDescription(action.LH_UNLOAD_TIPS, "", nil), *equipment.NewActionDescription(action.LH_SET_PIPPETE_SPEED, "", nil), *equipment.NewActionDescription(action.LH_SET_DRIVE_SPEED, "", nil), *equipment.NewActionDescription(action.LH_STOP, "", nil), *equipment.NewActionDescription(action.LH_SET_POSITION_STATE, "", nil), *equipment.NewActionDescription(action.LH_RESET_PISTONS, "", nil), *equipment.NewActionDescription(action.LH_WAIT, "", nil), *equipment.NewActionDescription(action.LH_MIX, "", nil), *equipment.NewActionDescription(action.IN_INCUBATE, "", nil), *equipment.NewActionDescription(action.IN_INCUBATE_SHAKE, "", nil), *equipment.NewActionDescription(action.MLH_CHANGE_TIPS, "", nil), } for _, b := range expectedBehaviours { if anthaManual.Can(b) == false { t.Fatal("anthaManual expected behaviour %s not fulfilled", b) } } }
//aggregate tries to merge and return actions. func (a *Aggregator) aggregate() (ret []equipment.ActionDescription) { out := "initial values " for k, v := range a.Calls { out = out + fmt.Sprintf("%d - %s, ", k, v.Action) } if len(a.Calls) > 3 { panic(errors.New("Unexpected Behaviour")) } if len(a.Calls) == 0 { return nil } else if len(a.Calls) == 1 { if !actionIsMove(a.Calls[0].Action) && a.Calls[0].Action != action.LH_DISPENSE && !actionIsSetup(a.Calls[0].Action) && !actionIsHandleTips(a.Calls[0].Action) { //return the action immediately ret = append(ret, a.Calls[0]) a.Calls = make([]equipment.ActionDescription, 0) return } } else if len(a.Calls) == 2 { //more than 1 action, we check for aggregates, we should not have more than 2 actually first := a.Calls[0] second := a.Calls[1] //cases are // move + move = move (preserve last) // move + asp = asp with pos // move + disp = disp with pos // move = disp(blowout) = nothing // disp + move = disp + move // disp + anything = disp out + check anything // move + other = return other, clean queue if actionIsMove(first.Action) && actionIsMove(second.Action) { a.Calls = a.Calls[1:] return nil // to be aggregated } else if actionIsMove(first.Action) && second.Action == action.LH_ASPIRATE { data := fmt.Sprintf("Aspirate from %s well %s, %sul. of %s.", first.Params["deckposition"], first.Params["wellcoords"], second.Params["volume"], second.Params["what"]) newAc := equipment.ActionDescription{ Action: action.LH_ASPIRATE, ActionData: data, Params: second.Params, } a.Calls = make([]equipment.ActionDescription, 0) //clean the queue ret = append(ret, newAc) return } else if actionIsMove(first.Action) && second.Action == action.LH_DISPENSE && second.Params["blowout"] == "true" { a.Calls = make([]equipment.ActionDescription, 0) //clean the queue return nil //command mean nothing for a human } else if actionIsMove(first.Action) && second.Action == action.LH_DISPENSE && second.Params["blowout"] != "true" { data := fmt.Sprintf("Dispense in %s well %s, %sul. of %s.", first.Params["deckposition"], first.Params["wellcoords"], second.Params["volume"], second.Params["what"]) newAc := equipment.ActionDescription{ Action: action.LH_DISPENSE, ActionData: data, Params: first.Params, } a.Calls = make([]equipment.ActionDescription, 0) //clean the queue a.Calls = append(a.Calls, newAc) return nil // we can have moves after the dispense } else if first.Action == action.LH_DISPENSE && actionIsMove(second.Action) { if second.Params["reference"] == "0" { data := fmt.Sprintf("%s. Touch off after dispense", first.ActionData) newAc := equipment.ActionDescription{ Action: action.LH_DISPENSE, ActionData: data, Params: first.Params, } a.Calls = make([]equipment.ActionDescription, 0) //clean the queue ret = append(ret, newAc) return } } else if first.Action == action.LH_DISPENSE { //obviously second action is not a move ret = append(ret, first) a.Calls = a.Calls[1:] ret = append(ret, a.aggregate()...) return } else if actionIsMove(first.Action) { //Move + unknown, ignore move a.Calls = a.Calls[1:] return a.aggregate() } else if actionIsSetup(first.Action) && (actionIsSetup(second.Action) || actionIsHandleTips(second.Action)) { newDesc := fmt.Sprintf("%s\n%s", first.ActionData, second.ActionData) newAc := equipment.NewActionDescription(action.LH_SETUP, newDesc, first.Params) a.Calls = make([]equipment.ActionDescription, 0) a.Calls = append(a.Calls, *newAc) return } else if actionIsSetup(first.Action) && actionIsMove(second.Action) { return } else if actionIsSetup(first.Action) && !actionIsSetup(second.Action) { //second is not handle tips ret = append(ret, first) a.Calls = a.Calls[1:] return } else if actionIsHandleTips(first.Action) && actionIsHandleTips(second.Action) { //unload and then load newDesc := fmt.Sprintf("Change tips with new tip of type %s", second.Params["platetype"]) newAc := equipment.NewActionDescription(action.MLH_CHANGE_TIPS, newDesc, first.Params) a.Calls = make([]equipment.ActionDescription, 0) ret = append(ret, *newAc) return } else if actionIsHandleTips(first.Action) && actionIsMove(second.Action) { return } else if actionIsHandleTips(first.Action) && !actionIsHandleTips(second.Action) { ret = append(ret, first) a.Calls = a.Calls[1:] ret = append(ret, a.aggregate()...) return } } else { //cases to get here are // disp + move + move = disp + move (merge the two moves and ignore the disp until a ref 0 is found // disp + move + otherthing = output disp, deal with the others // setup + move + tips = setup + tips // tips + move + tips = tips + tips // setup + move + otherthing = output tips + recursive first := a.Calls[0] second := a.Calls[1] third := a.Calls[2] if first.Action == action.LH_DISPENSE && !actionIsMove(third.Action) { //spit the dispense and merge the other two ret = append(ret, first) a.Calls = a.Calls[1:] ret = append(ret, a.aggregate()...) return } else if first.Action == action.LH_DISPENSE && actionIsMove(second.Action) && actionIsMove(third.Action) { //disp + two moves if third.Params["reference"] == "0" { //take away the man in the middle // we are basically ignoring the first move, and calling recursively a.Calls = append(a.Calls[0:1], third) ret = a.aggregate() return } else { //normal two move merge, ignore the second a.Calls = append(a.Calls[0:1], third) return } } else if actionIsSetup(first.Action) && actionIsMove(second.Action) && actionIsHandleTips(third.Action) { a.Calls = append(a.Calls[0:1], a.Calls[2]) return a.aggregate() } else if actionIsSetup(first.Action) && actionIsMove(second.Action) { //third is anything ret = append(ret, first) a.Calls = a.Calls[1:] ret = append(ret, a.aggregate()...) return } else if actionIsHandleTips(first.Action) && actionIsMove(second.Action) && actionIsHandleTips(third.Action) { a.Calls = append(a.Calls[0:1], a.Calls[2]) return a.aggregate() } actionStack := fmt.Sprintf("first %s, second %s, third %s", first.Action, second.Action, third.Action) panic(errors.New("Unhandled situation" + actionStack)) } return }