1 #include <sancus/reactive.h>
  2 
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <random.h>
  6 
  7 #include "wan_commands.h"
  8 
  9 #define SMNAME     ESME
 10 
 11 #define MAX_OBSERVERS 4
 12 
 13 SM_OUTPUT(SMNAME, load_switch_out);
 14 SM_OUTPUT(SMNAME, central_system_out);
 15 SM_OUTPUT(SMNAME, han_if_out);
 16 
 17 
 18 static int      SM_DATA(SMNAME) initialised;
 19 static uint16_t SM_DATA(SMNAME) time;
 20 static int      SM_DATA(SMNAME) seq;
 21 
 22 static uint8_t  SM_DATA(SMNAME) supply_state;
 23 static uint16_t SM_DATA(SMNAME) active_power_import;
 24 static uint16_t SM_DATA(SMNAME) active_import_register; // too small; CC bug
 25 static uint8_t  SM_DATA(SMNAME) observers[MAX_OBSERVERS];
 26 
 27 #define CHANNEL_LS   1
 28 #define CHANNEL_CS   2
 29 #define CHANNEL_HAN  3
 30 
 31 static uint32_t modu16 (uint32_t i, uint32_t j)
 32 {
 33     return (i % j);
 34 }
 35 
 36 void SM_FUNC(SMNAME) init(void)
 37 {
 38   if (! initialised) {
 39     time         = 0;
 40     seq          = 0;
 41 
 42     supply_state = 1;
 43     active_power_import    = 0;
 44     active_import_register = 0;
 45 
 46     random_init(0);
 47     for (int i = 0; i < MAX_OBSERVERS; i++) {
 48       observers[i] = 0 ;
 49     }
 50     observers[0] = CHANNEL_HAN;
 51 
 52     initialised  = 1;
 53   }
 54 }
 55 
 56 void SM_FUNC(SMNAME) produce_output(uint8_t channel, uint8_t info)
 57 {
 58     uint8_t data[4] __attribute__((aligned(2)))
 59                    = { (seq    >> (8*0)) & 0xff,
 60                        (seq    >> (8*1)) & 0xff,
 61                        info, 0 };
 62     seq += 1;
 63 
 64     if (channel == CHANNEL_CS) {
 65       central_system_out(data, sizeof(data));
 66     }
 67 
 68     if (channel == CHANNEL_LS) {
 69       load_switch_out(data, sizeof(data));
 70     }
 71 }
 72 
 73 void SM_FUNC(SMNAME) output_consumption_data(void)
 74 {
 75     uint8_t data[10] __attribute__((aligned(2)))
 76                      = { (seq                    >> (8*0)) & 0xff,
 77                          (seq                    >> (8*1)) & 0xff,
 78                          GET_CONSUMPTION_DATA, 0,
 79                          supply_state,
 80                          (active_power_import    >> (8*0)) & 0xff,
 81                          (active_power_import    >> (8*1)) & 0xff,
 82                          (active_import_register >> (8*0)) & 0xff,
 83                          (active_import_register >> (8*1)) & 0xff};
 84 
 85     for (int i = 0; i < MAX_OBSERVERS; i++) {
 86       if (observers[i] == CHANNEL_HAN) {
 87         han_if_out(data, sizeof(data));
 88       }
 89       else if (observers[i] == CHANNEL_CS) {
 90         central_system_out(data, sizeof(data));
 91       }
 92     }
 93 }
 94 
 95 void SM_FUNC(SMNAME) get_input(uint8_t channel, const uint8_t *data,
 96     size_t len)
 97 {
 98     if (channel == CHANNEL_LS && len >= 3) {
 99       supply_state = data[2]; /* only one opperation supported */
100     }
101 
102     if (channel == CHANNEL_CS && len >= 3) {
103       if (data[2] == GET_CONSUMPTION_DATA) {
104         for (int i = 0; i < MAX_OBSERVERS; i++) {
105           if (observers[i] == 0 || observers[i] == CHANNEL_CS) {
106             observers[i] = CHANNEL_CS;
107             produce_output(CHANNEL_CS, GET_CONSUMPTION_DATA);
108             break; }
109         }
110       }
111     }
112 }
113 
114 
115 SM_ENTRY(SMNAME) void advance_time(void)
116 {
117     if (! initialised) {
118       init();
119       produce_output(CHANNEL_LS, GET_SUPPLY_STATE);
120     }
121     time++;
122 
123     // measure consumption; should be a call to a protected driver
124     if (supply_state == SUPPLY_STATE_ENABLED) {
125       active_power_import = 50 + (modu16(random_rand(), 100));
126     } else {
127       active_power_import = 0;
128     }
129     // accumulate; wee need a notion of time her
130     active_import_register += active_power_import;
131 
132 
133     if (! (modu16(time, 5))) {
134       produce_output(CHANNEL_LS, GET_SUPPLY_STATE);
135       output_consumption_data();
136     }
137 }
138 
139 SM_INPUT(SMNAME, load_switch_in, data, len)
140 {
141     if (! initialised) { init(); }
142 
143     get_input(CHANNEL_LS, data, len);
144 }
145 
146 SM_INPUT(SMNAME, central_system_in, data, len)
147 {
148     if (! initialised) { init(); }
149 
150     get_input(CHANNEL_CS, data, len);
151 }
152