| /** |
| * @author generated by eTrice |
| * |
| * Source File of ActorClass ATcpServer |
| * |
| */ |
| |
| #include "ATcpServer.h" |
| |
| #include "modelbase/etActor.h" |
| #include "debugging/etLogger.h" |
| #include "debugging/etMSCLogger.h" |
| #include "etUnit/etUnit.h" |
| #include "base/etMemory.h" |
| |
| #include "etrice/api/tcp/PTcpControl.h" |
| #include "etrice/api/tcp/PTcpPayload.h" |
| |
| #include "ATcpServer_Utils.h" |
| |
| /*--------------------- begin user code ---------------------*/ |
| static int8* bufferProvider(void* slf, int* size) { |
| ATcpServer* self = (ATcpServer*) slf; |
| *size = DTcpPayload_getMaxLength(&payloadRecvBuffer); |
| return payloadRecvBuffer.data; |
| } |
| |
| static int socketReceiver(void* slf, int channel, int size, const int8* data) { |
| ATcpServer* self = (ATcpServer*) slf; |
| DTcpPayload_setData(&payloadRecvBuffer, data, size); |
| payloadPort_dataPackage(&payloadRecvBuffer); |
| return ETSOCKET_OK; |
| } |
| /*--------------------- end user code ---------------------*/ |
| |
| /* interface item IDs */ |
| enum interface_items { |
| IFITEM_controlPort = 1, |
| IFITEM_payloadPort = 2 |
| }; |
| |
| /* state IDs */ |
| enum state_ids { |
| NO_STATE = 0, |
| STATE_TOP = 1, |
| STATE_connected = 2, |
| STATE_unconnected = 3, |
| STATE_initError = 4, |
| STATE_MAX = 5 |
| }; |
| |
| /* transition chains */ |
| enum ChainIDs { |
| CHAIN_TRANS_INITIAL_TO__cp0 = 1, |
| CHAIN_TRANS_tr5_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr5 = 2, |
| CHAIN_TRANS_tr6_FROM_connected_TO_unconnected_BY_disconnectcontrolPort = 3, |
| CHAIN_TRANS_tr7_FROM_unconnected_TO_cp1_BY_connectcontrolPort = 4, |
| CHAIN_TRANS_tr2_FROM_initError_TO_initError_BY_connectcontrolPort_tr2 = 5 |
| }; |
| |
| /* triggers */ |
| enum triggers { |
| POLLING = 0, |
| TRIG_controlPort__connect = IFITEM_controlPort + EVT_SHIFT*PTcpControl_IN_connect, |
| TRIG_controlPort__disconnect = IFITEM_controlPort + EVT_SHIFT*PTcpControl_IN_disconnect, |
| TRIG_payloadPort__dataPackage = IFITEM_payloadPort + EVT_SHIFT*PTcpPayload_IN_dataPackage |
| }; |
| |
| /* state names */ |
| static const char* stateStrings[] = {"<no state>","<top>","connected", |
| "unconnected", |
| "initError" |
| }; |
| |
| static void setState(ATcpServer* self, etInt16 new_state) { |
| self->state = new_state; |
| ET_MSC_LOGGER_CHANGE_STATE(self->constData->instName, stateStrings[new_state]); |
| } |
| |
| static etInt16 getState(ATcpServer* self) { |
| return self->state; |
| } |
| |
| /* Entry and Exit Codes */ |
| static void entry_initError(ATcpServer* self) { |
| controlPort_error(); |
| } |
| |
| /* Action Codes */ |
| static void action_TRANS_tr5_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr5(ATcpServer* self, const InterfaceItemBase* ifitem, DTcpPayload* transitionData) { |
| /* send payload to connection */ |
| setErrorCode(etWriteServerSocket(server, transitionData->connectionId, transitionData->length, transitionData->data)); |
| if(hasError()) |
| controlPort_error(); |
| } |
| static void action_TRANS_tr6_FROM_connected_TO_unconnected_BY_disconnectcontrolPort(ATcpServer* self, const InterfaceItemBase* ifitem) { |
| /* close accept thread */ |
| etCloseAllServerSockets(server); |
| etStopSocketServer(server); |
| |
| controlPort_disconnected(); |
| } |
| static void action_TRANS_tr7_FROM_unconnected_TO_cp1_BY_connectcontrolPort(ATcpServer* self, const InterfaceItemBase* ifitem, DTcpControl* transitionData) { |
| /* start accept thread */ |
| setErrorCode(etStartListening(server, transitionData->TcpPort)); |
| } |
| static void action_TRANS_tr4_FROM_cp1_TO_connected(ATcpServer* self, const InterfaceItemBase* ifitem, DTcpControl* transitionData) { |
| controlPort_connected(); |
| } |
| static void action_TRANS_tr8_FROM_cp1_TO_unconnected_COND_tr8(ATcpServer* self, const InterfaceItemBase* ifitem, DTcpControl* transitionData) { |
| controlPort_error(); |
| } |
| |
| /* State Switch Methods */ |
| /** |
| * calls exit codes while exiting from the current state to one of its |
| * parent states while remembering the history |
| * @param current__et - the current state |
| * @param to - the final parent state |
| */ |
| static void exitTo(ATcpServer* self, etInt16 current__et, etInt16 to) { |
| while (current__et!=to) { |
| switch (current__et) { |
| case STATE_connected: |
| self->history[STATE_TOP] = STATE_connected; |
| current__et = STATE_TOP; |
| break; |
| case STATE_initError: |
| self->history[STATE_TOP] = STATE_initError; |
| current__et = STATE_TOP; |
| break; |
| case STATE_unconnected: |
| self->history[STATE_TOP] = STATE_unconnected; |
| current__et = STATE_TOP; |
| break; |
| default: |
| /* should not occur */ |
| break; |
| } |
| } |
| } |
| |
| /** |
| * calls action, entry and exit codes along a transition chain. The generic data are cast to typed data |
| * matching the trigger of this chain. The ID of the final state is returned |
| * @param chain__et - the chain ID |
| * @param generic_data__et - the generic data pointer |
| * @return the +/- ID of the final state either with a positive sign, that indicates to execute the state's entry code, or a negative sign vice versa |
| */ |
| static etInt16 executeTransitionChain(ATcpServer* self, int chain__et, const InterfaceItemBase* ifitem, void* generic_data__et) { |
| switch (chain__et) { |
| case CHAIN_TRANS_INITIAL_TO__cp0: |
| { |
| if (hasError()) { |
| return STATE_initError;} |
| else { |
| return STATE_unconnected;} |
| } |
| case CHAIN_TRANS_tr2_FROM_initError_TO_initError_BY_connectcontrolPort_tr2: |
| { |
| DTcpControl* transitionData = ((DTcpControl*) generic_data__et); |
| return STATE_initError; |
| } |
| case CHAIN_TRANS_tr5_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr5: |
| { |
| DTcpPayload* transitionData = ((DTcpPayload*) generic_data__et); |
| action_TRANS_tr5_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr5(self, ifitem, transitionData); |
| return STATE_connected; |
| } |
| case CHAIN_TRANS_tr6_FROM_connected_TO_unconnected_BY_disconnectcontrolPort: |
| { |
| action_TRANS_tr6_FROM_connected_TO_unconnected_BY_disconnectcontrolPort(self, ifitem); |
| return STATE_unconnected; |
| } |
| case CHAIN_TRANS_tr7_FROM_unconnected_TO_cp1_BY_connectcontrolPort: |
| { |
| DTcpControl* transitionData = ((DTcpControl*) generic_data__et); |
| action_TRANS_tr7_FROM_unconnected_TO_cp1_BY_connectcontrolPort(self, ifitem, transitionData); |
| if (hasError()) { |
| action_TRANS_tr8_FROM_cp1_TO_unconnected_COND_tr8(self, ifitem, transitionData); |
| return STATE_unconnected;} |
| else { |
| action_TRANS_tr4_FROM_cp1_TO_connected(self, ifitem, transitionData); |
| return STATE_connected;} |
| } |
| default: |
| /* should not occur */ |
| break; |
| } |
| return NO_STATE; |
| } |
| |
| /** |
| * calls entry codes while entering a state's history. The ID of the final leaf state is returned |
| * @param state__et - the state which is entered |
| * @return - the ID of the final leaf state |
| */ |
| static etInt16 enterHistory(ATcpServer* self, etInt16 state__et) { |
| etBool skip_entry__et = ET_FALSE; |
| if (state__et >= STATE_MAX) { |
| state__et = (etInt16) (state__et - STATE_MAX); |
| skip_entry__et = ET_TRUE; |
| } |
| while (ET_TRUE) { |
| switch (state__et) { |
| case STATE_connected: |
| /* in leaf state: return state id */ |
| return STATE_connected; |
| case STATE_initError: |
| if (!(skip_entry__et)) entry_initError(self); |
| /* in leaf state: return state id */ |
| return STATE_initError; |
| case STATE_unconnected: |
| /* in leaf state: return state id */ |
| return STATE_unconnected; |
| case STATE_TOP: |
| state__et = self->history[STATE_TOP]; |
| break; |
| default: |
| /* should not occur */ |
| break; |
| } |
| skip_entry__et = ET_FALSE; |
| } |
| /* return NO_STATE; // required by CDT but detected as unreachable by JDT because of while (true) */ |
| } |
| |
| static void ATcpServer_executeInitTransition(ATcpServer* self) { |
| int chain__et = CHAIN_TRANS_INITIAL_TO__cp0; |
| etInt16 next__et = executeTransitionChain(self, chain__et, NULL, NULL); |
| next__et = enterHistory(self, next__et); |
| setState(self, next__et); |
| } |
| |
| /* receiveEvent contains the main implementation of the FSM */ |
| static void ATcpServer_receiveEventInternal(ATcpServer* self, InterfaceItemBase* ifitem, int localId, int evt, void* generic_data__et) { |
| int trigger__et = localId + EVT_SHIFT*evt; |
| int chain__et = NOT_CAUGHT; |
| etInt16 catching_state__et = NO_STATE; |
| ((void)trigger__et); /* avoids unused warning */ |
| |
| if (!handleSystemEvent(ifitem, evt, generic_data__et)) { |
| switch (getState(self)) { |
| case STATE_connected: |
| switch(trigger__et) { |
| case TRIG_controlPort__disconnect: |
| { |
| chain__et = CHAIN_TRANS_tr6_FROM_connected_TO_unconnected_BY_disconnectcontrolPort; |
| catching_state__et = STATE_TOP; |
| } |
| break; |
| case TRIG_payloadPort__dataPackage: |
| { |
| chain__et = CHAIN_TRANS_tr5_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr5; |
| catching_state__et = STATE_TOP; |
| } |
| break; |
| default: |
| /* should not occur */ |
| break; |
| } |
| break; |
| case STATE_initError: |
| switch(trigger__et) { |
| case TRIG_controlPort__connect: |
| { |
| chain__et = CHAIN_TRANS_tr2_FROM_initError_TO_initError_BY_connectcontrolPort_tr2; |
| catching_state__et = STATE_TOP; |
| } |
| break; |
| default: |
| /* should not occur */ |
| break; |
| } |
| break; |
| case STATE_unconnected: |
| switch(trigger__et) { |
| case TRIG_controlPort__connect: |
| { |
| chain__et = CHAIN_TRANS_tr7_FROM_unconnected_TO_cp1_BY_connectcontrolPort; |
| catching_state__et = STATE_TOP; |
| } |
| break; |
| default: |
| /* should not occur */ |
| break; |
| } |
| break; |
| default: |
| /* should not occur */ |
| break; |
| } |
| } |
| if (chain__et != NOT_CAUGHT) { |
| exitTo(self, getState(self), catching_state__et); |
| { |
| etInt16 next__et = executeTransitionChain(self, chain__et, ifitem, generic_data__et); |
| next__et = enterHistory(self, next__et); |
| setState(self, next__et); |
| } |
| } |
| } |
| static void ATcpServer_receiveEvent(ATcpServer* self, InterfaceItemBase* ifitem, int evt, void* generic_data__et) { |
| int localId = (ifitem==NULL)? 0 : ifitem->localId; |
| ATcpServer_receiveEventInternal(self, ifitem, localId, evt, generic_data__et); |
| } |
| |
| void ATcpServer_init(ATcpServer* self){ |
| ET_MSC_LOGGER_SYNC_ENTRY("ATcpServer", "init") |
| self->state = STATE_TOP; |
| { |
| int i; |
| for (i=0; i<ATCPSERVER_HISTORY_SIZE; ++i) |
| self->history[i] = NO_STATE; |
| } |
| ATcpServer_executeInitTransition(self); |
| ET_MSC_LOGGER_SYNC_EXIT |
| } |
| |
| |
| void ATcpServer_receiveMessage(void* self, const void* ifitem, const etMessage* msg){ |
| ET_MSC_LOGGER_SYNC_ENTRY("ATcpServer", "_receiveMessage") |
| ATcpServer_receiveEvent((ATcpServer*) self, (etPort*)ifitem, msg->evtID, (void*)(((char*)msg)+MEM_CEIL(sizeof(etMessage)))); |
| |
| ET_MSC_LOGGER_SYNC_EXIT |
| } |
| |
| |
| /*--------------------- user constructor/destructor ---------------------*/ |
| void ATcpServer_ctor(ATcpServer* self){ |
| /* user defined constructor body */ |
| setErrorCode(etInitSockets()); |
| server = etCreateSocketServerData(); |
| server->receiver = socketReceiver; |
| server->bufferProvider = bufferProvider; |
| server->userData = self; |
| } |
| |
| void ATcpServer_dtor(ATcpServer* self){ |
| /* user defined destructor body */ |
| etCleanupSockets(); |
| etFreeSocketServerData(server); |
| } |
| |
| /*--------------------- operations ---------------------*/ |
| bool ATcpServer_hasError(ATcpServer* self) { |
| return lastError != ETSOCKET_OK; |
| } |
| void ATcpServer_setErrorCode(ATcpServer* self, int32 value) { |
| lastError = value; |
| } |
| |