SmartVehicle-Sortic
SmartFactory
VehicleCtrl.cpp
Go to the documentation of this file.
1 
13 #include "VehicleCtrl.h"
14 //=====PUBLIC====================================================================================
15 VehicleCtrl::VehicleCtrl() : currentState(State::waitForBox), doActionFPtr(&VehicleCtrl::doAction_waitForBox) {
16  DBFUNCCALLln("VehicleCtrl::VehicleCtrl()");
17  delay(100);
18  clearGui();
19  pComm.unsubscribe("#");
20  pComm.subscribe("Vehicle/" + String(vehicle.id) + "/error");
21  pComm.subscribe("Vehicle/error");
22  pComm.subscribe("error");
24  delay(100);
27  pRandomDelayFactor = random(3); // to prevent loops in acquireing Gateway or Handoverpoint
29 }
30 
32  DBFUNCCALLln("VehicleCtrl::loop()");
33  process((this->*doActionFPtr)()); //do actions
34 }
35 
36 void VehicleCtrl::loop(Event currentEvent) {
37  DBFUNCCALLln("VehicleCtrl::loop(Event)");
39  process((this->*doActionFPtr)()); //do actions
40 }
41 
42 //=====PRIVATE====================================================================================
44  DBFUNCCALL("VehicleCtrl::process ")
45  DBEVENTln(String("VehicleCtrl ") + decodeEvent(e));
46  switch (currentState) {
47  case State::waitForBox:
48  if (Event::AnswerReceived == e) {
49  exitAction_waitForBox(); // Exit-action current state
50  entryAction_handshake(); // Entry-actions next state
51  } else if (Event::Error == e) {
52  exitAction_waitForBox(); // Exit-action current state
53  entryAction_errorState(); // Entry-actions next state
54  }
55  break;
56  case State::handshake:
57  if (Event::HSsucessful == e) {
58  exitAction_handshake(); // Exit-action current state
59  entryAction_loadVehicle(); // Entry-actions next state
60  } else if (Event::NoAnswerReceived == e) {
61  exitAction_handshake(); // Exit-action current state
62  entryAction_waitForBox(); // Entry-actions next state
63  } else if (Event::Error == e) {
64  exitAction_handshake(); // Exit-action current state
65  entryAction_errorState(); // Entry-actions next state
66  }
67  break;
68  case State::loadVehicle:
69  if (Event::PosReached == e) {
70  exitAction_loadVehicle(); // Exit-action current state
71  entryAction_unloadVehicle(); // Entry-actions next state
72  } else if (Event::Error == e) {
73  exitAction_loadVehicle(); // Exit-action current state
74  entryAction_errorState(); // Entry-actions next state
75  }
76  break;
78  if (Event::PosReached == e) {
79  exitAction_unloadVehicle(); // Exit-action current state
80  entryAction_waitForBox(); // Entry-actions next state
81  } else if (Event::Error == e) {
82  exitAction_unloadVehicle(); // Exit-action current state
83  entryAction_errorState(); // Entry-actions next state
84  }
85  break;
86  case State::errorState:
87  if (Event::Resume == e) {
88  exitAction_errorState(); // Exit-action current state
89  pHoistCtrl.loop(HoistCtrl::Event::Resume); // Resume State for HoistCtrl
90  pNavCtrl.loop(NavigationCtrl::Event::Resume); // Resume State for NavigationCtrl
91  switch (lastStateBevorError) {
92  case State::waitForBox:
93  entryAction_waitForBox(); // Entry-actions next state
94  break;
95  case State::handshake:
96  entryAction_handshake(); // Entry-actions next state
97  break;
98  case State::loadVehicle:
99  entryAction_loadVehicle(); // Entry-actions next state
100  break;
102  entryAction_unloadVehicle(); // Entry-actions next state
103  break;
104  default:
105  break;
106  }
107  }
108  if (Event::Reset == e) {
109  exitAction_errorState(); // Exit-action current state
110  pHoistCtrl.loop(HoistCtrl::Event::Reset); // Reset State for HoistCtrl
111  pNavCtrl.loop(NavigationCtrl::Event::Reset); // Reset State for NavigationCtrl
112  entryAction_resetState(); // Entry-actions next state
113  }
114  break;
115  case State::resetState:
116  if (Event::Resume == e) {
117  pHoistCtrl.loop(HoistCtrl::Event::Resume); // Resume State for HoistCtrl
118  pNavCtrl.loop(NavigationCtrl::Event::Resume); // Resume State for NavigationCtrl
119  exitAction_resetState(); // Exit-action current state
120  entryAction_waitForBox(); // Entry-actions next state
121  }
122  break;
123  default:
124  break;
125  }
126 }
127 //==waitForBox========================================================
129  DBSTATUSln("Entering State: emptyState");
130  currentState = State::waitForBox; // state transition
132  publishState(currentState); //Update Current State and Publish
133  publishPosition(); //Update Current Position and Publish for GUI
134  pComm.clear(); //clear all old message
135 
136  //Clear Gui-Stuff
137  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/handshake", "{\"ack\":\"\",\"req\":\"\"}");
138  pComm.subscribe("Box/+/handshake");
139  previousMillis = millis();
143  pComm.publishMessage("Transfer/Handover", "{\"id\":\"\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.targetSector) + "\",\"line\":" + String(vehicle.targetLine) + "}");
145  pComm.publishMessage("Sortic/Handover", "{\"id\":\"\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.targetSector) + "\",\"line\":" + String(vehicle.targetLine) + "}");
146  }
147 }
148 
150  DBINFO1ln("State: emptyState");
151  //Generate the Event
152  pComm.loop(); //Check for new Messages
153  if (checkForError()) {
154  return Event::Error;
155  }
156 
157  DBINFO2ln("Wait for request");
158  if (!pComm.isEmpty()) {
159  myJSONStr temp = pComm.pop();
160  DBINFO2ln(String("temp.req: ") + String(temp.req) + String("==") + String("vehicle.id: ") + String(vehicle.id));
161  if ((temp.req == vehicle.id)) {
162  vehicle.req = temp.id;
163  return Event::AnswerReceived;
164  }
165  }
166 
167  currentMillis = millis();
168  if ((currentMillis - previousMillisPublish) > TIME_BETWEEN_PUBLISH) { //only publish all xx seconds
169  previousMillisPublish = millis();
170  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/available", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.actualSector) + "\",\"line\":\"" + String(vehicle.actualLine) + "\"}");
171  }
172  return Event::NoEvent;
173 }
174 
176  DBSTATUSln("Leaving State: emptyState");
177  pComm.unsubscribe("Box/+/handshake");
178  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/available", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"\",\"line\":\"\"}"); //clear available in GUI
179 }
180 
181 //==handshake========================================================
183  DBSTATUSln("Entering State: handshake");
184  currentState = State::handshake; // state transition
186  publishState(currentState); //Update Current State and Publish
187  publishPosition(); //Update Current Position and Publish for GUI
188  previousMillis = millis();
191  substate = 0;
192  pComm.subscribe("Box/" + String(vehicle.req) + "/handshake");
193 }
194 
196  DBINFO1ln("State: handshake");
197  pComm.loop(); //Check for new Messages
198  if (checkForError()) {
199  return Event::Error;
200  }
201  currentMillis = millis();
202 
203  switch (substate) {
204  case 0: //Publish request for Box and check for ack
205  //Check for Ack from Box and Timeout
207  DBINFO2ln("Check for ack. fron box");
208  if (!pComm.isEmpty()) {
209  myJSONStr temp = pComm.pop();
210  DBINFO2ln(String("temp.ack: ") + String(temp.ack) + String("==") + String("vehicle.id: ") + String(vehicle.id));
211  if ((temp.ack == vehicle.id) && (temp.id == vehicle.req)) {
212  //if ack received update traget pos
213  vehicle.ack = temp.id;
214  vehicle.targetSector = pNavCtrl.decodeSector(temp.sector);
215  vehicle.targetLine = temp.line;
216  vehicle.cargo = temp.cargo;
217  substate = 10;
218  previousMillis = millis();
219  break;
220  }
221  }
222  } else {
224  }
225 
226  //Publish request for Box
227  if ((currentMillis - previousMillisPublish) > TIME_BETWEEN_PUBLISH) { //only publish all xx seconds
228  previousMillisPublish = millis();
229  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/handshake", "{\"id\":\"" + String(vehicle.id) + "\",\"req\":\"" + String(vehicle.req) + "\"}");
230  }
231  break;
232  case 10: //Publish ack for Box
234  if ((currentMillis - previousMillisPublish) > TIME_BETWEEN_PUBLISH) { //only publish all xx seconds
235  previousMillisPublish = millis();
236  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/handshake", "{\"id\":\"" + String(vehicle.id) + "\",\"ack\":\"" + String(vehicle.ack) + "\"}");
237  }
238  } else {
239  substate = 0;
240  return Event::HSsucessful;
241  }
242  return Event::NoEvent;
243  break;
244  default:
245  break;
246  }
247  return Event::NoEvent;
248 }
249 
251  DBSTATUSln("Leaving State: handshake");
252  pComm.unsubscribe("Box/" + String(vehicle.req) + "/handshake");
253 }
254 
255 //==loadVehicle========================================================
257  DBSTATUSln("Entering State: loadVehicle");
258  currentState = State::loadVehicle; // state transition
260  publishState(currentState); //Update Current State and Publish
261  publishPosition(); //Update Current Position and Publish for GUI
262  pComm.clear(); //clear all old message
263  previousMillis = millis();
266 
267  //clear GUI-Entry TargetPosition
269  pComm.publishMessage("Transfer/Handover", "{\"id\":\"\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.targetSector) + "\",\"line\":" + String(vehicle.targetLine) + "}");
271  pComm.publishMessage("Sortic/Handover", "{\"id\":\"\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.targetSector) + "\",\"line\":" + String(vehicle.targetLine) + "}");
272  }
273 
276 }
277 
279  DBINFO1ln("State: loadVehicle");
280  //Check all saved Messages and save the best Vehicles to an Array
281  //Generate the Event
282  pNavCtrl.loop();
283  pComm.loop(); //Check for new Messages
284  if (checkForError()) {
285  return Event::Error;
286  }
287 
288  currentMillis = millis();
290  //only publish all xx seconds
291  previousMillisPublishPos = millis();
292  publishPosition(); //Update Current Position and Publish for GUI
293  publishTargetPosition(); //Publish TargetPosition so it will stay free
294  }
295 
296  switch (substate) {
297  case 0: //check if already in TargetPosition and subscribe to Gateway if waiting for one
300  substate = 40;
301  }
302 
303  if (pNavCtrl.getcurrentSector() == NavigationCtrl::Sector::SorticWaitForGateway) { //check in which sector and subscribe to actual gateway
304  pComm.subscribe("Sortic/Gateway");
305  substate = 10;
306  previousMillisPublishToken = millis();
308  pComm.subscribe("Transfer/Gateway");
309  substate = 10;
310  previousMillisPublishToken = millis();
311  }
312  break;
313  case 10: //check incomming messages. if gateway is free for some time take token
314  DBINFO2ln("if gateway is free for some time take token");
315  pComm.loop(); //Check for new Messages
316  while (!pComm.isEmpty()) { //check for message
317  myJSONStr temp = pComm.pop();
318  DBINFO2ln(String("vehicle.id: ") + String(vehicle.id) + String(": ") + String("temp.token: ") + String(temp.token));
319  if (temp.token && (temp.topic.endsWith("Gateway"))) {
320  //if token is not availabel reset time
321  previousMillisPublishToken = millis();
322  }
323  }
324  currentMillis = millis();
325  if ((currentMillis - previousMillisPublishToken) > (TIME_BETWEEN_PUBLISH_TOKEN * (6 + pRandomDelayFactor * 2))) { //if no message for some time + some rand time to prevent collision take token
326  previousMillisPublishToken = millis();
327  substate = 11;
328  }
329  break;
330  case 11: //start publish and check if the only one if not go back and listen for free gateway
332  //only publish token all xx seconds
333  previousMillisPublish = millis();
335  pComm.publishMessage("Sortic/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
337  pComm.publishMessage("Transfer/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
338  }
339  }
340 
341  pComm.loop(); //Check for new Messages
342  while (!pComm.isEmpty()) {
343  //check all new messages
344  myJSONStr temp = pComm.pop();
345  DBINFO2ln(String("vehicle.id: ") + String(vehicle.id) + String(": ") + String("temp.token: ") + String(temp.token));
346  if (temp.token && (temp.topic.endsWith("Gateway")) && (vehicle.id != temp.id)) {
347  //if token is not availabel reset time
348  substate = 10;
349  previousMillisPublishToken = millis();
350  }
351  }
352 
353  currentMillis = millis();
355  //if no message for some time publish token
357  pComm.unsubscribe("Sortic/Gateway");
358  pComm.publishMessage("Sortic/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
360  pComm.unsubscribe("Transfer/Gateway");
361  pComm.publishMessage("Transfer/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
362  }
364  substate = 20;
365  }
366 
367  break;
368  case 20: //choose which gateway to block
370  substate = 21;
372  substate = 22;
373  }
374  break;
375  case 21: //block gateway Sortic
377  //publish token to gateway as long as you're blocking it
378  previousMillisPublishToken = millis();
380  pComm.publishMessage("Sortic/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
381  } else { //exit substate
382  pComm.publishMessage("Sortic/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":false}");
383  substate = 30;
384  }
385  }
386  case 22: //block gateway Transfer
388  //publish token to gateway as long as you're blocking it
389  previousMillisPublishToken = millis();
391  pComm.publishMessage("Transfer/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
392  } else { //exit substate
393  pComm.publishMessage("Transfer/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":false}");
394  substate = 30;
395  }
396  }
397  case 30: //check if in position
400  substate = 40;
401  }
402  break;
403  case 40: //raise hoist and leave state
404  if (pHoistCtrl.getcurrentState() != HoistCtrl::State::high) {
405  pHoistCtrl.loop(HoistCtrl::Event::Raise);
406  } else {
407  substate = 0;
408  return Event::PosReached;
409  }
410  break;
411  default:
412  break;
413  }
414 
416  // return
417 }
418 
420  DBSTATUSln("Leaving State: loadVehicle");
421  // pComm.clear();
422 }
423 
424 //==unloadVehicle========================================================
426  DBSTATUSln("Entering State: unloadVehicle");
427  currentState = State::unloadVehicle; // state transition
429  publishState(currentState); //Update Current State and Publish
430  publishPosition(); //Update Current Position and Publish for GUI
431  previousMillis = millis();
434  pComm.clear(); //clear all old message
435 }
436 
438  DBINFO1ln("State: unloadVehicle " + String(substate));
439  currentMillis = millis();
440  pNavCtrl.loop();
441  pComm.loop(); //Check for new Messages
442  if (checkForError()) {
443  return Event::Error;
444  }
445 
446  if ((currentMillis - previousMillisPublishPos) > TIME_BETWEEN_PUBLISH) { //only publish all xx seconds
447  previousMillisPublishPos = millis();
448  publishPosition(); //Update Current Position and Publish for GUI
449  publishTargetPositionBlockLine(); //Publish TargetPosition so it will stay free
450  }
451 
452  switch (substate) {
453  case 0: //check actual sector and subscribe to handover
455  pComm.subscribe("Transfer/Handover");
456  substate = 10;
457  for (int i = 0; i < SORTIC_MAX_LINE; i++) {
458  pTransferPark[i] = 1; //reset
459  }
460  previousMillis = millis();
461  break;
463  pComm.subscribe("Sortic/Handover");
464  substate = 20;
465  for (int i = 0; i < SORTIC_MAX_LINE; i++) {
466  pSorticPark[i] = 0; //reset
467  }
468  previousMillis = millis();
469  break;
470  }
471  break;
472 
473  case 10: // listen for matching cargo in Transfer and a free place
474  DBINFO2ln("Substate 10: listen for matching cargo in Transfer and free place");
475  currentMillis = millis();
476  DBINFO2ln(String(currentMillis - previousMillis) + String(" < ") + String(TIME_BETWEEN_PUBLISH * (10 + pRandomDelayFactor * 2)));
478  //wait some time and add message to array
479  if (!pComm.isEmpty()) {
480  myJSONStr temp = pComm.pop();
481  if ((temp.line < SORTIC_MAX_LINE + 1) && (temp.line > 0)) {
482  if ((temp.id == String("Transfer")) && (temp.cargo == vehicle.cargo)) {
483  //Listen for Place with same Cargo as Vehicle
484  pTransferPark[temp.line - 1] = 0;
485  DBINFO2ln(String("Line with same Cargo: ") + String(temp.line));
486  DBINFO2ln(String("pTransferPark[temp.line - 1]: ") + String(pTransferPark[temp.line - 1]));
487  } else if ((pNavCtrl.decodeSector(temp.sector) == NavigationCtrl::Sector::TransferHandover) && (temp.id != vehicle.id)) {
488  // listen to occupied places
489  pTransferPark[temp.line - 1] = 1;
490  DBINFO2ln(String("Line occupied: ") + String(temp.line));
491  DBINFO2ln(String("pSorticPark[temp.line - 1]: ") + String(pTransferPark[temp.line - 1]));
492  }
493  break;
494  }
495  }
496  } else {
497  //time reached - evaluate array afer timeout
498  DBINFO2ln("time reached");
499  // for (int i = 0; i < SORTIC_MAX_LINE; i++) {
500  // Serial.println(pTransferPark[i]);
501  // }
502 
503  int line = 0;
504  for (int i = 0; i < SORTIC_MAX_LINE; i++) {
505  if (pTransferPark[SORTIC_MAX_LINE - i - 1] == 0) {
506  line = SORTIC_MAX_LINE - i; //update line with empty line
507  pTransferPark[SORTIC_MAX_LINE - i - 1] = 1; //reset arrayvalue at index
508  }
509  }
510  // int line = chooseLine(pSorticPark);
511  DBINFO2("Line: ");
512  DBINFO2ln(line);
513  // delay(10000);
514 
515  if ((line > 0) && (line < SORTIC_MAX_LINE + 1)) {
516  // if line choice is valid update and publish targetsector
517 
519  vehicle.targetLine = line;
521  substate = 11;
522  previousMillis = millis();
523  } else { //start again if no valid line is found
524  previousMillis = millis();
525  }
526  }
527  break;
528  case 11: //ensure valid target position
529  //publish taget and listen if not occupied
530  DBINFO2ln("Substate 11: publish taget and listen if not occupied");
531  pComm.loop(); //Check for new Messages
532  while (!pComm.isEmpty()) { //check for message
533  myJSONStr temp = pComm.pop();
534  if ((pNavCtrl.decodeSector(temp.sector) == vehicle.targetSector) && (temp.line == vehicle.targetLine) && (vehicle.id != temp.id)) {
535  //if place is not availabel reset time and go back to 10 and search new place
536  substate = 10;
537  for (int i = 0; i < SORTIC_MAX_LINE; i++) {
538  pTransferPark[i] = 1; //reset
539  }
540  previousMillis = millis();
541  }
542  }
543 
544  currentMillis = millis();
546  //if no message for some time
547  pComm.unsubscribe("Transfer/Handover");
548  substate = 50;
549  }
550  break;
551  case 20: // listen for empty place in Sortic
552  DBINFO2ln("Substate 20: listen for empty place in Sortic");
553  currentMillis = millis();
554  DBINFO2ln(String(currentMillis - previousMillis) + String(" < ") + String(5 + pRandomDelayFactor * 2));
555  if ((currentMillis - previousMillis) < (TIME_BETWEEN_PUBLISH * (5 + pRandomDelayFactor * 2))) { //wait some time and add message to array and evaluate afer timeout
556  if (!pComm.isEmpty()) {
557  myJSONStr temp = pComm.pop();
558  DBINFO2ln(String("Sector: ") + String(temp.sector) + String(" line: ") + String(temp.line));
559  DBINFO2ln("Sector: " + String(pNavCtrl.decodeSector(temp.sector) == NavigationCtrl::Sector::SorticHandover));
560  DBINFO2ln("Line: " + String("0 < ") + String(temp.line) + String(" < ") + String(SORTIC_MAX_LINE + 1));
561  if ((pNavCtrl.decodeSector(temp.sector) == NavigationCtrl::Sector::SorticHandover) && (temp.line < SORTIC_MAX_LINE + 1) && (temp.line > 0) && (temp.id != vehicle.id)) {
562  pSorticPark[temp.line - 1] = 1;
563  DBINFO2ln(String("Line occupied: ") + String(temp.line));
564  DBINFO2ln(String("pSorticPark[temp.line - 1]: ") + String(pSorticPark[temp.line - 1]));
565  break;
566  }
567  }
568  } else { // time reached
569  // DBINFO2ln("time reached");
570  // for (int i = 0; i < SORTIC_MAX_LINE; i++) {
571  // Serial.println(pSorticPark[i]);
572  // }
573 
574  int line = 0;
575  for (int i = 0; i < SORTIC_MAX_LINE; i++) {
576  if (pSorticPark[SORTIC_MAX_LINE - i - 1] == 0) {
577  line = SORTIC_MAX_LINE - i; //update line with empty line
578  pSorticPark[SORTIC_MAX_LINE - i - 1] = 0; //reset arrayvalue at index
579  }
580  }
581  DBINFO2("Line: ");
582  DBINFO2ln(line);
583 
584  if (line > 0 && line < SORTIC_MAX_LINE + 1) {
586  vehicle.targetLine = line;
588  substate = 21;
589  DBINFO2ln("Change Substate to 21");
590  previousMillis = millis();
591  } else { //start again if noavailable line found
592  previousMillis = millis();
593  }
594  }
595  break;
596  case 21: //ensure valid target position
597  //publish taget and listen if not occupied
598  DBINFO2ln("Substate 21: publish taget and listen if not occupied");
599  pComm.loop(); //Check for new Messages
600  while (!pComm.isEmpty()) { //check for message
601  myJSONStr temp = pComm.pop();
602  if ((pNavCtrl.decodeSector(temp.sector) == vehicle.targetSector) && (temp.line == vehicle.targetLine) && (vehicle.id != temp.id)) {
603  //if place is not availabel reset time and go back to 20 and search new place
604  substate = 20;
605  for (int i = 0; i < SORTIC_MAX_LINE; i++) {
606  pSorticPark[i] = 1; //reset
607  }
608  previousMillis = millis();
609  }
610  }
611 
612  currentMillis = millis();
614  //if no message for some time
615  pComm.unsubscribe("Sortic/Handover");
616  substate = 50;
617  }
618  break;
619  case 50: //update target position
622  substate = 100;
623  break;
624  case 100: //check position
627  substate = 400;
628  }
631  //if waiting for gateway Sortic subscribe to "Sortic/Gateway"
632  pComm.subscribe("Sortic/Gateway");
633  substate = 200;
634  previousMillisPublishToken = millis();
637  // if waiting for gateway Transfer subscribe to "Transfer/Gateway"
638  pComm.subscribe("Transfer/Gateway");
639  substate = 200;
640  previousMillisPublishToken = millis();
641  }
642  break;
643  case 200: // wait for free gateway
644  DBINFO2ln("if gateway is free for some time take token");
645  pComm.loop(); //Check for new Messages
646  while (!pComm.isEmpty()) { //check for message
647  myJSONStr temp = pComm.pop();
648  DBINFO2ln(String("vehicle.id: ") + String(vehicle.id) + String(": ") + String("temp.token: ") + String(temp.token));
649  if (temp.token && (temp.topic.endsWith("Gateway")) && (vehicle.id != temp.id)) { //if token is not availabel reset time
650  previousMillisPublishToken = millis();
651  }
652  }
653 
654  currentMillis = millis();
655  if ((currentMillis - previousMillisPublishToken) > (TIME_BETWEEN_PUBLISH_TOKEN * (6 + pRandomDelayFactor * 2))) { //if no message for some time take token
656  previousMillisPublishToken = millis();
657  substate = 210;
658  }
659  break;
660  case 210: // listen if only one in gateway
662  //only publish all xx seconds
663  previousMillisPublish = millis();
666  pComm.publishMessage("Sortic/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
669  pComm.publishMessage("Transfer/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
670  }
671  }
672 
673  pComm.loop(); //Check for new Messages
674  while (!pComm.isEmpty()) { //check for message in buffer
675  myJSONStr temp = pComm.pop();
676  DBINFO2ln(String("vehicle.id: ") + String(vehicle.id) + String(": ") + String("temp.token: ") + String(temp.token));
677  if (temp.token && (temp.topic.endsWith("Gateway")) && (vehicle.id != temp.id)) {
678  //if token is not availabel reset time
679  substate = 200;
680  previousMillisPublishToken = millis();
681  }
682  }
683 
684  currentMillis = millis();
686  //if no message for some time + some rand time to prevent collision take token
689  pComm.unsubscribe("Sortic/Gateway");
690  pComm.publishMessage("Sortic/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
693  pComm.unsubscribe("Transfer/Gateway");
694  pComm.publishMessage("Transfer/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
695  }
697  substate = 300;
698  }
699  break;
700  case 300: //choose which gateway to block
702  substate = 310;
704  substate = 320;
705  }
706  break;
707  case 310: //block Gateway Sortic
708  DBINFO2ln("Substate 310: Token Sortic");
710  //publish token all xx seconds to gateway as long as you're blocking it
711  previousMillisPublishToken = millis();
713  pComm.publishMessage("Sortic/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
714  } else { //exit substate
715  pComm.publishMessage("Sortic/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":false}"); //update for GUI
716  substate = 400;
717  }
718  }
719  break;
720  case 320: //publish token to gateway as long as you're blocking it
721  DBINFO2ln("Vehicle-Substate 32: Token Transfer");
722  if ((currentMillis - previousMillisPublishToken) > TIME_BETWEEN_PUBLISH_TOKEN) { //only publish all xx seconds
723  previousMillisPublishToken = millis();
725  pComm.publishMessage("Transfer/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":true}");
726  } else { //exit substate
727  pComm.publishMessage("Transfer/Gateway", "{\"id\":\"" + String(vehicle.id) + "\",\"token\":false}"); //update for GUI
728  substate = 400;
729  }
730  }
731  break;
732  case 400: //check if in position waitforHandover or in targetpos
733  DBINFO2ln("Vehicle-Substate 400: Check if in Position");
734  if (pNavCtrl.getcurrentSector() == NavigationCtrl::Sector::TransitWaitForGatewaySortic) { //check in which sector and subscribe to actual gateway
735  pComm.subscribe("Sortic/Gateway");
736  substate = 200;
737  previousMillis = millis();
739  pComm.subscribe("Transfer/Gateway");
740  substate = 200;
741  previousMillis = millis();
742  }
743 
746  substate = 500;
747  }
748  break;
749  case 500: //lower hoist and leave state
750  DBINFO2ln("Substate 50: Lower Hoist");
751  if (pHoistCtrl.getcurrentState() != HoistCtrl::State::low) {
752  pHoistCtrl.loop(HoistCtrl::Event::Lower);
753  } else {
754  substate = 600;
755  previousMillis = millis();
756  }
757  break;
758  case 600: //publish position to box
759  DBINFO2ln("Vehicle-Substate 60: Publish Position to Box");
760  if ((currentMillis - previousMillis) < TIME_BETWEEN_PUBLISH * 5) { //publish 5times
761  if ((currentMillis - previousMillisPublish) > TIME_BETWEEN_PUBLISH) { //only publish all xx seconds
762  previousMillisPublish = millis();
763  DBINFO2ln("Box/" + String(vehicle.ack) +
764  "/position"
765  "{\"id\":\"" +
766  String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.actualSector) + "\",\"line\":\"" + String(vehicle.actualLine) + "\"}");
767  pComm.publishMessage("Box/" + String(vehicle.ack) + "/position", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.actualSector) + "\",\"line\":\"" + String(vehicle.actualLine) + "\"}");
768  }
769  } else {
770  substate = 0;
771  return Event::PosReached;
772  }
773  break;
774 
775  default:
776  break;
777  }
778 
779  //Generate the Event
780  return Event::NoEvent;
781 }
782 
784  DBSTATUSln("Leaving State: unloadVehicle");
785 }
786 
787 //==errorState========================================================
789  DBERROR("Entering State: errorState");
791  currentState = State::errorState; // state transition
793  publishState(currentState); //Update Current State and Publish
794  pComm.clear();
795  pHoistCtrl.loop(HoistCtrl::Event::Error);
797 }
798 
800  DBINFO1ln("State: errorState");
801  //Generate the Event
802  pComm.loop(); //Check for new Messages
803  // if (!pComm.isEmpty()) {
804  while (!pComm.isEmpty()) {
805  // if (!pComm.first().error) {
806  myJSONStr temp = pComm.pop();
807  if (temp.topic.endsWith("error")) {
808  if (!temp.error && !temp.token) {
809  // pComm.shift();
810  pHoistCtrl.loop(HoistCtrl::Event::Resume);
812  return Event::Resume;
813  } else if (temp.error && temp.token) {
814  // pComm.shift();
815  return Event::Reset;
816  }
817  }
818  }
819  return Event::NoEvent;
820 }
821 
823  DBSTATUSln("Leaving State: errorState");
824  pComm.clear();
825 }
826 
827 //==resetState========================================================
829  DBERROR("Entering State: resetState");
831  currentState = State::resetState; // state transition
833  clearGui();
834  publishState(currentState); //Update Current State and Publish
835  pComm.clear();
836  pComm.unsubscribe("Box/+/handshake");
837  pComm.unsubscribe("Box/" + String(vehicle.req) + "/handshake");
838  pComm.unsubscribe("Sortic/Gateway");
839  pComm.unsubscribe("Sortic/Handover");
840  pComm.unsubscribe("Transfer/Gateway");
841  pComm.unsubscribe("Transfer/Handover");
842 }
843 
845  DBINFO1ln("State: resetState");
846  //Generate the Event
847  pComm.loop(); //Check for new Messages
848  while (!pComm.isEmpty()) {
849  myJSONStr temp = pComm.pop();
850  if (temp.topic.endsWith("error")) { //check if message from an error-topic
851  if (!temp.error && !temp.token) {
852  return Event::Resume;
853  }
854  }
855  }
856  pHoistCtrl.loop();
857  pNavCtrl.loop();
858  return Event::NoEvent;
859 }
860 
862  DBSTATUSln("Leaving State: resetState");
863  pComm.clear();
864  vehicle = {}; //reset struct
865  delay(100);
867  substate = 0;
868  clearGui();
869 }
870 
871 //============================================================================
872 //==Aux-Function==============================================================
874  switch (state) {
875  case State::waitForBox:
876  return "waitForBox";
877  break;
878  case State::handshake:
879  return "handshake";
880  break;
881  case State::loadVehicle:
882  return "loadVehicle";
883  break;
885  return "unloadVehicle";
886  break;
887  case State::errorState:
888  return "errorState";
889  break;
890  case State::resetState:
891  return "resetState";
892  break;
893  default:
894  return "ERROR: No matching state";
895  break;
896  }
897 }
898 
900  switch (event) {
901  case Event::PosReached:
902  return "Event::PosReached";
903  break;
904  case Event::HSsucessful:
905  return "Event::HSsucessful";
906  break;
908  return "Event::AnswerReceived";
909  break;
911  return "Event::NoAnswerReceived";
912  break;
913  case Event::Error:
914  return "Event::Error";
915  break;
916  case Event::Resume:
917  return "Event::Resume";
918  break;
919  case Event::Reset:
920  return "Event::Reset";
921  break;
922  case Event::NoEvent:
923  return "Event::NoEvent";
924  break;
925  default:
926  return "ERROR: No matching event";
927  break;
928  }
929 }
930 
931 // VehicleCtrl::Sector VehicleCtrl::decodeSector(String sector) {
932 // if (String("SorticHandover") == sector) {
933 // return Sector::SorticHandover;
934 // } else if (String("SorticToHandover") == sector) {
935 // return Sector::SorticToHandover;
936 // } else if (String("SorticWaitForGateway") == sector) {
937 // return Sector::SorticWaitForGateway;
938 // } else if (String("TransitWaitForGatewaySortic") == sector) {
939 // return Sector::TransitWaitForGatewaySortic;
940 // } else if (String("TransitToSortic") == sector) {
941 // return Sector::TransitToSortic;
942 // } else if (String("TransitToTransfer") == sector) {
943 // return Sector::TransitToTransfer;
944 // } else if (String("Parking") == sector) {
945 // return Sector::Parking;
946 // } else if (String("TransitWaitForGatewayTransfer") == sector) {
947 // return Sector::TransitWaitForGatewayTransfer;
948 // } else if (String("TransferGateway") == sector) {
949 // return Sector::TransferGateway;
950 // } else if (String("TransferWaitForGateway") == sector) {
951 // return Sector::TransferWaitForGateway;
952 // } else if (String("TransferToHandover") == sector) {
953 // return Sector::TransferToHandover;
954 // } else if (String("TransferHandover") == sector) {
955 // return Sector::TransferHandover;
956 // } else {
957 // return Sector::error;
958 // }
959 // }
960 
962  DBFUNCCALLln("VehicleCtrl::checkForError()");
963  if (!pComm.isEmpty()) {
964  DBINFO3ln(pComm.size());
965  DBINFO3ln(pComm.last().error);
966  if (pComm.first().error) {
967  pComm.shift();
968  return true;
969  }
970  }
971  return false;
972 }
973 
975  vehicle.status = decodeState(state);
976  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/status", "{\"status\":\"" + String(vehicle.status) + "\"}");
977 }
978 
982  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/position", "{\"sector\":\"" + pNavCtrl.decodeSector(vehicle.actualSector) + "\",\"line\":" + String(vehicle.actualLine) + "}");
984  pComm.publishMessage("Transfer/Handover", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.actualSector) + "\",\"line\":" + String(vehicle.actualLine) + "}");
986  pComm.publishMessage("Sortic/Handover", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.actualSector) + "\",\"line\":" + String(vehicle.actualLine) + "}");
987  }
988 }
989 
990 void VehicleCtrl::publishTargetPosition() { //Publish TargetPosition so it will stay free
992  pComm.publishMessage("Transfer/Handover", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.targetSector) + "\",\"line\":" + String(vehicle.targetLine) + "}");
994  pComm.publishMessage("Sortic/Handover", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.targetSector) + "\",\"line\":" + String(vehicle.targetLine) + "}");
995  }
996 }
997 void VehicleCtrl::publishTargetPositionBlockLine() { //Publish TargetPosition so it will stay free
999  pComm.publishMessage("Transfer/Handover", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.targetSector) + "\",\"line\":" + String(vehicle.targetLine) + "}");
1000  pComm.publishMessage("Sortic/Handover", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(NavigationCtrl::Sector::SorticHandover) + "\",\"line\":" + String(vehicle.targetLine) + "}");
1002  pComm.publishMessage("Sortic/Handover", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(vehicle.targetSector) + "\",\"line\":" + String(vehicle.targetLine) + "}");
1003  pComm.publishMessage("Transfer/Handover", "{\"id\":\"" + String(vehicle.id) + "\",\"sector\":\"" + pNavCtrl.decodeSector(NavigationCtrl::Sector::TransferHandover) + "\",\"line\":" + String(vehicle.targetLine) + "}");
1004  }
1005 }
1006 
1007 // int VehicleCtrl::chooseLine() {
1008 // int size = sizeof(array) / sizeof(array[0]);
1009 // int line = 0;
1010 // for (int i = 0; i < SORTIC_MAX_LINE; i++) {
1011 // if (array[i] == 0) {
1012 // line = i + 1; //update line with empty line
1013 // } else {
1014 // array[i] = 0; //reset arrayvalue at index
1015 // }
1016 // }
1017 // return line;
1018 // }
1019 
1021  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/status", "{\"status\":\"\"}");
1022  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/position", "{\"sector\":\"\",\"line\":\"\"}");
1023  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/available", "{\"sector\":\"\",\"line\":\"\"}");
1024  pComm.publishMessage("Vehicle/" + String(vehicle.id) + "/handshake", "{\"ack\":\"\",\"req\":\"\"}");
1025 }
#define DBEVENTln(x)
unsigned int pRandomDelayFactor
some sort of ALOHA stuff
Definition: VehicleCtrl.h:122
const Sector getcurrentSector()
Get the current Sector.
Event currentEvent
holds the current event of the FSM
Definition: VehicleCtrl.h:118
#define DBINFO1ln(x)
int actualLine
actual line initialised with 1
Definition: VehicleCtrl.h:44
VehicleCtrl::Event doAction_resetState()
main action of the resetState
Ext.: Reset after Error occured.
void publishTargetPosition()
Update position and Publish actual position.
VehicleCtrl::Event doAction_unloadVehicle()
main action of the unloadVehicle
VehicleCtrl::Event doAction_waitForBox()
main action of the waitForBox
Handshake was sucessful.
void giveToken()
give Token to access the Gateway
NavigationCtrl::Sector targetSector
actual sector initialise with Sortic handover
Definition: VehicleCtrl.h:45
void publishTargetPositionBlockLine()
Ext: Resume after Error occured.
bool checkForError()
Check if a new message with a error is received.
#define DBINFO2ln(x)
Resume after Error occured.
unsigned long previousMillisPublishToken
will store last time token published
Definition: VehicleCtrl.h:136
Ext: Start MoveToTargetPosition.
String ack
ack for handshake vehicle
Definition: VehicleCtrl.h:50
const unsigned int TIMEOUT_VACKS
How long the vehicle waits for acknoledgment from box.
Definition: Configuration.h:21
Event
Enum holds all possible events.
Definition: VehicleCtrl.h:58
String req
req for handshake vehicle
Definition: VehicleCtrl.h:51
VehicleCtrl::Event doAction_errorState()
main action of the errorState
void entryAction_loadVehicle()
entry action of the loadVehicle
void setTargetPosition(Sector sector, const int line)
Set the Target Position object.
Transit - Wait for Gateway Transfer.
VehicleCtrl()
Construct a new Vehicle Ctrl object.
Definition: VehicleCtrl.cpp:15
wait for box to transport
unsigned long previousMillis
will store last time published
Definition: VehicleCtrl.h:135
const unsigned int TIME_BETWEEN_PUBLISH_TOKEN
Time in ms between publish token.
Definition: Configuration.h:20
Event(VehicleCtrl::* doActionFPtr)(void)
Functionpointer to call the current states do-function.
Definition: VehicleCtrl.h:128
String id
Vehiclename.
Definition: VehicleCtrl.h:42
No event generated.
void exitAction_handshake()
exit action of the handshake
HoistCtrl pHoistCtrl
Hoist Controll object.
Definition: VehicleCtrl.h:132
void loop()
Calls the do-function of the active state and hence generates Events.
void process(Event e)
changes the state of the FSM based on the event
Definition: VehicleCtrl.cpp:43
The Vehicle Controll class contains the FSM for the complete Vehicle.
Definition: VehicleCtrl.h:34
NavigationCtrl::Sector actualSector
actual sector initialise with Sortic handover
Definition: VehicleCtrl.h:43
NavigationCtrl pNavCtrl
Navigation Controll object.
Definition: VehicleCtrl.h:130
int pTransferPark[SORTIC_MAX_LINE]
Sortic with 10 diffrent lines.
Definition: VehicleCtrl.h:121
State
Enum holds all possible state's.
Definition: VehicleCtrl.h:108
int pSorticPark[SORTIC_MAX_LINE]
Sortic with 10 diffrent lines.
Definition: VehicleCtrl.h:120
void clearGui()
clear node Red gui
The Vehicle Controll class contains the FSM for the Vehicle.
#define DBINFO3ln(x)
String cargo
cargo; not used atm
Definition: VehicleCtrl.h:47
VehicleCtrl::Event doAction_loadVehicle()
main action of the loadVehicle
VehicleCtrl::Event doAction_handshake()
main action of the handshake
void exitAction_waitForBox()
exit action of the waitForBox
#define DBERROR(x)
const unsigned int TIME_BETWEEN_PUBLISH
Time in ms between publishs.
Definition: Configuration.h:19
unsigned long previousMillisPublish
will store last publish time
Definition: VehicleCtrl.h:137
Communication pComm
Communication object.
Definition: VehicleCtrl.h:131
unsigned long currentMillis
will store current time
Definition: VehicleCtrl.h:134
void exitAction_unloadVehicle()
exit action of the unloadVehicle
void exitAction_errorState()
exit action of the errorState
Vehicle is in position.
State currentState
holds the current state of the FSM
Definition: VehicleCtrl.h:117
String status
status of the Vehicle FSM
Definition: VehicleCtrl.h:48
#define DBINFO2(x)
void entryAction_waitForBox()
entry action of the waitForBox
String decodeState(State state)
Decodes the State-Enum and returns a description.
void entryAction_errorState()
entry action of the errorState
const unsigned int SORTIC_MAX_LINE
How many lines are available. Needed atm to choose a free line without handshake with sortic.
Definition: Configuration.h:22
#define DBFUNCCALLln(x)
void loop()
Calls the do-function of the active state and hence generates Events.
Definition: VehicleCtrl.cpp:31
int targetLine
tartget line initialised with 1
Definition: VehicleCtrl.h:46
struct VehicleCtrl::Vehicle vehicle
#define DBSTATUSln(x)
String decodeSector(Sector sector)
Decodes the Sector-Enum and returns a description.
void exitAction_resetState()
exit action of the resetState
void entryAction_resetState()
entry action of the resetState
Transit - Wait for Gateway Sortic.
#define DBFUNCCALL(x)
const int getcurrentLine()
Get the current Line.
void publishState(State state)
Update State and Publish actual state.
unsigned long previousMillisPublishPos
will store last publish position time
Definition: VehicleCtrl.h:138
void setActualPosition(Sector sector, const int line)
Set the actual Position object.
void entryAction_handshake()
entry action of the handshake
int substate
actual Substate of FSM
Definition: VehicleCtrl.h:119
String decodeEvent(Event event)
Decodes the Event-Enum and returns a description.
void entryAction_unloadVehicle()
entry action of the unloadVehicle
void exitAction_loadVehicle()
exit action of the loadVehicle
void publishPosition()
Update position and Publish actual position.
State lastStateBevorError
holds the last state of the FSM so it's possible to resume after error
Definition: VehicleCtrl.h:116
Reset after Error occured.