altos: Add bit-bang i2c driver
[fw/altos] / src / kernel / ao_log_micro.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20 #include <ao_micropeak.h>
21 #include <ao_log_micro.h>
22 #ifndef LOG_MICRO_ASYNC
23 #define LOG_MICRO_ASYNC 1
24 #endif
25 #if LOG_MICRO_ASYNC
26 #include <ao_async.h>
27 #else
28 #include <ao_serial.h>
29 #endif
30 #include <ao_storage.h>
31
32 static N_SAMPLES_TYPE ao_log_offset = STARTING_LOG_OFFSET;
33
34
35 void
36 ao_log_micro_save(void)
37 {
38         N_SAMPLES_TYPE  n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t);
39
40         ao_eeprom_write(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
41         ao_eeprom_write(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
42         ao_eeprom_write(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
43 }
44
45 void
46 ao_log_micro_restore(void)
47 {
48         ao_eeprom_read(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
49         ao_eeprom_read(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
50 }
51
52 void
53 ao_log_micro_data(void)
54 {
55         uint16_t        low_bits = pa;
56
57         if (ao_log_offset < MAX_LOG_OFFSET) {
58                 ao_eeprom_write(ao_log_offset, &low_bits, sizeof (low_bits));
59                 ao_log_offset += sizeof (low_bits);
60         }
61 }
62
63 #define POLY 0x8408
64
65 static uint16_t
66 ao_log_micro_crc(uint16_t crc, uint8_t byte)
67 {
68         uint8_t i;
69
70         for (i = 0; i < 8; i++) {
71                 if ((crc & 0x0001) ^ (byte & 0x0001))
72                         crc = (crc >> 1) ^ POLY;
73                 else
74                         crc = crc >> 1;
75                 byte >>= 1;
76         }
77         return crc;
78 }
79
80 static void
81 ao_log_hex_nibble(uint8_t b)
82 {
83         if (b < 10)
84                 ao_async_byte('0' + b);
85         else
86                 ao_async_byte('a' - 10 + b);
87 }
88
89 void
90 ao_log_hex(uint8_t b)
91 {
92         ao_log_hex_nibble(b>>4);
93         ao_log_hex_nibble(b&0xf);
94 }
95
96 void
97 ao_log_newline(void)
98 {
99         ao_async_byte('\r');
100         ao_async_byte('\n');
101 }
102
103 #define MAX_N_SAMPLES   ((MAX_LOG_OFFSET - STARTING_LOG_OFFSET) / 2)
104
105 void
106 ao_log_micro_dump(void)
107 {
108         N_SAMPLES_TYPE  n_samples;
109         uint16_t        nbytes;
110         uint8_t         byte;
111         uint16_t        b;
112         uint16_t        crc = 0xffff;
113
114         ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
115
116         if (n_samples == (N_SAMPLES_TYPE) (~0))
117                 n_samples = 0;
118         nbytes = STARTING_LOG_OFFSET + sizeof (uint16_t) * n_samples;
119
120         /*
121          * Rewrite n_samples so that it includes the log ID value with
122          * 32-bit n_samples split into two chunks
123          */
124         if (sizeof (n_samples) > 2) {
125                 N_SAMPLES_TYPE  n_samples_low;
126                 N_SAMPLES_TYPE  n_samples_high;
127                 n_samples_low = n_samples & ((1 << AO_LOG_ID_SHIFT) - 1);
128                 n_samples_high = (n_samples - n_samples_low) << AO_LOG_ID_WIDTH;
129                 n_samples = n_samples_low | n_samples_high;
130         }
131 #if AO_LOG_ID
132         n_samples |= AO_LOG_ID << AO_LOG_ID_SHIFT;
133 #endif
134         ao_async_start();
135         ao_async_byte('M');
136         ao_async_byte('P');
137         for (b = 0; b < nbytes; b++) {
138                 if ((b & 0xf) == 0)
139                         ao_log_newline();
140                 ao_eeprom_read(b, &byte, 1);
141 #if AO_LOG_ID
142                 if (N_SAMPLES_OFFSET <= b && b < (N_SAMPLES_OFFSET + sizeof(n_samples))) {
143                         byte = n_samples >> ((b - N_SAMPLES_OFFSET) << 3);
144                 }
145 #endif
146                 ao_log_hex(byte);
147                 crc = ao_log_micro_crc(crc, byte);
148         }
149         ao_log_newline();
150         crc = ~crc;
151         ao_log_hex(crc >> 8);
152         ao_log_hex(crc);
153         ao_log_newline();
154         ao_async_stop();
155 }