summaryrefslogtreecommitdiffstats
path: root/Sensor Watch Starter Project/app/app.c
blob: 1ada8a3f70e47a9114a7e8c90f36a5f832b6003b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#include <stdio.h>
#include <string.h>
#include "app.h"

// these are implemented in main.c, just want to have access to them here.
void uart_putc(char c);
void uart_puts(char *s);

typedef enum ApplicationMode {
    MODE_TIME,
    MODE_SENSE,
    MODE_SET_HOUR,
    MODE_SET_MINUTE,
    MODE_SET_SECOND
} ApplicationMode;

typedef struct ApplicationState {
    ApplicationMode mode;
    bool light_pressed;
    bool mode_pressed;
    bool alarm_pressed;
    bool light_on;
    uint16_t dig_T1; /**< dig_T1 cal register. */
    int16_t dig_T2;  /**<  dig_T2 cal register. */
    int16_t dig_T3;  /**< dig_T3 cal register. */
} ApplicationState;

ApplicationState applicationState;

void cb_light_pressed() {
    applicationState.light_pressed = true;
}

void cb_mode_pressed() {
    applicationState.mode_pressed = true;
}

void cb_alarm_pressed() {
    applicationState.alarm_pressed = true;
}

void cb_tick() {
    ;
}
#define BMP280_REGISTER_DIG_T1 0x88
#define BMP280_REGISTER_DIG_T2 0x8A
#define BMP280_REGISTER_DIG_T3 0x8C
#define BMP280_REGISTER_SOFTRESET 0xE0
#define BMP280_REGISTER_STATUS 0xF3
#define BMP280_REGISTER_CONTROL 0xF4
#define BMP280_REGISTER_CONFIG 0xF5
#define BMP280_REGISTER_PRESSUREDATA 0xF7
#define BMP280_REGISTER_TEMPDATA 0xFA

uint16_t read8(uint8_t reg) {
    uint8_t val;
    watch_i2c_send(0x77, &reg, 1);
    watch_i2c_receive(0x77, &val, 1);
    return val;
}

uint16_t read16(uint8_t reg) {
    uart_puts("\nReading 2 bytes... ");
    uint8_t buf[2];
    watch_i2c_send(0x77, &reg, 1);
    watch_i2c_receive(0x77, (uint8_t *)&buf, 2);
    uart_puts("received!\n");
    char buf2[32] = {0};
    sprintf(buf2, "buf has values: %#02x, %#02x", buf[0], buf[1]);
    uart_puts(buf2);

    return (buf[0] << 8) | buf[1];
}

uint32_t read24(uint8_t reg) {
    uart_puts("\nReading 3 bytes... ");
    uint32_t value;
    uint8_t buf[3];

    watch_i2c_send(0x77, &reg, 1);
    watch_i2c_receive(0x77, (uint8_t *)&buf, 3);
    uart_puts("received!\n");
    char buf2[33] = {0};
    sprintf(buf2, "buf has values: %#02x, %#02x, %#02x", buf[0], buf[1], buf[2]);
    uart_puts(buf2);

    value = buf[0];
    value <<= 8;
    value |= buf[1];
    value <<= 8;
    value |= buf[2];

    return value;
}

uint16_t read16_LE(uint8_t reg) {
  uint16_t temp = read16(reg);
  return (temp >> 8) | (temp << 8);
}

int16_t readS16(uint8_t reg) { 
    return (int16_t)read16(reg); 
}

int16_t readS16_LE(uint8_t reg) {
  return (int16_t)read16_LE(reg);
}

void print_temperature() {
    int32_t var1, var2;
    int32_t t_fine;

    int32_t adc_T = read24(BMP280_REGISTER_TEMPDATA);
    adc_T >>= 4;

    var1 = ((((adc_T >> 3) - ((int32_t)applicationState.dig_T1 << 1))) *
        ((int32_t)applicationState.dig_T2)) >>
        11;

    var2 = (((((adc_T >> 4) - ((int32_t)applicationState.dig_T1)) *
        ((adc_T >> 4) - ((int32_t)applicationState.dig_T1))) >>
        12) *
        ((int32_t)applicationState.dig_T3)) >>
        14;

    t_fine = var1 + var2;

    float T = ((t_fine * 5 + 128) >> 8) / 100.0;

    char buf[32] = {0};
    sprintf(buf, "\n\nTemp is %3.2f degrees C", T);
    uart_puts(buf);
}

/**
 * @brief the app_init 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.)
 * 
 * @note If your app enters the ultra-low power BACKUP sleep mode, this function will 
 * be called again when it wakes from that deep sleep state. In this state, the RTC will
 * still be configured with the correct date and time.
 */
void app_init() {
    memset(&applicationState, 0, sizeof(applicationState));
    watch_enable_buttons();
    watch_register_button_callback(BTN_LIGHT, cb_light_pressed);

    watch_enable_date_time();
    watch_enable_tick_callback(cb_tick);
    
    watch_enable_display();
    watch_enable_led();
    watch_enable_i2c();

    uart_puts("\n\nI2C Driver Test\n");
    uint8_t reset_cmd[] = {0xE0, 0xB6};
    watch_i2c_send(0x77, reset_cmd, 2);
    uart_puts("Reset BMP280\n");
    applicationState.dig_T1 = read16_LE(BMP280_REGISTER_DIG_T1);
    applicationState.dig_T2 = readS16_LE(BMP280_REGISTER_DIG_T2);
    applicationState.dig_T3 = readS16_LE(BMP280_REGISTER_DIG_T3);

    uint8_t ctrl_cmd[] = {0xF4, 0xA3};
    watch_i2c_send(0x77, ctrl_cmd, 2);
}

/**
 * @brief the app_prepare_for_sleep function is called before the watch goes into the
 * STANDBY sleep 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_sleep() {
    applicationState.light_pressed = false;
    applicationState.mode_pressed = false;
    applicationState.alarm_pressed = false;
}

/**
 * @brief the app_wake_from_sleep function is called after the watch wakes from the
 * STANDBY sleep mode.
 */
void app_wake_from_sleep() {

}

void app_loop() {
    if (applicationState.light_pressed) {
        print_temperature();
    }
    uart_putc('.');
}