1 /*
2 
3   $Id$
4 
5   G N O K I I
6 
7   A Linux/Unix toolset and driver for the mobile phones.
8 
9   This file is part of gnokii.
10 
11   Gnokii is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 2 of the License, or
14   (at your option) any later version.
15 
16   Gnokii is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20 
21   You should have received a copy of the GNU General Public License
22   along with gnokii; if not, write to the Free Software
23   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 
25   Copyright 2004 Hugo Haas <hugo@larve.net>
26   Copyright 2004-2008 Pawel Kot
27 
28   This file provides functions specific to AT commands on Sony Ericsson
29   phones. See README for more details on supported mobile phones.
30 
31 */
32 
33 #include "config.h"
34 
35 #include <string.h>
36 #include <stdlib.h>
37 #include <ctype.h>
38 
39 #include "compat.h"
40 #include "misc.h"
41 #include "gnokii.h"
42 #include "phones/generic.h"
43 #include "phones/atgen.h"
44 #include "phones/atsoer.h"
45 #include "links/atbus.h"
46 
se_at_memory_type_set(gn_memory_type mt,struct gn_statemachine * state)47 static gn_error se_at_memory_type_set(gn_memory_type mt, struct gn_statemachine *state)
48 {
49 	at_driver_instance *drvinst = AT_DRVINST(state);
50 	gn_data data;
51 	char req[32];
52 	const char *memory_name;
53 	char memory_name_enc[16];
54 	int len;
55 	gn_error ret = GN_ERR_NONE;
56 
57 	if (mt != drvinst->memorytype) {
58 		memory_name = gn_memory_type2str(mt);
59 		if (!memory_name)
60 			return GN_ERR_INVALIDMEMORYTYPE;
61 		/* BC is "Own Business Card" as per the Sony Ericsson documentation */
62 		if (strcmp(memory_name, "ON") == 0)
63 			memory_name = "BC";
64 		if (drvinst->encode_memory_type) {
65 			gn_data_clear(&data);
66 			at_encode(drvinst->charset, memory_name_enc, sizeof(memory_name_enc), memory_name, strlen(memory_name));
67 			memory_name = memory_name_enc;
68 		}
69 		len = snprintf(req, sizeof(req), "AT+CPBS=\"%s\"\r", memory_name);
70 		ret = sm_message_send(len, GN_OP_Init, req, state);
71 		if (ret != GN_ERR_NONE)
72 			return ret;
73 		gn_data_clear(&data);
74 		ret = sm_block_no_retry(GN_OP_Init, &data, state);
75 		if (ret != GN_ERR_NONE)
76 			return ret;
77 		drvinst->memorytype = mt;
78 
79 		gn_data_clear(&data);
80 		ret = state->driver.functions(GN_OP_AT_GetMemoryRange, &data, state);
81 	}
82 	return ret;
83 }
84 
85 /*
86  * Calculate phonebook size for SonyEricsson phones: they don't respond
87  * with memory stats to AT+CPBS. Calculate by reading and counting all
88  * entries (which is fast -- just one command).
89  */
ReplyMemoryStatus(int messagetype,unsigned char * buffer,int length,gn_data * data,struct gn_statemachine * state)90 static gn_error ReplyMemoryStatus(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state)
91 {
92 	at_driver_instance *drvinst = AT_DRVINST(state);
93 	gn_error error;
94 	char *buf = buffer;
95 	int counter = 0;
96 
97 	if (!data->memory_status)
98 		return GN_ERR_INTERNALERROR;
99 
100 	if ((error = at_error_get(buffer, state)) != GN_ERR_NONE)
101 		return error;
102 
103 	while ((buf = strchr(buf, '\r'))) {
104 		buf++;
105 		if (strlen(buf) > 6 &&
106 			(!strncmp(buf, "+CPBR:", 6) || !strncmp(buf + 1, "+CPBR:", 6)))
107 			counter++;
108 	}
109 	data->memory_status->used += counter;
110 	data->memory_status->free = drvinst->memorysize - data->memory_status->used;
111 
112 	return error;
113 }
114 
115 /*
116  * Calculate phonebook size for SonyEricsson phones: they don't respond
117  * with memory stats to AT+CPBS. Calculate by reading and counting all
118  * entries (which is pretty fast).
119  */
120 #define PHONEBOOKREAD_CHUNK_SIZE 200
AT_GetMemoryStatus(gn_data * data,struct gn_statemachine * state)121 static gn_error AT_GetMemoryStatus(gn_data *data, struct gn_statemachine *state)
122 {
123 	at_driver_instance *drvinst = AT_DRVINST(state);
124 	gn_error ret = GN_ERR_NONE;
125 	char req[32];
126 	int top, bottom;
127 
128 	ret = se_at_memory_type_set(data->memory_status->memory_type,  state);
129 	if (ret)
130 		return ret;
131 	ret = state->driver.functions(GN_OP_AT_GetMemoryRange, data, state);
132 	if (ret)
133 		return ret;
134 	data->memory_status->used = 0;
135 	bottom = 0;
136 	at_set_charset(data, state, AT_CHAR_UCS2);
137 	top = (bottom + PHONEBOOKREAD_CHUNK_SIZE > drvinst->memorysize) ? drvinst->memorysize : bottom + PHONEBOOKREAD_CHUNK_SIZE;
138 	while (top <= drvinst->memorysize) {
139 		snprintf(req, sizeof(req) - 1, "AT+CPBR=%d,%d\r", drvinst->memoryoffset + 1 + bottom, top + drvinst->memoryoffset);
140 		ret = sm_message_send(strlen(req), GN_OP_GetMemoryStatus, req, state);
141 		if (ret)
142 			return GN_ERR_NOTREADY;
143 		ret = sm_block_no_retry(GN_OP_GetMemoryStatus, data, state);
144 		if (ret)
145 			return ret;
146 
147 		bottom = top;
148 		top = bottom + PHONEBOOKREAD_CHUNK_SIZE;
149 		if (bottom >= drvinst->memorysize)
150 			break;
151 		if (top > drvinst->memorysize)
152 			top = drvinst->memorysize;
153 	}
154 	dprintf("Got %d entries\n", data->memory_status->used);
155 
156 	return ret;
157 }
158 
at_sonyericsson_init(char * foundmodel,char * setupmodel,struct gn_statemachine * state)159 void at_sonyericsson_init(char* foundmodel, char* setupmodel, struct gn_statemachine *state)
160 {
161 	/* Sony Ericssons support just mode 2 */
162 	AT_DRVINST(state)->cnmi_mode = 2;
163 	AT_DRVINST(state)->encode_memory_type = 1;
164 	AT_DRVINST(state)->encode_number = 1;
165 	AT_DRVINST(state)->lac_swapped = 1;
166 
167 	/*
168 	 * Calculate phonebook size for SonyEricsson phones: they don't respond
169 	 * with memory stats to AT+CPBS. Calculate by reading and counting all
170 	 * entries (which is fast -- just one command).
171 	 */
172 	at_insert_send_function(GN_OP_GetMemoryStatus, AT_GetMemoryStatus, state);
173 	at_insert_recv_function(GN_OP_GetMemoryStatus, ReplyMemoryStatus, state);
174 }
175