Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_atsha204.c
1 #include <bc_atsha204.h>
2 #include <bc_tick.h>
3 
4 #define _BC_ATSHA204_OPCODE_NULL 0x00
5 #define _BC_ATSHA204_OPCODE_DEVREV 0x30
6 #define _BC_ATSHA204_OPCODE_READ 0x02
7 
8 static void _bc_atsha204_task(void *param);
9 static bool _bc_atsha204_send_command(bc_atsha204_t *self, uint8_t opcode, uint8_t param0, uint16_t param1);
10 static void _bc_atsha204_wakeup_puls(bc_atsha204_t *self);
11 static bool _bc_atsha204_wakeup(bc_atsha204_t *self);
12 static bool _bc_atsha204_read(bc_atsha204_t *self, uint8_t *buffer, size_t length);
13 static uint16_t _bc_atsha204_calculate_crc16(uint8_t *buffer, uint8_t length);
14 
15 void bc_atsha204_init(bc_atsha204_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
16 {
17  memset(self, 0, sizeof(*self));
18 
19  self->_i2c_channel = i2c_channel;
20  self->_i2c_address = i2c_address;
21 
22  bc_i2c_init(self->_i2c_channel, BC_I2C_SPEED_400_KHZ);
23 
24  self->_task_id = bc_scheduler_register(_bc_atsha204_task, self, BC_TICK_INFINITY);
25 
26  self->_ready = true;
27 }
28 
29 void bc_atsha204_set_event_handler(bc_atsha204_t *self, void (*event_handler)(bc_atsha204_t *, bc_atsha204_event_t, void *), void *event_param)
30 {
31  self->_event_handler = event_handler;
32  self->_event_param = event_param;
33 }
34 
36 {
37  return self->_ready;
38 }
39 
41 {
42  if (!bc_atsha204_is_ready(self))
43  {
44  return false;
45  }
46 
47  if (!_bc_atsha204_send_command(self, _BC_ATSHA204_OPCODE_READ, 0, 0x00))
48  {
49  return false;
50  }
51 
52  self->_ready = false;
53  self->_state = BC_ATSHA204_STATE_READ_SERIAL_NUMBER;
54 
55  bc_scheduler_plan_relative(self->_task_id, 4);
56  return true;
57 }
58 
59 bool bc_atsha204_get_serial_number(bc_atsha204_t *self, void *destination, size_t size)
60 {
61  if (!bc_atsha204_is_ready(self) || self->_state != BC_ATSHA204_STATE_SERIAL_NUMBER)
62  {
63  return false;
64  }
65 
66  uint8_t *number = (uint8_t *) destination;
67 
68  size_t i = 0;
69 
70  for (; (i < size) && (i < 2); i++)
71  {
72  *number++ = self->_rx_buffer[3 + i];
73  }
74 
75  for (; (i < size) && (i < 6); i++)
76  {
77  *number++ = self->_rx_buffer[6 + i];
78  }
79 
80  for (; i < size; i++)
81  {
82  *number++ = 0;
83  }
84 
85  return true;
86 }
87 
88 static void _bc_atsha204_task(void *param)
89 {
90  bc_atsha204_t *self = param;
91 
93 
94  switch (self->_state) {
95  case BC_ATSHA204_STATE_READ_SERIAL_NUMBER:
96  {
97  if (!_bc_atsha204_read(self, self->_rx_buffer, 7))
98  {
99  break;
100  }
101 
102  if (!_bc_atsha204_send_command(self, _BC_ATSHA204_OPCODE_READ, 0, 0x02))
103  {
104  break;
105  }
106 
107  self->_state = BC_ATSHA204_STATE_READ_SERIAL_NUMBER2;
109  return;
110  }
111  case BC_ATSHA204_STATE_READ_SERIAL_NUMBER2:
112  {
113  if (!_bc_atsha204_read(self, self->_rx_buffer + 7, 7))
114  {
115  break;
116  }
117 
118  self->_state = BC_ATSHA204_STATE_SERIAL_NUMBER;
120 
121  break;
122  }
123  case BC_ATSHA204_STATE_READY:
124  case BC_ATSHA204_STATE_SERIAL_NUMBER:
125  default:
126  {
127  return;
128  }
129  }
130 
131  self->_ready = true;
132 
133  if (self->_event_handler)
134  {
135  self->_event_handler(self, event, self->_event_param);
136  }
137 
138 
139 }
140 
141 static bool _bc_atsha204_send_command(bc_atsha204_t *self, uint8_t opcode, uint8_t param0, uint16_t param1)
142 {
143  uint8_t buffer[8];
144  buffer[0] = 0x03;
145  buffer[1] = 7;
146  buffer[2] = opcode;
147  buffer[3] = param0;
148  buffer[4] = param1 & 0xff;
149  buffer[5] = param1 >> 8;
150 
151  uint16_t crc = _bc_atsha204_calculate_crc16(buffer + 1, 5);
152 
153  buffer[6] = crc & 0xff;
154  buffer[7] = crc >> 8;
155 
156  bc_i2c_transfer_t transfer;
157  transfer.device_address = self->_i2c_address;
158  transfer.buffer = buffer;
159  transfer.length = 8;
160 
161  if (!bc_i2c_write(self->_i2c_channel, &transfer))
162  {
163  if (!_bc_atsha204_wakeup(self))
164  {
165  return false;
166  }
167 
168  if (!bc_i2c_write(self->_i2c_channel, &transfer))
169  {
170  return false;
171  }
172  }
173 
174  return true;
175 }
176 
177 static bool _bc_atsha204_read(bc_atsha204_t *self, uint8_t *buffer, size_t length)
178 {
179  bc_i2c_transfer_t transfer;
180  transfer.device_address = self->_i2c_address;
181  transfer.buffer = buffer;
182  transfer.length = length;
183 
184  if (!bc_i2c_read(self->_i2c_channel, &transfer))
185  {
186 
187  _bc_atsha204_wakeup_puls(self);
188 
189  if (!bc_i2c_read(self->_i2c_channel, &transfer))
190  {
191  if (!bc_i2c_read(self->_i2c_channel, &transfer))
192  {
193  return false;
194  }
195  }
196  }
197 
198  uint16_t crc = _bc_atsha204_calculate_crc16(buffer, length - 2);
199 
200  return (buffer[0] == length) &&
201  (buffer[length - 2] == (uint8_t) (crc & 0x00FF)) &&
202  (buffer[length - 1] = (uint8_t) (crc >> 8));
203 }
204 
205 static void _bc_atsha204_wakeup_puls(bc_atsha204_t *self)
206 {
207  bc_i2c_set_speed(self->_i2c_channel, BC_I2C_SPEED_100_KHZ);
208 
209  bc_i2c_transfer_t transfer = {.device_address = 0x00, .buffer = NULL, .length = 0};
210 
211  bc_i2c_write(self->_i2c_channel, &transfer);
212 
213  bc_i2c_set_speed(self->_i2c_channel, BC_I2C_SPEED_400_KHZ);
214 }
215 
216 static bool _bc_atsha204_wakeup(bc_atsha204_t *self)
217 {
218  _bc_atsha204_wakeup_puls(self);
219 
220  uint8_t buffer[4];
221  bc_i2c_transfer_t transfer;
222  transfer.device_address = self->_i2c_address;
223  transfer.buffer = buffer;
224  transfer.length = sizeof(buffer);
225 
226  if (!bc_i2c_read(self->_i2c_channel, &transfer))
227  {
228  if (!bc_i2c_read(self->_i2c_channel, &transfer))
229  {
230  return false;
231  }
232  }
233 
234  return ((buffer[0] == 0x04) && buffer[1] == 0x11 && buffer[2] == 0x33 && buffer[3] == 0x43);
235 }
236 
237 static uint16_t _bc_atsha204_calculate_crc16(uint8_t *buffer, uint8_t length)
238 {
239  uint16_t crc16;
240  uint8_t shift_register;
241  uint8_t data;
242  uint8_t data_bit;
243  uint8_t crc_bit;
244 
245  for (crc16 = 0; length != 0; length--, buffer++)
246  {
247  data = *buffer;
248 
249  for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) {
250 
251  data_bit = (data & shift_register) ? 1 : 0;
252 
253  crc_bit = crc16 >> 15;
254 
255  crc16 <<= 1;
256 
257  if (data_bit != crc_bit)
258  {
259  crc16 ^= 0x8005;
260  }
261  }
262  }
263 
264  return crc16;
265 }
I2C transfer parameters.
Definition: bc_i2c.h:42
I2C communication speed is 400 kHz.
Definition: bc_i2c.h:36
bool bc_atsha204_read_serial_number(bc_atsha204_t *self)
Reqeust for serial number.
Definition: bc_atsha204.c:40
bc_atsha204_event_t
Definition: bc_atsha204.h:14
uint8_t device_address
7-bit I2C device address
Definition: bc_i2c.h:45
bool bc_i2c_read(bc_i2c_channel_t channel, const bc_i2c_transfer_t *transfer)
Read from I2C channel.
Definition: bc_i2c.c:283
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_i2c_init(bc_i2c_channel_t channel, bc_i2c_speed_t speed)
Initialize I2C channel.
Definition: bc_i2c.c:54
I2C communication speed is 100 kHz.
Definition: bc_i2c.h:33
void * buffer
Pointer to buffer which is being written or read.
Definition: bc_i2c.h:48
bool bc_i2c_write(bc_i2c_channel_t channel, const bc_i2c_transfer_t *transfer)
Write to I2C channel.
Definition: bc_i2c.c:237
Event serial number is available.
Definition: bc_atsha204.h:23
bool bc_atsha204_is_ready(bc_atsha204_t *self)
Check if is ready for commands.
Definition: bc_atsha204.c:35
void bc_scheduler_plan_relative(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to tick relative from current spin.
Definition: bc_scheduler.c:129
struct bc_atsha204_t bc_atsha204_t
ATSHA204 instance.
Definition: bc_atsha204.h:29
bc_i2c_channel_t
I2C channels.
Definition: bc_i2c.h:15
void bc_i2c_set_speed(bc_i2c_channel_t channel, bc_i2c_speed_t speed)
Set I2C channel speed.
Definition: bc_i2c.c:194
size_t length
Length of buffer which is being written or read.
Definition: bc_i2c.h:51
void bc_scheduler_plan_current_from_now(bc_tick_t tick)
Schedule current task to tick relative from now.
Definition: bc_scheduler.c:154
bool bc_atsha204_get_serial_number(bc_atsha204_t *self, void *destination, size_t size)
Get serial number.
Definition: bc_atsha204.c:59
void bc_atsha204_set_event_handler(bc_atsha204_t *self, void(*event_handler)(bc_atsha204_t *, bc_atsha204_event_t, void *), void *event_param)
Set callback function.
Definition: bc_atsha204.c:29
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
void bc_atsha204_init(bc_atsha204_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize ATSHA204 driver.
Definition: bc_atsha204.c:15