fork Sensor-Watch to second-movement; remove non-Movement related files
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I./
|
||||
|
||||
SRCS += \
|
||||
./app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,72 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "watch.h"
|
||||
#include "lis2dw.h"
|
||||
|
||||
static void cb_light_pressed(void) {
|
||||
}
|
||||
|
||||
static void cb_mode_pressed(void) {
|
||||
}
|
||||
|
||||
static void cb_alarm_pressed(void) {
|
||||
}
|
||||
|
||||
uint8_t interrupts = 0;
|
||||
uint8_t last_interrupts = 0;
|
||||
bool tick = false;
|
||||
char buf[13] = {0};
|
||||
|
||||
static void cb_tick(void) {
|
||||
if (!lis2dw_have_new_data()) return;
|
||||
|
||||
tick = true;
|
||||
}
|
||||
|
||||
void app_init(void) {
|
||||
watch_enable_display();
|
||||
watch_display_string("AC Strean", 0);
|
||||
|
||||
watch_enable_external_interrupts();
|
||||
watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_RISING);
|
||||
watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_RISING);
|
||||
watch_register_interrupt_callback(BTN_ALARM, cb_alarm_pressed, INTERRUPT_TRIGGER_RISING);
|
||||
|
||||
watch_enable_i2c();
|
||||
lis2dw_begin();
|
||||
lis2dw_set_data_rate(LIS2DW_DATA_RATE_25_HZ);
|
||||
lis2dw_set_range(LIS2DW_RANGE_4_G);
|
||||
lis2dw_set_low_noise_mode(true);
|
||||
lis2dw_enable_fifo();
|
||||
|
||||
lis2dw_enable_fifo();
|
||||
|
||||
watch_rtc_register_periodic_callback(cb_tick, 1);
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
if (tick) {
|
||||
tick = false;
|
||||
lis2dw_fifo_t fifo;
|
||||
lis2dw_read_fifo(&fifo);
|
||||
for(int i = 0; i < fifo.count; i++) {
|
||||
printf("%d, %d, %d, %d, %d\n", fifo.readings[i].x, fifo.readings[i].y, fifo.readings[i].z, i, fifo.count);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "watch.h"
|
||||
#include "watch_utility.h"
|
||||
|
||||
const int8_t UTC_OFFSET = 4; // set to your current UTC offset to see correct beats time
|
||||
const uint8_t BEAT_REFRESH_FREQUENCY = 8;
|
||||
|
||||
typedef enum ApplicationMode {
|
||||
MODE_CLOCK = 0, // Displays month, day and current time.
|
||||
MODE_BEATS,
|
||||
MODE_SET, // (ST) Set time and date
|
||||
NUM_MODES // Last item in the enum, it's the number of cases.
|
||||
} ApplicationMode;
|
||||
|
||||
|
||||
typedef struct ApplicationState {
|
||||
// Internal application state
|
||||
ApplicationMode mode; // Current mode
|
||||
bool mode_changed; // Lets us perform one-time setup for a given mode
|
||||
uint16_t mode_ticks; // Timeout for the mode (returns to clock after timeout expires)
|
||||
uint8_t light_ticks; // Timeout for the light
|
||||
bool led_on; // Indicates that the LED is on
|
||||
uint8_t page; // Tracks the current page in log, prefs or settings.
|
||||
uint8_t last_second; // lets us see when the second changed, for subsecond timing
|
||||
uint8_t subsecond; // a value from 0 to (BEAT_REFRESH_FREQUENCY - 1) indicating the fractional second
|
||||
} ApplicationState;
|
||||
|
||||
void do_clock_mode(void);
|
||||
void do_beats_mode(void);
|
||||
void do_set_time_mode(void);
|
||||
void set_time_mode_handle_primary_button(void);
|
||||
void set_time_mode_handle_secondary_button(void);
|
||||
|
||||
float clock2beats(uint16_t, uint16_t, uint16_t, int16_t);
|
||||
|
||||
void cb_light_pressed(void);
|
||||
void cb_mode_pressed(void);
|
||||
void cb_alarm_pressed(void);
|
||||
void cb_tick(void);
|
||||
void cb_fast_tick(void);
|
||||
|
||||
ApplicationState application_state;
|
||||
char buf[16] = {0};
|
||||
|
||||
/**
|
||||
* @brief Zeroes out the application state struct.
|
||||
*/
|
||||
void app_init(void) {
|
||||
memset(&application_state, 0, sizeof(application_state));
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
// This app does not support BACKUP mode.
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
watch_enable_external_interrupts();
|
||||
watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_RISING);
|
||||
watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_RISING);
|
||||
watch_register_extwake_callback(BTN_ALARM, cb_alarm_pressed, true);
|
||||
|
||||
watch_enable_buzzer();
|
||||
watch_enable_leds();
|
||||
watch_enable_display();
|
||||
|
||||
watch_rtc_register_tick_callback(cb_tick);
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
static void update_tick_frequency(void) {
|
||||
watch_rtc_disable_all_periodic_callbacks();
|
||||
if (application_state.mode == MODE_BEATS) {
|
||||
watch_rtc_register_periodic_callback(cb_fast_tick, BEAT_REFRESH_FREQUENCY);
|
||||
} else {
|
||||
watch_rtc_register_tick_callback(cb_tick);
|
||||
}
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
// play a beep if the mode has changed in response to a user's press of the MODE button
|
||||
if (application_state.mode_changed) {
|
||||
// low note for nonzero case, high note for return to clock
|
||||
watch_buzzer_play_note(application_state.mode ? BUZZER_NOTE_C7 : BUZZER_NOTE_C8, 100);
|
||||
update_tick_frequency();
|
||||
application_state.mode_changed = false;
|
||||
}
|
||||
|
||||
// If the user is not in clock mode and the mode timeout has expired, return them to clock mode
|
||||
if (application_state.mode != MODE_CLOCK && application_state.mode_ticks == 0) {
|
||||
application_state.mode = MODE_CLOCK;
|
||||
application_state.mode_changed = true;
|
||||
update_tick_frequency();
|
||||
}
|
||||
|
||||
// If the LED is off and should be on, turn it on
|
||||
if (application_state.light_ticks > 0 && !application_state.led_on) {
|
||||
watch_set_led_green();
|
||||
application_state.led_on = true;
|
||||
}
|
||||
|
||||
// if the LED is on and should be off, turn it off
|
||||
if (application_state.led_on && application_state.light_ticks == 0) {
|
||||
// unless the user is holding down the LIGHT button, in which case, give them more time.
|
||||
if (watch_get_pin_level(BTN_LIGHT)) {
|
||||
application_state.light_ticks = 3;
|
||||
} else {
|
||||
watch_set_led_off();
|
||||
application_state.led_on = false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (application_state.mode) {
|
||||
case MODE_CLOCK:
|
||||
do_clock_mode();
|
||||
break;
|
||||
case MODE_BEATS:
|
||||
do_beats_mode();
|
||||
break;
|
||||
case MODE_SET:
|
||||
do_set_time_mode();
|
||||
break;
|
||||
case NUM_MODES:
|
||||
// dummy case, just silences a warning
|
||||
break;
|
||||
}
|
||||
|
||||
application_state.mode_changed = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void do_clock_mode(void) {
|
||||
watch_date_time date_time = watch_rtc_get_date_time();
|
||||
const char months[12][3] = {"JA", "FE", "MR", "AR", "MA", "JN", "JL", "AU", "SE", "OC", "NO", "dE"};
|
||||
|
||||
watch_display_string((char *)months[date_time.unit.month - 1], 0);
|
||||
sprintf(buf, "%2d%2d%02d%02d", date_time.unit.day, date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
|
||||
watch_display_string(buf, 2);
|
||||
watch_set_colon();
|
||||
|
||||
}
|
||||
|
||||
void do_beats_mode(void) {
|
||||
watch_clear_colon();
|
||||
|
||||
watch_date_time date_time = watch_rtc_get_date_time();
|
||||
float beats = clock2beats(date_time.unit.hour, date_time.unit.minute, date_time.unit.second, UTC_OFFSET);
|
||||
sprintf(buf, "bt %6.0f", beats * 100);
|
||||
|
||||
watch_display_string(buf, 0);
|
||||
}
|
||||
|
||||
float clock2beats(uint16_t hours, uint16_t minutes, uint16_t seconds, int16_t utc_offset) {
|
||||
float beats = seconds + ((float)application_state.subsecond / (float)BEAT_REFRESH_FREQUENCY);
|
||||
beats += 60 * minutes;
|
||||
beats += (float)hours * 60 * 60;
|
||||
beats += (1 - utc_offset) * 60 * 60; // offset from utc + 1 since beats in in UTC+1
|
||||
|
||||
beats /= 86.4; // convert to beats
|
||||
while(beats > 1000) beats -= 1000; // beats %= 1000 but for a float
|
||||
|
||||
return beats;
|
||||
}
|
||||
|
||||
void do_set_time_mode(void) {
|
||||
watch_date_time date_time = watch_rtc_get_date_time();
|
||||
|
||||
watch_display_string(" ", 0);
|
||||
switch (application_state.page) {
|
||||
case 0: // hour
|
||||
sprintf(buf, "ST t%2d", date_time.unit.hour);
|
||||
break;
|
||||
case 1: // minute
|
||||
sprintf(buf, "ST t %02d", date_time.unit.minute);
|
||||
break;
|
||||
case 2: // second
|
||||
sprintf(buf, "ST t %02d", date_time.unit.second);
|
||||
break;
|
||||
case 3: // year
|
||||
sprintf(buf, "ST d%2d", date_time.unit.year + 20);
|
||||
break;
|
||||
case 4: // month
|
||||
sprintf(buf, "ST d %02d", date_time.unit.month);
|
||||
break;
|
||||
case 5: // day
|
||||
sprintf(buf, "ST d %02d", date_time.unit.day);
|
||||
break;
|
||||
}
|
||||
watch_display_string(buf, 0);
|
||||
watch_set_pixel(1, 12); // required for T in position 1
|
||||
}
|
||||
|
||||
void set_time_mode_handle_primary_button(void) {
|
||||
application_state.page++;
|
||||
if (application_state.page == 6) application_state.page = 0;
|
||||
}
|
||||
|
||||
void set_time_mode_handle_secondary_button(void) {
|
||||
watch_date_time date_time = watch_rtc_get_date_time();
|
||||
|
||||
switch (application_state.page) {
|
||||
case 0: // hour
|
||||
date_time.unit.hour = (date_time.unit.hour + 1) % 24;
|
||||
break;
|
||||
case 1: // minute
|
||||
date_time.unit.minute = (date_time.unit.minute + 1) % 60;
|
||||
break;
|
||||
case 2: // second
|
||||
date_time.unit.second = 0;
|
||||
break;
|
||||
case 3: // year
|
||||
// only allow 2021-2030. fix this sometime next decade
|
||||
date_time.unit.year = ((date_time.unit.year % 10) + 1);
|
||||
break;
|
||||
case 4: // month
|
||||
date_time.unit.month = ((date_time.unit.month + 1) % 12);
|
||||
break;
|
||||
case 5: // day
|
||||
date_time.unit.day = date_time.unit.day + 1;
|
||||
break;
|
||||
}
|
||||
if (date_time.unit.day > days_in_month(date_time.unit.month, date_time.unit.year + WATCH_RTC_REFERENCE_YEAR))
|
||||
date_time.unit.day = 1;
|
||||
watch_rtc_set_date_time(date_time);
|
||||
}
|
||||
|
||||
void cb_mode_pressed(void) {
|
||||
application_state.mode = (application_state.mode + 1) % NUM_MODES;
|
||||
application_state.mode_changed = true;
|
||||
application_state.mode_ticks = 300;
|
||||
application_state.page = 0;
|
||||
}
|
||||
|
||||
void cb_light_pressed(void) {
|
||||
switch (application_state.mode) {
|
||||
case MODE_SET:
|
||||
set_time_mode_handle_secondary_button();
|
||||
break;
|
||||
default:
|
||||
application_state.light_ticks = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cb_alarm_pressed(void) {
|
||||
switch (application_state.mode) {
|
||||
case MODE_SET:
|
||||
set_time_mode_handle_primary_button();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cb_tick(void) {
|
||||
if (application_state.light_ticks > 0) {
|
||||
application_state.light_ticks--;
|
||||
}
|
||||
if (application_state.mode_ticks > 0) {
|
||||
application_state.mode_ticks--;
|
||||
}
|
||||
}
|
||||
|
||||
void cb_fast_tick(void) {
|
||||
watch_date_time date_time = watch_rtc_get_date_time();
|
||||
if (date_time.unit.second != application_state.last_second) {
|
||||
application_state.last_second = date_time.unit.second;
|
||||
application_state.subsecond = 0;
|
||||
} else {
|
||||
application_state.subsecond++;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
# Leave this line at the top of the file; it has all the watch library sources and includes.
|
||||
TOP = ../../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
# If you add any other subdirectories with header files you wish to include, add them after ../
|
||||
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
|
||||
# INCLUDES += \
|
||||
# -I../ \
|
||||
# -I../drivers/ \
|
||||
# -I../utils/
|
||||
INCLUDES += \
|
||||
-I../ \
|
||||
|
||||
# If you add any other source files you wish to compile, add them after ../app.c
|
||||
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
|
||||
# SRCS += \
|
||||
# ../app.c \
|
||||
# ../drivers/bmp280.c \
|
||||
# ../utils/temperature.c
|
||||
SRCS += \
|
||||
../app.c \
|
||||
|
||||
# Leave this line at the bottom of the file; it has all the targets for making your project.
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,134 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "watch.h"
|
||||
|
||||
typedef struct ApplicationState {
|
||||
bool play;
|
||||
} ApplicationState;
|
||||
|
||||
ApplicationState application_state;
|
||||
|
||||
|
||||
void cb_alarm_pressed(void) {
|
||||
application_state.play = true;
|
||||
}
|
||||
|
||||
void app_init(void) {
|
||||
memset(&application_state, 0, sizeof(application_state));
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
watch_register_extwake_callback(BTN_ALARM, cb_alarm_pressed, true);
|
||||
|
||||
watch_enable_display();
|
||||
|
||||
watch_enable_buzzer();
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
watch_display_string(" rains ", 2);
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
if (application_state.play) {
|
||||
printf("Playing song...\n");
|
||||
const BuzzerNote rains[] = {
|
||||
BUZZER_NOTE_A4,
|
||||
BUZZER_NOTE_F5,
|
||||
BUZZER_NOTE_REST,
|
||||
BUZZER_NOTE_A4,
|
||||
BUZZER_NOTE_E5,
|
||||
BUZZER_NOTE_REST,
|
||||
BUZZER_NOTE_A4,
|
||||
BUZZER_NOTE_F5,
|
||||
BUZZER_NOTE_G5,
|
||||
BUZZER_NOTE_E5,
|
||||
BUZZER_NOTE_REST,
|
||||
BUZZER_NOTE_A4,
|
||||
BUZZER_NOTE_G5,
|
||||
BUZZER_NOTE_F5,
|
||||
BUZZER_NOTE_E5,
|
||||
BUZZER_NOTE_D5,
|
||||
BUZZER_NOTE_E5,
|
||||
BUZZER_NOTE_REST,
|
||||
|
||||
BUZZER_NOTE_A5,
|
||||
BUZZER_NOTE_REST,
|
||||
BUZZER_NOTE_A5,
|
||||
BUZZER_NOTE_A5SHARP_B5FLAT,
|
||||
BUZZER_NOTE_G5,
|
||||
BUZZER_NOTE_REST,
|
||||
BUZZER_NOTE_C5,
|
||||
BUZZER_NOTE_A5,
|
||||
BUZZER_NOTE_A5SHARP_B5FLAT,
|
||||
BUZZER_NOTE_G5,
|
||||
BUZZER_NOTE_REST,
|
||||
BUZZER_NOTE_D5,
|
||||
BUZZER_NOTE_A5SHARP_B5FLAT,
|
||||
BUZZER_NOTE_A5,
|
||||
BUZZER_NOTE_G5,
|
||||
BUZZER_NOTE_F5,
|
||||
BUZZER_NOTE_E5,
|
||||
};
|
||||
const uint16_t durations[] = {
|
||||
200,
|
||||
600,
|
||||
100,
|
||||
200,
|
||||
600,
|
||||
100,
|
||||
200,
|
||||
400,
|
||||
400,
|
||||
600,
|
||||
100,
|
||||
200,
|
||||
400,
|
||||
400,
|
||||
400,
|
||||
400,
|
||||
800,
|
||||
600,
|
||||
|
||||
200,
|
||||
50,
|
||||
400,
|
||||
200,
|
||||
400,
|
||||
100,
|
||||
200,
|
||||
400,
|
||||
400,
|
||||
400,
|
||||
200,
|
||||
200,
|
||||
400,
|
||||
400,
|
||||
400,
|
||||
400,
|
||||
900,
|
||||
};
|
||||
application_state.play = false;
|
||||
for(size_t i = 0, count = sizeof(rains) / sizeof(rains[0]); i < count; i++) {
|
||||
char buf[9] = {0};
|
||||
if (rains[i] == BUZZER_NOTE_REST) {
|
||||
printf("rest for %d ms\n", durations[i]);
|
||||
sprintf(buf, "%2drESt ", i);
|
||||
} else {
|
||||
printf("playing note %2d: %3.0f Hz for %d ms\n", i, 1000000.0 / (float)NotePeriods[rains[i]], durations[i]);
|
||||
sprintf(buf, "%2d%6d", i, NotePeriods[rains[i]]);
|
||||
}
|
||||
watch_display_string(buf, 2);
|
||||
watch_buzzer_play_note(rains[i], durations[i]);
|
||||
}
|
||||
printf("done!\n\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I../
|
||||
|
||||
SRCS += \
|
||||
../app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,10 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I./
|
||||
|
||||
SRCS += \
|
||||
./app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,62 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <peripheral_clk_config.h>
|
||||
#include "watch.h"
|
||||
|
||||
void app_init(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
delay_ms(5000);
|
||||
while (!(NVMCTRL->INTFLAG.reg & NVMCTRL_INTFLAG_READY));
|
||||
uint32_t user_row = (*((uint32_t *)NVMCTRL_AUX0_ADDRESS));
|
||||
uint8_t eeprom = (user_row >> NVMCTRL_FUSES_EEPROM_SIZE_Pos) & 7;
|
||||
printf("User row read successfully: 0x%lx\n", user_row);
|
||||
|
||||
if (eeprom != 1) {
|
||||
user_row &= ~NVMCTRL_FUSES_EEPROM_SIZE_Msk;
|
||||
user_row |= NVMCTRL_FUSES_EEPROM_SIZE(1);
|
||||
if (NVMCTRL->STATUS.reg & NVMCTRL_STATUS_SB) {
|
||||
printf("Secured bit was set; cannot perform upgrade.\n");
|
||||
return;
|
||||
}
|
||||
printf("EEPROM configuration was %d.\nApplying change...\n", eeprom);
|
||||
|
||||
uint32_t temp = NVMCTRL->CTRLB.reg; // Backup settings
|
||||
NVMCTRL->CTRLB.reg = temp | NVMCTRL_CTRLB_CACHEDIS; // Disable Cache
|
||||
NVMCTRL->STATUS.reg |= NVMCTRL_STATUS_MASK; // Clear error flags
|
||||
NVMCTRL->ADDR.reg = NVMCTRL_AUX0_ADDRESS / 2; // Set address, command will be issued elsewhere
|
||||
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_EAR | NVMCTRL_CTRLA_CMDEX_KEY; // Erase the user page
|
||||
while (!(NVMCTRL->INTFLAG.reg & NVMCTRL_INTFLAG_READY)); // Wait for NVM command to complete
|
||||
NVMCTRL->STATUS.reg |= NVMCTRL_STATUS_MASK; // Clear error flags
|
||||
NVMCTRL->ADDR.reg = NVMCTRL_AUX0_ADDRESS / 2; // Set address, command will be issued elsewhere
|
||||
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_PBC | NVMCTRL_CTRLA_CMDEX_KEY; // Erase the page buffer before buffering new data
|
||||
while (!(NVMCTRL->INTFLAG.reg & NVMCTRL_INTFLAG_READY)); // Wait for NVM command to complete
|
||||
NVMCTRL->STATUS.reg |= NVMCTRL_STATUS_MASK; // Clear error flags
|
||||
NVMCTRL->ADDR.reg = NVMCTRL_AUX0_ADDRESS / 2; // Set address, command will be issued elsewhere
|
||||
*((uint32_t *)NVMCTRL_AUX0_ADDRESS) = user_row; // write the new fuse values to the memory buffer
|
||||
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_WAP | NVMCTRL_CTRLA_CMDEX_KEY; // Write the user page
|
||||
NVMCTRL->CTRLB.reg = temp; // Restore settings
|
||||
|
||||
printf("Done! Resetting...\n");
|
||||
delay_ms(1000);
|
||||
NVIC_SystemReset();
|
||||
} else {
|
||||
printf("EEPROM configuration was %d (8192 bytes). Upgrade successful!\n", eeprom);
|
||||
}
|
||||
printf("%d %d\n", eeprom, NVMCTRL->PARAM.bit.RWWEEP);
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
return true;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I$(TOP)/littlefs/ \
|
||||
-I./
|
||||
|
||||
SRCS += \
|
||||
$(TOP)/littlefs/lfs.c \
|
||||
$(TOP)/littlefs/lfs_util.c \
|
||||
./app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,131 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <peripheral_clk_config.h>
|
||||
#include "watch.h"
|
||||
#include "lfs.h"
|
||||
#include "hpl_flash.h"
|
||||
|
||||
int lfs_storage_read(const struct lfs_config *cfg, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size);
|
||||
int lfs_storage_prog(const struct lfs_config *cfg, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size);
|
||||
int lfs_storage_erase(const struct lfs_config *cfg, lfs_block_t block);
|
||||
int lfs_storage_sync(const struct lfs_config *cfg);
|
||||
|
||||
int lfs_storage_read(const struct lfs_config *cfg, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) {
|
||||
(void) cfg;
|
||||
return !watch_storage_read(block, off, (void *)buffer, size);
|
||||
}
|
||||
|
||||
int lfs_storage_prog(const struct lfs_config *cfg, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) {
|
||||
(void) cfg;
|
||||
return !watch_storage_write(block, off, (void *)buffer, size);
|
||||
}
|
||||
|
||||
int lfs_storage_erase(const struct lfs_config *cfg, lfs_block_t block) {
|
||||
(void) cfg;
|
||||
return !watch_storage_erase(block);
|
||||
}
|
||||
|
||||
int lfs_storage_sync(const struct lfs_config *cfg) {
|
||||
(void) cfg;
|
||||
return !watch_storage_sync();
|
||||
}
|
||||
|
||||
const struct lfs_config cfg = {
|
||||
// block device operations
|
||||
.read = lfs_storage_read,
|
||||
.prog = lfs_storage_prog,
|
||||
.erase = lfs_storage_erase,
|
||||
.sync = lfs_storage_sync,
|
||||
|
||||
// block device configuration
|
||||
.read_size = 16,
|
||||
.prog_size = NVMCTRL_PAGE_SIZE,
|
||||
.block_size = NVMCTRL_ROW_SIZE,
|
||||
.block_count = NVMCTRL_RWWEE_PAGES / 4,
|
||||
.cache_size = NVMCTRL_PAGE_SIZE,
|
||||
.lookahead_size = 16,
|
||||
.block_cycles = 100,
|
||||
};
|
||||
|
||||
lfs_t lfs;
|
||||
lfs_file_t file;
|
||||
|
||||
static int _traverse_df_cb(void *p, lfs_block_t block){
|
||||
(void) block;
|
||||
uint32_t *nb = p;
|
||||
*nb += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_free_space(void){
|
||||
int err;
|
||||
|
||||
uint32_t free_blocks = 0;
|
||||
err = lfs_fs_traverse(&lfs, _traverse_df_cb, &free_blocks);
|
||||
if(err < 0){
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t available = cfg.block_count * cfg.block_size - free_blocks * cfg.block_size;
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
static void cb_tick(void) {
|
||||
watch_date_time date_time = watch_rtc_get_date_time();
|
||||
if (date_time.unit.second == 0) {
|
||||
int err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
printf("Mount failed: %d\n", err);
|
||||
}
|
||||
// read current count
|
||||
uint32_t loop_count = 0;
|
||||
lfs_file_open(&lfs, &file, "loop_count", LFS_O_RDWR | LFS_O_CREAT);
|
||||
lfs_file_read(&lfs, &file, &loop_count, sizeof(loop_count));
|
||||
|
||||
// update loop count
|
||||
loop_count += 1;
|
||||
lfs_file_rewind(&lfs, &file);
|
||||
lfs_file_write(&lfs, &file, &loop_count, sizeof(loop_count));
|
||||
|
||||
// remember the storage is not updated until the file is closed successfully
|
||||
lfs_file_close(&lfs, &file);
|
||||
|
||||
// release any resources we were using
|
||||
lfs_unmount(&lfs);
|
||||
|
||||
// print the boot count
|
||||
printf("loop_count: %ld\n", loop_count);
|
||||
printf("free space: %d\n", get_free_space());
|
||||
}
|
||||
}
|
||||
|
||||
void app_init(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
// mount the filesystem
|
||||
int err = lfs_mount(&lfs, &cfg);
|
||||
|
||||
// reformat if we can't mount the filesystem
|
||||
// this should only happen on the first boot
|
||||
if (err) {
|
||||
lfs_format(&lfs, &cfg);
|
||||
lfs_mount(&lfs, &cfg);
|
||||
}
|
||||
watch_rtc_register_tick_callback(cb_tick);
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
return true;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "watch.h"
|
||||
|
||||
void app_init(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
watch_enable_display();
|
||||
|
||||
watch_enable_buzzer();
|
||||
|
||||
watch_enable_digital_output(RED);
|
||||
watch_enable_digital_output(GREEN);
|
||||
watch_enable_digital_input(BTN_ALARM);
|
||||
watch_enable_digital_input(BTN_LIGHT);
|
||||
watch_enable_digital_input(BTN_MODE);
|
||||
watch_enable_pull_down(BTN_ALARM);
|
||||
watch_enable_pull_down(BTN_LIGHT);
|
||||
watch_enable_pull_down(BTN_MODE);
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
static int last_button = 0;
|
||||
static int button = 0;
|
||||
static int8_t loop = 0;
|
||||
|
||||
watch_set_pin_level(GREEN, false);
|
||||
watch_set_pin_level(RED, false);
|
||||
if (watch_get_pin_level(BTN_ALARM)) {
|
||||
watch_set_pin_level(GREEN, true);
|
||||
button = 1;
|
||||
} else if (watch_get_pin_level(BTN_LIGHT)) {
|
||||
watch_set_pin_level(RED, true);
|
||||
button = 2;
|
||||
} else if (watch_get_pin_level(BTN_MODE)) {
|
||||
watch_set_pin_level(GREEN, true);
|
||||
watch_set_pin_level(RED, true);
|
||||
button = 3;
|
||||
}
|
||||
|
||||
if (button != last_button) {
|
||||
last_button = button;
|
||||
watch_buzzer_play_note(BUZZER_NOTE_C8, 100);
|
||||
}
|
||||
|
||||
static const bool segmap[3][24] = {
|
||||
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0},
|
||||
{0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1},
|
||||
{1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1}
|
||||
};
|
||||
|
||||
for(int com = 0; com < 3; com++) {
|
||||
for(int seg = 0; seg < 24; seg++) {
|
||||
if (segmap[com][seg]) (loop >= 0) ? watch_set_pixel(com, seg) : watch_clear_pixel(com, seg);
|
||||
else (loop < 0) ? watch_set_pixel(com, seg) : watch_clear_pixel(com, seg);
|
||||
}
|
||||
}
|
||||
|
||||
loop++;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I../
|
||||
|
||||
SRCS += \
|
||||
../app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,64 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "watch.h"
|
||||
|
||||
void app_init(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
watch_enable_leds();
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
static uint8_t red = 0;
|
||||
static uint8_t green = 0;
|
||||
static uint8_t blue = 255;
|
||||
static uint8_t phase = 0;
|
||||
|
||||
switch (phase) {
|
||||
case 0:
|
||||
red++;
|
||||
if (red == 255) phase = 1;
|
||||
break;
|
||||
case 1:
|
||||
green++;
|
||||
if (green == 255) phase = 2;
|
||||
break;
|
||||
case 2:
|
||||
red--;
|
||||
if (red == 0) phase = 3;
|
||||
break;
|
||||
case 3:
|
||||
blue++;
|
||||
if (blue == 255) phase = 4;
|
||||
break;
|
||||
case 4:
|
||||
green--;
|
||||
if (green == 0) phase = 5;
|
||||
break;
|
||||
case 5:
|
||||
red++;
|
||||
if (red == 255) phase = 6;
|
||||
break;
|
||||
case 6:
|
||||
blue--;
|
||||
if (blue == 0) {
|
||||
phase = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
watch_set_led_color_rgb(red, green, blue);
|
||||
delay_ms(2);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I../
|
||||
|
||||
SRCS += \
|
||||
../app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,75 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "watch.h"
|
||||
|
||||
bool even = false;
|
||||
|
||||
static void cb_tick(void) {
|
||||
even = !even;
|
||||
}
|
||||
|
||||
void app_init(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
watch_enable_digital_output(RED);
|
||||
watch_enable_digital_output(GREEN);
|
||||
watch_enable_digital_output(A0);
|
||||
watch_enable_digital_output(SCL);
|
||||
watch_enable_digital_output(SDA);
|
||||
watch_enable_digital_output(A1);
|
||||
watch_enable_digital_output(A2);
|
||||
watch_enable_digital_output(A3);
|
||||
watch_enable_digital_output(A4);
|
||||
|
||||
watch_set_pin_level(A0, false);
|
||||
watch_set_pin_level(SCL, false);
|
||||
watch_set_pin_level(SDA, false);
|
||||
watch_set_pin_level(A1, false);
|
||||
watch_set_pin_level(A2, false);
|
||||
watch_set_pin_level(A3, false);
|
||||
watch_set_pin_level(A4, false);
|
||||
|
||||
watch_rtc_register_periodic_callback(cb_tick, 2);
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
watch_date_time date_time = watch_rtc_get_date_time();
|
||||
char buf[16];
|
||||
sprintf(buf, "%2d:%02d:%02d: ", date_time.unit.hour, date_time.unit.minute, date_time.unit.second);
|
||||
printf(buf);
|
||||
if (even) {
|
||||
printf("Even\n");
|
||||
watch_set_pin_level(RED, false);
|
||||
watch_set_pin_level(GREEN, true);
|
||||
watch_set_pin_level(A0, true);
|
||||
watch_set_pin_level(SCL, false);
|
||||
watch_set_pin_level(SDA, true);
|
||||
watch_set_pin_level(A1, false);
|
||||
watch_set_pin_level(A2, true);
|
||||
watch_set_pin_level(A3, false);
|
||||
watch_set_pin_level(A4, true);
|
||||
} else {
|
||||
printf("Odd\n");
|
||||
watch_set_pin_level(RED, true);
|
||||
watch_set_pin_level(GREEN, false);
|
||||
watch_set_pin_level(A0, false);
|
||||
watch_set_pin_level(SCL, true);
|
||||
watch_set_pin_level(SDA, false);
|
||||
watch_set_pin_level(A1, true);
|
||||
watch_set_pin_level(A2, false);
|
||||
watch_set_pin_level(A3, true);
|
||||
watch_set_pin_level(A4, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I../
|
||||
|
||||
SRCS += \
|
||||
../app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,283 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "watch.h"
|
||||
|
||||
bool has_ticked = false;
|
||||
|
||||
// array of lcd pins from pins.h
|
||||
const uint8_t lcd_pins[] = {
|
||||
SLCD26, // SEG23
|
||||
SLCD25, // SEG22
|
||||
SLCD24, // SEG21
|
||||
SLCD23, // SEG20
|
||||
SLCD22, // SEG19
|
||||
SLCD21, // SEG18
|
||||
SLCD20, // SEG17
|
||||
SLCD19, // SEG16
|
||||
SLCD18, // SEG15
|
||||
SLCD17, // SEG14
|
||||
SLCD16, // SEG13
|
||||
SLCD15, // SEG12
|
||||
SLCD14, // SEG11
|
||||
SLCD13, // SEG10
|
||||
SLCD12, // SEG9
|
||||
SLCD11, // SEG8
|
||||
SLCD10, // SEG7
|
||||
SLCD9, // SEG6
|
||||
SLCD8, // SEG5
|
||||
SLCD7, // SEG4
|
||||
SLCD6, // SEG3
|
||||
SLCD5, // SEG2
|
||||
SLCD4, // SEG1
|
||||
SLCD3, // SEG0
|
||||
SLCD2, // COM2
|
||||
SLCD1, // COM1
|
||||
SLCD0, // COM0
|
||||
};
|
||||
|
||||
void cb_tick(void);
|
||||
void cb_tick(void) {
|
||||
has_ticked = true;
|
||||
watch_rtc_disable_periodic_callback(8);
|
||||
}
|
||||
|
||||
void pass_if(bool passed);
|
||||
void pass_if(bool passed) {
|
||||
if (passed) {
|
||||
watch_uart_puts("P");
|
||||
} else {
|
||||
watch_uart_puts("F");
|
||||
}
|
||||
}
|
||||
|
||||
void app_init(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
// Set up tick for RTC test
|
||||
watch_rtc_register_periodic_callback(cb_tick, 8);
|
||||
|
||||
// Set up UART for communication with tester
|
||||
watch_enable_uart(A4, A1, 19200);
|
||||
|
||||
// Set up LED pins
|
||||
watch_enable_leds();
|
||||
watch_enable_buzzer();
|
||||
|
||||
// Set up buttons with pull-down resistors
|
||||
gpio_set_pin_direction(BTN_ALARM, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(BTN_ALARM, GPIO_PULL_DOWN);
|
||||
gpio_set_pin_direction(BTN_LIGHT, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(BTN_LIGHT, GPIO_PULL_DOWN);
|
||||
gpio_set_pin_direction(BTN_MODE, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(BTN_MODE, GPIO_PULL_DOWN);
|
||||
|
||||
// Set up ADC for thermistor test
|
||||
watch_enable_adc();
|
||||
watch_enable_analog_input(A2);
|
||||
// Pin A0 is the thermistor enable pin
|
||||
gpio_set_pin_direction(A0, GPIO_DIRECTION_OUT);
|
||||
|
||||
watch_set_led_yellow();
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
uint8_t buf[5] = {0};
|
||||
watch_storage_read(0, 0, buf, 4);
|
||||
printf("%s\n", (const char *)buf);
|
||||
if (strcmp((const char *)buf, "PASS") == 0) {
|
||||
watch_buzzer_play_note(BUZZER_NOTE_C5, 150);
|
||||
watch_buzzer_play_note(BUZZER_NOTE_REST, 25);
|
||||
watch_buzzer_play_note(BUZZER_NOTE_E5, 150);
|
||||
watch_buzzer_play_note(BUZZER_NOTE_REST, 25);
|
||||
watch_buzzer_play_note(BUZZER_NOTE_G5, 150);
|
||||
watch_buzzer_play_note(BUZZER_NOTE_REST, 25);
|
||||
watch_buzzer_play_note(BUZZER_NOTE_C6, 150);
|
||||
watch_set_led_green();
|
||||
return true;
|
||||
}
|
||||
|
||||
char char_received = watch_uart_getc();
|
||||
|
||||
if (char_received) {
|
||||
switch (char_received) {
|
||||
// - [X] UART echo
|
||||
case 'S':
|
||||
// Automatically passes if received by tester
|
||||
pass_if(true);
|
||||
break;
|
||||
// - [X] RTC
|
||||
case 'R':
|
||||
pass_if(has_ticked);
|
||||
break;
|
||||
// - [X] LCD pin continuity
|
||||
case 'O':
|
||||
// Set all LCD pins high
|
||||
for (int i = 0; i < 27; i++) {
|
||||
gpio_set_pin_function(lcd_pins[i], GPIO_PIN_FUNCTION_OFF);
|
||||
gpio_set_pin_direction(lcd_pins[i], GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(lcd_pins[i], true);
|
||||
}
|
||||
// It is the tester's responsibility to check that the pins are high
|
||||
pass_if(true);
|
||||
break;
|
||||
case 'P':
|
||||
// Set all LCD pins low
|
||||
for (int i = 0; i < 27; i++) {
|
||||
gpio_set_pin_function(lcd_pins[i], GPIO_PIN_FUNCTION_OFF);
|
||||
gpio_set_pin_direction(lcd_pins[i], GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(lcd_pins[i], false);
|
||||
}
|
||||
// It is the tester's responsibility to check that the pins are low
|
||||
pass_if(true);
|
||||
break;
|
||||
// - [X] LCD pin bridging
|
||||
case 'Q':
|
||||
{
|
||||
bool passed = true;
|
||||
// Pull all LCD pins up
|
||||
for (int i = 0; i < 27; i++) {
|
||||
gpio_set_pin_function(lcd_pins[i], GPIO_PIN_FUNCTION_OFF);
|
||||
gpio_set_pin_direction(lcd_pins[i], GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(lcd_pins[i], GPIO_PULL_UP);
|
||||
}
|
||||
// SEG23 is adjacent to the red LED.
|
||||
// setting the LED red drives RED low.
|
||||
watch_set_led_red();
|
||||
if (!gpio_get_pin_level(lcd_pins[0])) {
|
||||
// If SEG23 is low, then it must be bridged to the red pin
|
||||
pass_if(false);
|
||||
}
|
||||
watch_set_led_off();
|
||||
// After this, all LCD pins are adjacent. Test if each pin is bridged to the previous one.
|
||||
for (int i = 1; i < 27; i++) {
|
||||
gpio_set_pin_direction(lcd_pins[i - 1], GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(lcd_pins[i - 1], false);
|
||||
if (!gpio_get_pin_level(lcd_pins[i])) {
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
gpio_set_pin_direction(lcd_pins[i - 1], GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(lcd_pins[i - 1], GPIO_PULL_UP);
|
||||
}
|
||||
// Special cases:
|
||||
// SLCD0 neighbors VCC
|
||||
gpio_set_pin_direction(SLCD0, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(SLCD0, GPIO_PULL_DOWN);
|
||||
if (gpio_get_pin_level(SLCD0)) {
|
||||
passed = false;
|
||||
}
|
||||
// SLCD11 neighbors VCC
|
||||
gpio_set_pin_direction(SLCD11, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(SLCD11, GPIO_PULL_DOWN);
|
||||
if (gpio_get_pin_level(SLCD11)) {
|
||||
passed = false;
|
||||
}
|
||||
// SLCD21 neighbors VCC
|
||||
gpio_set_pin_direction(SLCD21, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(SLCD21, GPIO_PULL_DOWN);
|
||||
if (gpio_get_pin_level(SLCD21)) {
|
||||
passed = false;
|
||||
}
|
||||
watch_enable_display();
|
||||
delay_ms(50);
|
||||
// SLCD12 neighbors VLCD
|
||||
gpio_set_pin_function(SLCD12, GPIO_PIN_FUNCTION_OFF);
|
||||
gpio_set_pin_direction(SLCD12, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(SLCD12, GPIO_PULL_DOWN);
|
||||
if (gpio_get_pin_level(SLCD12)) {
|
||||
passed = false;
|
||||
}
|
||||
for (int i = 0; i < 27; i++) {
|
||||
gpio_set_pin_function(lcd_pins[i], GPIO_PIN_FUNCTION_OFF);
|
||||
gpio_set_pin_direction(lcd_pins[i], GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(lcd_pins[i], GPIO_PULL_OFF);
|
||||
}
|
||||
|
||||
pass_if(passed);
|
||||
}
|
||||
break;
|
||||
// - [X] Thermistor high
|
||||
case 'U':
|
||||
// Set A0 high and read the value of A2 via the ADC.
|
||||
// Pass if the value is near VCC.
|
||||
gpio_set_pin_level(A0, true);
|
||||
pass_if(watch_get_analog_pin_level(A2) > 65000);
|
||||
break;
|
||||
// - [X] Thermistor low
|
||||
case 'T':
|
||||
{
|
||||
// Set A0 low and read the value of A2 via the ADC.
|
||||
// Pass if the value is within the realm of reasonable temperatures.
|
||||
// 15000 is a few minutes in the freezer, 45000 is holding it a few feet over
|
||||
gpio_set_pin_level(A0, false);
|
||||
uint16_t value = watch_get_analog_pin_level(A2);
|
||||
pass_if(value < 45000 && value > 15000);
|
||||
}
|
||||
break;
|
||||
// - [X] VLCD low
|
||||
case 'V':
|
||||
watch_enable_display();
|
||||
SLCD->CTRLA.bit.ENABLE = 0;
|
||||
while(SLCD->SYNCBUSY.bit.ENABLE);
|
||||
SLCD->CTRLC.bit.CTST = 0x0;
|
||||
SLCD->CTRLA.bit.ENABLE = 1;
|
||||
while(SLCD->SYNCBUSY.bit.ENABLE);
|
||||
break;
|
||||
// - [X] VLCD high
|
||||
case 'W':
|
||||
watch_enable_display();
|
||||
SLCD->CTRLA.bit.ENABLE = 0;
|
||||
while(SLCD->SYNCBUSY.bit.ENABLE);
|
||||
SLCD->CTRLC.bit.CTST = 0xD;
|
||||
SLCD->CTRLA.bit.ENABLE = 1;
|
||||
while(SLCD->SYNCBUSY.bit.ENABLE);
|
||||
break;
|
||||
// - [X] Buttons
|
||||
case 'B':
|
||||
// Pass if all three buttons are low
|
||||
pass_if(!gpio_get_pin_level(BTN_ALARM) && !gpio_get_pin_level(BTN_LIGHT) && !gpio_get_pin_level(BTN_MODE));
|
||||
break;
|
||||
case 'L':
|
||||
// pass if BTN_LIGHT is high and the other two are low
|
||||
pass_if(gpio_get_pin_level(BTN_LIGHT) && !gpio_get_pin_level(BTN_ALARM) && !gpio_get_pin_level(BTN_MODE));
|
||||
watch_uart_puts("P");
|
||||
break;
|
||||
case 'A':
|
||||
// pass if BTN_ALARM is high and the other two are low
|
||||
pass_if(gpio_get_pin_level(BTN_ALARM) && !gpio_get_pin_level(BTN_LIGHT) && !gpio_get_pin_level(BTN_MODE));
|
||||
break;
|
||||
case 'M':
|
||||
// pass if BTN_MODE is high and the other two are low
|
||||
pass_if(gpio_get_pin_level(BTN_MODE) && !gpio_get_pin_level(BTN_ALARM) && !gpio_get_pin_level(BTN_LIGHT));
|
||||
break;
|
||||
|
||||
// - [X] File system
|
||||
case 'F':
|
||||
watch_storage_erase(0);
|
||||
watch_storage_write(0, 0, (const char *)"PASS", 4);
|
||||
watch_storage_sync();
|
||||
watch_storage_read(0, 0, buf, 4);
|
||||
delay_ms(10);
|
||||
pass_if(strcmp((const char *)buf, (const char *)"PASS") == 0);
|
||||
break;
|
||||
|
||||
// - [ ] Buzzer
|
||||
case 'Z':
|
||||
// reset the board
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I../
|
||||
|
||||
SRCS += \
|
||||
../app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,10 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I./
|
||||
|
||||
SRCS += \
|
||||
./app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,224 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <peripheral_clk_config.h>
|
||||
#include "watch.h"
|
||||
#include "watch_utility.h"
|
||||
#include "spiflash.h"
|
||||
#include "lis2dw.h"
|
||||
|
||||
#define ACCELEROMETER_DATA_ACQUISITION_INVALID ((uint64_t)(0b11)) // all bits are 1 when the flash is erased
|
||||
#define ACCELEROMETER_DATA_ACQUISITION_HEADER ((uint64_t)(0b10))
|
||||
#define ACCELEROMETER_DATA_ACQUISITION_DATA ((uint64_t)(0b01))
|
||||
#define ACCELEROMETER_DATA_ACQUISITION_DELETED ((uint64_t)(0b00)) // You can always write a 0 to any 1 bit
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
struct {
|
||||
uint16_t record_type : 2; // see above, helps us identify record types when reading back
|
||||
uint16_t range : 2; // accelerometer range (see lis2dw_range_t)
|
||||
uint16_t temperature : 12; // raw value from the temperature sensor
|
||||
} info;
|
||||
uint8_t char1 : 8; // First character of the activity type
|
||||
uint8_t char2 : 8; // Second character of the activity type
|
||||
uint32_t timestamp : 32; // UNIX timestamp for the measurement
|
||||
} header;
|
||||
struct {
|
||||
struct {
|
||||
uint16_t record_type : 2; // duplicate; this is the same field as info above
|
||||
uint16_t accel : 14; // X acceleration value, raw, offset by 8192
|
||||
} x;
|
||||
struct {
|
||||
uint16_t lpmode : 2; // low power mode (see lis2dw_low_power_mode_t)
|
||||
uint16_t accel : 14; // Y acceleration value, raw, offset by 8192
|
||||
} y;
|
||||
struct {
|
||||
uint16_t filter : 2; // bandwidth filtering selection (see lis2dw_bandwidth_filtering_mode_t)
|
||||
uint16_t accel : 14; // Z acceleration value, raw, offset by 8192
|
||||
} z;
|
||||
uint32_t counter : 16; // number of centiseconds since timestamp in header
|
||||
} data;
|
||||
uint64_t value;
|
||||
} accelerometer_data_acquisition_record_t;
|
||||
|
||||
static bool wait_for_flash_ready(void) {
|
||||
watch_set_pin_level(A3, false);
|
||||
bool ok = true;
|
||||
uint8_t read_status_response[1] = {0x00};
|
||||
do {
|
||||
ok = spi_flash_read_command(CMD_READ_STATUS, read_status_response, 1);
|
||||
} while ((read_status_response[0] & 0x3) != 0);
|
||||
delay_ms(1); // why do i need this?
|
||||
watch_set_pin_level(A3, true);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void write_buffer_to_page(uint8_t *buf, uint16_t page) {
|
||||
uint32_t address = 256 * page;
|
||||
|
||||
wait_for_flash_ready();
|
||||
watch_set_pin_level(A3, false);
|
||||
spi_flash_command(CMD_ENABLE_WRITE);
|
||||
wait_for_flash_ready();
|
||||
watch_set_pin_level(A3, false);
|
||||
spi_flash_write_data(address, buf, 256);
|
||||
wait_for_flash_ready();
|
||||
|
||||
uint8_t buf2[256];
|
||||
watch_set_pin_level(A3, false);
|
||||
spi_flash_read_data(address, buf2, 256);
|
||||
wait_for_flash_ready();
|
||||
|
||||
uint8_t used_pages[256] = {0xFF};
|
||||
uint16_t address_to_mark_used = page / 8;
|
||||
uint8_t header_page = address_to_mark_used / 256;
|
||||
uint8_t used_byte = 0x7F >> (page % 8);
|
||||
uint8_t offset_in_buf = address_to_mark_used % 256;
|
||||
|
||||
watch_set_pin_level(A3, false);
|
||||
spi_flash_read_data(header_page * 256, used_pages, 256);
|
||||
used_pages[offset_in_buf] = used_byte;
|
||||
watch_set_pin_level(A3, false);
|
||||
spi_flash_command(CMD_ENABLE_WRITE);
|
||||
wait_for_flash_ready();
|
||||
watch_set_pin_level(A3, false);
|
||||
spi_flash_write_data(header_page * 256, used_pages, 256);
|
||||
wait_for_flash_ready();
|
||||
}
|
||||
|
||||
static void print_records_at_page(uint16_t page) {
|
||||
accelerometer_data_acquisition_record_t records[32];
|
||||
static uint64_t timestamp = 0;
|
||||
// static uint16_t temperature = 0;
|
||||
static lis2dw_range_t range = LIS2DW_RANGE_2_G;
|
||||
static double lsb_value = 1;
|
||||
static bool printing_header = false;
|
||||
|
||||
wait_for_flash_ready();
|
||||
spi_flash_read_data(page * 256, (void *)records, 256);
|
||||
for(int i = 0; i < 32; i++) {
|
||||
switch (records[i].header.info.record_type) {
|
||||
case ACCELEROMETER_DATA_ACQUISITION_HEADER:
|
||||
printing_header = true;
|
||||
timestamp = records[i].header.timestamp;
|
||||
// temperature = records[i].header.info.temperature;
|
||||
printf("%c%c.%lld.", records[i].header.char1, records[i].header.char2, timestamp);
|
||||
range = records[i].header.info.range;
|
||||
break;
|
||||
case ACCELEROMETER_DATA_ACQUISITION_DATA:
|
||||
if (printing_header) {
|
||||
printing_header = false;
|
||||
uint8_t filter = 0;
|
||||
switch (records[i].data.z.filter) {
|
||||
case LIS2DW_BANDWIDTH_FILTER_DIV2:
|
||||
filter = 2;
|
||||
break;
|
||||
case LIS2DW_BANDWIDTH_FILTER_DIV4:
|
||||
filter = 4;
|
||||
break;
|
||||
case LIS2DW_BANDWIDTH_FILTER_DIV10:
|
||||
filter = 10;
|
||||
break;
|
||||
case LIS2DW_BANDWIDTH_FILTER_DIV20:
|
||||
filter = 20;
|
||||
break;
|
||||
}
|
||||
switch (range) {
|
||||
case LIS2DW_RANGE_16_G:
|
||||
lsb_value = (records[i].data.y.lpmode == LIS2DW_LP_MODE_1) ? 7.808 : 1.952;
|
||||
range = 16;
|
||||
break;
|
||||
case LIS2DW_RANGE_8_G:
|
||||
lsb_value = (records[i].data.y.lpmode == LIS2DW_LP_MODE_1) ? 3.904 : 0.976;
|
||||
range = 8;
|
||||
break;
|
||||
case LIS2DW_RANGE_4_G:
|
||||
lsb_value = (records[i].data.y.lpmode == LIS2DW_LP_MODE_1) ? 1.952 : 0.488;
|
||||
range = 4;
|
||||
break;
|
||||
case LIS2DW_RANGE_2_G:
|
||||
lsb_value = (records[i].data.y.lpmode == LIS2DW_LP_MODE_1) ? 0.976 : 0.244;
|
||||
range = 2;
|
||||
break;
|
||||
}
|
||||
printf("RANGE%d_LP%d_FILT%d.CSV\n", range, records[i].data.y.lpmode + 1, filter);
|
||||
printf("timestamp,accX,accY,accZ\n");
|
||||
}
|
||||
printf("%lld,%f,%f,%f\n",
|
||||
(timestamp * 100 + records[i].data.counter) * 10,
|
||||
9.80665 * ((double)(records[i].data.x.accel - 8192)) * lsb_value / 1000,
|
||||
9.80665 * ((double)(records[i].data.y.accel - 8192)) * lsb_value / 1000,
|
||||
9.80665 * ((double)(records[i].data.z.accel - 8192)) * lsb_value / 1000);
|
||||
break;
|
||||
case ACCELEROMETER_DATA_ACQUISITION_INVALID:
|
||||
case ACCELEROMETER_DATA_ACQUISITION_DELETED:
|
||||
// don't print anything
|
||||
break;
|
||||
}
|
||||
records[i].header.info.record_type = ACCELEROMETER_DATA_ACQUISITION_DELETED;
|
||||
}
|
||||
|
||||
// uncomment this to mark all pages deleted
|
||||
// write_buffer_to_page((uint8_t *)records, page);
|
||||
}
|
||||
|
||||
static void print_records() {
|
||||
uint8_t buf[256];
|
||||
for(int16_t i = 0; i < 4; i++) {
|
||||
wait_for_flash_ready();
|
||||
spi_flash_read_data(i * 256, buf, 256);
|
||||
for(int16_t j = 0; j < 256; j++) {
|
||||
uint8_t pages_written = buf[j];
|
||||
uint8_t start = 0;
|
||||
if (i == 0 && j == 0) {
|
||||
pages_written <<= 4;
|
||||
start = 4;
|
||||
}
|
||||
for(int k = start; k < 8; k++) {
|
||||
if ((pages_written & 0x80) == 0) {
|
||||
print_records_at_page(i * 2048 + j * 8 + k);
|
||||
}
|
||||
pages_written <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("=== END ===\n");
|
||||
}
|
||||
|
||||
void app_init(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
spi_flash_init();
|
||||
delay_ms(5000);
|
||||
|
||||
// bool erase = false;
|
||||
// if (erase) {
|
||||
// printf("Erasing...\n");
|
||||
// wait_for_flash_ready();
|
||||
// watch_set_pin_level(A3, false);
|
||||
// spi_flash_command(CMD_ENABLE_WRITE);
|
||||
// wait_for_flash_ready();
|
||||
// watch_set_pin_level(A3, false);
|
||||
// spi_flash_command(CMD_CHIP_ERASE);
|
||||
// delay_ms(10000);
|
||||
// }
|
||||
|
||||
print_records();
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
delay_ms(5000);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
# Leave these lines at the top of the file.
|
||||
# TOP should get us to the root of the project...
|
||||
TOP = ../..
|
||||
# ...and make.mk has all the watch library sources and includes.
|
||||
include $(TOP)/make.mk
|
||||
|
||||
# If you add any other subdirectories with header files you wish to include, add them after ./
|
||||
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
|
||||
# INCLUDES += \
|
||||
# -I./ \
|
||||
# -I drivers/ \
|
||||
# -I utils/
|
||||
INCLUDES += \
|
||||
-I./ \
|
||||
|
||||
# If you add any other source files you wish to compile, add them after app.c
|
||||
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
|
||||
# SRCS += \
|
||||
# ./app.c \
|
||||
# ./drivers/bmp280.c \
|
||||
# ./utils/temperature.c
|
||||
SRCS += \
|
||||
./app.c \
|
||||
|
||||
# Leave this line at the bottom of the file; rules.mk has all the targets for making your project.
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,198 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "watch.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This section sets up types and storage for our application state.
|
||||
// You can tear this out and replace it with whatever you want.
|
||||
typedef enum ApplicationMode {
|
||||
MODE_HELLO = 0,
|
||||
MODE_THERE
|
||||
} ApplicationMode;
|
||||
|
||||
typedef enum LightColor {
|
||||
COLOR_RED = 0,
|
||||
COLOR_GREEN,
|
||||
COLOR_YELLOW
|
||||
} LightColor;
|
||||
|
||||
typedef struct ApplicationState {
|
||||
ApplicationMode mode;
|
||||
LightColor color;
|
||||
bool light_on;
|
||||
bool beep;
|
||||
uint8_t wake_count;
|
||||
bool enter_sleep_mode;
|
||||
} ApplicationState;
|
||||
|
||||
ApplicationState application_state;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This section defines the callbacks for our button press events (implemented at bottom).
|
||||
// Add any other callbacks you may need either here or in another file.
|
||||
void cb_light_pressed(void);
|
||||
void cb_mode_pressed(void);
|
||||
void cb_alarm_pressed(void);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This section contains the required functions for any watch app. You should tear out
|
||||
// all the code in these functions when writing your app, but you must implement all
|
||||
// of the functions, even if they are empty stubs. You can also replace the documentation
|
||||
// lines with documentation that describes what your functions do!
|
||||
|
||||
/**
|
||||
* @brief the app_init function is called before anything else. Use it to set up any
|
||||
* internal data structures or application state required by your app.
|
||||
*/
|
||||
void app_init(void) {
|
||||
memset(&application_state, 0, sizeof(application_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief the app_wake_from_backup function is only called if your app is waking from
|
||||
* the ultra-low power BACKUP sleep mode. You may have chosen to store some state in the
|
||||
* RTC's backup registers prior to entering this mode. You may restore that state here.
|
||||
*
|
||||
* @see watch_enter_deep_sleep()
|
||||
*/
|
||||
void app_wake_from_backup(void) {
|
||||
// This app does not support BACKUP mode.
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief the app_setup function is like setup() in Arduino. It is called once when the
|
||||
* program begins. You should set pin modes and enable any peripherals you want to
|
||||
* set up (real-time clock, I2C, etc.) Depending on your application, you may or may not
|
||||
* want to configure sensors on your sensor board here. For example, a low-power
|
||||
* accelerometer that will run at all times should be configured here, whereas you may
|
||||
* want to enable a more power-hungry environmental sensor only when you need it.
|
||||
*
|
||||
* @note If your app enters the Sleep or Deep Sleep modes, this function will be called
|
||||
* again on wake, since those modes will have disabled all pins and peripherals; you'll
|
||||
* likely need to set them up again. This function will also be called again if your app
|
||||
* entered the ultra-low power BACKUP mode, since BACKUP mode will have done all that and
|
||||
* also wiped out the system RAM. Note that when this is called after waking from sleep,
|
||||
* the RTC will still be configured with the correct date and time.
|
||||
*/
|
||||
void app_setup(void) {
|
||||
watch_enable_leds();
|
||||
watch_enable_buzzer();
|
||||
|
||||
watch_enable_external_interrupts();
|
||||
// This starter app demonstrates three different ways of using the button interrupts.
|
||||
// The BTN_MODE interrupt only triggers on a rising edge, so the mode changes once per press.
|
||||
watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_RISING);
|
||||
// The BTN_LIGHT interrupt triggers on both rising and falling edges. The callback then checks
|
||||
// the pin state when triggered: on a button down event, it increments the color and turns the
|
||||
// LED on, whereas on a button up event, it turns the light off.
|
||||
watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_BOTH);
|
||||
// The BTN_ALARM callback is on an external wake pin; we can avoid using the EIC for this pin
|
||||
// by using the extwake interrupt — but note that it can only trigger on either a rising or
|
||||
// a falling edge, not both.
|
||||
watch_register_extwake_callback(BTN_ALARM, cb_alarm_pressed, true);
|
||||
|
||||
watch_enable_display();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief the app_prepare_for_standby function is called before the watch goes into STANDBY mode.
|
||||
* In STANDBY mode, most peripherals are shut down, and no code will run until the watch receives
|
||||
* an interrupt (generally either the 1Hz tick or a press on one of the buttons).
|
||||
*/
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief the app_wake_from_standby function is called after the watch wakes from STANDBY mode,
|
||||
* but before your main app_loop.
|
||||
*/
|
||||
void app_wake_from_standby(void) {
|
||||
application_state.wake_count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief the app_loop function is called once on app startup and then again each time the
|
||||
* watch exits STANDBY mode.
|
||||
*/
|
||||
bool app_loop(void) {
|
||||
if (application_state.beep) {
|
||||
watch_buzzer_play_note(BUZZER_NOTE_C7, 50);
|
||||
application_state.beep = false;
|
||||
}
|
||||
|
||||
// set the LED to a color
|
||||
if (application_state.light_on) {
|
||||
switch (application_state.color) {
|
||||
case COLOR_RED:
|
||||
watch_set_led_red();
|
||||
break;
|
||||
case COLOR_GREEN:
|
||||
watch_set_led_green();
|
||||
break;
|
||||
case COLOR_YELLOW:
|
||||
watch_set_led_yellow();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
watch_set_led_off();
|
||||
}
|
||||
|
||||
// Display the number of times we've woken up (modulo 32 to fit in 2 digits at top right)
|
||||
char buf[3] = {0};
|
||||
sprintf(buf, "%2d", application_state.wake_count % 32);
|
||||
watch_display_string(buf, 2);
|
||||
|
||||
// display "Hello there" text
|
||||
switch (application_state.mode) {
|
||||
case MODE_HELLO:
|
||||
watch_display_string("Hello", 5);
|
||||
break;
|
||||
case MODE_THERE:
|
||||
watch_display_string("there", 5);
|
||||
break;
|
||||
}
|
||||
|
||||
if (application_state.enter_sleep_mode) {
|
||||
// wait a moment for the user's finger to be off the button
|
||||
delay_ms(250);
|
||||
|
||||
// nap time :)
|
||||
watch_enter_deep_sleep_mode();
|
||||
|
||||
// we just woke up; wait a moment again for the user's finger to be off the button...
|
||||
delay_ms(250);
|
||||
|
||||
// and prevent ourselves from going right back to sleep.
|
||||
application_state.enter_sleep_mode = false;
|
||||
|
||||
// finally, after sleep, return false so that our app loop runs again and updates the display.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementations for our callback functions. Replace these with whatever functionality
|
||||
// your app requires.
|
||||
void cb_light_pressed(void) {
|
||||
// always turn the light off when the pin goes low
|
||||
if (watch_get_pin_level(BTN_LIGHT) == 0) {
|
||||
application_state.light_on = false;
|
||||
return;
|
||||
}
|
||||
application_state.color = (application_state.color + 1) % 3;
|
||||
application_state.light_on = true;
|
||||
}
|
||||
|
||||
void cb_mode_pressed(void) {
|
||||
application_state.mode = (application_state.mode + 1) % 2;
|
||||
application_state.beep = true;
|
||||
}
|
||||
|
||||
void cb_alarm_pressed(void) {
|
||||
application_state.enter_sleep_mode = true;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/make.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I./
|
||||
|
||||
SRCS += \
|
||||
./app.c
|
||||
|
||||
include $(TOP)/rules.mk
|
||||
@@ -1,104 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <peripheral_clk_config.h>
|
||||
#include "watch.h"
|
||||
|
||||
/*
|
||||
Beginnings of a program to take UART input and update the screen accordingly.
|
||||
Use alongside a prpgram that communicates with the watch over the UART pins.
|
||||
This CircuitPython script turns the LED red in response to pressing the LIGHT button,
|
||||
and turns it off when the MODE button is pressed:
|
||||
|
||||
```
|
||||
import board
|
||||
import busio
|
||||
|
||||
uart = busio.UART(board.TX, board.RX, baudrate=19200)
|
||||
|
||||
while True:
|
||||
uart.write(b"\x00")
|
||||
data = uart.read(1)
|
||||
|
||||
if data is not None:
|
||||
data_string = ''.join([chr(b) for b in data])
|
||||
print(data_string, end="")
|
||||
if data_string[0] == 'L':
|
||||
uart.write(b"R")
|
||||
elif data_string[0] == 'M':
|
||||
uart.write(b"O")
|
||||
```
|
||||
*/
|
||||
|
||||
|
||||
char button_pressed = 0;
|
||||
|
||||
static void cb_light_pressed(void) {
|
||||
button_pressed = 'L';
|
||||
}
|
||||
|
||||
static void cb_mode_pressed(void) {
|
||||
button_pressed = 'M';
|
||||
}
|
||||
|
||||
static void cb_alarm_pressed(void) {
|
||||
button_pressed = 'A';
|
||||
}
|
||||
|
||||
void app_init(void) {
|
||||
watch_enable_leds();
|
||||
watch_enable_buzzer();
|
||||
|
||||
watch_enable_external_interrupts();
|
||||
watch_register_interrupt_callback(BTN_MODE, cb_mode_pressed, INTERRUPT_TRIGGER_RISING);
|
||||
watch_register_interrupt_callback(BTN_LIGHT, cb_light_pressed, INTERRUPT_TRIGGER_RISING);
|
||||
watch_register_interrupt_callback(BTN_ALARM, cb_alarm_pressed, INTERRUPT_TRIGGER_RISING);
|
||||
|
||||
watch_enable_display();
|
||||
|
||||
watch_enable_uart(A2, A1, 19200);
|
||||
}
|
||||
|
||||
void app_wake_from_backup(void) {
|
||||
}
|
||||
|
||||
void app_setup(void) {
|
||||
}
|
||||
|
||||
void app_prepare_for_standby(void) {
|
||||
}
|
||||
|
||||
void app_wake_from_standby(void) {
|
||||
}
|
||||
|
||||
bool app_loop(void) {
|
||||
char buf[3];
|
||||
|
||||
if (button_pressed) {
|
||||
sprintf(buf, "%c", button_pressed);
|
||||
printf("%s\n", buf);
|
||||
watch_uart_puts(buf);
|
||||
button_pressed = 0;
|
||||
}
|
||||
char char_received = watch_uart_getc();
|
||||
if (char_received) {
|
||||
switch (char_received) {
|
||||
case 'R':
|
||||
watch_set_led_red();
|
||||
break;
|
||||
case 'G':
|
||||
watch_set_led_green();
|
||||
break;
|
||||
case 'Y':
|
||||
watch_set_led_yellow();
|
||||
break;
|
||||
case 'O':
|
||||
watch_set_led_off();
|
||||
break;
|
||||
case 'U':
|
||||
// receive a display update?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user