Subversion Repositories HomeAutomation

Rev

Rev 1534 | Rev 1537 | 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
 
1532 myhrman 115
static uint8_t outputStateTarget[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
 *---------------------------------------------------------------------------*/
125
static void updateOutput(void);
126
static void readDiagPin(void);
127
static void pcIntCallback(uint8_t id, uint8_t status);
128
 
129
 
130
/*-----------------------------------------------------------------------------
131
 * Function Implementations
132
 *---------------------------------------------------------------------------*/
133
 
134
static void updateOutput() {
1528 myhrman 135
 
1532 myhrman 136
    #if act_protectedOutput_CH_COUNT >= 1
1528 myhrman 137
    if (outputStateTarget[0] == 0) {
1532 myhrman 138
        gpio_set_statement(CH0_OFF, CH0_PIN);
1503 myhrman 139
    }
1528 myhrman 140
    else if (outputStateTarget[0] == 1) {
1503 myhrman 141
        if (diagState == DIAG_NORMAL) {
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
1528 myhrman 152
    if (outputStateTarget[1] == 0) {
1532 myhrman 153
        gpio_set_statement(CH1_OFF, CH1_PIN);
1528 myhrman 154
    }
155
    else if (outputStateTarget[1] == 1) {
156
        if (diagState == DIAG_NORMAL) {
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
1528 myhrman 167
    if (outputStateTarget[2] == 0) {
1532 myhrman 168
        gpio_set_statement(CH2_OFF, CH2_PIN);
1528 myhrman 169
    }
170
    else if (outputStateTarget[2] == 1) {
171
        if (diagState == DIAG_NORMAL) {
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
1528 myhrman 182
    if (outputStateTarget[3] == 0) {
1532 myhrman 183
        gpio_set_statement(CH3_OFF, CH3_PIN);
1528 myhrman 184
    }
185
    else if (outputStateTarget[3] == 1) {
186
        if (diagState == DIAG_NORMAL) {
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;
207
        updateOutput();
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++) {
1528 myhrman 217
                    outputStateTarget[i] = 0;
218
                }
1503 myhrman 219
            }
220
        }
221
        // something interesting obviously happened. let's report it
222
        diagReportPending = 1;
223
    }
224
}
225
 
226
 
227
void act_protectedOutput_Init() {
1528 myhrman 228
    /*
1532 myhrman 229
     * Init target state vector, in case EEPROM is disabled
230
     */
231
    for (uint8_t i=0; i<act_protectedOutput_CH_COUNT; i++) {
232
        outputStateTarget[i] = 0;
233
    }
234
 
235
    /*
1528 myhrman 236
     * Configure DIAG input pin
237
     */
1503 myhrman 238
    if (act_protectedOutput_DIAG_PIN_PULL_ENABLED) {
239
        // if DIAG is asserted low, we need pull-up
1532 myhrman 240
        gpio_set_statement(act_protectedOutput_DIAG_PIN_POLARITY == 0 ? 1 : 0, DIAG_PIN);
1503 myhrman 241
    }
242
    gpio_set_in(DIAG_PIN);
243
    Pcint_SetCallbackPin(act_protectedOutput_DIAG_PIN_PCINT, DIAG_PIN, &pcIntCallback);
244
 
1528 myhrman 245
    /*
1532 myhrman 246
     * Read EEPROM data
247
     */
1535 myhrman 248
#if act_protectedOutput_EEPROM_ENABLED == 1
1534 myhrman 249
    if (EEDATA_OK) {
1532 myhrman 250
#if act_protectedOutput_CH_COUNT >= 1
251
      outputStateTarget[0] = eeprom_read_byte(EEDATA.ch0);
252
#endif
253
#if act_protectedOutput_CH_COUNT >= 2
254
      outputStateTarget[1] = eeprom_read_byte(EEDATA.ch1);
255
#endif
256
#if act_protectedOutput_CH_COUNT >= 3
257
      outputStateTarget[2] = eeprom_read_byte(EEDATA.ch2);
258
#endif
259
#if act_protectedOutput_CH_COUNT >= 4
260
      outputStateTarget[3] = eeprom_read_byte(EEDATA.ch3);
261
#endif
262
    }
263
    else {
264
        //The CRC of the EEPROM is not correct, store default values and update CRC
265
#if act_protectedOutput_CH_COUNT >= 1
266
        eeprom_write_byte_crc(EEDATA.ch0, 0x00, WITHOUT_CRC);
267
#endif
268
#if act_protectedOutput_CH_COUNT >= 2
269
        eeprom_write_byte_crc(EEDATA.ch1, 0x00, WITHOUT_CRC);
270
#endif
271
#if act_protectedOutput_CH_COUNT >= 3
272
        eeprom_write_byte_crc(EEDATA.ch2, 0x00, WITHOUT_CRC);
273
#endif
274
#if act_protectedOutput_CH_COUNT >= 4
275
        eeprom_write_byte_crc(EEDATA.ch3, 0x00, WITHOUT_CRC);
276
#endif
277
        EEDATA_UPDATE_CRC;
278
    }
279
#endif
280
 
281
    /*
1528 myhrman 282
     * Configure OUTPUT pins
283
     */
1532 myhrman 284
    #if act_protectedOutput_CH_COUNT >= 1
285
    gpio_set_statement(CH0_OFF, CH0_PIN);
286
    gpio_set_out(act_protectedOutput_CH0);
1528 myhrman 287
    #endif
1503 myhrman 288
 
1532 myhrman 289
    #if act_protectedOutput_CH_COUNT >= 2
290
    gpio_set_statement(CH1_OFF, CH1_PIN);
291
    gpio_set_out(act_protectedOutput_CH1);
1528 myhrman 292
    #endif
293
 
1532 myhrman 294
    #if act_protectedOutput_CH_COUNT >= 3
295
    gpio_set_statement(CH2_OFF, CH2_PIN);
296
    gpio_set_out(act_protectedOutput_CH2);
1528 myhrman 297
    #endif
298
 
1532 myhrman 299
    #if act_protectedOutput_CH_COUNT >= 4
300
    gpio_set_statement(CH3_OFF, CH3_PIN);
301
    gpio_set_out(act_protectedOutput_CH3);
1528 myhrman 302
    #endif
303
 
1503 myhrman 304
    diagState = DIAG_NORMAL;
305
}
306
 
307
 
308
void act_protectedOutput_Process() {
309
 
1535 myhrman 310
#if act_protectedOutput_EEPROM_ENABLED == 1
1534 myhrman 311
    if (Timer_Expired(act_protectedOutput_STORE_VALUE_TIMEOUT)) {
312
#if act_protectedOutput_CH_COUNT >= 1
313
        eeprom_write_byte_crc(EEDATA.ch0, outputStateTarget[0], WITHOUT_CRC);
314
#endif
315
#if act_protectedOutput_CH_COUNT >= 2
316
        eeprom_write_byte_crc(EEDATA.ch1, outputStateTarget[1], WITHOUT_CRC);
317
#endif
318
#if act_protectedOutput_CH_COUNT >= 3
319
        eeprom_write_byte_crc(EEDATA.ch2, outputStateTarget[2], WITHOUT_CRC);
320
#endif
321
#if act_protectedOutput_CH_COUNT >= 4
322
        eeprom_write_byte_crc(EEDATA.ch3, outputStateTarget[3], WITHOUT_CRC);
323
#endif
324
        EEDATA_UPDATE_CRC;
325
    }
1535 myhrman 326
#endif
1534 myhrman 327
 
1503 myhrman 328
    // shall we retry to set target output state?
329
    if (Timer_Expired(act_protectedOutput_RETRY_TIMER)) {
330
        // read DIAG pin again and update outputs accordingly
331
        readDiagPin();
332
        updateOutput();
1512 myhrman 333
        if (diagState == DIAG_ASSERTED) {
334
            // if DIAG was still asserted, initiate another timer run
335
            Timer_SetTimeout(act_protectedOutput_RETRY_TIMER, act_protectedOutput_RETRY_TIMER_TIME_S*1000, TimerTypeOneShot, 0);
336
        }
337
        else {
338
            // things went back to normal. report this
339
            diagReportPending = 1;
340
        }
1503 myhrman 341
    }
342
 
343
    // shall we report diag status to CAN?
344
    if (diagReportPending) {
345
        StdCan_Msg_t txMsg;
346
        StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
347
        StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
1511 arune 348
        txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
1504 myhrman 349
        txMsg.Header.ModuleId = act_protectedOutput_ID;
1503 myhrman 350
        txMsg.Header.Command = CAN_MODULE_CMD_PHYSICAL_PINSTATUS;
351
        txMsg.Length = 2;
352
        txMsg.Data[0] = 0; //TODO: add support for more channels
353
        // we follow the standard SNS_INPUT format, but the data corresponds to the "health" rather than physical level
354
        if (diagState == DIAG_NORMAL) {
355
            txMsg.Data[1] = 1;  //healthy, target output state stable
356
        } else {
357
            txMsg.Data[1] = 0;  //not healthy, DIAG pin ASSERTED, not in target output state
358
        }
359
        while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
360
        diagReportPending = 0;
361
    }
362
}
363
 
364
 
365
void act_protectedOutput_HandleMessage(StdCan_Msg_t *rxMsg) {
366
    if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_ACT &&
367
        StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
1511 arune 368
        rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT &&
1503 myhrman 369
        rxMsg->Header.ModuleId == act_protectedOutput_ID)
370
    {
371
        switch (rxMsg->Header.Command) {
372
 
373
            case CAN_MODULE_CMD_PHYSICAL_SETPIN:
1532 myhrman 374
                /*
375
                 * This message is used to activate/deactivate
376
                 * an output channel.
377
                 */
1503 myhrman 378
                if (rxMsg->Length == 2) {
1528 myhrman 379
                    uint8_t channel = rxMsg->Data[0];
1532 myhrman 380
                    if (channel >= 0 && channel < act_protectedOutput_CH_COUNT) {
1528 myhrman 381
                        outputStateTarget[channel] = rxMsg->Data[1];
1503 myhrman 382
                        readDiagPin();
383
                        updateOutput();
1535 myhrman 384
#if act_protectedOutput_EEPROM_ENABLED == 1
1534 myhrman 385
                        // output states changed, store to EE after thie timer delay
386
                        Timer_SetTimeout(act_protectedOutput_STORE_VALUE_TIMEOUT, act_protectedOutput_STORE_VALUE_TIMEOUT_TIME_S*1000, TimerTypeOneShot, 0);
1535 myhrman 387
#endif
1503 myhrman 388
                    }              
389
                    StdCan_Set_direction(rxMsg->Header, DIRECTIONFLAG_FROM_OWNER);
390
                    rxMsg->Length = 2;
391
                    while (StdCan_Put(rxMsg) != StdCan_Ret_OK);
392
                }
393
                break;
394
        }
395
    }
396
}
397
 
398
 
399
void act_protectedOutput_List(uint8_t ModuleSequenceNumber)
400
{
401
    StdCan_Msg_t txMsg;
402
    StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_ACT);
403
    StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
1511 arune 404
    txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
1503 myhrman 405
    txMsg.Header.ModuleId = act_protectedOutput_ID;
406
    txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
407
    txMsg.Length = 6;
408
 
409
    txMsg.Data[0] = NODE_HW_ID_BYTE0;
410
    txMsg.Data[1] = NODE_HW_ID_BYTE1;
411
    txMsg.Data[2] = NODE_HW_ID_BYTE2;
412
    txMsg.Data[3] = NODE_HW_ID_BYTE3;
413
 
414
    txMsg.Data[4] = NUMBER_OF_MODULES;
415
    txMsg.Data[5] = ModuleSequenceNumber;
416
 
417
    while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
418
}
419