Subversion Repositories HomeAutomation

Rev

Rev 1535 | Rev 1538 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
1503 myhrman 1
/*-----------------------------------------------------------------------------
2
 * Includes
3
 *---------------------------------------------------------------------------*/
4
#include "act_protectedOutput.h"
5
 
6
 
7
/*-----------------------------------------------------------------------------
8
 * Defines
9
 *---------------------------------------------------------------------------*/
10
 
1532 myhrman 11
// make sure all config params are present
1528 myhrman 12
 
1532 myhrman 13
#ifndef act_protectedOutput_CH_COUNT
14
#error Config value missing: "act_protectedOutput_CH_COUNT"
15
#endif
1528 myhrman 16
 
1532 myhrman 17
#ifndef act_protectedOutput_EEPROM_ENABLED
18
#error Config value missing: "act_protectedOutput_EEPROM_ENABLED"
19
#endif
1528 myhrman 20
 
1532 myhrman 21
#if act_protectedOutput_CH_COUNT >= 1
22
#ifndef act_protectedOutput_CH0
23
#error Config value missing: "act_protectedOutput_CH0"
24
#endif
25
#ifndef act_protectedOutput_CH0_POLARITY
26
#error Config value missing: "act_protectedOutput_CH0_POLARITY"
27
#endif
28
#endif
29
 
30
#if act_protectedOutput_CH_COUNT >= 2
31
#ifndef act_protectedOutput_CH1
32
#error Config value missing: "act_protectedOutput_CH1"
33
#endif
34
#ifndef act_protectedOutput_CH1_POLARITY
35
#error Config value missing: "act_protectedOutput_CH1_POLARITY"
36
#endif
37
#endif
38
 
39
#if act_protectedOutput_CH_COUNT >= 3
40
#ifndef act_protectedOutput_CH2
41
#error Config value missing: "act_protectedOutput_CH2"
42
#endif
43
#ifndef act_protectedOutput_CH2_POLARITY
44
#error Config value missing: "act_protectedOutput_CH2_POLARITY"
45
#endif
46
#endif
47
 
48
#if act_protectedOutput_CH_COUNT >= 4
49
#ifndef act_protectedOutput_CH3
50
#error Config value missing: "act_protectedOutput_CH3"
51
#endif
52
#ifndef act_protectedOutput_CH3_POLARITY
53
#error Config value missing: "act_protectedOutput_CH3_POLARITY"
54
#endif
55
#endif
56
 
57
#if act_protectedOutput_CH_COUNT >= 5
58
#error Config value out of range: "act_protectedOutput_CH_COUNT"
59
#endif
60
 
61
#define CH0_ON      (act_protectedOutput_CH0_POLARITY)
62
#define CH0_OFF     (1 - CH0_ON)
63
#define CH0_PIN     act_protectedOutput_CH0
64
 
65
#define CH1_ON      (act_protectedOutput_CH1_POLARITY)
66
#define CH1_OFF     (1 - CH1_ON)
67
#define CH1_PIN     act_protectedOutput_CH1
68
 
69
#define CH2_ON      (act_protectedOutput_CH2_POLARITY)
70
#define CH2_OFF     (1 - CH2_ON)
71
#define CH2_PIN     act_protectedOutput_CH2
72
 
73
#define CH3_ON      (act_protectedOutput_CH3_POLARITY)
74
#define CH3_OFF     (1 - CH3_ON)
75
#define CH3_PIN     act_protectedOutput_CH3
76
 
77
#define DIAG_ASSERTED   (act_protectedOutput_DIAG_PIN_POLARITY)
1503 myhrman 78
#define DIAG_NORMAL     (1 - DIAG_ASSERTED)
79
#define DIAG_PIN        act_protectedOutput_DIAG_PIN
80
 
81
 
82
/*-----------------------------------------------------------------------------
83
 * Types
84
 *---------------------------------------------------------------------------*/
85
 
86
 
1532 myhrman 87
#if act_protectedOutput_EEPROM_ENABLED == 1
88
#include "act_protectedOutput_eeprom.h"
89
struct eeprom_act_protectedOutput EEMEM eeprom_act_protectedOutput =
90
{
91
    {
92
        ///TODO: Define initialization values on the EEPROM variables here, this will generate a *.eep file that can be used to store this values to the node, can in future be done with a EEPROM module and the make-scrips. Write the values in the exact same order as the struct is defined in the *.h file.
93
#if act_protectedOutput_CH_COUNT >= 1
94
        0x00,
95
#endif
96
#if act_protectedOutput_CH_COUNT >= 2
97
        0x00,
98
#endif
99
#if act_protectedOutput_CH_COUNT >= 3
100
        0x00,
101
#endif
102
#if act_protectedOutput_CH_COUNT >= 4
103
        0x00,
104
#endif
105
    },
106
 
107
};
108
#endif
109
 
110
 
1503 myhrman 111
/*-----------------------------------------------------------------------------
112
 * Variables
113
 *---------------------------------------------------------------------------*/
1528 myhrman 114
 
1537 myhrman 115
static uint8_t chTargetState[act_protectedOutput_CH_COUNT];
1503 myhrman 116
static uint8_t diagState = DIAG_NORMAL;
117
 
118
// is there a recent status change that we should report via CAN?
119
static uint8_t diagReportPending = 0;
120
 
121
 
122
/*-----------------------------------------------------------------------------
123
 * Internal Function Prototypes
124
 *---------------------------------------------------------------------------*/
1537 myhrman 125
static void updateOutput(uint8_t skipDiagCheck);
1503 myhrman 126
static void readDiagPin(void);
127
static void pcIntCallback(uint8_t id, uint8_t status);
128
 
129
 
130
/*-----------------------------------------------------------------------------
131
 * Function Implementations
132
 *---------------------------------------------------------------------------*/
133
 
1537 myhrman 134
static void updateOutput(uint8_t skipDiagCheck) {
1528 myhrman 135
 
1532 myhrman 136
    #if act_protectedOutput_CH_COUNT >= 1
1537 myhrman 137
    if (chTargetState[0] == 0) {
1532 myhrman 138
        gpio_set_statement(CH0_OFF, CH0_PIN);
1503 myhrman 139
    }
1537 myhrman 140
    else if (chTargetState[0] == 1) {
141
        if (diagState == DIAG_NORMAL || skipDiagCheck) {
1532 myhrman 142
            gpio_set_statement(CH0_ON, CH0_PIN);
1503 myhrman 143
        }
144
        else {
145
            // DIAG override, we cannot set ON state right now
1532 myhrman 146
            gpio_set_statement(CH0_OFF, CH0_PIN);
1503 myhrman 147
        }
148
    }
1528 myhrman 149
    #endif
150
 
1532 myhrman 151
    #if act_protectedOutput_CH_COUNT >= 2
1537 myhrman 152
    if (chTargetState[1] == 0) {
1532 myhrman 153
        gpio_set_statement(CH1_OFF, CH1_PIN);
1528 myhrman 154
    }
1537 myhrman 155
    else if (chTargetState[1] == 1) {
156
        if (diagState == DIAG_NORMAL || skipDiagCheck) {
1532 myhrman 157
            gpio_set_statement(CH1_ON, CH1_PIN);
1528 myhrman 158
        }
159
        else {
160
            // DIAG override, we cannot set ON state right now
1532 myhrman 161
            gpio_set_statement(CH1_OFF, CH1_PIN);
1528 myhrman 162
        }
163
    }
164
    #endif
165
 
1532 myhrman 166
    #if act_protectedOutput_CH_COUNT >= 3
1537 myhrman 167
    if (chTargetState[2] == 0) {
1532 myhrman 168
        gpio_set_statement(CH2_OFF, CH2_PIN);
1528 myhrman 169
    }
1537 myhrman 170
    else if (chTargetState[2] == 1) {
171
        if (diagState == DIAG_NORMAL || skipDiagCheck) {
1532 myhrman 172
            gpio_set_statement(CH2_ON, CH2_PIN);
1528 myhrman 173
        }
174
        else {
175
            // DIAG override, we cannot set ON state right now
1532 myhrman 176
            gpio_set_statement(CH2_OFF, CH2_PIN);
1528 myhrman 177
        }
178
    }
179
    #endif
180
 
1532 myhrman 181
    #if act_protectedOutput_CH_COUNT >= 4
1537 myhrman 182
    if (chTargetState[3] == 0) {
1532 myhrman 183
        gpio_set_statement(CH3_OFF, CH3_PIN);
1528 myhrman 184
    }
1537 myhrman 185
    else if (chTargetState[3] == 1) {
186
        if (diagState == DIAG_NORMAL || skipDiagCheck) {
1532 myhrman 187
            gpio_set_statement(CH3_ON, CH3_PIN);
1528 myhrman 188
        }
189
        else {
190
            // DIAG override, we cannot set ON state right now
1532 myhrman 191
            gpio_set_statement(CH3_OFF, CH3_PIN);
1528 myhrman 192
        }
193
    }
194
    #endif
1503 myhrman 195
}
196
 
197
 
198
static void readDiagPin() {
199
    diagState = gpio_get_state(DIAG_PIN);
200
}
201
 
202
 
203
static void pcIntCallback(uint8_t id, uint8_t status) {
204
    // new state of the DIAG pin?
205
    if (id == act_protectedOutput_DIAG_PIN_PCINT) {
206
        diagState = status;
1537 myhrman 207
        updateOutput(0);
1503 myhrman 208
        // DIAG asserted?
209
        if (diagState == DIAG_ASSERTED) {
210
            // if retry-timer mechanism is enabled, initiate timer
211
            if (act_protectedOutput_RETRY_TIMER_TIME_S > 0) {
212
                Timer_SetTimeout(act_protectedOutput_RETRY_TIMER, act_protectedOutput_RETRY_TIMER_TIME_S*1000, TimerTypeOneShot, 0);
213
            }
214
            // if the retry-mechanism is disabled, change the target output state to OFF
215
            else {
1532 myhrman 216
                for (uint8_t i=0; i<act_protectedOutput_CH_COUNT; i++) {
1537 myhrman 217
                    chTargetState[i] = 0;
1528 myhrman 218
                }
1537 myhrman 219
#if act_protectedOutput_EEPROM_ENABLED == 1
220
                // output states changed, store to EE after this timer delay
221
                Timer_SetTimeout(act_protectedOutput_STORE_VALUE_TIMEOUT, act_protectedOutput_STORE_VALUE_TIMEOUT_TIME_S*1000, TimerTypeOneShot, 0);
222
#endif
1503 myhrman 223
            }
224
        }
225
        // something interesting obviously happened. let's report it
226
        diagReportPending = 1;
227
    }
228
}
229
 
230
 
231
void act_protectedOutput_Init() {
1528 myhrman 232
    /*
1532 myhrman 233
     * Init target state vector, in case EEPROM is disabled
234
     */
235
    for (uint8_t i=0; i<act_protectedOutput_CH_COUNT; i++) {
1537 myhrman 236
        chTargetState[i] = 0;
1532 myhrman 237
    }
238
 
239
    /*
1528 myhrman 240
     * Configure DIAG input pin
241
     */
1503 myhrman 242
    if (act_protectedOutput_DIAG_PIN_PULL_ENABLED) {
243
        // if DIAG is asserted low, we need pull-up
1532 myhrman 244
        gpio_set_statement(act_protectedOutput_DIAG_PIN_POLARITY == 0 ? 1 : 0, DIAG_PIN);
1503 myhrman 245
    }
246
    gpio_set_in(DIAG_PIN);
247
    Pcint_SetCallbackPin(act_protectedOutput_DIAG_PIN_PCINT, DIAG_PIN, &pcIntCallback);
248
 
1528 myhrman 249
    /*
1532 myhrman 250
     * Read EEPROM data
251
     */
1535 myhrman 252
#if act_protectedOutput_EEPROM_ENABLED == 1
1534 myhrman 253
    if (EEDATA_OK) {
1532 myhrman 254
#if act_protectedOutput_CH_COUNT >= 1
1537 myhrman 255
      chTargetState[0] = eeprom_read_byte(EEDATA.ch0);
1532 myhrman 256
#endif
257
#if act_protectedOutput_CH_COUNT >= 2
1537 myhrman 258
      chTargetState[1] = eeprom_read_byte(EEDATA.ch1);
1532 myhrman 259
#endif
260
#if act_protectedOutput_CH_COUNT >= 3
1537 myhrman 261
      chTargetState[2] = eeprom_read_byte(EEDATA.ch2);
1532 myhrman 262
#endif
263
#if act_protectedOutput_CH_COUNT >= 4
1537 myhrman 264
      chTargetState[3] = eeprom_read_byte(EEDATA.ch3);
1532 myhrman 265
#endif
266
    }
267
    else {
268
        //The CRC of the EEPROM is not correct, store default values and update CRC
269
#if act_protectedOutput_CH_COUNT >= 1
270
        eeprom_write_byte_crc(EEDATA.ch0, 0x00, WITHOUT_CRC);
271
#endif
272
#if act_protectedOutput_CH_COUNT >= 2
273
        eeprom_write_byte_crc(EEDATA.ch1, 0x00, WITHOUT_CRC);
274
#endif
275
#if act_protectedOutput_CH_COUNT >= 3
276
        eeprom_write_byte_crc(EEDATA.ch2, 0x00, WITHOUT_CRC);
277
#endif
278
#if act_protectedOutput_CH_COUNT >= 4
279
        eeprom_write_byte_crc(EEDATA.ch3, 0x00, WITHOUT_CRC);
280
#endif
281
        EEDATA_UPDATE_CRC;
282
    }
283
#endif
284
 
285
    /*
1528 myhrman 286
     * Configure OUTPUT pins
287
     */
1532 myhrman 288
    #if act_protectedOutput_CH_COUNT >= 1
289
    gpio_set_statement(CH0_OFF, CH0_PIN);
290
    gpio_set_out(act_protectedOutput_CH0);
1528 myhrman 291
    #endif
1503 myhrman 292
 
1532 myhrman 293
    #if act_protectedOutput_CH_COUNT >= 2
294
    gpio_set_statement(CH1_OFF, CH1_PIN);
295
    gpio_set_out(act_protectedOutput_CH1);
1528 myhrman 296
    #endif
297
 
1532 myhrman 298
    #if act_protectedOutput_CH_COUNT >= 3
299
    gpio_set_statement(CH2_OFF, CH2_PIN);
300
    gpio_set_out(act_protectedOutput_CH2);
1528 myhrman 301
    #endif
302
 
1532 myhrman 303
    #if act_protectedOutput_CH_COUNT >= 4
304
    gpio_set_statement(CH3_OFF, CH3_PIN);
305
    gpio_set_out(act_protectedOutput_CH3);
1528 myhrman 306
    #endif
307
 
1503 myhrman 308
    diagState = DIAG_NORMAL;
309
}
310
 
311
 
312
void act_protectedOutput_Process() {
313
 
1535 myhrman 314
#if act_protectedOutput_EEPROM_ENABLED == 1
1534 myhrman 315
    if (Timer_Expired(act_protectedOutput_STORE_VALUE_TIMEOUT)) {
316
#if act_protectedOutput_CH_COUNT >= 1
1537 myhrman 317
        eeprom_write_byte_crc(EEDATA.ch0, chTargetState[0], WITHOUT_CRC);
1534 myhrman 318
#endif
319
#if act_protectedOutput_CH_COUNT >= 2
1537 myhrman 320
        eeprom_write_byte_crc(EEDATA.ch1, chTargetState[1], WITHOUT_CRC);
1534 myhrman 321
#endif
322
#if act_protectedOutput_CH_COUNT >= 3
1537 myhrman 323
        eeprom_write_byte_crc(EEDATA.ch2, chTargetState[2], WITHOUT_CRC);
1534 myhrman 324
#endif
325
#if act_protectedOutput_CH_COUNT >= 4
1537 myhrman 326
        eeprom_write_byte_crc(EEDATA.ch3, chTargetState[3], WITHOUT_CRC);
1534 myhrman 327
#endif
328
        EEDATA_UPDATE_CRC;
329
    }
1535 myhrman 330
#endif
1534 myhrman 331
 
1503 myhrman 332
    // shall we retry to set target output state?
333
    if (Timer_Expired(act_protectedOutput_RETRY_TIMER)) {
334
        // read DIAG pin again and update outputs accordingly
335
        readDiagPin();
1537 myhrman 336
#if act_protectedOutput_FORCED_RETRIES == 1
337
        // forced retry to set output states, regardless of DIAG
338
        updateOutput(1);
339
        // read DIAG pin again and hope we have a better flag
340
        readDiagPin();
341
#else
342
        // if DIAG allows it, retry to set the output states
343
        updateOutput(0);
344
#endif
1512 myhrman 345
        if (diagState == DIAG_ASSERTED) {
346
            // if DIAG was still asserted, initiate another timer run
347
            Timer_SetTimeout(act_protectedOutput_RETRY_TIMER, act_protectedOutput_RETRY_TIMER_TIME_S*1000, TimerTypeOneShot, 0);
348
        }
349
        else {
350
            // things went back to normal. report this
351
            diagReportPending = 1;
352
        }
1503 myhrman 353
    }
354
 
355
    // shall we report diag status to CAN?
356
    if (diagReportPending) {
357
        StdCan_Msg_t txMsg;
358
        StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
359
        StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
1511 arune 360
        txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
1504 myhrman 361
        txMsg.Header.ModuleId = act_protectedOutput_ID;
1503 myhrman 362
        txMsg.Header.Command = CAN_MODULE_CMD_PHYSICAL_PINSTATUS;
363
        txMsg.Length = 2;
364
        txMsg.Data[0] = 0; //TODO: add support for more channels
365
        // we follow the standard SNS_INPUT format, but the data corresponds to the "health" rather than physical level
366
        if (diagState == DIAG_NORMAL) {
367
            txMsg.Data[1] = 1;  //healthy, target output state stable
368
        } else {
369
            txMsg.Data[1] = 0;  //not healthy, DIAG pin ASSERTED, not in target output state
370
        }
371
        while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
372
        diagReportPending = 0;
373
    }
374
}
375
 
376
 
377
void act_protectedOutput_HandleMessage(StdCan_Msg_t *rxMsg) {
378
    if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_ACT &&
379
        StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
1511 arune 380
        rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT &&
1503 myhrman 381
        rxMsg->Header.ModuleId == act_protectedOutput_ID)
382
    {
383
        switch (rxMsg->Header.Command) {
384
 
385
            case CAN_MODULE_CMD_PHYSICAL_SETPIN:
1532 myhrman 386
                /*
387
                 * This message is used to activate/deactivate
388
                 * an output channel.
389
                 */
1503 myhrman 390
                if (rxMsg->Length == 2) {
1528 myhrman 391
                    uint8_t channel = rxMsg->Data[0];
1532 myhrman 392
                    if (channel >= 0 && channel < act_protectedOutput_CH_COUNT) {
1537 myhrman 393
                        chTargetState[channel] = rxMsg->Data[1];
1503 myhrman 394
                        readDiagPin();
1537 myhrman 395
#if act_protectedOutput_FORCED_RETRIES == 1
396
                        updateOutput(1);
397
#else
398
                        updateOutput(0);
399
#endif
1535 myhrman 400
#if act_protectedOutput_EEPROM_ENABLED == 1
1537 myhrman 401
                        // output states changed, store to EE after this timer delay
1534 myhrman 402
                        Timer_SetTimeout(act_protectedOutput_STORE_VALUE_TIMEOUT, act_protectedOutput_STORE_VALUE_TIMEOUT_TIME_S*1000, TimerTypeOneShot, 0);
1535 myhrman 403
#endif
1537 myhrman 404
                    }
1503 myhrman 405
                    StdCan_Set_direction(rxMsg->Header, DIRECTIONFLAG_FROM_OWNER);
406
                    rxMsg->Length = 2;
407
                    while (StdCan_Put(rxMsg) != StdCan_Ret_OK);
408
                }
409
                break;
410
        }
411
    }
412
}
413
 
414
 
415
void act_protectedOutput_List(uint8_t ModuleSequenceNumber)
416
{
417
    StdCan_Msg_t txMsg;
418
    StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_ACT);
419
    StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
1511 arune 420
    txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
1503 myhrman 421
    txMsg.Header.ModuleId = act_protectedOutput_ID;
422
    txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
423
    txMsg.Length = 6;
424
 
425
    txMsg.Data[0] = NODE_HW_ID_BYTE0;
426
    txMsg.Data[1] = NODE_HW_ID_BYTE1;
427
    txMsg.Data[2] = NODE_HW_ID_BYTE2;
428
    txMsg.Data[3] = NODE_HW_ID_BYTE3;
429
 
430
    txMsg.Data[4] = NUMBER_OF_MODULES;
431
    txMsg.Data[5] = ModuleSequenceNumber;
432
 
433
    while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
434
}
435