| /** |
| * @author generated by eTrice |
| * |
| * Source File of ActorClass ATcpClient |
| * |
| */ |
| |
| #include "ATcpClient.h" |
| |
| #include "modelbase/etActor.h" |
| #include "debugging/etLogger.h" |
| #include "debugging/etMSCLogger.h" |
| #include "etUnit/etUnit.h" |
| #include "base/etMemory.h" |
| |
| #include "room/basic/service/tcp/PTcpControl.h" |
| #include "room/basic/service/tcp/PTcpPayload.h" |
| |
| #include "ATcpClient_Utils.h" |
| |
| /*--------------------- begin user code ---------------------*/ |
| static int8* bufferProvider(void* slf, int* size) { |
| ATcpClient* self = (ATcpClient*) slf; |
| *size = DTcpPayload_getMaxLength(&payloadRecvBuffer); |
| return payloadRecvBuffer.data; |
| } |
| |
| static int socketReceiver(void* slf, int channel, int size, const int8* data) { |
| ATcpClient* self = (ATcpClient*) slf; |
| DTcpPayload_setData(&payloadRecvBuffer, /* cast away constness to avoid warning*/(int8*)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_unconnected = 2, |
| STATE_connected = 3, |
| STATE_initError = 4, |
| STATE_MAX = 5 |
| }; |
| |
| /* transition chains */ |
| enum ChainIDs { |
| CHAIN_TRANS_INITIAL_TO__cp1 = 1, |
| CHAIN_TRANS_tr0_FROM_unconnected_TO_cp0_BY_connectcontrolPort = 2, |
| CHAIN_TRANS_tr1_FROM_connected_TO_unconnected_BY_disconnectcontrolPort = 3, |
| CHAIN_TRANS_tr3_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr3 = 4, |
| CHAIN_TRANS_tr6_FROM_initError_TO_initError_BY_connectcontrolPort_tr6 = 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 char* stateStrings[] = {"<no state>","<top>","unconnected", |
| "connected", |
| "initError" |
| }; |
| |
| static void setState(ATcpClient* self, etInt16 new_state) { |
| self->state = new_state; |
| ET_MSC_LOGGER_CHANGE_STATE(self->constData->instName, stateStrings[new_state]); |
| } |
| |
| static etInt16 getState(ATcpClient* self) { |
| return self->state; |
| } |
| |
| /* Entry and Exit Codes */ |
| static void entry_initError(ATcpClient* self) { |
| controlPort_error(); |
| } |
| |
| /* Action Codes */ |
| static void action_TRANS_INITIAL_TO__cp1(ATcpClient* self) { |
| printf("Client Init!\n"); |
| } |
| static void action_TRANS_tr0_FROM_unconnected_TO_cp0_BY_connectcontrolPort(ATcpClient* self, const InterfaceItemBase* ifitem, DTcpControl* transitionData) { |
| /* connect to server */ |
| setErrorCode(etConnectServer(client, transitionData->IPAddr, transitionData->TcpPort)); |
| } |
| static void action_TRANS_tr1_FROM_connected_TO_unconnected_BY_disconnectcontrolPort(ATcpClient* self, const InterfaceItemBase* ifitem) { |
| /* close read thread */ |
| etCloseSocket(client); |
| |
| controlPort_disconnected(); |
| } |
| static void action_TRANS_tr2_FROM_cp0_TO_connected(ATcpClient* self, const InterfaceItemBase* ifitem, DTcpControl* transitionData) { |
| controlPort_connected(); |
| } |
| static void action_TRANS_tr7_FROM_cp0_TO_unconnected_COND_tr7(ATcpClient* self, const InterfaceItemBase* ifitem, DTcpControl* transitionData) { |
| controlPort_error(); |
| } |
| static void action_TRANS_tr3_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr3(ATcpClient* self, const InterfaceItemBase* ifitem, DTcpPayload* transitionData) { |
| setErrorCode(etWriteSocket(client, transitionData->length, transitionData->data)); |
| if(hasError()) |
| 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(ATcpClient* 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(ATcpClient* self, int chain__et, const InterfaceItemBase* ifitem, void* generic_data__et) { |
| switch (chain__et) { |
| case CHAIN_TRANS_INITIAL_TO__cp1: |
| { |
| action_TRANS_INITIAL_TO__cp1(self); |
| if (hasError()) { |
| return STATE_initError;} |
| else { |
| return STATE_unconnected;} |
| } |
| case CHAIN_TRANS_tr0_FROM_unconnected_TO_cp0_BY_connectcontrolPort: |
| { |
| DTcpControl* transitionData = ((DTcpControl*) generic_data__et); |
| action_TRANS_tr0_FROM_unconnected_TO_cp0_BY_connectcontrolPort(self, ifitem, transitionData); |
| if (hasError()) { |
| action_TRANS_tr7_FROM_cp0_TO_unconnected_COND_tr7(self, ifitem, transitionData); |
| return STATE_unconnected;} |
| else { |
| action_TRANS_tr2_FROM_cp0_TO_connected(self, ifitem, transitionData); |
| return STATE_connected;} |
| } |
| case CHAIN_TRANS_tr1_FROM_connected_TO_unconnected_BY_disconnectcontrolPort: |
| { |
| action_TRANS_tr1_FROM_connected_TO_unconnected_BY_disconnectcontrolPort(self, ifitem); |
| return STATE_unconnected; |
| } |
| case CHAIN_TRANS_tr3_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr3: |
| { |
| DTcpPayload* transitionData = ((DTcpPayload*) generic_data__et); |
| action_TRANS_tr3_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr3(self, ifitem, transitionData); |
| return STATE_connected; |
| } |
| case CHAIN_TRANS_tr6_FROM_initError_TO_initError_BY_connectcontrolPort_tr6: |
| { |
| DTcpControl* transitionData = ((DTcpControl*) generic_data__et); |
| return STATE_initError; |
| } |
| 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(ATcpClient* 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 ATcpClient_executeInitTransition(ATcpClient* self) { |
| int chain__et = CHAIN_TRANS_INITIAL_TO__cp1; |
| 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 ATcpClient_receiveEventInternal(ATcpClient* 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_tr1_FROM_connected_TO_unconnected_BY_disconnectcontrolPort; |
| catching_state__et = STATE_TOP; |
| } |
| break; |
| case TRIG_payloadPort__dataPackage: |
| { |
| chain__et = CHAIN_TRANS_tr3_FROM_connected_TO_connected_BY_dataPackagepayloadPort_tr3; |
| 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_tr6_FROM_initError_TO_initError_BY_connectcontrolPort_tr6; |
| 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_tr0_FROM_unconnected_TO_cp0_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 ATcpClient_receiveEvent(ATcpClient* self, InterfaceItemBase* ifitem, int evt, void* generic_data__et) { |
| int localId = (ifitem==NULL)? 0 : ifitem->localId; |
| ATcpClient_receiveEventInternal(self, ifitem, localId, evt, generic_data__et); |
| } |
| |
| void ATcpClient_init(ATcpClient* self){ |
| ET_MSC_LOGGER_SYNC_ENTRY("ATcpClient", "init") |
| self->state = STATE_TOP; |
| { |
| int i; |
| for (i=0; i<ATCPCLIENT_HISTORY_SIZE; ++i) |
| self->history[i] = NO_STATE; |
| } |
| ATcpClient_executeInitTransition(self); |
| ET_MSC_LOGGER_SYNC_EXIT |
| } |
| |
| |
| void ATcpClient_receiveMessage(void* self, const void* ifitem, const etMessage* msg){ |
| ET_MSC_LOGGER_SYNC_ENTRY("ATcpClient", "_receiveMessage") |
| ATcpClient_receiveEvent(self, (etPort*)ifitem, msg->evtID, (void*)(((char*)msg)+MEM_CEIL(sizeof(etMessage)))); |
| |
| ET_MSC_LOGGER_SYNC_EXIT |
| } |
| |
| |
| /*--------------------- user constructor/destructor ---------------------*/ |
| void ATcpClient_ctor(ATcpClient* self){ |
| /* user defined constructor body */ |
| setErrorCode(etInitSockets()); |
| client = etCreateSocketConnectionData(); |
| client->receiver = socketReceiver; |
| client->bufferProvider = bufferProvider; |
| client->userData = self; |
| } |
| |
| void ATcpClient_dtor(ATcpClient* self){ |
| /* user defined destructor body */ |
| etCloseSocket(client); |
| etCleanupSockets(); |
| etFreeSocketConnectionData(client); |
| } |
| |
| /*--------------------- operations ---------------------*/ |
| bool ATcpClient_hasError(ATcpClient* self) { |
| return lastError != ETSOCKET_OK; |
| } |
| void ATcpClient_setErrorCode(ATcpClient* self, int32 value) { |
| lastError = value; |
| } |
| |