sync/gen_statemachine.ysl2
author Edouard Tisserant <edouard@pep-project.org>
Fri, 17 Feb 2017 19:51:04 +0100
branchGroupMerge
changeset 1587 6db4fde2cdae
parent 1513 e7f7e42385b5
child 1590 6e007351ccde
permissions -rw-r--r--
KeySync: fixed problem with GroupKeys events not being generated. Added better memory handling policy for keysync events extras.
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
vb@609
   189
        // state machine for «@name»
vb@609
   190
vb@609
   191
        «@name»_state fsm_«@name»(
vb@627
   192
                PEP_SESSION session,
vb@609
   193
                «@name»_state state,
vb@609
   194
                «@name»_event event,
vb@939
   195
                Identity partner,
edouard@1445
   196
                void *extra,
edouard@1445
   197
                time_t *timeout
vb@609
   198
            )
vb@609
   199
        {
vb@964
   200
            int cond_result;
vb@959
   201
            PEP_STATUS status = PEP_STATUS_OK;
vb@959
   202
vb@609
   203
            switch (state) {
vb@951
   204
            `` apply "state", 2
vb@609
   205
                default:
vb@743
   206
                    return («@name»_state) invalid_state;
vb@609
   207
            }
vb@609
   208
vb@609
   209
            return state;
vb@577
   210
        }
vb@582
   211
vb@609
   212
        ||
vb@577
   213
    }
vb@577
   214
vb@580
   215
    template "state"
vb@577
   216
    ||
vb@577
   217
    case «@name»:
edouard@1460
   218
    {
edouard@1460
   219
        `` if "count(parm) > 1" error | # TODO composite state payload 
edouard@1460
   220
        `` apply "parm", 1 mode="stateParm"
edouard@1445
   221
        *timeout = «@timeout»;
edouard@1490
   222
        DEBUG_LOG("Entering FSM state", "«../@filename»_fsm.c", "state=«@name»")
vb@578
   223
        switch (event) {
edouard@1490
   224
        `` if "not(event[@name='Init'])" |>> case Init: DEBUG_LOG("FSM event", "«../@filename»_fsm.c, state=«@name»", "event=Init") break;
vb@578
   225
        `` apply "event", 2
vb@951
   226
            default:
vb@951
   227
                return («../@name»_state) invalid_event;
vb@578
   228
        }
vb@577
   229
        break;
edouard@1460
   230
    }
edouard@1460
   231
    ||
vb@577
   232
edouard@1460
   233
    template "parm" mode="stateParm" 
edouard@1460
   234
    {
edouard@1460
   235
        | «name(*[1])» «name(*[2])» = («name(*[1])»)session->sync_state_payload;
edouard@1460
   236
    }
vb@578
   237
vb@578
   238
    template "event"
vb@578
   239
    ||
vb@578
   240
    case «@name»:
edouard@1460
   241
    {
edouard@1490
   242
        DEBUG_LOG("FSM event", "«../../@filename»_fsm.c, state=«../@name»", "event=«@name»")
vb@951
   243
    `` apply "action|transition|condition";
vb@582
   244
    `` if "name(*[position()=last()]) != 'transition'" |> break;
edouard@1460
   245
    }
vb@578
   246
    ||
vb@578
   247
vb@582
   248
    template "action" {
edouard@1490
   249
        | DEBUG_LOG("FSM action", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "action=«@name»")
vb@582
   250
        indent(0);
vb@959
   251
        > status = «@name»(session, state, 
vb@582
   252
        choose {
vb@582
   253
            when "parm" > «name(parm/*)»
vb@582
   254
            otherwise > NULL
vb@582
   255
        }
edouard@1166
   256
        choose {
edouard@1166
   257
            when "parm[2]" > , extra /*«name(parm[2]/*)»*/
edouard@1166
   258
            otherwise > , NULL
edouard@1166
   259
        }
edouard@1166
   260
        > );\n
vb@964
   261
        | if (status == PEP_OUT_OF_MEMORY)
vb@1043
   262
        |> return (int) invalid_out_of_memory;
vb@959
   263
        | if (status != PEP_STATUS_OK)
vb@1043
   264
        |> return (int) invalid_action;
vb@582
   265
    }
vb@582
   266
vb@951
   267
    template "condition" {
vb@959
   268
        | cond_result = «@name»(session`apply "parm", 0`);
edouard@1490
   269
        | #ifndef NDEBUG
edouard@1490
   270
        | char resstr[11] = {0,};
edouard@1490
   271
        | snprintf(resstr,10,"result=%d",cond_result);
edouard@1490
   272
        | #endif
edouard@1490
   273
        | DEBUG_LOG("FSM condition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name», condition=«@name»", resstr)
vb@964
   274
        | if (cond_result < 0)
vb@964
   275
        |> return cond_result;
vb@959
   276
        | if (cond_result) {
vb@951
   277
        apply "action|transition|condition";
vb@951
   278
        | }
edouard@1477
   279
        const "else", "./following-sibling::*[position()=1][name(.)='else']";
edouard@1477
   280
        if "$else" {
edouard@1477
   281
        | else {
edouard@1477
   282
        apply "$else/action|transition|condition";
edouard@1477
   283
        | }
edouard@1477
   284
        }
vb@951
   285
    }
vb@951
   286
vb@951
   287
    template "parm" choose {
vb@951
   288
        when "count(*) = 1"
vb@951
   289
            > , «name(*)»
vb@951
   290
        otherwise
vb@951
   291
            > , «name(*[1])» «name(*[2])»
vb@951
   292
    }
vb@951
   293
edouard@1460
   294
    template "transition"{
edouard@1460
   295
        const "stateparm", "ancestor::state/child::parm";
edouard@1460
   296
        if "$stateparm" {
edouard@1460
   297
            | if(session->sync_state_payload){
edouard@1460
   298
            |     free_«yml:lcase(name($stateparm[1]/*))»((«name($stateparm[1]/*)»)session->sync_state_payload);
edouard@1460
   299
            |     session->sync_state_payload = NULL;
edouard@1460
   300
            | }
edouard@1460
   301
        }
edouard@1460
   302
        if "parm" {
edouard@1460
   303
            const "nextstatename", "@target";
edouard@1460
   304
            const "nextstateparm", "ancestor::fsm/child::state[@name = $nextstatename]/child::parm";
edouard@1460
   305
            | session->sync_state_payload = «yml:lcase(name($nextstateparm/*))»_dup(«name(parm/*)»);
edouard@1460
   306
        }
edouard@1490
   307
        | DEBUG_LOG("FSM transition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "target=«@target»")
edouard@1460
   308
        | return «@target»;
edouard@1460
   309
    }
vb@577
   310
}
vb@577
   311