sync/gen_statemachine.ysl2
author Edouard Tisserant <edouard@pep-project.org>
Mon, 20 Feb 2017 10:29:45 +0100
branchKeySyncWaitForAccept
changeset 1590 6e007351ccde
parent 1587 6db4fde2cdae
child 1595 ddf2993d75fe
permissions -rw-r--r--
KeySync : added composit state payload to hold multiple state parameters
vb@1513
     1
// This file is under GNU General Public License 3.0
vb@1513
     2
// see LICENSE.txt
vb@1513
     3
vb@577
     4
// generate state machine code
vb@577
     5
vb@577
     6
// Copyleft (c) 2016, p≡p foundation
vb@577
     7
vb@577
     8
// Written by Volker Birk
vb@577
     9
vb@577
    10
include yslt.yml2
vb@577
    11
vb@577
    12
tstylesheet {
edouard@1460
    13
    include standardlib.ysl2
vb@623
    14
    include ./functions.ysl2
Edouard@605
    15
vb@811
    16
    template "/protocol" {
edouard@1467
    17
        document "generated/Makefile.protocols", "text"
vb@811
    18
            apply "fsm", 0, mode="make";
vb@811
    19
        apply "fsm", 0, mode=gen;
vb@811
    20
    }
vb@811
    21
vb@811
    22
    template "fsm", mode=make
vb@811
    23
    ||
vb@811
    24
    «@filename»_fsm.c: ../sync/devicegroup.fsm
vb@811
    25
    \tmake -C ../«@filename»
vb@811
    26
    ||
vb@811
    27
vb@811
    28
    template "fsm", mode=gen {
edouard@1467
    29
        document "generated/{@filename}_fsm.h", "text" {
vb@609
    30
        ||
vb@609
    31
        #pragma once
vb@577
    32
vb@609
    33
        // state machine for «@name»
vb@577
    34
vb@1099
    35
        #include "message_api.h"
vb@654
    36
        
vb@654
    37
        #ifdef __cplusplus
vb@654
    38
        extern "C" {
vb@654
    39
        #endif
vb@608
    40
vb@609
    41
        // types
Edouard@605
    42
vb@609
    43
        typedef pEp_identity * Identity;
vb@939
    44
        typedef stringlist_t * Stringlist;
vb@583
    45
vb@609
    46
        // error values
vb@577
    47
vb@609
    48
        typedef enum _fsm_error {
vb@964
    49
            // these error values are corresponding to
vb@964
    50
            // PEP_SYNC_STATEMACHINE_ERROR - value
vb@743
    51
            invalid_state = -2,
vb@959
    52
            invalid_event = -3,
vb@959
    53
            invalid_condition = -4,
vb@964
    54
            invalid_action = -5,
vb@964
    55
vb@964
    56
            // out of memory condition
vb@964
    57
            invalid_out_of_memory = -128
vb@609
    58
        } fsm_error;
vb@583
    59
vb@951
    60
        // conditions
vb@951
    61
vb@959
    62
        `` for "func:distinctName(condition)" | int «@name»(PEP_SESSION session`apply "parm", 0`);
vb@951
    63
vb@609
    64
        // states
vb@578
    65
vb@609
    66
        typedef enum _«@name»_state {
vb@1043
    67
            // error values also in this namespace
vb@1043
    68
            «@name»_state_invalid_state = (int) invalid_state,
vb@1043
    69
            «@name»_state_invalid_event = (int) invalid_event,
vb@1043
    70
            «@name»_state_invalid_condition = (int) invalid_condition,
vb@1043
    71
            «@name»_state_invalid_action = (int) invalid_action,
vb@1043
    72
            «@name»_state_invalid_out_of_memory = (int) invalid_out_of_memory,
vb@1043
    73
vb@951
    74
            «@name»_state_NONE = 0,
vb@623
    75
        `` for "func:distinctName(state)" |> «@name»`if "position()!=last()" > , `
vb@609
    76
        } «@name»_state;
vb@583
    77
vb@609
    78
        // events
vb@578
    79
vb@609
    80
        typedef enum _«@name»_event {
vb@951
    81
            «@name»_event_NONE = 0,
vb@711
    82
        ||
vb@711
    83
        for "func:distinctName(state/event[not(not(/protocol/fsm/tag/@name=@name))])" {
vb@711
    84
            const "name", "@name";
vb@711
    85
            |> «$name» = «/protocol/fsm/tag[@name=$name]/@id»,
vb@711
    86
        }
vb@711
    87
        for "func:distinctName(state/event[not(/protocol/fsm/tag/@name=@name)])"
vb@711
    88
            |> «@name»`if "position()!=last()" > , `
vb@711
    89
        ||
vb@609
    90
        } «@name»_event;
vb@583
    91
vb@609
    92
        // actions
vb@582
    93
vb@690
    94
        `` const "name", "@name"
vb@939
    95
        `` for "func:distinctName(//action)" | PEP_STATUS «@name»(PEP_SESSION session, «$name»_state state, Identity partner, void *extra);
Edouard@605
    96
edouard@1205
    97
        // event injector
edouard@1205
    98
edouard@1205
    99
        PEP_STATUS inject_DeviceState_event(
edouard@1205
   100
            PEP_SESSION session, 
edouard@1205
   101
            DeviceState_event event,
edouard@1205
   102
            Identity partner,
edouard@1205
   103
            void *extra);
edouard@1205
   104
vb@951
   105
        // message receiver
vb@951
   106
        
edouard@1165
   107
        PEP_STATUS receive_DeviceState_msg(
edouard@1165
   108
                PEP_SESSION session, 
edouard@1165
   109
                message *src, 
edouard@1165
   110
                PEP_rating rating, 
edouard@1165
   111
                stringlist_t *keylist
edouard@1165
   112
            );
vb@951
   113
vb@626
   114
        // state machine
vb@626
   115
vb@626
   116
        «@name»_state fsm_«@name»(
vb@627
   117
                PEP_SESSION session,
vb@626
   118
                «@name»_state state,
vb@626
   119
                «@name»_event event,
vb@939
   120
                Identity partner,
edouard@1445
   121
                void *extra,
edouard@1445
   122
                time_t *timeout
vb@626
   123
            );
vb@626
   124
vb@609
   125
        // driver
Edouard@605
   126
vb@782
   127
        DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
vb@690
   128
                PEP_SESSION session,
vb@690
   129
                «@name»_event event,
vb@690
   130
                Identity partner,
edouard@1445
   131
                void *extra,
edouard@1445
   132
                time_t *timeout
vb@690
   133
            );
Edouard@605
   134
vb@654
   135
        #ifdef __cplusplus
vb@654
   136
        }
vb@654
   137
        #endif
vb@654
   138
vb@609
   139
        ||
vb@711
   140
        }
edouard@1467
   141
        document "generated/{@filename}_driver.c", "text"
vb@690
   142
        ||
vb@690
   143
        // Driver for «@name» state machine
vb@690
   144
vb@690
   145
        #include <assert.h>
vb@690
   146
        #include "pEp_internal.h"
vb@690
   147
vb@690
   148
vb@743
   149
        DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
vb@690
   150
                PEP_SESSION session,
vb@690
   151
                «@name»_event event,
vb@690
   152
                Identity partner,
edouard@1445
   153
                void *extra,
edouard@1445
   154
                time_t *timeout
vb@690
   155
            )
vb@690
   156
        {
vb@951
   157
            assert(session);
vb@951
   158
            if (!session)
vb@951
   159
                return PEP_ILLEGAL_VALUE;
vb@690
   160
edouard@1152
   161
            while(true)
edouard@1152
   162
            {
edouard@1152
   163
                «@name»_state new_state = fsm_«@name»(session,
edouard@1445
   164
                    session->«@filename»_state, event, partner, extra, timeout);
edouard@1157
   165
edouard@1152
   166
                if (new_state == «@name»_state_invalid_out_of_memory)
edouard@1152
   167
                    return PEP_OUT_OF_MEMORY;
edouard@1157
   168
edouard@1152
   169
                if (new_state < 0)
edouard@1152
   170
                    return PEP_SYNC_STATEMACHINE_ERROR - new_state;
edouard@1152
   171
                
edouard@1157
   172
                if (new_state == session->«@filename»_state)
edouard@1152
   173
                    break;
vb@690
   174
edouard@1157
   175
                event = Init;
edouard@1157
   176
                extra = NULL;
edouard@1152
   177
                session->«@filename»_state = new_state;
edouard@1152
   178
            } 
edouard@1152
   179
vb@951
   180
            return PEP_STATUS_OK;
vb@690
   181
        }
vb@690
   182
vb@690
   183
        ||
edouard@1467
   184
        document "generated/{@filename}_fsm.c", "text"
vb@609
   185
        ||
vb@1476
   186
        #include "pEp_internal.h"
vb@807
   187
        #include "«@filename»_fsm.h"
vb@609
   188
edouard@1590
   189
        // local definitions for «@name»'s state machine 
edouard@1590
   190
edouard@1590
   191
        `` apply "state", 2 mode="declStatePayload"
edouard@1590
   192
vb@609
   193
        // state machine for «@name»
vb@609
   194
vb@609
   195
        «@name»_state fsm_«@name»(
vb@627
   196
                PEP_SESSION session,
vb@609
   197
                «@name»_state state,
vb@609
   198
                «@name»_event event,
vb@939
   199
                Identity partner,
edouard@1445
   200
                void *extra,
edouard@1445
   201
                time_t *timeout
vb@609
   202
            )
vb@609
   203
        {
vb@964
   204
            int cond_result;
vb@959
   205
            PEP_STATUS status = PEP_STATUS_OK;
vb@959
   206
vb@609
   207
            switch (state) {
vb@951
   208
            `` apply "state", 2
vb@609
   209
                default:
vb@743
   210
                    return («@name»_state) invalid_state;
vb@609
   211
            }
vb@609
   212
vb@609
   213
            return state;
vb@577
   214
        }
vb@582
   215
vb@609
   216
        ||
vb@577
   217
    }
vb@577
   218
edouard@1590
   219
    template "state" {
edouard@1590
   220
        ||
edouard@1590
   221
        case «@name»:
edouard@1590
   222
        {
edouard@1590
   223
            DEBUG_LOG("Entering FSM state", "«../@filename»_fsm.c", "state=«@name»")
edouard@1590
   224
        ||
edouard@1590
   225
edouard@1590
   226
        if "count(parm) > 0" 
edouard@1590
   227
        || 
edouard@1590
   228
            assert(session->sync_state_payload);
edouard@1590
   229
            if(!session->sync_state_payload) return («../@name»_state) invalid_state;
edouard@1590
   230
            `` apply "parm", 1 mode="unpackStatePayloadParm" with "stateName", "@name"
edouard@1590
   231
        ||
edouard@1590
   232
edouard@1590
   233
        ||
edouard@1590
   234
            *timeout = «@timeout»;
edouard@1590
   235
            switch (event) {
edouard@1590
   236
        ||
edouard@1590
   237
edouard@1590
   238
        if "not(event[@name='Init'])" 
edouard@1590
   239
        ||
edouard@1590
   240
                case Init: 
edouard@1590
   241
                    DEBUG_LOG("FSM event", "«../@filename»_fsm.c, state=«@name»", "event=Init") 
edouard@1590
   242
                    break;
edouard@1590
   243
        ||
edouard@1590
   244
edouard@1590
   245
        apply "event", 2;
edouard@1590
   246
edouard@1590
   247
        ||
edouard@1590
   248
                default:
edouard@1590
   249
                    return («../@name»_state) invalid_event;
edouard@1590
   250
            }
edouard@1590
   251
            break;
edouard@1590
   252
        }
edouard@1590
   253
        ||
edouard@1590
   254
    }
edouard@1590
   255
edouard@1590
   256
    template "parm" mode="unpackStatePayloadParm" 
edouard@1590
   257
    {
edouard@1590
   258
        param "stateName";
edouard@1590
   259
        | «name(*[1])» «name(*[2])» = ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»;
edouard@1590
   260
    }
edouard@1590
   261
edouard@1590
   262
    template "state" mode="declStatePayload" if "count(parm) > 0"
vb@577
   263
    ||
edouard@1590
   264
    typedef struct _«@name»_state_payload {
edouard@1590
   265
        `` apply "parm", 1 mode="declStatePayloadParm"
edouard@1590
   266
    } «@name»_state_payload_t;
edouard@1590
   267
edouard@1460
   268
    ||
vb@577
   269
edouard@1590
   270
    template "parm" mode="declStatePayloadParm" 
edouard@1590
   271
    | «name(*[1])» «name(*[2])»;
vb@578
   272
vb@578
   273
    template "event"
vb@578
   274
    ||
vb@578
   275
    case «@name»:
edouard@1460
   276
    {
edouard@1490
   277
        DEBUG_LOG("FSM event", "«../../@filename»_fsm.c, state=«../@name»", "event=«@name»")
vb@951
   278
    `` apply "action|transition|condition";
vb@582
   279
    `` if "name(*[position()=last()]) != 'transition'" |> break;
edouard@1460
   280
    }
vb@578
   281
    ||
vb@578
   282
vb@582
   283
    template "action" {
edouard@1490
   284
        | DEBUG_LOG("FSM action", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "action=«@name»")
vb@582
   285
        indent(0);
vb@959
   286
        > status = «@name»(session, state, 
vb@582
   287
        choose {
vb@582
   288
            when "parm" > «name(parm/*)»
vb@582
   289
            otherwise > NULL
vb@582
   290
        }
edouard@1166
   291
        choose {
edouard@1166
   292
            when "parm[2]" > , extra /*«name(parm[2]/*)»*/
edouard@1166
   293
            otherwise > , NULL
edouard@1166
   294
        }
edouard@1166
   295
        > );\n
vb@964
   296
        | if (status == PEP_OUT_OF_MEMORY)
vb@1043
   297
        |> return (int) invalid_out_of_memory;
vb@959
   298
        | if (status != PEP_STATUS_OK)
vb@1043
   299
        |> return (int) invalid_action;
vb@582
   300
    }
vb@582
   301
vb@951
   302
    template "condition" {
vb@959
   303
        | cond_result = «@name»(session`apply "parm", 0`);
edouard@1490
   304
        | #ifndef NDEBUG
edouard@1490
   305
        | char resstr[11] = {0,};
edouard@1490
   306
        | snprintf(resstr,10,"result=%d",cond_result);
edouard@1490
   307
        | #endif
edouard@1490
   308
        | DEBUG_LOG("FSM condition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name», condition=«@name»", resstr)
vb@964
   309
        | if (cond_result < 0)
vb@964
   310
        |> return cond_result;
vb@959
   311
        | if (cond_result) {
vb@951
   312
        apply "action|transition|condition";
vb@951
   313
        | }
edouard@1477
   314
        const "else", "./following-sibling::*[position()=1][name(.)='else']";
edouard@1477
   315
        if "$else" {
edouard@1477
   316
        | else {
edouard@1477
   317
        apply "$else/action|transition|condition";
edouard@1477
   318
        | }
edouard@1477
   319
        }
vb@951
   320
    }
vb@951
   321
vb@951
   322
    template "parm" choose {
vb@951
   323
        when "count(*) = 1"
vb@951
   324
            > , «name(*)»
vb@951
   325
        otherwise
vb@951
   326
            > , «name(*[1])» «name(*[2])»
vb@951
   327
    }
vb@951
   328
edouard@1460
   329
    template "transition"{
edouard@1460
   330
        const "stateparm", "ancestor::state/child::parm";
edouard@1590
   331
        if "count($stateparm) > 0" {
edouard@1590
   332
            ||
edouard@1590
   333
            assert(session->sync_state_payload);
edouard@1590
   334
            if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_state;
edouard@1590
   335
            `` apply "$stateparm", 0 mode="freeStatePayloadParm" with "stateName", "ancestor::state/@name"
edouard@1590
   336
            free(session->sync_state_payload);
edouard@1590
   337
            session->sync_state_payload = NULL;
edouard@1590
   338
            ||
edouard@1460
   339
        }
edouard@1590
   340
        if "count(parm) > 0" {
edouard@1460
   341
            const "nextstatename", "@target";
edouard@1460
   342
            const "nextstateparm", "ancestor::fsm/child::state[@name = $nextstatename]/child::parm";
edouard@1590
   343
            if "count(parm) != count($nextstateparm)" 
edouard@1590
   344
                error > different state parameters and transition parameters count state=«ancestor::state/@name», event=«ancestor::event/@name» target=«@target»
edouard@1590
   345
            ||
edouard@1590
   346
            session->sync_state_payload = malloc(sizeof(«$nextstatename»_state_payload_t));
edouard@1590
   347
            assert(session->sync_state_payload);
edouard@1590
   348
            if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_out_of_memory;
edouard@1590
   349
            ||
edouard@1590
   350
            apply "$nextstateparm", 0 mode="dupStatePayloadParm" {
edouard@1590
   351
                with "stateName", "$nextstatename";
edouard@1590
   352
                with "transitionParms", "parm";
edouard@1590
   353
            }
edouard@1460
   354
        }
edouard@1490
   355
        | DEBUG_LOG("FSM transition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "target=«@target»")
edouard@1460
   356
        | return «@target»;
edouard@1460
   357
    }
edouard@1590
   358
edouard@1590
   359
    template "parm" mode="freeStatePayloadParm" 
edouard@1590
   360
    {
edouard@1590
   361
        param "stateName";
edouard@1590
   362
        | free_«yml:lcase(name(*[1]))»(((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»);
edouard@1590
   363
    }
edouard@1590
   364
edouard@1590
   365
    template "parm" mode="dupStatePayloadParm" 
edouard@1590
   366
    {
edouard@1590
   367
        param "stateName";
edouard@1590
   368
        param "transitionParms";
edouard@1590
   369
        | ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])» =
edouard@1590
   370
        |     «yml:lcase(name(*[1]))»_dup(«name($transitionParms[position()]/*)»);
edouard@1590
   371
    }
vb@577
   372
}
vb@577
   373