161be49efb86949caf40830e0effd3f1a17b86f8
[libam7xxx.git] / picoproj.c
1 /* picoproj - communication with AM7xxx based USB pico projectors
2  *
3  * Copyright (C) 2011  Antonio Ospite <ospite@studenti.unina.it>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <endian.h>
24 #include <errno.h>
25 #include <sys/mman.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30
31 typedef enum {
32         AM7x01_PACKET_TYPE_INIT    = 0x01,
33         AM7x01_PACKET_TYPE_IMAGE   = 0x02,
34         AM7x01_PACKET_TYPE_POWER   = 0x04,
35         AM7x01_PACKET_TYPE_UNKNOWN = 0x05,
36 } am7x01_packet_type;
37
38 typedef enum {
39         AM7x01_IMAGE_FORMAT_JPEG = 1,
40 } am7x01_image_format;
41
42 typedef enum {
43         AM7x01_POWER_OFF  = 0,
44         AM7x01_POWER_LOW  = 1,
45         AM7x01_POWER_MID  = 2,
46         AM7x01_POWER_HIGH = 3,
47 } am7x01_power_mode;
48
49 struct image_header {
50         uint32_t format;
51         uint32_t width;
52         uint32_t height;
53         uint32_t image_size;
54 };
55
56 struct power_header {
57         uint32_t power_low;
58         uint32_t power_mid;
59         uint32_t power_high;
60 };
61
62 /*
63  * Examples of packet headers:
64  *
65  * Image widget:
66  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
67  * +02|00|00|00|00|10|3e|10|01|00|00|00|20|03|00|00|e0|01|00|00|53|E8|00|00+
68  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
69  *
70  * Brightness widget:
71  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
72  * +04|00|00|00|00|0c|ff|ff|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00+
73  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
74  */
75
76 static uint8_t reference_image_header[] = {
77         0x02, 0x00, 0x00, 0x00,
78         0x00,
79         0x10,
80         0x3e,
81         0x10,
82         0x01, 0x00, 0x00, 0x00,
83         0x20, 0x03, 0x00, 0x00,
84         0xe0, 0x01, 0x00, 0x00,
85         0x53, 0xE8, 0x00, 0x00
86 };
87
88 struct header {
89         uint32_t packet_type;
90         uint8_t unknown0;
91         uint8_t header_len;
92         uint8_t unknown2;
93         uint8_t unknown3;
94         union {
95                 struct image_header image;
96                 struct power_header power;
97         } header_data;
98 };
99
100
101 static void dump_image_header(struct image_header *i)
102 {
103         if (i == NULL)
104                 return;
105
106         printf("Image header:\n");
107         printf("format:      0x%08x (%u)\n", i->format, i->format);
108         printf("width:       0x%08x (%u)\n", i->width, i->width);
109         printf("height:      0x%08x (%u)\n", i->height, i->height);
110         printf("image size:  0x%08x (%u)\n", i->image_size, i->image_size);
111 }
112
113 static void dump_header(struct header *h)
114 {
115         if (h == NULL)
116                 return;
117
118         printf("packet_type: 0x%08x (%u)\n", h->packet_type, h->packet_type);
119         printf("unknown0:    0x%02hhx (%hhu)\n", h->unknown0, h->unknown0);
120         printf("header_len:  0x%02hhx (%hhu)\n", h->header_len, h->header_len);
121         printf("unknown2:    0x%02hhx (%hhu)\n", h->unknown2, h->unknown2);
122         printf("unknown3:    0x%02hhx (%hhu)\n", h->unknown3, h->unknown3);
123
124         switch(h->packet_type) {
125         case AM7x01_PACKET_TYPE_IMAGE:
126                 dump_image_header(&(h->header_data.image));
127                 break;
128
129         default:
130                 printf("Packet type not supported!\n");
131                 break;
132         }
133
134         fflush(stdout);
135 }
136
137 static inline unsigned int in_80chars(unsigned int i)
138 {
139         return ((i+1) % (80/3));
140 }
141
142 static void dump_buffer(uint8_t *buffer, unsigned int len)
143 {
144         unsigned int i;
145
146         if (buffer == NULL || len == 0)
147                 return;
148
149         for (i = 0; i < len; i++) {
150                 printf("%02hhX%c", buffer[i], (in_80chars(i) && (i < len - 1)) ? ' ' : '\n');
151         }
152         fflush(stdout);
153 }
154
155 static int send_data(uint8_t *buffer, unsigned int len)
156 {
157         dump_buffer(buffer, len);
158         return 0;
159 }
160
161 static int send_header(struct header *h)
162 {
163         union {
164                 struct header header;
165                 uint8_t buffer[sizeof (struct header)];
166         } data;
167
168         data.header = *h;
169
170         return send_data(data.buffer, sizeof (struct header));
171 }
172
173 static int send_image(am7x01_image_format format,
174                       unsigned int width,
175                       unsigned int height,
176                       uint8_t *image,
177                       unsigned int size)
178 {
179         int ret;
180         struct header h = {
181                 .packet_type = htole32(AM7x01_PACKET_TYPE_IMAGE),
182                 .unknown0    = 0x00,
183                 .header_len  = sizeof(struct image_header),
184                 .unknown2    = 0x3e,
185                 .unknown3    = 0x10,
186                 .header_data = {
187                         .image = {
188                                 .format     = htole32(format),
189                                 .width      = htole32(width),
190                                 .height     = htole32(height),
191                                 .image_size = htole32(size),
192                         },
193                 },
194         };
195
196         dump_header(&h);
197         printf("\n");
198
199         printf("Dump Buffers\n");
200         dump_buffer(reference_image_header, sizeof(struct header));
201
202         ret = send_header(&h);
203         if (ret < 0)
204                 return ret;
205
206         if (image == NULL || size == 0)
207                 return 0;
208
209         return send_data(image, size);
210 }
211
212 static void usage(char *name)
213 {
214         printf("usage: %s [OPTIONS]\n\n", name);
215         printf("OPTIONS:\n");
216         printf("\t-f <filename>\t\tthe image file to upload\n");
217         printf("\t-F <format>\t\tthe image format to use (default is JPEG).\n");
218         printf("\t\t\t\tSUPPORTED FORMATS:\n");
219         printf("\t\t\t\t\t1 - JPEG\n");
220         printf("\t-W <image width>\tthe width of the image to upload\n");
221         printf("\t-H <image height>\tthe height of the image to upload\n");
222         printf("\t-h \t\t\tthis help message\n");
223 }
224
225 int main(int argc, char *argv[])
226 {
227         int ret;
228         int exit_code = EXIT_SUCCESS;
229         int opt;
230
231         char filename[FILENAME_MAX] = {0};
232         int image_fd = -1;
233         int format = AM7x01_IMAGE_FORMAT_JPEG;
234         int width = 800;
235         int height = 480;
236         uint8_t *image = NULL;
237         unsigned int size = 59475;
238
239         while ((opt = getopt(argc, argv, "f:F:W:H:h")) != -1) {
240                 switch (opt) {
241                 case 'f':
242                         strncpy(filename, optarg, FILENAME_MAX);
243                         break;
244                 case 'F':
245                         format = atoi(optarg);
246                         if (format != 1) {
247                                 fprintf(stderr, "Unsupported format\n");
248                                 exit(EXIT_FAILURE);
249                         }
250                         break;
251                 case 'W':
252                         width = atoi(optarg);
253                         if (width < 0) {
254                                 fprintf(stderr, "Unsupported width\n");
255                                 exit(EXIT_FAILURE);
256                         }
257                         break;
258                 case 'H':
259                         height = atoi(optarg);
260                         if (height < 0) {
261                                 fprintf(stderr, "Unsupported height\n");
262                                 exit(EXIT_FAILURE);
263                         }
264                         break;
265                 default: /* '?' */
266                         usage(argv[0]);
267                         exit(EXIT_FAILURE);
268                 }
269         }
270
271         if (filename[0] != '\0') {
272                 struct stat st;
273                 
274                 image_fd = open(filename, O_RDONLY);
275                 if (image_fd < 0) {
276                         perror("open");
277                         exit_code = EXIT_FAILURE;
278                         goto out;
279                 }
280                 if (fstat(image_fd, &st) < 0) {
281                         perror("fstat");
282                         exit_code = EXIT_FAILURE;
283                         goto out_close_image_fd;
284                 }
285                 size = st.st_size;
286
287                 image = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, image_fd, 0);
288                 if (image == NULL) {
289                         perror("mmap");
290                         exit_code = EXIT_FAILURE;
291                         goto out_close_image_fd;
292                 }
293         }
294
295         ret = send_image(format, width, height, image, size);
296         if (ret < 0) {
297                 perror("send_image");
298                 exit_code = EXIT_FAILURE;
299                 goto cleanup;
300         }
301
302         exit_code = EXIT_SUCCESS;
303
304 cleanup:
305         if (image != NULL) {
306                 ret = munmap(image, size);
307                 if (ret < 0)
308                         perror("munmap");
309         }
310
311 out_close_image_fd:
312         if (image_fd >= 0) {
313                 ret = close(image_fd);
314                 if (ret < 0)
315                         perror("close");
316         }
317
318 out:
319         exit(exit_code);
320 }