main.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * Moistcontrol
  3. *
  4. * Copyright (c) 2013 Michael Buesch <m@bues.ch>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. */
  20. #include "main.h"
  21. #include "comm.h"
  22. #include "util.h"
  23. #include "sensor.h"
  24. #include "controller.h"
  25. #include "log.h"
  26. #include "twi_master.h"
  27. #include "pcf8574.h"
  28. #include "rv3029.h"
  29. #include <avr/io.h>
  30. #include <avr/wdt.h>
  31. /* RTC time fetch interval, in milliseconds. */
  32. #define RTC_FETCH_INTERVAL_MS 1000
  33. /* Message IDs of control messages transferred to and from
  34. * the host over serial wire. */
  35. enum user_message_id {
  36. MSG_LOG, /* Log message */
  37. MSG_LOG_FETCH, /* Log message request */
  38. MSG_RTC, /* RTC time */
  39. MSG_RTC_FETCH, /* RTC time request */
  40. MSG_CONTR_CONF, /* Global configuration */
  41. MSG_CONTR_CONF_FETCH, /* Global configuration request */
  42. MSG_CONTR_POT_CONF, /* Pot configuration */
  43. MSG_CONTR_POT_CONF_FETCH, /* Pot configuration request */
  44. MSG_CONTR_POT_STATE, /* Pot state */
  45. MSG_CONTR_POT_STATE_FETCH, /* Pot state request */
  46. MSG_MAN_MODE, /* Manual mode settings */
  47. MSG_MAN_MODE_FETCH, /* Manual mode settings request */
  48. };
  49. /* Payload of host communication messages. */
  50. struct msg_payload {
  51. /* The ID number. (enum user_message_id) */
  52. uint8_t id;
  53. union {
  54. /* Log message. */
  55. struct {
  56. struct log_item item;
  57. } _packed log;
  58. /* RTC time. */
  59. struct {
  60. struct rtc_time time;
  61. } _packed rtc;
  62. /* Global controller configuration. */
  63. struct {
  64. struct controller_global_config conf;
  65. } _packed contr_conf;
  66. /* Controller flower pot configuration. */
  67. struct {
  68. uint8_t pot_number;
  69. struct flowerpot_config conf;
  70. } _packed contr_pot_conf;
  71. /* Controller flower pot state. */
  72. struct {
  73. uint8_t pot_number;
  74. struct flowerpot_state state;
  75. } _packed contr_pot_state;
  76. /* Manual mode settings. */
  77. struct {
  78. uint8_t force_stop_watering_mask;
  79. uint8_t valve_manual_mask;
  80. uint8_t valve_manual_state;
  81. } _packed manual_mode;
  82. } _packed;
  83. } _packed;
  84. /* The current timekeeping count. */
  85. static jiffies_t jiffies_count;
  86. /* Serial communication timer. */
  87. static jiffies_t comm_timer;
  88. /* Timestamp for the next RTC time fetch. */
  89. static jiffies_t next_rtc_fetch;
  90. /* Host message handler.
  91. * Handle all received control messages sent by the host.
  92. */
  93. bool comm_handle_rx_message(const struct comm_message *msg,
  94. void *reply_payload)
  95. {
  96. const struct msg_payload *pl = comm_payload(const struct msg_payload *, msg);
  97. struct msg_payload *reply = reply_payload;
  98. bool ok;
  99. if (msg->fc & COMM_FC_ACK) {
  100. /* This is just an acknowledge. Ignore. */
  101. return 1;
  102. }
  103. switch (pl->id) {
  104. case MSG_LOG_FETCH: {
  105. /* Fetch of the first log item. */
  106. /* Fill the reply message. */
  107. reply->id = MSG_LOG;
  108. /* Get the first item from the log stack. */
  109. ok = log_pop(&reply->log.item);
  110. if (!ok) {
  111. /* No log available.
  112. * Signal an error to the host. */
  113. return 0;
  114. }
  115. break;
  116. }
  117. case MSG_RTC: {
  118. /* RTC time adjustment. */
  119. /* Write the new time to the RTC hardware. */
  120. rv3029_write_time(&pl->rtc.time);
  121. break;
  122. }
  123. case MSG_RTC_FETCH: {
  124. /* RTC time fetch. */
  125. /* Fill the reply message. */
  126. reply->id = MSG_RTC;
  127. rv3029_get_time(&reply->rtc.time);
  128. break;
  129. }
  130. case MSG_CONTR_CONF: {
  131. /* Set controller config. */
  132. struct controller_config conf;
  133. /* Get the current configuration. */
  134. controller_get_config(&conf);
  135. /* Write the new configuration. */
  136. conf.global = pl->contr_conf.conf;
  137. controller_update_config(&conf);
  138. break;
  139. }
  140. case MSG_CONTR_CONF_FETCH: {
  141. /* Fetch controller config. */
  142. struct controller_config conf;
  143. /* Get the current configuration. */
  144. controller_get_config(&conf);
  145. /* Fill the reply message. */
  146. reply->id = MSG_CONTR_CONF;
  147. reply->contr_conf.conf = conf.global;
  148. break;
  149. }
  150. case MSG_CONTR_POT_CONF: { /* Set flower pot config. */
  151. uint8_t pot_number = pl->contr_pot_conf.pot_number;
  152. struct controller_config conf;
  153. if (pot_number >= MAX_NR_FLOWERPOTS) {
  154. /* Invalid pot number. */
  155. return 0;
  156. }
  157. /* Get the current configuration. */
  158. controller_get_config(&conf);
  159. /* Write the new configuration. */
  160. conf.pots[pot_number] = pl->contr_pot_conf.conf;
  161. controller_update_config(&conf);
  162. break;
  163. }
  164. case MSG_CONTR_POT_CONF_FETCH: {
  165. /* Fetch flower pot config. */
  166. uint8_t pot_number = pl->contr_pot_conf.pot_number;
  167. struct controller_config conf;
  168. if (pot_number >= MAX_NR_FLOWERPOTS) {
  169. /* Invalid pot number. */
  170. return 0;
  171. }
  172. /* Get the current configuration. */
  173. controller_get_config(&conf);
  174. /* Fill the reply message. */
  175. reply->id = MSG_CONTR_POT_CONF;
  176. reply->contr_pot_conf.pot_number = pot_number;
  177. reply->contr_pot_conf.conf = conf.pots[pot_number];
  178. break;
  179. }
  180. case MSG_CONTR_POT_STATE_FETCH: {
  181. /* Fetch flower pot state. */
  182. uint8_t pot_number = pl->contr_pot_state.pot_number;
  183. if (pot_number >= MAX_NR_FLOWERPOTS) {
  184. /* Invalid pot number. */
  185. return 0;
  186. }
  187. /* Fill the reply message. */
  188. reply->id = MSG_CONTR_POT_STATE;
  189. reply->contr_pot_state.pot_number = pot_number;
  190. controller_get_pot_state(pot_number,
  191. &reply->contr_pot_state.state);
  192. break;
  193. }
  194. case MSG_MAN_MODE: {
  195. /* Set controller manual mode state. */
  196. controller_manual_mode(pl->manual_mode.force_stop_watering_mask,
  197. pl->manual_mode.valve_manual_mask,
  198. pl->manual_mode.valve_manual_state);
  199. break;
  200. }
  201. default:
  202. /* Unsupported message. Return failure. */
  203. return 0;
  204. }
  205. return 1;
  206. }
  207. /* 200 Hz system timer. */
  208. ISR(TIMER1_COMPA_vect)
  209. {
  210. mb();
  211. /* Increment the system time counter. */
  212. jiffies_count++;
  213. mb();
  214. }
  215. /* Get the current system time counter. */
  216. jiffies_t jiffies_get(void)
  217. {
  218. uint8_t sreg;
  219. jiffies_t j;
  220. /* Fetch system time counter with interrupts disabled. */
  221. sreg = irq_disable_save();
  222. j = jiffies_count;
  223. irq_restore(sreg);
  224. return j;
  225. }
  226. /* Initialize the system timer. */
  227. static void systimer_init(void)
  228. {
  229. /* Initialize timer-1 to 200 Hz interrupt frequency. */
  230. /* Set OC value for 16 Mhz CPU clock. */
  231. build_assert(F_CPU == 16000000ul);
  232. OCR1A = 1250;
  233. TCNT1 = 0;
  234. TCCR1A = 0;
  235. /* CTC mode, prescaler 64 */
  236. TCCR1B = (1 << WGM12) | (1 << CS10) | (1 << CS11);
  237. /* Enable OC interrupt. */
  238. TIMSK |= (1 << OCIE1A);
  239. }
  240. /* Handle realtime clock work. */
  241. static void handle_rtc(jiffies_t now)
  242. {
  243. /* Only, if the RTC fetch timer expired. */
  244. if (time_before(now, next_rtc_fetch))
  245. return;
  246. /* Re-trigger the RTC fetch timer. */
  247. next_rtc_fetch = now + msec_to_jiffies(RTC_FETCH_INTERVAL_MS);
  248. /* Read the current time from RTC. */
  249. rv3029_read_time();
  250. }
  251. /* Program entry point. */
  252. int main(void) _mainfunc;
  253. int main(void)
  254. {
  255. jiffies_t now;
  256. irq_disable();
  257. wdt_enable(WDTO_120MS);
  258. /* Initialize the system. */
  259. twi_init();
  260. systimer_init();
  261. rv3029_init();
  262. sensor_init();
  263. controller_init();
  264. comm_init();
  265. /* Sanity checks. */
  266. build_assert(sizeof(struct msg_payload) <= COMM_PAYLOAD_LEN);
  267. /* Enable interrupts and enter the mainloop. */
  268. irq_enable();
  269. while (1) {
  270. /* Poke the watchdog. */
  271. wdt_reset();
  272. /* Get the current timestamp. */
  273. now = jiffies_get();
  274. /* Handle serial host communication. */
  275. comm_work();
  276. if (!time_before(now, comm_timer)) {
  277. comm_timer = now + msec_to_jiffies(10);
  278. comm_centisecond_tick();
  279. }
  280. /* Handle realtime clock work. */
  281. handle_rtc(now);
  282. /* Run the controller state machine. */
  283. controller_work();
  284. }
  285. }