Gammu internals  1.38.0
sonyericsson.c
Go to the documentation of this file.
1 /* Sony Ericsson specific functions
2  * Copyright (C) 2011 Márton Németh <nm127@freemail.hu>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  */
19 
20 #include <gammu-config.h>
21 
22 #include <string.h>
23 
24 #ifdef GSM_ENABLE_ATGEN
25 
26 //#include "atgen.h"
27 #include "sonyericsson.h"
28 
29 // Tokens
30 #define TOKEN_DATA_0 0x00
31 #define TOKEN_DATA_1 0x01
32 #define TOKEN_DATA_2 0x02
33 #define TOKEN_DATA_3 0x03
34 #define TOKEN_DATA_4 0x04
35 #define TOKEN_DATA_5 0x05
36 #define TOKEN_DATA_6 0x06
37 #define TOKEN_DATA_7 0x07
38 #define TOKEN_DATA_8 0x08
39 #define TOKEN_DATA_9 0x09
40 #define TOKEN_DATA_A 0x0A
41 #define TOKEN_DATA_B 0x0B
42 #define TOKEN_DATA_C 0x0C
43 #define TOKEN_DATA_D 0x0D
44 #define TOKEN_DATA_E 0x0E
45 #define TOKEN_DATA_F 0x0F
46 #define TOKEN_COMMAND_ZISI_ECHO 0x10
47 #define TOKEN_RESPONSE_ZISI 0x11
48 #define TOKEN_RESPONSE_OK 0x12
49 #define TOKEN_WHITESPACE 0x13
50 #define TOKEN_UNKNOWN 0x14
51 
52 #define STATE_ALPHA0 0
53 #define STATE_ALPHA1 1
54 #define STATE_RED0 2
55 #define STATE_RED1 3
56 #define STATE_GREEN0 4
57 #define STATE_GREEN1 5
58 #define STATE_BLUE0 6
59 #define STATE_BLUE1 7
60 
61 typedef unsigned char u8;
62 typedef unsigned short u16;
63 typedef unsigned int u32;
64 
66 {
67  GSM_Error error;
68 
69  s->Phone.Data.Picture = picture;
70 
71  smprintf(s, "Get Sony Ericsson screenshot\n");
72 
73  /* Fetch screen dimensions */
74  error = GSM_WaitForAutoLen(s, "AT*ZISI=?\r", 0, SONYERICSSON_TIMEOUT, ID_Screenshot);
75 
76  if (error == ERR_NONE) {
77  /* Fetch screen data */
78  error = GSM_WaitForAutoLen(s, "AT*ZISI\r", 0, SONYERICSSON_TIMEOUT, ID_Screenshot);
79  }
80 
81  s->Phone.Data.Picture = NULL;
82 
83  return error;
84 }
85 
87 {
88  GSM_Error error;
89  GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
90  const char *string;
91  int line;
92  int h, w, param3, param4;
93 
94  switch (Priv->ReplyState) {
95  case AT_Reply_OK:
96  smprintf(s, "Screenshot size received\n");
97 
98  /* Parse the lines looking for "*ZISI:" */
99  line = 1;
100  h = 0;
101  w = 0;
102  param3 = 0;
103  param4 = 0;
104  do {
105  string = GetLineString(msg->Buffer, &Priv->Lines, line+1);
106 
107  /*
108  * *ZISI: 320, 240, 16, 0
109  */
110  error = ATGEN_ParseReply(s, string,
111  "*ZISI: @i, @i, @i, @i",
112  &h,
113  &w,
114  &param3,
115  &param4);
116 
117  if (error != ERR_NONE) {
118  /* Try again. Some phones like Sony Ericsson
119  * K508i returns data in different format:
120  *
121  * *ZISI: 160, 128, 16
122  *
123  */
124  error = ATGEN_ParseReply(s, string,
125  "*ZISI: @i, @i, @i",
126  &h,
127  &w,
128  &param3);
129  }
130 
131  if (error == ERR_NONE) {
132  smprintf(s, "Screen size is %ix%i\n", w, h);
133  /* Remember the screen size */
134  Priv->ScreenWidth = w;
135  Priv->ScreenHeigth = h;
136  }
137 
138  line++;
139 
140  } while (strcmp("OK", string) != 0);
141 
142  return ERR_NONE;
143  case AT_Reply_Error:
144  return ERR_UNKNOWN;
145  case AT_Reply_CMSError:
146  return ATGEN_HandleCMSError(s);
147  case AT_Reply_CMEError:
148  return ATGEN_HandleCMEError(s);
149  default:
151  s->Phone.Data.Picture->Buffer = NULL;
152  s->Phone.Data.Picture->Length = 0;
153  return ERR_UNKNOWNRESPONSE;
154  }
155 }
156 
157 static void u32_store(u8 *p, u32 data) {
158  u32 tmp;
159 
160  tmp = data;
161  *p = tmp & 0xFF;
162  tmp >>= 8;
163  *(p+1) = tmp & 0xFF;
164  tmp >>= 8;
165  *(p+2) = tmp & 0xFF;
166  tmp >>= 8;
167  *(p+3) = tmp & 0xFF;
168 }
169 
170 static void u16_store(u8 *p, u16 data) {
171  u16 tmp;
172 
173  tmp = data;
174  *p = tmp & 0xFF;
175  tmp >>= 8;
176  *(p+1) = tmp & 0xFF;
177 }
178 
179 static int SONYERICSSON_Screenshot_createBMPHeader(unsigned int w, unsigned int h, u8 *p) {
180  u32 data;
181  u16 data16;
182 
183  // BMP magic "BM"
184  *p = 0x42;
185  *(p+1) = 0x4D;
186 
187  // size of the BMP file in bytes
188  data = 14 + 40 + w * h * 4;
189  u32_store(p+2, data);
190 
191  // reserved
192  data = 0;
193  u32_store(p+6, data);
194 
195  // start of image data
196  data = 14 + 40;
197  u32_store(p+10, data);
198 
199  // size of this header
200  data = 40;
201  u32_store(p+14, data);
202 
203  // width in pixels (240)
204  data = w;
205  u32_store(p+18, data);
206 
207  // height in pixels (-320)
208  data = (u32)(-h);
209  u32_store(p+22, data);
210 
211  // color planes (1)
212  data16 = 1;
213  u16_store(p+26, data16);
214 
215  // bits per pixel (32)
216  data16 = 32;
217  u16_store(p+28, data16);
218 
219  // compression method
220  data = 0;
221  u32_store(p+30, data);
222 
223  // image size (320*240*4)
224  data = w * h * 4;
225  u32_store(p+34, data);
226 
227  // horizontal resolution (2835 pixel per meter = 72 dpi)
228  data = 2835;
229  u32_store(p+38, data);
230 
231  // vertical resolution (2835 pixel per meter = 72 dpi)
232  data = 2835;
233  u32_store(p+42, data);
234 
235  // number of colors in the color palette
236  data = 0;
237  u32_store(p+46, data);
238 
239  // number of important colors used
240  data = 0;
241  u32_store(p+50, data);
242 
243  return 54;
244 }
245 
246 static int SONYERICSSON_Screenshot_addPixel(u8 alpha, u8 red, u8 green, u8 blue, u8 *p) {
247 
248  *p = blue;
249  *(p+1) = green;
250  *(p+2) = red;
251  *(p+3) = alpha;
252 
253  return 4;
254 }
255 
256 
258 {
259  GSM_Error error = ERR_NONE;
260  GSM_Phone_ATGENData *Priv = &s->Phone.Data.Priv.ATGEN;
261  unsigned int i;
262  int state;
263  int token;
264  u8 alpha = 0, red = 0, green = 0, blue = 0;
265  u8 *p;
266  unsigned int length;
267  unsigned int w, h;
268 
269  switch (Priv->ReplyState) {
270  case AT_Reply_OK:
271  smprintf(s, "Screenshot data received\n");
272 
273  w = Priv->ScreenWidth;
274  h = Priv->ScreenHeigth;
275 
277  s->Phone.Data.Picture->Buffer = (unsigned char *)malloc(54 + w * h * 4);
278  if (s->Phone.Data.Picture->Buffer == NULL) {
279  return ERR_MOREMEMORY;
280  }
281  p = s->Phone.Data.Picture->Buffer;
282 
283  length = SONYERICSSON_Screenshot_createBMPHeader(w, h, p);
284  s->Phone.Data.Picture->Length = length;
285  p += length;
286 
287  i = 0;
288  state = STATE_ALPHA0;
289  while (i < msg->BufferUsed) {
290  /* Tokenize. The tokens are:
291  * - TOKEN_COMMAND_ZISI_ECHO: "AT*ZISI"
292  * - TOKEN_RESPONSE_ZISI: "*ZISI:"
293  * - TOKEN_RESPONSE_OK: "OK"
294  * - TOKEN_WHITESPACE: " ", "\r", "\n"
295  * - TOKEN_DATA_0: "0"
296  * - TOKEN_DATA_1: "1"
297  * - TOKEN_DATA_2: "2"
298  * - TOKEN_DATA_3: "3"
299  * - TOKEN_DATA_4: "4"
300  * - TOKEN_DATA_5: "5"
301  * - TOKEN_DATA_6: "6"
302  * - TOKEN_DATA_7: "7"
303  * - TOKEN_DATA_8: "8"
304  * - TOKEN_DATA_9: "9"
305  * - TOKEN_DATA_A: "A"
306  * - TOKEN_DATA_B: "B"
307  * - TOKEN_DATA_C: "C"
308  * - TOKEN_DATA_D: "D"
309  * - TOKEN_DATA_E: "E"
310  * - TOKEN_DATA_F: "F"
311  */
312 
313  switch (msg->Buffer[i]) {
314  case 'A':
315  if (strlen("AT*ZISI") <= msg->BufferUsed - i && strncmp(&msg->Buffer[i], "AT*ZISI", strlen("AT*ZISI")) == 0) {
316  token = TOKEN_COMMAND_ZISI_ECHO;
317  i += strlen("AT*ZISI");
318  } else {
319  token = TOKEN_DATA_A;
320  i++;
321  }
322  break;
323  case '*':
324  if (strlen("*ZISI:") <= msg->BufferUsed - i && strncmp(&msg->Buffer[i], "*ZISI:", strlen("*ZISI:")) == 0) {
325  token = TOKEN_RESPONSE_ZISI;
326  i += strlen("*ZISI:");
327  } else {
328  token = TOKEN_UNKNOWN;
329  i++;
330  }
331  break;
332  case 'O':
333  if (strlen("OK") <= msg->BufferUsed - i && strncmp(&msg->Buffer[i], "OK", strlen("OK")) == 0) {
334  token = TOKEN_RESPONSE_OK;
335  i += strlen("OK");
336  } else {
337  token = TOKEN_UNKNOWN;
338  i++;
339  }
340  break;
341  case ' ':
342  case '\r':
343  case '\n':
344  token = TOKEN_WHITESPACE;
345  i++;
346  break;
347  case '0':
348  token = TOKEN_DATA_0;
349  i++;
350  break;
351  case '1':
352  token = TOKEN_DATA_1;
353  i++;
354  break;
355  case '2':
356  token = TOKEN_DATA_2;
357  i++;
358  break;
359  case '3':
360  token = TOKEN_DATA_3;
361  i++;
362  break;
363  case '4':
364  token = TOKEN_DATA_4;
365  i++;
366  break;
367  case '5':
368  token = TOKEN_DATA_5;
369  i++;
370  break;
371  case '6':
372  token = TOKEN_DATA_6;
373  i++;
374  break;
375  case '7':
376  token = TOKEN_DATA_7;
377  i++;
378  break;
379  case '8':
380  token = TOKEN_DATA_8;
381  i++;
382  break;
383  case '9':
384  token = TOKEN_DATA_9;
385  i++;
386  break;
387  case 'B':
388  token = TOKEN_DATA_B;
389  i++;
390  break;
391  case 'C':
392  token = TOKEN_DATA_C;
393  i++;
394  break;
395  case 'D':
396  token = TOKEN_DATA_D;
397  i++;
398  break;
399  case 'E':
400  token = TOKEN_DATA_E;
401  i++;
402  break;
403  case 'F':
404  token = TOKEN_DATA_F;
405  i++;
406  break;
407  default:
408  token = TOKEN_UNKNOWN;
409  i++;
410  }
411 
412  switch (token) {
413  case TOKEN_COMMAND_ZISI_ECHO:
414  case TOKEN_RESPONSE_ZISI:
415  case TOKEN_RESPONSE_OK:
416  case TOKEN_WHITESPACE:
417  /* nothing to do, just skip */
418  break;
419  case TOKEN_DATA_0:
420  case TOKEN_DATA_1:
421  case TOKEN_DATA_2:
422  case TOKEN_DATA_3:
423  case TOKEN_DATA_4:
424  case TOKEN_DATA_5:
425  case TOKEN_DATA_6:
426  case TOKEN_DATA_7:
427  case TOKEN_DATA_8:
428  case TOKEN_DATA_9:
429  case TOKEN_DATA_A:
430  case TOKEN_DATA_B:
431  case TOKEN_DATA_C:
432  case TOKEN_DATA_D:
433  case TOKEN_DATA_E:
434  case TOKEN_DATA_F:
435  switch (state) {
436  case STATE_ALPHA0:
437  alpha = token;
438  state = STATE_ALPHA1;
439  break;
440  case STATE_ALPHA1:
441  alpha = (alpha << 4) | token;
442  state = STATE_RED0;
443  break;
444  case STATE_RED0:
445  red = token;
446  state = STATE_RED1;
447  break;
448  case STATE_RED1:
449  red = (red << 4) | token;
450  state = STATE_GREEN0;
451  break;
452  case STATE_GREEN0:
453  green = token;
454  state = STATE_GREEN1;
455  break;
456  case STATE_GREEN1:
457  green = (green << 4) | token;
458  state = STATE_BLUE0;
459  break;
460  case STATE_BLUE0:
461  blue = token;
462  state = STATE_BLUE1;
463  break;
464  case STATE_BLUE1:
465  blue = (blue << 4) | token;
466  length = SONYERICSSON_Screenshot_addPixel(alpha, red, green, blue, p);
467  s->Phone.Data.Picture->Length += length;
468  p += length;
469  state = STATE_ALPHA0;
470  break;
471  }
472  break;
473  case TOKEN_UNKNOWN:
474  break;
475 
476  }
477 
478  }
479  break;
480 
481  case AT_Reply_Error:
482  error = ERR_UNKNOWN;
483  break;
484 
485  case AT_Reply_CMSError:
486  error = ATGEN_HandleCMSError(s);
487  break;
488 
489  case AT_Reply_CMEError:
490  error = ATGEN_HandleCMEError(s);
491  break;
492 
493  default:
494  error = ERR_UNKNOWNRESPONSE;
495  }
496 
497  return error;
498 }
499 
500 #endif
GSM_BinaryPicture * Picture
Definition: gsmstate.h:593
GSM_Error ATGEN_HandleCMEError(GSM_StateMachine *s)
GSM_CutLines Lines
Definition: atgen.h:243
GSM_Error ATGEN_HandleCMSError(GSM_StateMachine *s)
GSM_Error
Definition: gammu-error.h:23
const char * GetLineString(const char *message, GSM_CutLines *lines, int start)
Definition: misc.c:492
GSM_BinaryPicture_Types Type
Definition: gammu-bitmap.h:44
unsigned char * Buffer
Definition: gammu-bitmap.h:45
#define SONYERICSSON_TIMEOUT
Definition: sonyericsson.h:40
#define GSM_WaitForAutoLen(s, buffer, type, timeout, request)
Definition: gsmstate.h:1478
GSM_Phone Phone
Definition: gsmstate.h:1431
struct GSM_Phone_Data::@2 Priv
GSM_Error ATGEN_ParseReply(GSM_StateMachine *s, const unsigned char *input, const char *format,...)
GSM_Error SONYERICSSON_Reply_ScreenshotData(GSM_Protocol_Message *msg, GSM_StateMachine *s)
GSM_Phone_Data Data
Definition: gsmstate.h:1369
GSM_Error SONYERICSSON_Reply_Screenshot(GSM_Protocol_Message *msg, GSM_StateMachine *s)
GSM_Error SONYERICSSON_GetScreenshot(GSM_StateMachine *s, GSM_BinaryPicture *picture)
unsigned char * Buffer
Definition: protocol.h:22
GSM_AT_Reply_State ReplyState
Definition: atgen.h:247
int smprintf(GSM_StateMachine *s, const char *format,...)
Definition: debug.c:261