aboutsummaryrefslogtreecommitdiff
path: root/main/i2c.c
blob: d37a9b7c9871dc9a205923246c4dc51f2e402d45 (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
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <pico/stdlib.h>
#include <hardware/i2c.h>

#include "i2c.h"
#include "pb-mod.h"
#include "config.h"
#include "pb-buf.h"
#include "pb-send.h"

static pb_global_state_t _global_state = PB_GS_IDLE; 
pb_puzzle_module_t modules[CFG_PB_MOD_MAX];
// stolen from lib/pico-sdk/src/rp2_common/hardware_i2c/i2c.c
#define i2c_reserved_addr(addr) (((addr) & 0x78) == 0 || ((addr) & 0x78) == 0x78)
size_t modules_size = 0;

static void bus_scan() {
	pb_buf_t buf = pb_send_magic_req();

	// check for all 7-bit addresses
	uint16_t addr_max = 1 << 7;
	for (uint16_t addr = 0x00; addr < addr_max; addr++) {
		if (i2c_reserved_addr(addr)) continue;
		if (addr == PB_MOD_ADDR) continue;

		pb_i2c_send(addr, (uint8_t *) buf.data, buf.size);
	}

	pb_buf_free(&buf);
}

static void state_exchange() {
	

	for (size_t i = 0; i < modules_size; i++) {
		pb_buf_t buf = pb_send_state_req();
		
		pb_buf_free(&buf);
	}
}

void update_state() {
	// TODO: Add calculation(?) to get global state
	// all states idle == idle -> set first address as playingz
	// all states solved == solved
	// any state plater == playing

	pb_global_state_t module_state;
	bool playing = false; 	// default false -> loop through modules to see if one is playing -> set to true
	bool solved = true;		// default true	 -> loop through modules to see if any is not solved -> set to false

	for (size_t i = 0; i < modules_size; i++) {
		module_state = modules[i].state;
		if (module_state != PB_GS_SOLVED)
			solved == false;	
		
		if (module_state == PB_GS_PLAYING)
			playing == true;
	}

	// set state if no further processing is needed
	if (solved == true) {
		pb_hook_mod_state_write(PB_GS_SOLVED);
		return;
	} else if (playing == true) {
		pb_hook_mod_state_write(PB_GS_PLAYING);
		return;
	}

	// IF no module playing, get/set next module THAT IS NOT SOLVED to playing
	// and set mc state to playing
	// pb_i2c_send(addr, buff.msg, buff.size)
	
	for (size_t i = 0; i < modules_size; i++) {
		module_state = modules[i].state;
		if (module_state == PB_GS_IDLE) {
			pb_buf_t buff = pb_send_state_set(PB_GS_PLAYING);
			pb_i2c_send(modules[i].sender, (uint8_t*)buff.data, buff.size);
			pb_hook_mod_state_write(PB_GS_PLAYING);
			return;
		}
	}
}

void bus_task() {
	// do a scan of the bus
	bus_scan();

	while(1) {
		// send my state to all puzzle modules
		state_exchange();

		// wait 1 second
		vTaskDelay(1e3 / portTICK_PERIOD_MS);
	}
}

/**
 * \ingroup main_pb_override
 * \anchor main_route_cmd_magic_res
 *
 * This function registers the I2C address of the puzzle module that replied to
 * the \c MAGIC \c REQ command into a list of "known puzzle modules", which are
 * then periodically updated during gameplay.
 *
 * \note Up to \ref CFG_PB_MOD_MAX puzzle modules can be registered
 * simultaniously.
 */
void pb_route_cmd_magic_res(pb_msg_t * msg) {
	if (modules_size == CFG_PB_MOD_MAX) return;
	pb_puzzle_module_t tmp_module = {msg->sender, PB_GS_NOINIT};
	modules[modules_size++] = tmp_module;
	printf("i2c: registered puzzle module w/ address 0x%02x\n", msg->sender);
}

void pb_route_cmd_state_res(pb_msg_t * msg) {
	pb_cmd_state_t * cmd = msg->cmd;
	i2c_addr_t sender = msg->sender;
	
	// update sender state
	for( size_t i = 0; i < modules_size; i++ ) {
		if (modules[i].sender == sender) {
			modules[i].state = (pb_global_state_t)cmd;
			break;
		}
	}
}

pb_global_state_t pb_hook_mod_state_read() {
	return _global_state;
}

void pb_hook_mod_state_write(pb_global_state_t state) {
	_global_state = state;
}