-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathi2c.cpp
166 lines (126 loc) · 4.6 KB
/
i2c.cpp
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
#include <stdio.h>
#include <pico/stdlib.h>
#include <pico/cyw43_arch.h>
#include <hardware/i2c.h>
#include <FreeRTOS.h>
#include <task.h>
#include <queue.h>
#include "matrix_display.h"
#include "messages.h"
#define PICO_I2C_SDA_PIN 20
#define PICO_I2C_SCL_PIN 21
#define DS3231_I2C_ADDR 0x68
#define CLIMATE_SEND_INTERVAL 60 // Send climate data every 60 seconds
#if BME680_PRESENT
extern int configure_bme680(void);
extern int receive_data(void);
extern int request_run(void);
extern float get_temperature(void);
extern float get_pressure(void);
extern float get_humidity(void);
#else
extern float get_temperature(void);
#endif
static void setup_i2c(void);
static void get_ds3231_time(uint8_t *buffer);
static void set_ds3231_time(uint8_t *buffer);
extern QueueHandle_t i2c_queue; // For listening
extern QueueHandle_t animate_queue;
extern QueueHandle_t mqtt_queue;
void i2c_task(void *dummy)
{
#if FREE_RTOS_KERNEL_SMP
vTaskCoreAffinitySet(NULL, 1 << 0);
DEBUG_printf("%s: core%u\n", pcTaskGetName(NULL), get_core_num());
#endif
static message_anim_t message_anim = {
message_type: MESSAGE_ANIM_DS3231,
};
TickType_t ticks_on_get_ds3231_time = 0;
static message_mqtt_t message_mqtt = {
message_type: MESSAGE_MQTT_CLIMATE,
};
setup_i2c();
ds3231_t old_ds3231 = {};
#if BME680_PRESENT
bool got_data = false;
bool requested_run = false;
if (!(configure_bme680())) {
DEBUG_printf("BME680: Configure failed\n");
}
#endif
static int climate_count = 0;
while (1) {
ticks_on_get_ds3231_time = xTaskGetTickCount();
get_ds3231_time(message_anim.ds3231.datetime_buffer);
// See if we are at the top of the next second
if (memcmp(&message_anim.ds3231, &old_ds3231, sizeof(ds3231_t)) != 0) {
if (xQueueSend(animate_queue, &message_anim, 10) != pdTRUE) {
DEBUG_printf("Could not send clock data; dropping\n");
}
if (climate_count == CLIMATE_SEND_INTERVAL) {
#if BME680_PRESENT
if (requested_run) {
if (!(receive_data())) {
DEBUG_printf("BME680: Failed to recieve data\n");
}
got_data = true;
}
if (!(request_run())) {
DEBUG_printf("BME680: Failed to request run\n");
}
requested_run = true;
if (got_data) {
message_mqtt.climate.temperature = get_temperature();
message_mqtt.climate.pressure = get_pressure();
message_mqtt.climate.humidity = get_humidity();
if (xQueueSend(mqtt_queue, &message_mqtt, 10) != pdTRUE) {
DEBUG_printf("Could not send climate data; dropping\n");
}
}
#else
message_mqtt.climate.temperature = get_temperature();
if (xQueueSend(mqtt_queue, &message_mqtt, 10) != pdTRUE) {
DEBUG_printf("Could not send climate data; dropping\n");
}
#endif
climate_count = 0;
}
climate_count++;
}
old_ds3231 = message_anim.ds3231;
ds3231_t set_ds3231 = {};
if (xQueueReceive(i2c_queue, &set_ds3231, 0) == pdTRUE) {
DEBUG_printf("Clock set\n");
set_ds3231_time(set_ds3231.datetime_buffer);
}
// Calculate a tenth of a second later since we got the time at the top of of the loop
int tenth_second_delay = (((100 / portTICK_PERIOD_MS) + ticks_on_get_ds3231_time)) - xTaskGetTickCount();
if (tenth_second_delay > 0) {
vTaskDelay(tenth_second_delay);
}
}
}
static void setup_i2c(void)
{
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
i2c_init(i2c_default, 100 * 1000);
gpio_set_function(PICO_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_I2C_SDA_PIN);
gpio_pull_up(PICO_I2C_SCL_PIN);
}
static void get_ds3231_time(uint8_t *buffer)
{
uint8_t val = 0x00; // device address to read from
// true to keep master control of bus
i2c_write_blocking(i2c_default, DS3231_I2C_ADDR, &val, 1, true);
i2c_read_blocking(i2c_default, DS3231_I2C_ADDR, buffer, DS3231_DATETIME_LEN, false);
}
static void set_ds3231_time(uint8_t *buffer)
{
uint8_t out[DS3231_DATETIME_LEN + 1];
out[0] = 0x00;
memcpy(&out[1], buffer, DS3231_DATETIME_LEN);
i2c_write_blocking(i2c_default, DS3231_I2C_ADDR, out, 1 + DS3231_DATETIME_LEN, false);
}