1 // Copyright (C) 2019 Jaslo Ziska
10 #include <mipea/gpio.h>
11 #include <curl/curl.h>
14 #include "photobox_photo.h"
15 #include "apikey.h" // are you looking for this? :)
18 #define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
22 void pb_show_main(void);
23 void pb_show_send(void);
24 void pb_show_qr(void);
26 gboolean
pb_poll_buttton(void);
27 gboolean
pb_countdown(void);
28 void pb_takepic(void);
30 int pb_cp_dp(char *id
);
32 static GtkWidget
*img
;
33 static GtkWidget
*button_take
;
34 static GtkWidget
*label_countdown
;
36 static GtkWidget
*button_upload
;
37 static GtkWidget
*button_cancel
;
39 static GtkWidget
*qr_img
;
40 static GtkWidget
*qr_label
;
41 static GtkWidget
*qr_button_back
;
43 static const unsigned int IMG_WIDTH
= 512;
44 static const unsigned int IMG_HEIGHT
= 384;
45 static const unsigned int QR_SIZE
= 350;
47 static unsigned int button_pin
= 26;
49 int main(int argc
, char *argv
[])
51 if (pb_ph_init() != 0) {
52 fprintf(stderr
, "ERROR in pb_ph_init\n");
55 if (gpio_map() == NULL
) {
56 fprintf(stderr
, "ERROR in gpio_map\n");
59 gtk_init(&argc
, &argv
);
61 signal(SIGCHLD
, SIG_IGN
);
65 gpio_pud(button_pin
, PUD_UP
);
68 GtkWidget
*window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
69 gtk_window_set_title(GTK_WINDOW(window
), "Photobox");
70 gtk_window_fullscreen(GTK_WINDOW(window
));
71 //g_signal_connect(window, "delete-event", G_CALLBACK(pb_gui_on_delete_main), NULL);
72 g_signal_connect(window
, "destroy", G_CALLBACK(pb_exit
), NULL
);
74 gtk_widget_realize(window
);
75 GdkCursor
* cursor_blank
= gdk_cursor_new(GDK_BLANK_CURSOR
);
76 gdk_window_set_cursor(gtk_widget_get_window(window
), cursor_blank
);
79 GtkWidget
*box_v
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0);
80 gtk_container_add(GTK_CONTAINER(window
), box_v
);
81 gtk_widget_show(box_v
);
84 GtkWidget
*box_h
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0);
85 gtk_box_pack_end(GTK_BOX(box_v
), box_h
, TRUE
, FALSE
, 0);
86 gtk_widget_show(box_h
);
89 img
= gtk_image_new_from_file("no_signal.png");
90 gtk_box_pack_end(GTK_BOX(box_v
), img
, TRUE
, FALSE
, 0);
92 // BUTTON: TAKE PICTURE
93 button_take
= gtk_button_new();
95 GtkWidget
*button_take_label
= gtk_label_new(NULL
);
96 gtk_label_set_markup(GTK_LABEL(button_take_label
), "<span font='50'>Bild aufnehmen</span>");
97 gtk_container_add(GTK_CONTAINER(button_take
), button_take_label
);
98 gtk_widget_show(button_take_label
);
100 gtk_box_pack_start(GTK_BOX(box_h
), button_take
, TRUE
, FALSE
, 0);
101 g_signal_connect(button_take
, "clicked", G_CALLBACK(pb_countdown
), NULL
);
104 label_countdown
= gtk_label_new(NULL
);
105 gtk_box_pack_end(GTK_BOX(box_v
), label_countdown
, TRUE
, FALSE
, 0);
108 button_upload
= gtk_button_new_with_label("Hochladen");
109 //g_signal_connect(button_upload, "clicked", G_CALLBACK(pb_exit), NULL);
110 g_signal_connect(button_upload
, "clicked", G_CALLBACK(pb_show_qr
), NULL
);
111 gtk_box_pack_start(GTK_BOX(box_h
), button_upload
, TRUE
, FALSE
, 0);
114 button_cancel
= gtk_button_new_with_label("Abbrechen");
115 //g_signal_connect(button_cancel, "clicked", G_CALLBACK(pb_exit), NULL);
116 g_signal_connect(button_cancel
, "clicked", G_CALLBACK(pb_show_main
), NULL
);
117 gtk_box_pack_start(GTK_BOX(box_h
), button_cancel
, TRUE
, FALSE
, 0);
120 qr_img
= gtk_image_new_from_file("no_signal.png");
121 gtk_box_pack_end(GTK_BOX(box_v
), qr_img
, TRUE
, FALSE
, 0);
124 qr_label
= gtk_label_new(NULL
);
125 gtk_label_set_justify(GTK_LABEL(qr_label
), GTK_JUSTIFY_CENTER
);
126 gtk_label_set_line_wrap(GTK_LABEL(qr_label
), TRUE
);
127 gtk_box_pack_end(GTK_BOX(box_v
), qr_label
, TRUE
, FALSE
, 0);
130 qr_button_back
= gtk_button_new_with_label("Zurück");
131 g_signal_connect(qr_button_back
, "clicked", G_CALLBACK(pb_show_main
), NULL
);
132 //g_signal_connect(qr_button_back, "clicked", G_CALLBACK(pb_exit), NULL);
133 gtk_box_pack_start(GTK_BOX(box_h
), qr_button_back
, TRUE
, FALSE
, 0);
136 gtk_widget_show(window
);
150 void pb_show_main(void)
152 gtk_widget_hide(img
);
153 gtk_widget_hide(button_upload
);
154 gtk_widget_hide(button_cancel
);
155 gtk_widget_hide(qr_img
);
156 gtk_widget_hide(qr_label
);
157 gtk_widget_hide(qr_button_back
);
159 gtk_widget_show(button_take
);
161 // take picture with button (ugly)
162 g_idle_add(G_SOURCE_FUNC(pb_poll_buttton
), NULL
);
165 void pb_show_send(void)
167 gtk_widget_show(img
);
168 gtk_widget_show(button_upload
);
169 gtk_widget_show(button_cancel
);
171 gtk_widget_hide(label_countdown
);
174 void pb_show_qr(void)
176 gtk_widget_hide(img
);
177 gtk_widget_hide(button_upload
);
178 gtk_widget_hide(button_cancel
);
180 gtk_widget_show(qr_img
);
181 gtk_widget_show(qr_label
);
182 gtk_widget_show(qr_button_back
);
186 strftime(id
, 7, "%H%M%S", localtime(&(time_t) {time(NULL
)}));
190 // child -> copy and upload
191 if (pb_cp_dp(id
) != 0) {
192 fprintf(stderr
, "ERROR in pb_cp_dp\n");
197 } else if (pid
< 0) {
198 fprintf(stderr
, "ERROR in fork (big problem)\n");
200 // try to at least save the picture (the ugly way)
201 char *cmd
= "cp tmp.jpg bilder/xxxxxx.jpg";
202 for (unsigned int i
= 0; i
< 6; ++i
) {
205 if (system(cmd
) != 0)
206 perror("ERROR in system(), picture could not be saved");
208 // go back to start, dont show qr
213 // parent -> continue GUI
215 // url qr should point to
216 // example: https://www.dropbox.com/sh/3pq0pwednyuig86/AACx0_vjn-liY5_pP_C3nJD8a?dl=0&preview=c1b052c5.jpg
217 char url
[] = "https://www.dropbox.com/sh/3pq0pwednyuig86/AACx0_vjn-liY5_pP_C3nJD8a?dl=0&preview=xxxxxx.jpg";
218 for (unsigned int i
= 0; i
< 6; ++i
) {
223 QRcode
*qr
= QRcode_encodeString(url
, 0, QR_ECLEVEL_H
, QR_MODE_8
, 1);
225 perror("Failed to generate QR-Code");
230 unsigned int size
= qr
->width
;
232 sprintf(values
, "%d %d 2 1", size
, size
);
234 const char *xface
[3 + size
];
236 xface
[1] = "a c #ffffff";
237 xface
[2] = "b c #000000";
239 char qrcode_char
[size
][size
+ 1];
240 for (unsigned int i
= 0; i
< size
; ++i
) {
241 qrcode_char
[i
][size
] = '\0';
242 for (unsigned int j
= 0; j
< size
; ++j
) {
243 qrcode_char
[i
][j
] = qr
->data
[j
+ i
* size
] & 1 ? 'b' : 'a';
245 xface
[3 + i
] = &qrcode_char
[i
][0];
249 GdkPixbuf
*pb
= gdk_pixbuf_new_from_xpm_data(xface
);
251 pb
= gdk_pixbuf_scale_simple(pb
, QR_SIZE
, QR_SIZE
, GDK_INTERP_NEAREST
);
252 gtk_image_set_from_pixbuf((GtkImage
*)qr_img
, pb
);
255 char text
[] = "<span font='12'>QR-Code scannen oder auf <b>https://www.dropbox.com/sh/3pq0pwednyuig86/AACx0_vjn-liY5_pP_C3nJD8a</b> gehen. <small>Der Upload kann einige Minuten dauern.</small></span>";
256 gtk_label_set_markup(GTK_LABEL(qr_label
), text
);
260 gboolean
pb_poll_buttton(void)
262 if (gpio_tst(button_pin
) == 0) {
264 return G_SOURCE_REMOVE
;
266 return G_SOURCE_CONTINUE
;
271 gboolean
pb_countdown(void)
279 g_idle_remove_by_data(NULL
);
281 gtk_label_set_markup(GTK_LABEL(label_countdown
),
282 "<span font='300' color='red'>5</span>");
283 gtk_widget_hide(button_take
);
284 gtk_widget_show(label_countdown
);
286 g_timeout_add(1000, G_SOURCE_FUNC(pb_countdown
), NULL
);
287 return G_SOURCE_CONTINUE
;
290 gtk_label_set_markup(GTK_LABEL(label_countdown
),
291 "<span font='300' color='red'>4</span>");
292 return G_SOURCE_CONTINUE
;
295 gtk_label_set_markup(GTK_LABEL(label_countdown
),
296 "<span font='300' color='red'>3</span>");
297 return G_SOURCE_CONTINUE
;
300 gtk_label_set_markup(GTK_LABEL(label_countdown
),
301 "<span font='300' color='red'>2</span>");
302 return G_SOURCE_CONTINUE
;
305 gtk_label_set_markup(GTK_LABEL(label_countdown
),
306 "<span font='300' color='red'>1</span>");
307 return G_SOURCE_CONTINUE
;
310 gtk_label_set_markup(GTK_LABEL(label_countdown
),
311 "<span font='300' color='red'>0</span>");
313 // do all pendfing events (show 0) before taking picture
314 while (gtk_events_pending()) {
315 gtk_main_iteration();
321 return G_SOURCE_REMOVE
;
324 printf("ERROR: this should never happen?\n");
325 return G_SOURCE_REMOVE
;
328 void pb_takepic(void)
330 char *fn
= "tmp.jpg";
331 if (pb_ph_capture_file(fn
) != 0) {
332 fprintf(stderr
, "ERROR in pb_ph_capture_file\n");
337 GdkPixbuf
*pb
= gdk_pixbuf_new_from_file(fn
, NULL
);
338 pb
= gdk_pixbuf_scale_simple(pb
, IMG_WIDTH
, IMG_HEIGHT
, GDK_INTERP_BILINEAR
);
339 gtk_image_set_from_pixbuf(GTK_IMAGE(img
), pb
);
343 int pb_cp_dp(char *id
)
349 char src
[] = "tmp.jpg";
350 char dest
[] = "bilder/xxxxxx.jpg";
351 char dropbox_arg
[] = "Dropbox-API-Arg: {\"path\": \"/bilder/xxxxxx.jpg\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}";
353 for (unsigned int i
= 0; i
< 6; ++i
) {
355 dropbox_arg
[i
+ 35] = id
[i
];
358 FILE *src_file
= fopen(src
, "rb");
359 if (src_file
== NULL
) {
360 perror("Error opening tmp.jpg");
363 FILE *dest_file
= fopen(dest
, "wb+");
364 if (dest_file
== NULL
) {
366 perror("Error opening destination file");
372 num_read
= fread(buffer
, 1, 4096, src_file
);
373 dest_fsize
+= num_read
;
374 if (fwrite(buffer
, 1, num_read
, dest_file
) != num_read
&& ferror(dest_file
) != 0) {
375 fprintf(stderr
, "Error writing to destination file");
379 } while(num_read
== 4096);
381 if (ferror(src_file
) != 0) {
383 fprintf(stderr
, "Error reading from tmp.jpg\n");
390 rewind(dest_file
); // from beginning for upload
393 curl_global_init(CURL_GLOBAL_ALL
);
394 CURL
*curl
= curl_easy_init();
396 fprintf(stderr
, "ERROR in curl_easy_init\n");
397 curl_global_cleanup();
401 struct curl_slist
*header
= NULL
;
402 header
= curl_slist_append(header
, "Authorization: Bearer " APIKEY
);
403 header
= curl_slist_append(header
, dropbox_arg
);
404 header
= curl_slist_append(header
, "Content-Type: application/octet-stream");
405 curl_easy_setopt(curl
, CURLOPT_HTTPHEADER
, header
);
407 curl_easy_setopt(curl
, CURLOPT_URL
, "https://content.dropboxapi.com/2/files/upload");
409 curl_easy_setopt(curl
, CURLOPT_POST
, 1L); // post request
410 curl_easy_setopt(curl
, CURLOPT_POSTFIELDSIZE
, dest_fsize
); // file size
411 curl_easy_setopt(curl
, CURLOPT_POSTFIELDS
, NULL
); // use read callback
412 curl_easy_setopt(curl
, CURLOPT_READDATA
, dest_file
); // file pointer
413 curl_easy_setopt(curl
, CURLOPT_READFUNCTION
, NULL
); // default callback
415 curl_easy_setopt(curl
, CURLOPT_WRITEDATA
, NULL
); // disable output
417 CURLcode ret
= curl_easy_perform(curl
);
418 if (ret
!= CURLE_OK
) {
419 fprintf(stderr
, "ERROR in curl_easy_perform: %s\n", curl_easy_strerror(ret
));
424 curl_slist_free_all(header
);
425 curl_easy_cleanup(curl
);
427 curl_global_cleanup();