Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
fsm_generator.h
00001 /****************************************************************************** 00002 The MIT License(MIT) 00003 00004 Embedded Template Library. 00005 https://github.com/ETLCPP/etl 00006 https://www.etlcpp.com 00007 00008 Copyright(c) 2017 jwellbelove 00009 00010 Permission is hereby granted, free of charge, to any person obtaining a copy 00011 of this software and associated documentation files(the "Software"), to deal 00012 in the Software without restriction, including without limitation the rights 00013 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 00014 copies of the Software, and to permit persons to whom the Software is 00015 furnished to do so, subject to the following conditions : 00016 00017 The above copyright notice and this permission notice shall be included in all 00018 copies or substantial portions of the Software. 00019 00020 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00021 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00022 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 00023 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00024 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00025 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00026 SOFTWARE. 00027 ******************************************************************************/ 00028 00029 /*[[[cog 00030 import cog 00031 cog.outl("#if 0") 00032 ]]]*/ 00033 /*[[[end]]]*/ 00034 #error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. 00035 /*[[[cog 00036 import cog 00037 cog.outl("#endif") 00038 ]]]*/ 00039 /*[[[end]]]*/ 00040 00041 /*[[[cog 00042 import cog 00043 cog.outl("//***************************************************************************") 00044 cog.outl("// This file has been auto generated. Do not edit this file.") 00045 cog.outl("//***************************************************************************") 00046 ]]]*/ 00047 /*[[[end]]]*/ 00048 00049 //*************************************************************************** 00050 // To generate to header file, run this at the command line. 00051 // Note: You will need Python and COG installed. 00052 // 00053 // python -m cogapp -d -e -ofsm.h -DHandlers=<n> fsm_generator.h 00054 // Where <n> is the number of messages to support. 00055 // 00056 // e.g. 00057 // To generate handlers for up to 16 events... 00058 // python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h 00059 // 00060 // See generate.bat 00061 //*************************************************************************** 00062 00063 #ifndef __ETL_FSM__ 00064 #define __ETL_FSM__ 00065 00066 #include <stdint.h> 00067 00068 #include "platform.h " 00069 #include "array.h " 00070 #include "nullptr.h " 00071 #include "error_handler.h " 00072 #include "exception.h " 00073 #include "user_type.h " 00074 #include "message_router.h" 00075 #include "integral_limits.h " 00076 #include "largest.h " 00077 00078 #undef ETL_FILE 00079 #define ETL_FILE "34" 00080 00081 #ifdef ETL_COMPILER_MICROSOFT 00082 #undef max 00083 #endif 00084 00085 namespace etl 00086 { 00087 class fsm; 00088 00089 /// Allow alternative type for state id. 00090 #if !defined(ETL_FSM_STATE_ID_TYPE) 00091 typedef uint_least8_t fsm_state_id_t; 00092 #else 00093 typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t; 00094 #endif 00095 00096 // For internal FSM use. 00097 typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t; 00098 00099 //*************************************************************************** 00100 /// Base exception class for FSM. 00101 //*************************************************************************** 00102 class fsm_exception : public etl::exception 00103 { 00104 public: 00105 00106 fsm_exception(string_type reason_, string_type file_name_, numeric_type line_number_) 00107 : etl::exception(reason_, file_name_, line_number_) 00108 { 00109 } 00110 }; 00111 00112 //*************************************************************************** 00113 /// Exception for null state pointer. 00114 //*************************************************************************** 00115 class fsm_null_state_exception : public etl::fsm_exception 00116 { 00117 public: 00118 00119 fsm_null_state_exception(string_type file_name_, numeric_type line_number_) 00120 : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name_, line_number_) 00121 { 00122 } 00123 }; 00124 00125 //*************************************************************************** 00126 /// Exception for invalid state id. 00127 //*************************************************************************** 00128 class fsm_state_id_exception : public etl::fsm_exception 00129 { 00130 public: 00131 00132 fsm_state_id_exception(string_type file_name_, numeric_type line_number_) 00133 : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name_, line_number_) 00134 { 00135 } 00136 }; 00137 00138 //*************************************************************************** 00139 /// Exception for incompatible state list. 00140 //*************************************************************************** 00141 class fsm_state_list_exception : public etl::fsm_exception 00142 { 00143 public: 00144 00145 fsm_state_list_exception(string_type file_name_, numeric_type line_number_) 00146 : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name_, line_number_) 00147 { 00148 } 00149 }; 00150 00151 //*************************************************************************** 00152 /// Interface class for FSM states. 00153 //*************************************************************************** 00154 class ifsm_state 00155 { 00156 public: 00157 00158 /// Allows ifsm_state functions to be private. 00159 friend class etl::fsm; 00160 00161 //******************************************* 00162 /// Gets the id for this state. 00163 //******************************************* 00164 etl::fsm_state_id_t get_state_id() const 00165 { 00166 return state_id; 00167 } 00168 00169 protected: 00170 00171 //******************************************* 00172 /// Constructor. 00173 //******************************************* 00174 ifsm_state(etl::fsm_state_id_t state_id_) 00175 : state_id(state_id_), 00176 p_context(std::nullptr) 00177 { 00178 } 00179 00180 //******************************************* 00181 inline etl::fsm& get_fsm_context() const 00182 { 00183 return *p_context; 00184 } 00185 00186 private: 00187 00188 virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0; 00189 00190 virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing. 00191 virtual void on_exit_state() {} // By default, do nothing. 00192 00193 //******************************************* 00194 void set_fsm_context(etl::fsm& context) 00195 { 00196 p_context = &context; 00197 } 00198 00199 // The state id. 00200 const etl::fsm_state_id_t state_id; 00201 00202 // A pointer to the FSM context. 00203 etl::fsm* p_context; 00204 00205 // Disabled. 00206 ifsm_state(const ifsm_state&); 00207 ifsm_state& operator =(const ifsm_state&); 00208 }; 00209 00210 //*************************************************************************** 00211 /// The FSM class. 00212 //*************************************************************************** 00213 class fsm : public etl::imessage_router 00214 { 00215 public: 00216 00217 //******************************************* 00218 /// Constructor. 00219 //******************************************* 00220 fsm(etl::message_router_id_t id) 00221 : imessage_router(id), 00222 p_state(std::nullptr) 00223 { 00224 } 00225 00226 //******************************************* 00227 /// Set the states for the FSM 00228 //******************************************* 00229 template <typename TSize> 00230 void set_states(etl::ifsm_state** p_states, TSize size) 00231 { 00232 state_list = p_states; 00233 number_of_states = etl::fsm_state_id_t(size); 00234 00235 ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception)); 00236 00237 for (etl::fsm_state_id_t i = 0; i < size; ++i) 00238 { 00239 ETL_ASSERT((state_list[i] != std::nullptr), ETL_ERROR(etl::fsm_null_state_exception)); 00240 state_list[i]->set_fsm_context(*this); 00241 } 00242 } 00243 00244 //******************************************* 00245 /// Starts the FSM. 00246 /// Can only be called once. 00247 /// Subsequent calls will do nothing. 00248 //******************************************* 00249 void start() 00250 { 00251 // Can only be started once. 00252 if (p_state == std::nullptr) 00253 { 00254 p_state = state_list[0]; 00255 ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); 00256 00257 p_state->on_enter_state(); 00258 } 00259 } 00260 00261 //******************************************* 00262 /// Top level message handler for the FSM. 00263 //******************************************* 00264 void receive(const etl::imessage& message) 00265 { 00266 etl::null_message_router nmr; 00267 receive(nmr, message); 00268 } 00269 00270 //******************************************* 00271 /// Top level message handler for the FSM. 00272 //******************************************* 00273 void receive(etl::imessage_router& source, const etl::imessage& message) 00274 { 00275 etl::fsm_state_id_t next_state_id = p_state->process_event(source, message); 00276 ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); 00277 00278 etl::ifsm_state* p_next_state = state_list[next_state_id]; 00279 00280 // Have we changed state? 00281 if (p_next_state != p_state) 00282 { 00283 do 00284 { 00285 p_state->on_exit_state(); 00286 p_state = p_next_state; 00287 00288 next_state_id = p_state->on_enter_state(); 00289 ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); 00290 00291 p_next_state = state_list[next_state_id]; 00292 00293 } while (p_next_state != p_state); // Have we changed state again? 00294 } 00295 } 00296 00297 using imessage_router::accepts; 00298 00299 //******************************************* 00300 /// Does this FSM accept the message id? 00301 /// Yes, it accepts everything! 00302 //******************************************* 00303 bool accepts(etl::message_id_t id) const 00304 { 00305 return true; 00306 } 00307 00308 //******************************************* 00309 /// Gets the current state id. 00310 //******************************************* 00311 etl::fsm_state_id_t get_state_id() const 00312 { 00313 ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); 00314 return p_state->get_state_id(); 00315 } 00316 00317 //******************************************* 00318 /// Gets a reference to the current state interface. 00319 //******************************************* 00320 ifsm_state& get_state() 00321 { 00322 ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); 00323 return *p_state; 00324 } 00325 00326 //******************************************* 00327 /// Gets a const reference to the current state interface. 00328 //******************************************* 00329 const ifsm_state& get_state() const 00330 { 00331 ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); 00332 return *p_state; 00333 } 00334 00335 //******************************************* 00336 /// Checks if the FSM has been started. 00337 //******************************************* 00338 bool is_started() const 00339 { 00340 return p_state != std::nullptr; 00341 } 00342 00343 //******************************************* 00344 /// Reset the FSM to pre-started state. 00345 //******************************************* 00346 void reset() 00347 { 00348 p_state = std::nullptr; 00349 } 00350 00351 private: 00352 00353 etl::ifsm_state* p_state; ///< A pointer to the current state. 00354 etl::ifsm_state** state_list; ///< The list of added states. 00355 etl::fsm_state_id_t number_of_states; ///< The number of states. 00356 }; 00357 00358 /*[[[cog 00359 import cog 00360 ################################################ 00361 # The first definition for all of the events. 00362 ################################################ 00363 cog.outl("//***************************************************************************") 00364 cog.outl("// The definition for all %s message types." % Handlers) 00365 cog.outl("//***************************************************************************") 00366 cog.outl("template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, ") 00367 cog.out(" ") 00368 for n in range(1, int(Handlers)): 00369 cog.out("typename T%s = void, " % n) 00370 if n % 4 == 0: 00371 cog.outl("") 00372 cog.out(" ") 00373 cog.outl("typename T%s = void>" % Handlers) 00374 cog.outl("class fsm_state : public ifsm_state") 00375 cog.outl("{") 00376 cog.outl("public:") 00377 cog.outl("") 00378 cog.outl(" enum") 00379 cog.outl(" {") 00380 cog.outl(" STATE_ID = STATE_ID_") 00381 cog.outl(" };") 00382 cog.outl("") 00383 cog.outl(" fsm_state()") 00384 cog.outl(" : ifsm_state(STATE_ID)") 00385 cog.outl(" {") 00386 cog.outl(" }") 00387 cog.outl("") 00388 cog.outl("protected:") 00389 cog.outl("") 00390 cog.outl(" inline TContext& get_fsm_context() const") 00391 cog.outl(" {") 00392 cog.outl(" return static_cast<TContext&>(ifsm_state::get_fsm_context());") 00393 cog.outl(" }") 00394 cog.outl("") 00395 cog.outl("private:") 00396 cog.outl("") 00397 cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") 00398 cog.outl(" {") 00399 cog.outl(" etl::fsm_state_id_t new_state_id;") 00400 cog.outl(" etl::message_id_t event_id = message.message_id;") 00401 cog.outl("") 00402 cog.outl(" switch (event_id)") 00403 cog.outl(" {") 00404 for n in range(1, int(Handlers) + 1): 00405 cog.out(" case T%d::ID:" % n) 00406 cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T%d&>(message));" % n) 00407 cog.outl(" break;") 00408 cog.out(" default:") 00409 cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message);") 00410 cog.outl(" break;") 00411 cog.outl(" }") 00412 cog.outl("") 00413 cog.outl(" return new_state_id;") 00414 cog.outl(" }") 00415 cog.outl("};") 00416 00417 #################################### 00418 # All of the other specialisations. 00419 #################################### 00420 for n in range(int(Handlers) - 1, 0, -1): 00421 cog.outl("") 00422 cog.outl("//***************************************************************************") 00423 if n == 1: 00424 cog.outl("// Specialisation for %d message type." % n) 00425 else: 00426 cog.outl("// Specialisation for %d message types." % n) 00427 cog.outl("//***************************************************************************") 00428 cog.outl("template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, ") 00429 cog.out(" ") 00430 for t in range(1, n): 00431 cog.out("typename T%d, " % t) 00432 if t % 4 == 0: 00433 cog.outl("") 00434 cog.out(" ") 00435 cog.outl("typename T%d>" % n) 00436 cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ") 00437 for t in range(1, n + 1): 00438 cog.out("T%d, " % t) 00439 if t % 16 == 0: 00440 cog.outl("") 00441 cog.out(" ") 00442 for t in range(n + 1, int(Handlers)): 00443 cog.out("void, ") 00444 if t % 16 == 0: 00445 cog.outl("") 00446 cog.out(" ") 00447 cog.outl("void> : public ifsm_state") 00448 cog.outl("{") 00449 cog.outl("public:") 00450 cog.outl("") 00451 cog.outl(" enum") 00452 cog.outl(" {") 00453 cog.outl(" STATE_ID = STATE_ID_") 00454 cog.outl(" };") 00455 cog.outl("") 00456 cog.outl(" fsm_state()") 00457 cog.outl(" : ifsm_state(STATE_ID)") 00458 cog.outl(" {") 00459 cog.outl(" }") 00460 cog.outl("") 00461 cog.outl("protected:") 00462 cog.outl("") 00463 cog.outl(" inline TContext& get_fsm_context() const") 00464 cog.outl(" {") 00465 cog.outl(" return static_cast<TContext&>(ifsm_state::get_fsm_context());") 00466 cog.outl(" }") 00467 cog.outl("") 00468 cog.outl("private:") 00469 cog.outl("") 00470 cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") 00471 cog.outl(" {") 00472 cog.outl(" etl::fsm_state_id_t new_state_id;") 00473 cog.outl(" etl::message_id_t event_id = message.message_id;") 00474 cog.outl("") 00475 cog.outl(" switch (event_id)") 00476 cog.outl(" {") 00477 for n in range(1, n + 1): 00478 cog.out(" case T%d::ID:" % n) 00479 cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T%d&>(message));" % n) 00480 cog.outl(" break;") 00481 cog.out(" default:") 00482 cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message);") 00483 cog.outl(" break;") 00484 cog.outl(" }") 00485 cog.outl("") 00486 cog.outl(" return new_state_id;") 00487 cog.outl(" }") 00488 cog.outl("};") 00489 #################################### 00490 # Specialisation for zero messages. 00491 #################################### 00492 cog.outl("") 00493 cog.outl("//***************************************************************************") 00494 cog.outl("// Specialisation for 0 message types.") 00495 cog.outl("//***************************************************************************") 00496 cog.outl("template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_>") 00497 cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ") 00498 for t in range(1, int(Handlers)): 00499 cog.out("void, ") 00500 if t % 16 == 0: 00501 cog.outl("") 00502 cog.out(" ") 00503 cog.outl("void> : public ifsm_state") 00504 cog.outl("{") 00505 cog.outl("public:") 00506 cog.outl("") 00507 cog.outl(" enum") 00508 cog.outl(" {") 00509 cog.outl(" STATE_ID = STATE_ID_") 00510 cog.outl(" };") 00511 cog.outl("") 00512 cog.outl(" fsm_state()") 00513 cog.outl(" : ifsm_state(STATE_ID)") 00514 cog.outl(" {") 00515 cog.outl(" }") 00516 cog.outl("") 00517 cog.outl(" inline TContext& get_fsm_context() const") 00518 cog.outl(" {") 00519 cog.outl(" return static_cast<TContext&>(ifsm_state::get_fsm_context());") 00520 cog.outl(" }") 00521 cog.outl("private:") 00522 cog.outl("") 00523 cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") 00524 cog.outl(" {") 00525 cog.outl(" return static_cast<TDerived*>(this)->on_event_unknown(source, message);") 00526 cog.outl(" }") 00527 cog.outl("};") 00528 ]]]*/ 00529 /*[[[end]]]*/ 00530 } 00531 00532 #undef ETL_FILE 00533 00534 #ifdef ETL_COMPILER_MICROSOFT 00535 #define max(a,b) (((a) > (b)) ? (a) : (b)) 00536 #endif 00537 00538 #endif 00539
Generated on Tue Jul 12 2022 14:05:41 by
