Subversion Repositories HomeAutomation

Rev

Rev 1528 | Rev 1534 | 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
     */
248
#ifdef act_protectedOutput_EEPROM_ENABLED
249
    if (EEDATA_OK)
250
    {
251
      ///TODO: Use stored data to set initial values for the module
252
      uint8_t index = 0;
253
#if act_protectedOutput_CH_COUNT >= 1
254
      outputStateTarget[0] = eeprom_read_byte(EEDATA.ch0);
255
#endif
256
#if act_protectedOutput_CH_COUNT >= 2
257
      outputStateTarget[1] = eeprom_read_byte(EEDATA.ch1);
258
#endif
259
#if act_protectedOutput_CH_COUNT >= 3
260
      outputStateTarget[2] = eeprom_read_byte(EEDATA.ch2);
261
#endif
262
#if act_protectedOutput_CH_COUNT >= 4
263
      outputStateTarget[3] = eeprom_read_byte(EEDATA.ch3);
264
#endif
265
    }
266
    else {
267
        //The CRC of the EEPROM is not correct, store default values and update CRC
268
#if act_protectedOutput_CH_COUNT >= 1
269
        eeprom_write_byte_crc(EEDATA.ch0, 0x00, WITHOUT_CRC);
270
#endif
271
#if act_protectedOutput_CH_COUNT >= 2
272
        eeprom_write_byte_crc(EEDATA.ch1, 0x00, WITHOUT_CRC);
273
#endif
274
#if act_protectedOutput_CH_COUNT >= 3
275
        eeprom_write_byte_crc(EEDATA.ch2, 0x00, WITHOUT_CRC);
276
#endif
277
#if act_protectedOutput_CH_COUNT >= 4
278
        eeprom_write_byte_crc(EEDATA.ch3, 0x00, WITHOUT_CRC);
279
#endif
280
        EEDATA_UPDATE_CRC;
281
    }
282
#endif
283
 
284
    /*
1528 myhrman 285
     * Configure OUTPUT pins
286
     */
1532 myhrman 287
    #if act_protectedOutput_CH_COUNT >= 1
288
    gpio_set_statement(CH0_OFF, CH0_PIN);
289
    gpio_set_out(act_protectedOutput_CH0);
1528 myhrman 290
    #endif
1503 myhrman 291
 
1532 myhrman 292
    #if act_protectedOutput_CH_COUNT >= 2
293
    gpio_set_statement(CH1_OFF, CH1_PIN);
294
    gpio_set_out(act_protectedOutput_CH1);
1528 myhrman 295
    #endif
296
 
1532 myhrman 297
    #if act_protectedOutput_CH_COUNT >= 3
298
    gpio_set_statement(CH2_OFF, CH2_PIN);
299
    gpio_set_out(act_protectedOutput_CH2);
1528 myhrman 300
    #endif
301
 
1532 myhrman 302
    #if act_protectedOutput_CH_COUNT >= 4
303
    gpio_set_statement(CH3_OFF, CH3_PIN);
304
    gpio_set_out(act_protectedOutput_CH3);
1528 myhrman 305
    #endif
306
 
1503 myhrman 307
    diagState = DIAG_NORMAL;
308
}
309
 
310
 
311
void act_protectedOutput_Process() {
312
 
313
    // shall we retry to set target output state?
314
    if (Timer_Expired(act_protectedOutput_RETRY_TIMER)) {
315
        // read DIAG pin again and update outputs accordingly
316
        readDiagPin();
317
        updateOutput();
1512 myhrman 318
        if (diagState == DIAG_ASSERTED) {
319
            // if DIAG was still asserted, initiate another timer run
320
            Timer_SetTimeout(act_protectedOutput_RETRY_TIMER, act_protectedOutput_RETRY_TIMER_TIME_S*1000, TimerTypeOneShot, 0);
321
        }
322
        else {
323
            // things went back to normal. report this
324
            diagReportPending = 1;
325
        }
1503 myhrman 326
    }
327
 
328
    // shall we report diag status to CAN?
329
    if (diagReportPending) {
330
        StdCan_Msg_t txMsg;
331
        StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
332
        StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
1511 arune 333
        txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
1504 myhrman 334
        txMsg.Header.ModuleId = act_protectedOutput_ID;
1503 myhrman 335
        txMsg.Header.Command = CAN_MODULE_CMD_PHYSICAL_PINSTATUS;
336
        txMsg.Length = 2;
337
        txMsg.Data[0] = 0; //TODO: add support for more channels
338
        // we follow the standard SNS_INPUT format, but the data corresponds to the "health" rather than physical level
339
        if (diagState == DIAG_NORMAL) {
340
            txMsg.Data[1] = 1;  //healthy, target output state stable
341
        } else {
342
            txMsg.Data[1] = 0;  //not healthy, DIAG pin ASSERTED, not in target output state
343
        }
344
        while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
345
        diagReportPending = 0;
346
    }
347
}
348
 
349
 
350
void act_protectedOutput_HandleMessage(StdCan_Msg_t *rxMsg) {
351
    if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_ACT &&
352
        StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
1511 arune 353
        rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT &&
1503 myhrman 354
        rxMsg->Header.ModuleId == act_protectedOutput_ID)
355
    {
356
        switch (rxMsg->Header.Command) {
357
 
358
            case CAN_MODULE_CMD_PHYSICAL_SETPIN:
1532 myhrman 359
                /*
360
                 * This message is used to activate/deactivate
361
                 * an output channel.
362
                 */
1503 myhrman 363
                if (rxMsg->Length == 2) {
1528 myhrman 364
                    uint8_t channel = rxMsg->Data[0];
1532 myhrman 365
                    if (channel >= 0 && channel < act_protectedOutput_CH_COUNT) {
1528 myhrman 366
                        outputStateTarget[channel] = rxMsg->Data[1];
1503 myhrman 367
                        readDiagPin();
368
                        updateOutput();
369
                    }              
370
                    StdCan_Set_direction(rxMsg->Header, DIRECTIONFLAG_FROM_OWNER);
371
                    rxMsg->Length = 2;
372
                    while (StdCan_Put(rxMsg) != StdCan_Ret_OK);
373
                }
374
                break;
375
        }
376
    }
377
}
378
 
379
 
380
void act_protectedOutput_List(uint8_t ModuleSequenceNumber)
381
{
382
    StdCan_Msg_t txMsg;
383
    StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_ACT);
384
    StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
1511 arune 385
    txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
1503 myhrman 386
    txMsg.Header.ModuleId = act_protectedOutput_ID;
387
    txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
388
    txMsg.Length = 6;
389
 
390
    txMsg.Data[0] = NODE_HW_ID_BYTE0;
391
    txMsg.Data[1] = NODE_HW_ID_BYTE1;
392
    txMsg.Data[2] = NODE_HW_ID_BYTE2;
393
    txMsg.Data[3] = NODE_HW_ID_BYTE3;
394
 
395
    txMsg.Data[4] = NUMBER_OF_MODULES;
396
    txMsg.Data[5] = ModuleSequenceNumber;
397
 
398
    while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
399
}
400