32f90ea31f0aa026af7086a95adf6fb5c06e3bed
[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 <unistd.h>
26
27 typedef enum {
28         AM7x01_PACKET_TYPE_INIT    = 0x01,
29         AM7x01_PACKET_TYPE_IMAGE   = 0x02,
30         AM7x01_PACKET_TYPE_POWER   = 0x04,
31         AM7x01_PACKET_TYPE_UNKNOWN = 0x05,
32 } am7x01_packet_type;
33
34 typedef enum {
35         AM7x01_IMAGE_FORMAT_JPEG = 1,
36 } am7x01_image_format;
37
38 typedef enum {
39         AM7x01_POWER_OFF  = 0,
40         AM7x01_POWER_LOW  = 1,
41         AM7x01_POWER_MID  = 2,
42         AM7x01_POWER_HIGH = 3,
43 } am7x01_power_mode;
44
45 struct image_header {
46         uint32_t format;
47         uint32_t width;
48         uint32_t height;
49         uint32_t image_size;
50 };
51
52 struct power_header {
53         uint32_t power_low;
54         uint32_t power_mid;
55         uint32_t power_high;
56 };
57
58 /*
59  * Examples of packet headers:
60  *
61  * Image widget:
62  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
63  * +02|00|00|00|00|10|3e|10|01|00|00|00|20|03|00|00|e0|01|00|00|53|E8|00|00+
64  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
65  *
66  * Brightness widget:
67  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
68  * +04|00|00|00|00|0c|ff|ff|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00+
69  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
70  */
71
72 static uint8_t reference_image_header[] = {
73         0x02, 0x00, 0x00, 0x00,
74         0x00,
75         0x10,
76         0x3e,
77         0x10,
78         0x01, 0x00, 0x00, 0x00,
79         0x20, 0x03, 0x00, 0x00,
80         0xe0, 0x01, 0x00, 0x00,
81         0x53, 0xE8, 0x00, 0x00
82 };
83
84 struct header {
85         uint32_t packet_type;
86         uint8_t unknown0;
87         uint8_t header_len;
88         uint8_t unknown2;
89         uint8_t unknown3;
90         union {
91                 struct image_header image;
92                 struct power_header power;
93         } header_data;
94 };
95
96
97 static void dump_image_header(struct image_header *i)
98 {
99         if (i == NULL)
100                 return;
101
102         printf("Image header:\n");
103         printf("format:      0x%08x (%u)\n", i->format, i->format);
104         printf("width:       0x%08x (%u)\n", i->width, i->width);
105         printf("height:      0x%08x (%u)\n", i->height, i->height);
106         printf("image size:  0x%08x (%u)\n", i->image_size, i->image_size);
107 }
108
109 static void dump_header(struct header *h)
110 {
111         if (h == NULL)
112                 return;
113
114         printf("packet_type: 0x%08x (%u)\n", h->packet_type, h->packet_type);
115         printf("unknown0:    0x%02hhx (%hhu)\n", h->unknown0, h->unknown0);
116         printf("header_len:  0x%02hhx (%hhu)\n", h->header_len, h->header_len);
117         printf("unknown2:    0x%02hhx (%hhu)\n", h->unknown2, h->unknown2);
118         printf("unknown3:    0x%02hhx (%hhu)\n", h->unknown3, h->unknown3);
119
120         switch(h->packet_type) {
121         case AM7x01_PACKET_TYPE_IMAGE:
122                 dump_image_header(&(h->header_data.image));
123                 break;
124
125         default:
126                 printf("Packet type not supported!\n");
127                 break;
128         }
129
130         fflush(stdout);
131 }
132
133 static inline unsigned int in_80chars(unsigned int i)
134 {
135         return ((i+1) % (80/3));
136 }
137
138 static void dump_buffer(uint8_t *buffer, unsigned int len)
139 {
140         unsigned int i;
141
142         if (buffer == NULL || len == 0)
143                 return;
144
145         for (i = 0; i < len; i++) {
146                 printf("%02hhX%c", buffer[i], (in_80chars(i) && (i < len - 1)) ? ' ' : '\n');
147         }
148         fflush(stdout);
149 }
150
151 static int send_data(uint8_t *buffer, unsigned int len)
152 {
153         dump_buffer(buffer, len);
154         return 0;
155 }
156
157 static int send_header(struct header *h)
158 {
159         union {
160                 struct header header;
161                 uint8_t buffer[sizeof (struct header)];
162         } data;
163
164         data.header = *h;
165
166         return send_data(data.buffer, sizeof (struct header));
167 }
168
169 static int send_image(am7x01_image_format format,
170                       unsigned int width,
171                       unsigned int height,
172                       uint8_t *image,
173                       unsigned int size)
174 {
175         int ret;
176         struct header h = {
177                 .packet_type = htole32(AM7x01_PACKET_TYPE_IMAGE),
178                 .unknown0    = 0x00,
179                 .header_len  = sizeof(struct image_header),
180                 .unknown2    = 0x3e,
181                 .unknown3    = 0x10,
182                 .header_data = {
183                         .image = {
184                                 .format     = htole32(format),
185                                 .width      = htole32(width),
186                                 .height     = htole32(height),
187                                 .image_size = htole32(size),
188                         },
189                 },
190         };
191
192         dump_header(&h);
193         printf("\n");
194
195         printf("Dump Buffers\n");
196         dump_buffer(reference_image_header, sizeof(struct header));
197
198         ret = send_header(&h);
199         if (ret < 0)
200                 return ret;
201
202         if (image == NULL || size == 0)
203                 return 0;
204
205         return send_data(image, size);
206 }
207
208 static void usage(char *name)
209 {
210         printf("usage: %s [OPTIONS]\n\n", name);
211         printf("OPTIONS:\n");
212         printf("\t-f <filename>\t\tthe image file to upload\n");
213         printf("\t-F <format>\t\tthe image format to use (default is JPEG).\n");
214         printf("\t\t\t\tSUPPORTED FORMATS:\n");
215         printf("\t\t\t\t\t1 - JPEG\n");
216         printf("\t-W <image width>\tthe width of the image to upload\n");
217         printf("\t-H <image height>\tthe height of the image to upload\n");
218         printf("\t-h \t\t\tthis help message\n");
219 }
220
221 int main(int argc, char *argv[])
222 {
223         int ret;
224         int opt;
225
226         char filename[FILENAME_MAX] = {0};
227         int format = AM7x01_IMAGE_FORMAT_JPEG;
228         int width = 800;
229         int height = 480;
230         uint8_t *image = NULL;
231         unsigned int size = 59475;
232
233         while ((opt = getopt(argc, argv, "f:F:W:H:h")) != -1) {
234                 switch (opt) {
235                 case 'f':
236                         strncpy(filename, optarg, FILENAME_MAX);
237                         break;
238                 case 'F':
239                         format = atoi(optarg);
240                         if (format != 1) {
241                                 fprintf(stderr, "Unsupported format\n");
242                                 exit(EXIT_FAILURE);
243                         }
244                         break;
245                 case 'W':
246                         width = atoi(optarg);
247                         if (width < 0) {
248                                 fprintf(stderr, "Unsupported width\n");
249                                 exit(EXIT_FAILURE);
250                         }
251                         break;
252                 case 'H':
253                         height = atoi(optarg);
254                         if (height < 0) {
255                                 fprintf(stderr, "Unsupported height\n");
256                                 exit(EXIT_FAILURE);
257                         }
258                         break;
259                 default: /* '?' */
260                         usage(argv[0]);
261                         exit(EXIT_FAILURE);
262                 }
263         }
264
265         ret = send_image(format, width, height, image, size);
266         if (ret < 0) {
267                 perror("send_image");
268                 exit(EXIT_FAILURE);
269         }
270
271         exit(EXIT_SUCCESS);
272 }