Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2010 The Android Open-Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License |
| 15 | */ |
| 16 | |
| 17 | /* |
| 18 | * Define the basic structure for messages from the host. |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 19 | * Messages are MESSAGE_SIZE bytes, with a 2-byte opcode, a 2-byte |
| 20 | * unique ID defined by the sender, and the remainder payload. |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 21 | * The remaining 2 bytes must be 0xFEEDFACE. This is used by |
| 22 | * the message handler as a tail sentinel to resync with the |
| 23 | * sender in case data is lost and the fixed-byte messages |
| 24 | * get out of sync. |
| 25 | */ |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 26 | #define MESSAGE_SIZE 128 // serial buffer size on TTL is 128 bytes |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 27 | #define MESSAGE_DELIMITER 0xBEEF |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 28 | #define MESSAGE_ESCAPE 0x2a |
| 29 | struct message { |
| 30 | uint16_t opcode; |
| 31 | uint16_t id; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 32 | uint8_t data[MESSAGE_SIZE - 6]; |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 33 | uint16_t tail; |
| 34 | }; |
| 35 | struct message CURRENT_MESSAGE; |
| 36 | |
| 37 | #define OPCODE_RESET 0x00 |
| 38 | struct reset { |
| 39 | uint16_t opcode; |
| 40 | uint16_t id; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 41 | uint8_t unused[MESSAGE_SIZE - 4]; |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 42 | }; |
| 43 | |
| 44 | #define OPCODE_INIT_TIME (OPCODE_RESET + 1) |
| 45 | struct init_time { |
| 46 | uint16_t opcode; |
| 47 | uint16_t id; |
| 48 | uint32_t cur_raw_time; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 49 | uint8_t unused[MESSAGE_SIZE - 6]; |
| 50 | }; |
| 51 | |
| 52 | #define OPCODE_CURRENT_TIME (OPCODE_RESET + 2) |
| 53 | struct current_time { // we never actually use this, but here for consistency |
| 54 | uint16_t opcode; |
| 55 | uint16_t id; |
| 56 | uint8_t unused[MESSAGE_SIZE - 4]; |
| 57 | }; |
| 58 | |
| 59 | #define OPCODE_SETMODE_PONG (OPCODE_RESET + 3) |
| 60 | struct setmode_pong { |
| 61 | uint16_t opcode; |
| 62 | uint16_t id; |
| 63 | uint16_t playfield_width; |
| 64 | uint16_t playfield_height; |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 65 | uint16_t ball_x; |
| 66 | uint16_t ball_y; |
| 67 | uint16_t ball_radius; |
| 68 | uint16_t ball_velocity_x; |
| 69 | uint16_t ball_velocity_y; |
| 70 | uint8_t unused[MESSAGE_SIZE - 18]; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 71 | }; |
| 72 | |
| 73 | #define OPCODE_PONG_BALL_STATE (OPCODE_RESET + 4) |
| 74 | struct pong_ball_state { |
| 75 | uint16_t opcode; |
| 76 | uint16_t id; |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 77 | uint8_t unused[MESSAGE_SIZE - 4]; |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 78 | }; |
| 79 | |
| 80 | struct wall_time_struct { |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 81 | uint32_t raw; |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 82 | uint8_t initialized; |
| 83 | uint8_t hours; |
| 84 | uint8_t minutes; |
| 85 | uint8_t seconds; |
| 86 | }; |
| 87 | struct wall_time_struct WALL_TIME; |
| 88 | |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 89 | /* |
| 90 | * Main ball-playing state record. |
| 91 | */ |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 92 | struct pong_state_struct { |
| 93 | uint16_t playfield_width; |
| 94 | uint16_t playfield_height; |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 95 | int16_t ball_x; |
| 96 | int16_t ball_y; |
| 97 | int16_t ball_radius; |
| 98 | int16_t velocity_x; |
| 99 | int16_t velocity_y; |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 100 | }; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 101 | struct pong_state_struct PONG_STATE; |
| 102 | |
| 103 | |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 104 | /* This is a temporary buffer used by the message handler */ |
| 105 | struct message_buffer { |
| 106 | uint16_t count; // number of bytes read into the buffer |
| 107 | uint8_t buffer[MESSAGE_SIZE]; // contents of a 'struct message' |
| 108 | }; |
| 109 | struct message_buffer MESSAGE_BUFFER; |
| 110 | |
| 111 | |
| 112 | /* |
| 113 | * Clears all stateful values, including the wall clock time, current message |
| 114 | * data, and user/app state. Also clears the message handler's buffer. By |
| 115 | * "clear" we mean "memset to 0". |
| 116 | */ |
| 117 | void reset() { |
| 118 | memset(&WALL_TIME, 0, sizeof(WALL_TIME)); |
| 119 | memset(&CURRENT_MESSAGE, 0, sizeof(CURRENT_MESSAGE)); |
| 120 | memset(&MESSAGE_BUFFER, 0, sizeof(MESSAGE_BUFFER)); |
| 121 | memset(&PONG_STATE, 0, sizeof(PONG_STATE)); |
| 122 | } |
| 123 | |
| 124 | |
| 125 | /* |
| 126 | * Closes out a serial response, which involves sending a blank line in |
| 127 | * between messages. Also prints the current time, for funsies. |
| 128 | */ |
| 129 | void close_response() { |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 130 | if (WALL_TIME.initialized) { |
| 131 | Serial.print("current_time="); |
| 132 | Serial.print(WALL_TIME.hours, DEC); |
| 133 | Serial.print(":"); |
| 134 | if (WALL_TIME.minutes < 10) |
| 135 | Serial.print("0"); |
| 136 | Serial.print(WALL_TIME.minutes, DEC); |
| 137 | Serial.print(":"); |
| 138 | if (WALL_TIME.seconds < 10) |
| 139 | Serial.print("0"); |
| 140 | Serial.println(WALL_TIME.seconds, DEC); |
| 141 | } else { |
| 142 | Serial.println("current_time=00:00:00"); |
| 143 | } |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 144 | Serial.print("\r\n"); |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 145 | } |
| 146 | |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 147 | |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 148 | /* |
| 149 | * Opcode processor/handler. |
| 150 | */ |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 151 | void handle_current_message() { |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 152 | static uint16_t last_id = 999999; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 153 | static struct setmode_pong* setmode_pong_msg; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 154 | |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 155 | if (CURRENT_MESSAGE.id == last_id) { |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 156 | return; |
| 157 | } |
| 158 | last_id = CURRENT_MESSAGE.id; |
| 159 | |
| 160 | switch (CURRENT_MESSAGE.opcode) { |
| 161 | |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 162 | case OPCODE_SETMODE_PONG: // initialize ball animation state |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 163 | memset(&PONG_STATE, 0, sizeof(PONG_STATE)); |
| 164 | setmode_pong_msg = (struct setmode_pong*)(&CURRENT_MESSAGE); |
| 165 | PONG_STATE.playfield_width = setmode_pong_msg->playfield_width; |
| 166 | PONG_STATE.playfield_height = setmode_pong_msg->playfield_height; |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 167 | PONG_STATE.ball_x = setmode_pong_msg->ball_x; |
| 168 | PONG_STATE.ball_y = setmode_pong_msg->ball_y; |
| 169 | PONG_STATE.ball_radius = setmode_pong_msg->ball_radius; |
| 170 | PONG_STATE.velocity_x = setmode_pong_msg->ball_velocity_x; |
| 171 | PONG_STATE.velocity_y = setmode_pong_msg->ball_velocity_y; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 172 | |
| 173 | Serial.println("message_type=setmode_pong_ack"); |
| 174 | Serial.print("id="); |
| 175 | Serial.println(CURRENT_MESSAGE.id); |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 176 | Serial.print("ball_x="); |
| 177 | Serial.println(PONG_STATE.ball_x, DEC); |
| 178 | Serial.print("ball_y="); |
| 179 | Serial.println(PONG_STATE.ball_y, DEC); |
| 180 | Serial.print("ball_velocity_x="); |
| 181 | Serial.println(PONG_STATE.velocity_x, DEC); |
| 182 | Serial.print("ball_velocity_y="); |
| 183 | Serial.println(PONG_STATE.velocity_y, DEC); |
| 184 | Serial.print("playfield_width="); |
| 185 | Serial.println(PONG_STATE.playfield_width, DEC); |
| 186 | Serial.print("playfield_height="); |
| 187 | Serial.println(PONG_STATE.playfield_height, DEC); |
| 188 | Serial.print("ball_radius="); |
| 189 | Serial.println(PONG_STATE.ball_radius, DEC); |
| 190 | close_response(); |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 191 | break; |
| 192 | |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 193 | case OPCODE_PONG_BALL_STATE: // update a frame |
| 194 | /* This gets called once per update/refresh request from host. From the |
| 195 | * perspective of the AVR, we are running this animation in arbitrary |
| 196 | * time units. If host calls this at 10 FPS, we return data at 10 FPS. |
| 197 | * If it calls us at 100FPS, we return data at 100FPS. */ |
| 198 | PONG_STATE.ball_x += PONG_STATE.velocity_x; |
| 199 | PONG_STATE.ball_y += PONG_STATE.velocity_y; |
| 200 | |
| 201 | // all we do is bounce around the inside of the box we were given |
| 202 | if ((PONG_STATE.ball_x - PONG_STATE.ball_radius) < 0) { |
| 203 | PONG_STATE.velocity_x *= -1; |
| 204 | PONG_STATE.ball_x = PONG_STATE.ball_radius; |
| 205 | } else if ((PONG_STATE.ball_x + PONG_STATE.ball_radius) > PONG_STATE.playfield_width) { |
| 206 | PONG_STATE.velocity_x *= -1; |
| 207 | PONG_STATE.ball_x = PONG_STATE.playfield_width - PONG_STATE.ball_radius; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 208 | } |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 209 | |
| 210 | if ((PONG_STATE.ball_y - PONG_STATE.ball_radius) < 0) { |
| 211 | PONG_STATE.velocity_y *= -1; |
| 212 | PONG_STATE.ball_y = PONG_STATE.ball_radius; |
| 213 | } else if ((PONG_STATE.ball_y + PONG_STATE.ball_radius) > PONG_STATE.playfield_height) { |
| 214 | PONG_STATE.velocity_y *= -1; |
| 215 | PONG_STATE.ball_y = PONG_STATE.playfield_height - PONG_STATE.ball_radius; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 216 | } |
| 217 | |
| 218 | Serial.println("message_type=pong_paddle_state"); |
| 219 | Serial.print("id="); |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 220 | Serial.println(CURRENT_MESSAGE.id, DEC); |
| 221 | Serial.print("ball_x="); |
| 222 | Serial.println(PONG_STATE.ball_x, DEC); |
| 223 | Serial.print("ball_y="); |
| 224 | Serial.println(PONG_STATE.ball_y, DEC); |
| 225 | close_response(); |
| 226 | break; |
| 227 | |
| 228 | case OPCODE_RESET: |
| 229 | reset(); |
| 230 | Serial.println("message_type=reset_ack"); |
| 231 | Serial.print("id="); |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 232 | Serial.println(CURRENT_MESSAGE.id); |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 233 | close_response(); |
| 234 | break; |
| 235 | |
| 236 | case OPCODE_INIT_TIME: |
| 237 | // cast CURRENT_MESSAGE to our time struct to conveniently fetch |
| 238 | // out the current time |
| 239 | WALL_TIME.raw = ((struct init_time*)(&CURRENT_MESSAGE))->cur_raw_time; |
| 240 | WALL_TIME.initialized = 1; |
| 241 | |
| 242 | Serial.println("message_type=init_time_ack"); |
| 243 | Serial.print("id="); |
| 244 | Serial.println(CURRENT_MESSAGE.id); |
| 245 | close_response(); |
| 246 | break; |
| 247 | |
| 248 | case OPCODE_CURRENT_TIME: |
| 249 | Serial.println("message_type=current_time_ack"); |
| 250 | Serial.print("id="); |
| 251 | Serial.println(CURRENT_MESSAGE.id); |
| 252 | close_response(); |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 253 | break; |
| 254 | |
| 255 | default: |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 256 | Serial.println("message_type=unknown_command_ack"); |
| 257 | Serial.print("id="); |
| 258 | Serial.println(CURRENT_MESSAGE.id); |
| 259 | close_response(); |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 260 | break; |
| 261 | } |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 262 | } |
| 263 | |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 264 | |
| 265 | /* |
| 266 | * Pumps the message processor. That is, this function is intended to be |
| 267 | * called once per loop to read all pending Serial/TTL data, and decode a |
| 268 | * message from the peer if one is complete. In cases where data is corrupted |
| 269 | * (such as by dropping bytes), this function also attempts to re-sync with |
| 270 | * the host by discarding messages until it finds a MESSAGE_DELIMITER, after |
| 271 | * which is resyncs its buffer on the first subsequent byte. |
| 272 | * |
| 273 | * This functional also handles two low-level 'system' messages: a reset |
| 274 | * instruction which invokes reset(), and an init_time instruction which |
| 275 | * provides the soft clock with the current time so that it can start keeping |
| 276 | * time. |
| 277 | */ |
| 278 | void pump_message_processor() { |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 279 | static uint8_t cur_byte; |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 280 | static uint16_t* cur_word; |
| 281 | static int8_t delimiter_index; |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 282 | static char buf[6]; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 283 | while (Serial.available() > 0) { // keep going as long as we might have messages |
| 284 | cur_byte = (uint8_t)(Serial.read() & 0x000000ff); |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 285 | MESSAGE_BUFFER.buffer[(MESSAGE_BUFFER.count)++] = cur_byte; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 286 | if (MESSAGE_BUFFER.count >= MESSAGE_SIZE) { |
| 287 | if ((*(uint16_t*)(MESSAGE_BUFFER.buffer + MESSAGE_SIZE - 2)) != MESSAGE_DELIMITER) { |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 288 | // whoops, we got out of sync with the transmitter. Scan current |
| 289 | // buffer for the delimiter, discard previous message, and shift |
| 290 | // partial next message to front of buffer. This loses a message but |
| 291 | // gets us back in sync |
| 292 | delimiter_index = -2; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 293 | for (int i = MESSAGE_SIZE - 2; i >= 0; --i) { |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 294 | if (*((uint16_t*)(MESSAGE_BUFFER.buffer + i)) == MESSAGE_DELIMITER) { |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 295 | if (((i - 1) >= 0) && (MESSAGE_BUFFER.buffer[i - 1] != MESSAGE_ESCAPE)) { |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 296 | delimiter_index = i; |
| 297 | break; |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | MESSAGE_BUFFER.count = 0; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 302 | if (delimiter_index >= 0) { |
| 303 | for (int i = delimiter_index + 2; i < MESSAGE_SIZE; ++i, ++(MESSAGE_BUFFER.count)) { |
| 304 | MESSAGE_BUFFER.buffer[MESSAGE_BUFFER.count] = MESSAGE_BUFFER.buffer[i]; |
| 305 | } |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 306 | } |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 307 | memset(MESSAGE_BUFFER.buffer + MESSAGE_BUFFER.count, 0, MESSAGE_SIZE - MESSAGE_BUFFER.count); |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 308 | close_response(); |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 309 | } else { |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 310 | memcpy(&CURRENT_MESSAGE, MESSAGE_BUFFER.buffer, MESSAGE_SIZE); |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 311 | memset(&MESSAGE_BUFFER, 0, sizeof(MESSAGE_BUFFER)); |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 312 | } |
| 313 | } |
| 314 | } |
| 315 | } |
| 316 | |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 317 | |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 318 | /* |
| 319 | * Pumps the system wall clock. This checks the device's monotonic clock to |
| 320 | * determine elapsed time since last invocation, and updates wall clock time |
| 321 | * by dead reckoning. Since the device has no battery backup, a power-off will |
| 322 | * lose the current time, so timekeeping cannot begin until an INIT_TIME |
| 323 | * message is received. (The pump_message_processor() function handles that.) |
| 324 | * |
| 325 | * Once timekeeping is underway, current time is exposed to user/app code via |
| 326 | * the WALL_TIME object, which has 24-hour HH/MM/SS fields. |
| 327 | */ |
| 328 | void pump_clock() { |
| 329 | static uint32_t prev_millis = 0; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 330 | static uint32_t tmp_prev_millis = 0; |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 331 | uint32_t tmp = 0; |
| 332 | |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 333 | if (millis() / 1000 != tmp_prev_millis) { |
| 334 | tmp_prev_millis = millis() / 1000; |
Dan Morrill | 7b12399 | 2010-10-20 12:22:44 -0700 | [diff] [blame] | 335 | } |
| 336 | |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 337 | if (WALL_TIME.initialized) { |
| 338 | tmp = millis() / 1000; |
| 339 | if (tmp != prev_millis) { |
| 340 | prev_millis = tmp; |
| 341 | WALL_TIME.raw++; |
| 342 | } |
| 343 | WALL_TIME.seconds = WALL_TIME.raw % 60; |
| 344 | WALL_TIME.minutes = (WALL_TIME.raw / 60) % 60; |
| 345 | WALL_TIME.hours = (WALL_TIME.raw / (60 * 60)) % 24; |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | |
| 350 | /* |
| 351 | * Standard Arduino setup hook. |
| 352 | */ |
| 353 | void setup() { |
| 354 | Serial.begin(115200); |
| 355 | } |
| 356 | |
| 357 | |
| 358 | /* |
| 359 | * Standard Arduino loop-pump hook. |
| 360 | */ |
| 361 | void loop() { |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 362 | pump_clock(); |
| 363 | pump_message_processor(); |
Dan Morrill | 6bfbb18 | 2011-01-21 10:04:37 -0800 | [diff] [blame] | 364 | handle_current_message(); |
Dan Morrill | 8f1028f | 2010-09-12 12:02:59 -0700 | [diff] [blame] | 365 | } |