-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpcf2123.c
219 lines (196 loc) · 6.18 KB
/
pcf2123.c
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/* Copyright (C) 2012 Owen DeLong
This software is licensed under the GNU LGPL. You may
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this software; if not, see
<http://www.gnu.org/licenses/>. */
#include <pcf2123.h>
#include <stdarg.h>
#include <time.h>
void debug(int lvl, char *fmt, ...);
#define DEBUG 0
/* Delay 30 nanoseconds to let RTC catch up after each operation */
void delay_rtc_trec()
{
struct timespec tv;
tv.tv_sec=0;
tv.tv_nsec=30;
nanosleep(&tv, NULL);
}
/* Connect to the clock and return a valid handle. Returns NULL on failure. */
struct mpsse_context *OpenClock(int VID, int PID, uint32_t FREQ)
{
int vid;
int pid;
uint32_t freq;
struct mpsse_context *rv;
debug(5, "OpenClock: VID=%d, PID=%d, FREQ=%d\n", VID, PID, FREQ);
vid = (VID ? VID : 0x0403); /* Default VID/PID */
pid = (PID ? PID : 0x6010);
freq = (FREQ ? FREQ : 5000); /* Default to 100 Khz */
debug(5, "OpenClock: vid=%d, pid=%d, freq=%d\n", vid, pid, freq);
rv=Open(vid, pid, SPI0, freq, MSB, IFACE_A, NULL, NULL);
debug(6, "OpenClock: Open returned %s\n", (rv ? "Success" : "Failure"));
SetCSIdle(rv, 0);
return(rv);
}
/* Reset the Clock */
int ResetClock(struct mpsse_context *clock_handle)
{
char c[2];
int rv;
debug(5, "ResetClock\n");
c[0] = CLOCK_RESET;
rv=WriteClock(clock_handle, 0, c, 1);
delay_rtc_trec();
return(rv);
}
/* Read from Clock starting at register start for size bytes */
char *ReadClock(struct mpsse_context *clock_handle, unsigned char start, int size)
{
char c[2];
char *rv;
debug(5, "ReadClock: Start=%d Size=%d\n", start, size);
c[0] = CLOCK_READ | (start & 0x0f);
Start(clock_handle);
Write(clock_handle, c, 1);
rv = Read(clock_handle, size);
Stop(clock_handle);
delay_rtc_trec();
return(rv);
}
/* Write buffer to Clock starting at register start for size bytes */
int WriteClock(struct mpsse_context *clock_handle, unsigned char start, char *buffer, int size)
{
char c[2];
int rv;
debug(5, "WriteClock: Start=%d Size=%d\n", start, size);
c[0] = CLOCK_WRITE | (start & 0x0f);
Start(clock_handle);
Write(clock_handle, c, 1);
rv = Write(clock_handle, buffer, size);
Stop(clock_handle);
delay_rtc_trec();
return(rv);
}
/* Attempt to start the Clock and verify the Oscillator is running
*
* Return values: 0 -- Oscillator successfully started or already running
* -1 -- Failed to start oscillator
*/
int StartOscillator(struct mpsse_context *clock_handle)
{
char *buf;
char c[2];
int rv;
debug(5, "StartOscillator\n");
c[0]=CLOCK_READ; /* Read current Control1 values */
debug(10, "\tStart\n");
Start(clock_handle);
debug(10, "\tWriteCommand\n");
Write(clock_handle, c, 1);
debug(10, "\tReadData\n");
buf = Read(clock_handle, 1);
debug(10, "\tStop\n");
Stop(clock_handle);
delay_rtc_trec();
debug(9, "\tRetrieved: %02x from Control1\n", buf[0]);
c[0]=CLOCK_WRITE | 0x00; /* Clear STOP flag in Control1 */
buf[0] &= 0xdf;
debug(9, "\tSetting: %02x to Control1\n", buf[0]);
Start(clock_handle);
Write(clock_handle, c, 1);
Write(clock_handle, buf, 1);
Stop(clock_handle);
free(buf); /* free buffer from previous operations */
delay_rtc_trec();
c[0]=CLOCK_READ | 0x02; /* Read current Seconds register */
Start(clock_handle);
Write(clock_handle, c, 1);
buf = Read(clock_handle, 1);
Stop(clock_handle);
delay_rtc_trec();
debug(9, "\tRetrieved: %02x from OS/Seconds\n", buf[0]);
c[0]=CLOCK_WRITE | 0x02; /* Attempt to clear OS flag in Seconds register */
buf[0] &= 0x7f;
debug(9, "\tSetting: %02x to OS/Seconds\n", buf[0]);
Start(clock_handle);
Write(clock_handle, c, 1);
Write(clock_handle, buf, 1);
Stop(clock_handle);
free(buf); /* free buffer from previous operations */
delay_rtc_trec();
c[0]=CLOCK_READ | 0x02; /* Read Seconds register to verify OS Cleared */
Start(clock_handle);
Write(clock_handle, c, 1);
buf = Read(clock_handle, 1);
Stop(clock_handle);
delay_rtc_trec();
debug(7, "\tResulting OS/Seconds: %d\n", buf[0]);
rv=0; /* Prepare return value */
if (buf[0] & 0x80) rv=-1;
free(buf); /* Free buffer from previous operations */
debug(5, "StartOscillator: Return %d\n", rv);
return(rv);
}
/* Stop the clock and verify it stopped
*
* Return values: 0 -- Oscillator successfully stopped or not running
* -1 -- Failed to stop oscillator
*/
int StopOscillator(struct mpsse_context *clock_handle)
{
char *buf;
char c[2];
int rv;
debug(5, "StopOscillator:\n");
c[0]=CLOCK_READ; /* Read in the Control1 Register */
Start(clock_handle);
Write(clock_handle, c, 1);
buf = Read(clock_handle, 1);
debug(9, "\tRetrieved: %02x from Control1\n", buf[0]);
Stop(clock_handle);
delay_rtc_trec();
c[0]=CLOCK_WRITE; /* Prepare to Write new value to Control1 Register */
buf[0] |= 0x20; /* Bring STOP flag high in Control1 Register */
debug(9, "\tSetting: %02x to Control1\n", buf[0]);
Start(clock_handle);
Write(clock_handle, c, 1);
Write(clock_handle, buf, 1); /* Write out new value */
Stop(clock_handle);
delay_rtc_trec();
free(buf);
c[0]=CLOCK_READ | 0x00; /* Read in the Control1 Register */
Start(clock_handle);
Write(clock_handle, c, 1);
buf = Read(clock_handle, 1);
Stop(clock_handle);
delay_rtc_trec();
debug(9, "\tResulting: %02x in Control1\n", buf[0]);
rv=0; /* Prepare return value */
if (buf[0] & 0x20) rv=-1;
free(buf); /* Free buffer from previous operations */
debug(5, "StopOscillator: Return %d\n", rv);
return(rv);
}
void CloseClock(struct mpsse_context *clock_handle)
{
debug(5, "CloseClock\n");
return(Close(clock_handle));
}
void debug(int lvl, char *fmt, ...)
{
va_list ap;
if (DEBUG > lvl)
{
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
}