-
Notifications
You must be signed in to change notification settings - Fork 1
/
application.c
320 lines (303 loc) · 9.29 KB
/
application.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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/*
* application.c
*
* A simple example of using cairo with c on the Raspberry Pi
*
* Copyright 2016 rricharz
*
* Modified by Frank Adams to display battery state of charge
*
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>
#include "main.h"
#include "application.h"
// Pin number declarations
#define clock 3 // SMBus clock on Pin 5, GPIO3
#define data 27 // SMBus data on Pin 15, GPIO27 (I ruined gpio 2)
#define quarter 10 // quarter period time in usec
//
_Bool error = 0; // set to 1 when battery gives a NACK
int soc = 50; // state of charge. Initial value shown until timer expires the first time
const char *utf8 = "%"; //needed to display % sign after soc
// SM Bus functions
void go_z(int pin) // float the pin and let pullup or battery set level
{
pinMode(pin, INPUT); // set pin as input to tri-state the driver
}
//
void go_0(int pin) // drive the pin low
{
pinMode(pin, OUTPUT); // set pin as output
digitalWrite(pin, LOW); // drive pin low
}
//
void go_1(int pin) // drive the pin high
{
pinMode(pin, OUTPUT); // set pin as output
digitalWrite(pin, HIGH); // drive pin high
}
//
int read_pin(int pin) // read the pin and return logic level
{
pinMode(pin, INPUT); // set pin as input
return (digitalRead(pin)); // return the logic level
}
//
void setupbus(void)
{
wiringPiSetupGpio(); //Init wiringPi using the Broadcom GPIO numbers
piHiPri(99); //Make program the highest priority (Linux will still out prioritize)
go_z(clock); // set clock and data to inactive state
go_z(data);
delayMicroseconds(200); // wait before sending data
}
//
void startbus(void)
{
delayMicroseconds(1000); // needed when doing multiple reads
go_0(data); // start condition - data low when clock goes low
delayMicroseconds(quarter);
go_0(clock);
delayMicroseconds(4 * quarter); // wait 1 period before proceeding
}
//
void send8(char sendbits)
{
// send bits 7 down to 0, using a mask that starts with 10000000
// and gets shifted right 1 bit each loop
char mask = 0x80;
for (char j=0; j<8; j++) { //loop 8 times
if (!(sendbits & mask)) { // check if mask bit is low
go_0(data); // send low
}
else
{
go_z(data); // send high
}
delayMicroseconds(quarter);
go_z(clock); // clock high
delayMicroseconds(quarter * 2);
go_0(clock); // clock low
delayMicroseconds(quarter);
mask = mask >> 1; // shift mask 1 bit to the right
}
// ack/nack
delayMicroseconds(quarter * 4);
go_z(data); // float data to see ack
delayMicroseconds(quarter);
go_z(clock); // clock high
// read data to see if battery sends a low (acknowledge transfer)
if (read_pin(data)) { // is the data bit high?
error = 1; // battery did not acknowledge the transfer
}
delayMicroseconds(quarter * 2);
go_0(clock); // clock low
go_0(data); // data low
delayMicroseconds(quarter * 90);
}
//
void sendrptstart(void) // send repeated start condition
{
go_z(data); // data high
delayMicroseconds(quarter * 8);
go_z(clock); // clock high
delayMicroseconds(quarter * 2);
go_0(data); // data low
delayMicroseconds(quarter * 2);
go_0(clock); // clock low
delayMicroseconds(quarter * 16);
}
//
int read16(void) // read low byte and high byte, return the 16 bit word
{
int readval = 0x00; // initialize read word to zero
int mask = 0x80; // start with bit 7 of low byte
// read low byte
for (int k=0; k<8; k++) {
go_z(data);
delayMicroseconds(quarter);
if (read_pin(data)) {
readval = readval | mask;
}
mask = mask >> 1; // shift mask 1 bit right
go_z(clock); // clock high
delayMicroseconds(quarter * 2);
go_0(clock); // clock low
delayMicroseconds(quarter);
}
// ack/nack of low byte
delayMicroseconds(quarter * 2);
go_0(data); // send ack back to battery
delayMicroseconds(quarter);
go_z(clock); // clock high
delayMicroseconds(quarter * 2);
go_0(clock); // clock low
go_0(data); // data low
delayMicroseconds(quarter * 40);
// read high byte
mask = 0x8000; // start with bit 7 of high byte
for (int k=0; k<8; k++) {
go_z(data);
delayMicroseconds(quarter);
if (read_pin(data)) {
readval = readval | mask;
}
mask = mask >> 1; // shift mask 1 bit right
go_z(clock); // clock high
delayMicroseconds(quarter * 2);
go_0(clock); // clock low
delayMicroseconds(quarter);
}
// ack/nack of high byte
delayMicroseconds(quarter * 2);
go_z(data); // send nack back to battery
delayMicroseconds(quarter);
go_z(clock); // clock high
delayMicroseconds(quarter * 2);
go_0(clock); // clock low
go_0(data); // data low
delayMicroseconds(quarter * 8);
return readval;
}
//
void stopbus(void) // stop condition, data low when clock goes high
{
go_z(clock); // clock high
delayMicroseconds(quarter);
go_z(data); // data high
delayMicroseconds(quarter * 30);
}
// rricharz cairo functions. All printf are commented out but can be used for debug
void application_init()
// put SMBus code here to initialize the application
{
// printf("application_init called\n");
setupbus(); // initialize wiringPi and setup the GPIO SMBus
}
int application_on_timer_event()
// if TIMER_INTERVAL in application.h is larger than zero, this function
// is called every TIMER_INTERVAL milliseconds
// if the function returns 1, the window is redrawn by calling applicatin_draw
{
// printf("application_on_timer_event called\n");
// Read the SOC over the SM Bus
error = 0; // initialize to no error
startbus(); // send start condition
send8(0x16); // send battery address 0x16 (0x0b w/ write)
send8(0x0d); // load soc register pointer 0x0d
sendrptstart(); // send repeated start codition
send8(0x17); // send battery address 0x17 (0x0b w/ read)
soc = read16(); // read soc low & high bytes
stopbus(); // send stop condition
if ((soc >= 150) | (error)) {//if out of range or any nack's, try again
startbus(); // send start condition
send8(0x16); // send battery address 0x16 (0x0b w/ write)
send8(0x0d); // load register pointer 0x0d
sendrptstart(); // send repeated start codition
send8(0x17); // send battery address 0x17 (0x0b w/ read)
soc = read16(); //read low & high bytes
stopbus(); // send stop condition
}
// printf ("State of Charge = %d percent\n", soc);
return 1;
}
int application_clicked(int button, int x, int y)
// is called if a mouse button is clicked in the window
// button = 1: means left mouse button; button = 3 means right mouse button
// x and y are the coordinates
// if the function returns 1, the window is redrawn by calling applicatin_draw
{
// printf("application_clicked called, button %d, x = %d, y= %d\n", button, x, y);
return 1;
}
void application_quit()
// is called if the main window is called before the applcation exits
// put any code here which needs to be called on exit
{
// printf("application quit called\n");
}
void application_draw(cairo_t *cr, int width, int height)
// draw onto the main window using cairo
// width is the actual width of the main window
// height is the actual height of the main window
{
// printf("application_draw called\n");
// show battery symbol with fill = soc
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); //black
cairo_set_line_width (cr, 2);
cairo_rectangle (cr, 52, 16, 2, 2); // make little box for battery + terminal
cairo_rectangle (cr, 10, 10, 42, 14); // draw overall battery rectangle
cairo_stroke (cr);
cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); //red
if (soc < 10) {
cairo_rectangle (cr, 11, 11, 5, 12); // draw soc rectangle
}
else if (soc < 15) {
cairo_rectangle (cr, 11, 11, 7, 12); // draw soc rectangle
}
else if (soc < 20) {
cairo_rectangle (cr, 11, 11, 9, 12); // draw soc rectangle
}
else if (soc < 25) {
cairo_rectangle (cr, 11, 11, 11, 12); // draw soc rectangle
}
else if (soc < 30) {
cairo_rectangle (cr, 11, 11, 13, 12); // draw soc rectangle
}
else if (soc < 35) {
cairo_rectangle (cr, 11, 11, 15, 12); // draw soc rectangle
}
else if (soc < 40) {
cairo_rectangle (cr, 11, 11, 17, 12); // draw soc rectangle
}
else if (soc < 45) {
cairo_rectangle (cr, 11, 11, 19, 12); // draw soc rectangle
}
else if (soc < 50) {
cairo_rectangle (cr, 11, 11, 21, 12); // draw soc rectangle
}
else if (soc < 55) {
cairo_rectangle (cr, 11, 11, 23, 12); // draw soc rectangle
}
else if (soc < 60) {
cairo_rectangle (cr, 11, 11, 25, 12); // draw soc rectangle
}
else if (soc < 65) {
cairo_rectangle (cr, 11, 11, 27, 12); // draw soc rectangle
}
else if (soc < 70) {
cairo_rectangle (cr, 11, 11, 29, 12); // draw soc rectangle
}
else if (soc < 75) {
cairo_rectangle (cr, 11, 11, 31, 12); // draw soc rectangle
}
else if (soc < 80) {
cairo_rectangle (cr, 11, 11, 33, 12); // draw soc rectangle
}
else if (soc < 85) {
cairo_rectangle (cr, 11, 11, 35, 12); // draw soc rectangle
}
else if (soc < 90) {
cairo_rectangle (cr, 11, 11, 37, 12); // draw soc rectangle
}
else if (soc < 95) {
cairo_rectangle (cr, 11, 11, 40, 12); // draw soc rectangle
}
else {
cairo_rectangle (cr, 11, 11, 42, 12); // draw soc rectangle
}
cairo_fill(cr); //fill the soc rectangle
cairo_stroke (cr);
// display SOC Text
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); //black
cairo_select_font_face(cr, "Purisa", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 16);
cairo_move_to(cr, width / 8, height / 1);
char s[16]; //
sprintf(s, "%d", soc);
cairo_show_text(cr, s);
cairo_show_text(cr, utf8); // display the % sign
}