1 //indent -gnu -ts4 -br -brs -cdw -lp -ce -nbfda -npcs -nprs -npsl -nbbo -saf -sai -saw -cs -bbo -nhnl -nut -sob -l90
2 #include "celliax.h"
3 #include "iconv.h"
4
5 extern int celliax_debug;
6 extern char *celliax_console_active;
7 extern char celliax_type[];
8 extern struct celliax_pvt *celliax_iflist;
9 extern int celliax_dir_entry_extension;
10
11 #ifndef GIOVA48
12 #define SAMPLES_PER_FRAME 160
13 #else // GIOVA48
14 #define SAMPLES_PER_FRAME 960
15 #endif // GIOVA48
16
17 #ifdef CELLIAX_ALSA
18 /*! \brief ALSA pcm format, according to endianess */
19 #if __BYTE_ORDER == __LITTLE_ENDIAN
20 snd_pcm_format_t celliax_format = SND_PCM_FORMAT_S16_LE;
21 #else
22 snd_pcm_format_t celliax_format = SND_PCM_FORMAT_S16_BE;
23 #endif
24
25 /*!
26 * \brief Initialize the ALSA soundcard channels (capture AND playback) used by one interface (a multichannel soundcard can be used by multiple interfaces)
27 * \param p the celliax_pvt of the interface
28 *
29 * This function call alsa_open_dev to initialize the ALSA soundcard for each channel (capture AND playback) used by one interface (a multichannel soundcard can be used by multiple interfaces). Called by sound_init
30 *
31 * \return zero on success, -1 on error.
32 */
alsa_init(struct celliax_pvt * p)33 int alsa_init(struct celliax_pvt *p)
34 {
35 p->alsac = alsa_open_dev(p, SND_PCM_STREAM_CAPTURE);
36 if (!p->alsac) {
37 ERRORA("Failed opening ALSA capture device: %s\n", CELLIAX_P_LOG, p->alsacname);
38 if (alsa_shutdown(p)) {
39 ERRORA("alsa_shutdown failed\n", CELLIAX_P_LOG);
40 return -1;
41 }
42 return -1;
43 }
44 p->alsap = alsa_open_dev(p, SND_PCM_STREAM_PLAYBACK);
45 if (!p->alsap) {
46 ERRORA("Failed opening ALSA playback device: %s\n", CELLIAX_P_LOG, p->alsapname);
47 if (alsa_shutdown(p)) {
48 ERRORA("alsa_shutdown failed\n", CELLIAX_P_LOG);
49 return -1;
50 }
51 return -1;
52 }
53
54 /* make valgrind very happy */
55 snd_config_update_free_global();
56 return 0;
57 }
58
59 /*!
60 * \brief Shutdown the ALSA soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces)
61 * \param p the celliax_pvt of the interface
62 *
63 * This function shutdown the ALSA soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces). Called by sound_init
64 *
65 * \return zero on success, -1 on error.
66 */
67
alsa_shutdown(struct celliax_pvt * p)68 int alsa_shutdown(struct celliax_pvt *p)
69 {
70
71 int err;
72
73 if (p->alsap) {
74 err = snd_pcm_drop(p->alsap);
75 if (err < 0) {
76 ERRORA("device [%s], snd_pcm_drop failed with error '%s'\n", CELLIAX_P_LOG,
77 p->alsapname, snd_strerror(err));
78 return -1;
79 }
80 err = snd_pcm_close(p->alsap);
81 if (err < 0) {
82 ERRORA("device [%s], snd_pcm_close failed with error '%s'\n", CELLIAX_P_LOG,
83 p->alsapname, snd_strerror(err));
84 return -1;
85 }
86 }
87 if (p->alsac) {
88 err = snd_pcm_drop(p->alsac);
89 if (err < 0) {
90 ERRORA("device [%s], snd_pcm_drop failed with error '%s'\n", CELLIAX_P_LOG,
91 p->alsacname, snd_strerror(err));
92 return -1;
93 }
94 err = snd_pcm_close(p->alsac);
95 if (err < 0) {
96 ERRORA("device [%s], snd_pcm_close failed with error '%s'\n", CELLIAX_P_LOG,
97 p->alsacname, snd_strerror(err));
98 return -1;
99 }
100 }
101
102 return 0;
103 }
104
105 /*!
106 * \brief Setup and open the ALSA device (capture OR playback)
107 * \param p the celliax_pvt of the interface
108 * \param stream the ALSA capture/playback definition
109 *
110 * This function setup and open the ALSA device (capture OR playback). Called by alsa_init
111 *
112 * \return zero on success, -1 on error.
113 */
alsa_open_dev(struct celliax_pvt * p,snd_pcm_stream_t stream)114 snd_pcm_t *alsa_open_dev(struct celliax_pvt * p, snd_pcm_stream_t stream)
115 {
116
117 snd_pcm_t *handle = NULL;
118 snd_pcm_hw_params_t *params;
119 snd_pcm_sw_params_t *swparams;
120 snd_pcm_uframes_t buffer_size;
121 int err;
122 size_t n;
123 //snd_pcm_uframes_t xfer_align;
124 unsigned int rate;
125 snd_pcm_uframes_t start_threshold, stop_threshold;
126 snd_pcm_uframes_t period_size = 0;
127 snd_pcm_uframes_t chunk_size = 0;
128 int start_delay = 0;
129 int stop_delay = 0;
130 snd_pcm_state_t state;
131 snd_pcm_info_t *info;
132
133 period_size = p->alsa_period_size;
134
135 snd_pcm_hw_params_alloca(¶ms);
136 snd_pcm_sw_params_alloca(&swparams);
137
138 if (stream == SND_PCM_STREAM_CAPTURE) {
139 err = snd_pcm_open(&handle, p->alsacname, stream, 0 | SND_PCM_NONBLOCK);
140 } else {
141 err = snd_pcm_open(&handle, p->alsapname, stream, 0 | SND_PCM_NONBLOCK);
142 }
143 if (err < 0) {
144 ERRORA
145 ("snd_pcm_open failed with error '%s' on device '%s', if you are using a plughw:n device please change it to be a default:n device (so to allow it to be shared with other concurrent programs), or maybe you are using an ALSA voicemodem and slmodemd"
146 " is running?\n", CELLIAX_P_LOG, snd_strerror(err),
147 stream == SND_PCM_STREAM_CAPTURE ? p->alsacname : p->alsapname);
148 return NULL;
149 }
150
151 snd_pcm_info_alloca(&info);
152
153 if ((err = snd_pcm_info(handle, info)) < 0) {
154 ERRORA("info error: %s", CELLIAX_P_LOG, snd_strerror(err));
155 return NULL;
156 }
157
158 err = snd_pcm_nonblock(handle, 1);
159 if (err < 0) {
160 ERRORA("nonblock setting error: %s", CELLIAX_P_LOG, snd_strerror(err));
161 return NULL;
162 }
163
164 err = snd_pcm_hw_params_any(handle, params);
165 if (err < 0) {
166 ERRORA("Broken configuration for this PCM, no configurations available: %s\n",
167 CELLIAX_P_LOG, snd_strerror(err));
168 return NULL;
169 }
170
171 err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
172 if (err < 0) {
173 ERRORA("Access type not available: %s\n", CELLIAX_P_LOG, snd_strerror(err));
174 return NULL;
175 }
176 err = snd_pcm_hw_params_set_format(handle, params, celliax_format);
177 if (err < 0) {
178 ERRORA("Sample format non available: %s\n", CELLIAX_P_LOG, snd_strerror(err));
179 return NULL;
180 }
181 err = snd_pcm_hw_params_set_channels(handle, params, 1);
182 if (err < 0) {
183 DEBUGA_SOUND("Channels count set failed: %s\n", CELLIAX_P_LOG, snd_strerror(err));
184 }
185 #if 1
186 unsigned int chan_num;
187 err = snd_pcm_hw_params_get_channels(params, &chan_num);
188 if (err < 0) {
189 ERRORA("Channels count non available: %s\n", CELLIAX_P_LOG, snd_strerror(err));
190 return NULL;
191 }
192 if (chan_num < 1 || chan_num > 2) {
193 ERRORA("Channels count MUST BE 1 or 2, it is: %d\n", CELLIAX_P_LOG, chan_num);
194 ERRORA("Channels count MUST BE 1 or 2, it is: %d on %s %s\n", CELLIAX_P_LOG, chan_num,
195 p->alsapname, p->alsacname);
196 return NULL;
197 } else {
198 if (chan_num == 1) {
199 if (stream == SND_PCM_STREAM_CAPTURE)
200 p->alsa_capture_is_mono = 1;
201 else
202 p->alsa_play_is_mono = 1;
203 } else {
204 if (stream == SND_PCM_STREAM_CAPTURE)
205 p->alsa_capture_is_mono = 0;
206 else
207 p->alsa_play_is_mono = 0;
208 }
209 }
210 #else
211 p->alsa_capture_is_mono = 1;
212 p->alsa_play_is_mono = 1;
213 #endif
214
215 #if 0
216 unsigned int buffer_time = 0;
217 unsigned int period_time = 0;
218 snd_pcm_uframes_t period_frames = 0;
219 snd_pcm_uframes_t buffer_frames = 0;
220
221 if (buffer_time == 0 && buffer_frames == 0) {
222 err = snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0);
223 assert(err >= 0);
224 if (buffer_time > 500000)
225 buffer_time = 500000;
226 }
227 if (period_time == 0 && period_frames == 0) {
228 if (buffer_time > 0)
229 period_time = buffer_time / 4;
230 else
231 period_frames = buffer_frames / 4;
232 }
233 if (period_time > 0)
234 err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0);
235 else
236 err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_frames, 0);
237 assert(err >= 0);
238 if (buffer_time > 0) {
239 err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0);
240 } else {
241 err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_frames);
242 }
243 #endif
244
245 #if 1
246 rate = p->celliax_sound_rate;
247 err = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0);
248 if ((float) p->celliax_sound_rate * 1.05 < rate
249 || (float) p->celliax_sound_rate * 0.95 > rate) {
250 WARNINGA("Rate is not accurate (requested = %iHz, got = %iHz)\n", CELLIAX_P_LOG,
251 p->celliax_sound_rate, rate);
252 }
253
254 if (err < 0) {
255 ERRORA("Error setting rate: %s\n", CELLIAX_P_LOG, snd_strerror(err));
256 return NULL;
257 }
258 p->celliax_sound_rate = rate;
259
260 err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, 0);
261
262 if (err < 0) {
263 ERRORA("Error setting period_size: %s\n", CELLIAX_P_LOG, snd_strerror(err));
264 return NULL;
265 }
266
267 p->alsa_period_size = period_size;
268
269 p->alsa_buffer_size = p->alsa_period_size * p->alsa_periods_in_buffer;
270
271 err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &p->alsa_buffer_size);
272
273 if (err < 0) {
274 ERRORA("Error setting buffer_size: %s\n", CELLIAX_P_LOG, snd_strerror(err));
275 return NULL;
276 }
277 #endif
278
279 err = snd_pcm_hw_params(handle, params);
280 if (err < 0) {
281 ERRORA("Unable to install hw params: %s\n", CELLIAX_P_LOG, snd_strerror(err));
282 return NULL;
283 }
284
285 snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
286 snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
287 if (chunk_size == buffer_size) {
288 ERRORA("Can't use period equal to buffer size (%lu == %lu)\n", CELLIAX_P_LOG,
289 chunk_size, buffer_size);
290 return NULL;
291 }
292
293 snd_pcm_sw_params_current(handle, swparams);
294
295 #if 0
296 err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
297 if (err < 0) {
298 ERRORA("Unable to obtain xfer align: %s\n", CELLIAX_P_LOG, snd_strerror(err));
299 }
300 NOTICA("xfer_align: %d\n", CELLIAX_P_LOG, xfer_align);
301 /* for some reason, on some platforms, xfer_align here is zero, that gives a floating point exception later. So, let's try to force it to 160, the frame size used by celliax */
302 xfer_align = p->alsa_period_size;
303 NOTICA("xfer_align: %d\n", CELLIAX_P_LOG, xfer_align);
304
305 err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
306 if (err < 0) {
307 ERRORA("Error setting xfer_align: %s\n", CELLIAX_P_LOG, snd_strerror(err));
308 }
309 NOTICA("xfer_align: %d\n", CELLIAX_P_LOG, xfer_align);
310
311 err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
312 if (err < 0) {
313 ERRORA("Unable to obtain xfer align: %s\n", CELLIAX_P_LOG, snd_strerror(err));
314 }
315 NOTICA("xfer_align: %d\n", CELLIAX_P_LOG, xfer_align);
316 #endif
317
318 /*
319 if (sleep_min)
320 xfer_align = 1;
321 err = snd_pcm_sw_params_set_sleep_min(handle, swparams,
322 0);
323
324 if (err < 0) {
325 ERRORA("Error setting slep_min: %s\n", CELLIAX_P_LOG, snd_strerror(err));
326 }
327 */
328 n = chunk_size;
329 err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);
330 if (err < 0) {
331 ERRORA("Error setting avail_min: %s\n", CELLIAX_P_LOG, snd_strerror(err));
332 }
333 #if 0
334 /* round up to closest transfer boundary */
335 if (xfer_align == 0) { //so to avoid floating point exception ????
336 xfer_align = 160;
337 }
338 //original n = (buffer_size / xfer_align) * xfer_align;
339 n = (chunk_size / xfer_align) * xfer_align;
340 #endif
341 if (stream == SND_PCM_STREAM_CAPTURE) {
342 start_delay = 1;
343 }
344 if (start_delay <= 0) {
345 start_threshold = n + (double) rate *start_delay / 1000000;
346 } else {
347 start_threshold = (double) rate *start_delay / 1000000;
348 }
349 if (start_threshold < 1)
350 start_threshold = 1;
351 if (start_threshold > n)
352 start_threshold = n;
353 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
354 if (err < 0) {
355 ERRORA("Error setting start_threshold: %s\n", CELLIAX_P_LOG, snd_strerror(err));
356 }
357
358 if (stop_delay <= 0)
359 stop_threshold = buffer_size + (double) rate *stop_delay / 1000000;
360 else
361 stop_threshold = (double) rate *stop_delay / 1000000;
362
363 if (stream == SND_PCM_STREAM_CAPTURE) {
364 stop_threshold = -1;
365 }
366
367 err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
368
369 if (err < 0) {
370 ERRORA("Error setting stop_threshold: %s\n", CELLIAX_P_LOG, snd_strerror(err));
371 }
372 #if 0
373 err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
374
375 if (err < 0) {
376 ERRORA("Error setting xfer_align: %s\n", CELLIAX_P_LOG, snd_strerror(err));
377 }
378 #endif
379
380 if (snd_pcm_sw_params(handle, swparams) < 0) {
381 ERRORA("Error installing software parameters: %s\n", CELLIAX_P_LOG,
382 snd_strerror(err));
383 }
384
385 err = snd_pcm_poll_descriptors_count(handle);
386 if (err <= 0) {
387 ERRORA("Unable to get a poll descriptors count, error is %s\n", CELLIAX_P_LOG,
388 snd_strerror(err));
389 return NULL;
390 }
391
392 if (err != 1) { //number of poll descriptors
393 DEBUGA_SOUND("Can't handle more than one device\n", CELLIAX_P_LOG);
394 return NULL;
395 }
396
397 err = snd_pcm_poll_descriptors(handle, &p->pfd, err);
398 if (err != 1) {
399 ERRORA("snd_pcm_poll_descriptors failed, %s\n", CELLIAX_P_LOG, snd_strerror(err));
400 return NULL;
401 }
402 DEBUGA_SOUND("Acquired fd %d from the poll descriptor\n", CELLIAX_P_LOG, p->pfd.fd);
403
404 if (stream == SND_PCM_STREAM_CAPTURE) {
405 p->celliax_sound_capt_fd = p->pfd.fd;
406 }
407
408 state = snd_pcm_state(handle);
409
410 if (state != SND_PCM_STATE_RUNNING) {
411 if (state != SND_PCM_STATE_PREPARED) {
412 err = snd_pcm_prepare(handle);
413 if (err) {
414 ERRORA("snd_pcm_prepare failed, %s\n", CELLIAX_P_LOG, snd_strerror(err));
415 return NULL;
416 }
417 DEBUGA_SOUND("prepared!\n", CELLIAX_P_LOG);
418 }
419 if (stream == SND_PCM_STREAM_CAPTURE) {
420 err = snd_pcm_start(handle);
421 if (err) {
422 ERRORA("snd_pcm_start failed, %s\n", CELLIAX_P_LOG, snd_strerror(err));
423 return NULL;
424 }
425 DEBUGA_SOUND("started!\n", CELLIAX_P_LOG);
426 }
427 }
428 if (option_debug > 1) {
429 snd_output_t *output = NULL;
430 err = snd_output_stdio_attach(&output, stdout, 0);
431 if (err < 0) {
432 ERRORA("snd_output_stdio_attach failed: %s\n", CELLIAX_P_LOG, snd_strerror(err));
433 }
434 snd_pcm_dump(handle, output);
435 }
436 if (option_debug > 1)
437 DEBUGA_SOUND("ALSA handle = %ld\n", CELLIAX_P_LOG, (long int) handle);
438 return handle;
439
440 }
441
442 /*! \brief Read audio frames from interface */
443
alsa_read(struct celliax_pvt * p)444 struct ast_frame *alsa_read(struct celliax_pvt *p)
445 {
446 static struct ast_frame f;
447 static short __buf[CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
448 static short __buf2[(CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2) * 2];
449 short *buf;
450 short *buf2;
451 static int readpos = 0;
452 static int left = CELLIAX_FRAME_SIZE;
453 snd_pcm_state_t state;
454 int r = 0;
455 int off = 0;
456 int error = 0;
457 //time_t now_timestamp;
458
459 //memset(&f, 0, sizeof(struct ast_frame)); //giova
460
461 f.frametype = AST_FRAME_NULL;
462 f.subclass = 0;
463 f.samples = 0;
464 f.datalen = 0;
465 f.data = NULL;
466 f.offset = 0;
467 f.src = celliax_type;
468 f.mallocd = 0;
469 f.delivery.tv_sec = 0;
470 f.delivery.tv_usec = 0;
471
472 state = snd_pcm_state(p->alsac);
473 if (state != SND_PCM_STATE_RUNNING) {
474 DEBUGA_SOUND("ALSA read state is not SND_PCM_STATE_RUNNING\n", CELLIAX_P_LOG);
475
476 if (state != SND_PCM_STATE_PREPARED) {
477 error = snd_pcm_prepare(p->alsac);
478 if (error) {
479 ERRORA("snd_pcm_prepare failed, %s\n", CELLIAX_P_LOG, snd_strerror(error));
480 return &f;
481 }
482 DEBUGA_SOUND("prepared!\n", CELLIAX_P_LOG);
483 }
484 usleep(1000);
485 error = snd_pcm_start(p->alsac);
486 if (error) {
487 ERRORA("snd_pcm_start failed, %s\n", CELLIAX_P_LOG, snd_strerror(error));
488 return &f;
489 }
490 DEBUGA_SOUND("started!\n", CELLIAX_P_LOG);
491 usleep(1000);
492 }
493
494 buf = __buf + AST_FRIENDLY_OFFSET / 2;
495 buf2 = __buf2 + ((AST_FRIENDLY_OFFSET / 2) * 2);
496
497 if (p->alsa_capture_is_mono) {
498 r = snd_pcm_readi(p->alsac, buf + readpos, left);
499 } else {
500 r = snd_pcm_readi(p->alsac, buf2 + (readpos * 2), left);
501
502 int a = 0;
503 int i = 0;
504 for (i = 0; i < (CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2) * 2;) {
505 __buf[a] = (__buf2[i] + __buf2[i + 1]) / 2; //comment out this line to use only left
506 //__buf[a] = __buf2[i]; // enable this line to use only left
507 a++;
508 i++;
509 i++;
510 }
511 }
512
513 if (r == -EPIPE) {
514 ERRORA("XRUN read\n\n\n\n\n", CELLIAX_P_LOG);
515 return &f;
516 } else if (r == -ESTRPIPE) {
517 ERRORA("-ESTRPIPE\n", CELLIAX_P_LOG);
518 return &f;
519
520 } else if (r == -EAGAIN) {
521 DEBUGA_SOUND("ALSA read -EAGAIN, the soundcard is not ready to be read by celliax\n",
522 CELLIAX_P_LOG);
523 while (r == -EAGAIN) {
524 usleep(1000);
525
526 if (p->alsa_capture_is_mono) {
527 r = snd_pcm_readi(p->alsac, buf + readpos, left);
528 } else {
529 r = snd_pcm_readi(p->alsac, buf2 + (readpos * 2), left);
530
531 int a = 0;
532 int i = 0;
533 for (i = 0; i < (CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2) * 2;) {
534 __buf[a] = (__buf2[i] + __buf2[i + 1]) / 2;
535 a++;
536 i++;
537 i++;
538 }
539 }
540
541 }
542 } else if (r < 0) {
543 WARNINGA("ALSA Read error: %s\n", CELLIAX_P_LOG, snd_strerror(r));
544 } else if (r >= 0) {
545 //DEBUGA_SOUND("read: r=%d, readpos=%d, left=%d, off=%d\n", CELLIAX_P_LOG, r, readpos, left, off);
546 off -= r; //what is the meaning of this? a leftover, probably
547 }
548 /* Update positions */
549 readpos += r;
550 left -= r;
551
552 if (readpos >= CELLIAX_FRAME_SIZE) {
553 /* A real frame */
554 readpos = 0;
555 left = CELLIAX_FRAME_SIZE;
556
557 f.frametype = AST_FRAME_VOICE;
558 f.subclass = AST_FORMAT_SLINEAR;
559 f.samples = CELLIAX_FRAME_SIZE;
560 f.datalen = CELLIAX_FRAME_SIZE * 2;
561 f.data = buf;
562 f.offset = AST_FRIENDLY_OFFSET;
563 f.src = celliax_type;
564 f.mallocd = 0;
565 #ifdef ALSA_MONITOR
566 alsa_monitor_read((char *) buf, CELLIAX_FRAME_SIZE * 2);
567 #endif
568
569 }
570 return &f;
571 }
572
573 /*! \brief Write audio frames to interface */
alsa_write(struct celliax_pvt * p,struct ast_frame * f)574 int alsa_write(struct celliax_pvt *p, struct ast_frame *f)
575 {
576 static char sizbuf[8000];
577 static char sizbuf2[16000];
578 static char silencebuf[8000];
579 static int sizpos = 0;
580 int len = sizpos;
581 int pos;
582 int res = 0;
583 time_t now_timestamp;
584 /* size_t frames = 0; */
585 snd_pcm_state_t state;
586 snd_pcm_sframes_t delayp1;
587 snd_pcm_sframes_t delayp2;
588
589 /* We have to digest the frame in 160-byte portions */
590 if (f->datalen > sizeof(sizbuf) - sizpos) {
591 ERRORA("Frame too large\n", CELLIAX_P_LOG);
592 res = -1;
593 } else {
594 memcpy(sizbuf + sizpos, f->data, f->datalen);
595 len += f->datalen;
596 pos = 0;
597 #ifdef ALSA_MONITOR
598 alsa_monitor_write(sizbuf, len);
599 #endif
600 state = snd_pcm_state(p->alsap);
601 if (state == SND_PCM_STATE_XRUN) {
602 int i;
603
604 DEBUGA_SOUND
605 ("You've got an ALSA write XRUN in the past (celliax can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file\n",
606 CELLIAX_P_LOG, p->alsa_periods_in_buffer);
607 res = snd_pcm_prepare(p->alsap);
608 if (res) {
609 ERRORA("audio play prepare failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
610 } else {
611 res = snd_pcm_format_set_silence(celliax_format, silencebuf, len / 2);
612 if (res < 0) {
613 DEBUGA_SOUND("Silence error %s\n", CELLIAX_P_LOG, snd_strerror(res));
614 res = -1;
615 }
616 for (i = 0; i < (p->alsa_periods_in_buffer - 1); i++) {
617 res = snd_pcm_writei(p->alsap, silencebuf, len / 2);
618 if (res != len / 2) {
619 DEBUGA_SOUND("Write returned a different quantity: %d\n", CELLIAX_P_LOG, res);
620 res = -1;
621 } else if (res < 0) {
622 DEBUGA_SOUND("Write error %s\n", CELLIAX_P_LOG, snd_strerror(res));
623 res = -1;
624 }
625 }
626 }
627
628 }
629
630 res = snd_pcm_delay(p->alsap, &delayp1);
631 if (res < 0) {
632 DEBUGA_SOUND("Error %d on snd_pcm_delay: \"%s\"\n", CELLIAX_P_LOG, res,
633 snd_strerror(res));
634 res = snd_pcm_prepare(p->alsap);
635 if (res) {
636 DEBUGA_SOUND("snd_pcm_prepare failed: '%s'\n", CELLIAX_P_LOG, snd_strerror(res));
637 }
638 res = snd_pcm_delay(p->alsap, &delayp1);
639 }
640
641 delayp2 = snd_pcm_avail_update(p->alsap);
642 if (delayp2 < 0) {
643 DEBUGA_SOUND("Error %d on snd_pcm_avail_update: \"%s\"\n", CELLIAX_P_LOG,
644 (int) delayp2, snd_strerror(delayp2));
645
646 res = snd_pcm_prepare(p->alsap);
647 if (res) {
648 DEBUGA_SOUND("snd_pcm_prepare failed: '%s'\n", CELLIAX_P_LOG, snd_strerror(res));
649 }
650 delayp2 = snd_pcm_avail_update(p->alsap);
651 }
652
653 if ( /* delayp1 != 0 && delayp1 != 160 */
654 delayp1 < 160 || delayp2 > p->alsa_buffer_size) {
655
656 res = snd_pcm_prepare(p->alsap);
657 if (res) {
658 DEBUGA_SOUND
659 ("snd_pcm_prepare failed while trying to prevent an ALSA write XRUN: %s, delayp1=%d, delayp2=%d\n",
660 CELLIAX_P_LOG, snd_strerror(res), (int) delayp1, (int) delayp2);
661 } else {
662
663 int i;
664 for (i = 0; i < (p->alsa_periods_in_buffer - 1); i++) {
665 res = snd_pcm_format_set_silence(celliax_format, silencebuf, len / 2);
666 if (res < 0) {
667 DEBUGA_SOUND("Silence error %s\n", CELLIAX_P_LOG, snd_strerror(res));
668 res = -1;
669 }
670 res = snd_pcm_writei(p->alsap, silencebuf, len / 2);
671 if (res < 0) {
672 DEBUGA_SOUND("Write error %s\n", CELLIAX_P_LOG, snd_strerror(res));
673 res = -1;
674 } else if (res != len / 2) {
675 DEBUGA_SOUND("Write returned a different quantity: %d\n", CELLIAX_P_LOG, res);
676 res = -1;
677 }
678 }
679
680 DEBUGA_SOUND
681 ("PREVENTING an ALSA write XRUN (celliax can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file. delayp1=%d, delayp2=%d\n",
682 CELLIAX_P_LOG, p->alsa_periods_in_buffer, (int) delayp1, (int) delayp2);
683 }
684
685 }
686
687 memset(sizbuf2, 0, sizeof(sizbuf2));
688 if (p->alsa_play_is_mono) {
689 res = snd_pcm_writei(p->alsap, sizbuf, len / 2);
690 } else {
691 int a = 0;
692 int i = 0;
693 for (i = 0; i < 8000;) {
694 sizbuf2[a] = sizbuf[i];
695 a++;
696 i++;
697 sizbuf2[a] = sizbuf[i];
698 a++;
699 i--;
700 sizbuf2[a] = sizbuf[i]; // comment out this line to use only left
701 a++;
702 i++;
703 sizbuf2[a] = sizbuf[i]; // comment out this line to use only left
704 a++;
705 i++;
706 }
707 res = snd_pcm_writei(p->alsap, sizbuf2, len);
708 }
709 if (res == -EPIPE) {
710 DEBUGA_SOUND
711 ("ALSA write EPIPE (XRUN) (celliax can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file. delayp1=%d, delayp2=%d\n",
712 CELLIAX_P_LOG, p->alsa_periods_in_buffer, (int) delayp1, (int) delayp2);
713 res = snd_pcm_prepare(p->alsap);
714 if (res) {
715 ERRORA("audio play prepare failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
716 } else {
717
718 if (p->alsa_play_is_mono) {
719 res = snd_pcm_writei(p->alsap, sizbuf, len / 2);
720 } else {
721 int a = 0;
722 int i = 0;
723 for (i = 0; i < 8000;) {
724 sizbuf2[a] = sizbuf[i];
725 a++;
726 i++;
727 sizbuf2[a] = sizbuf[i];
728 a++;
729 i--;
730 sizbuf2[a] = sizbuf[i];
731 a++;
732 i++;
733 sizbuf2[a] = sizbuf[i];
734 a++;
735 i++;
736 }
737 res = snd_pcm_writei(p->alsap, sizbuf2, len);
738 }
739
740 }
741
742 } else {
743 if (res == -ESTRPIPE) {
744 ERRORA("You've got some big problems\n", CELLIAX_P_LOG);
745 } else if (res == -EAGAIN) {
746 res = 0;
747 } else if (res < 0) {
748 ERRORA("Error %d on audio write: \"%s\"\n", CELLIAX_P_LOG, res,
749 snd_strerror(res));
750 }
751 }
752 }
753
754 if (p->audio_play_reset_period) {
755 time(&now_timestamp);
756 if ((now_timestamp - p->audio_play_reset_timestamp) > p->audio_play_reset_period) {
757 if (option_debug)
758 DEBUGA_SOUND("reset audio play\n", CELLIAX_P_LOG);
759 res = snd_pcm_wait(p->alsap, 1000);
760 if (res < 0) {
761 ERRORA("audio play wait failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
762 }
763 res = snd_pcm_drop(p->alsap);
764 if (res) {
765 ERRORA("audio play drop failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
766 }
767 res = snd_pcm_prepare(p->alsap);
768 if (res) {
769 ERRORA("audio play prepare failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
770 }
771 res = snd_pcm_wait(p->alsap, 1000);
772 if (res < 0) {
773 ERRORA("audio play wait failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
774 }
775 time(&p->audio_play_reset_timestamp);
776 }
777 }
778 res = 0;
779 if (res > 0)
780 res = 0;
781 return res;
782 }
783
784
785 /*! \brief Write audio frames to interface */
786 #endif /* CELLIAX_ALSA */
787
788 #ifdef CELLIAX_PORTAUDIO
celliax_portaudio_devlist(struct celliax_pvt * p)789 int celliax_portaudio_devlist(struct celliax_pvt *p)
790 {
791 int i, numDevices;
792 const PaDeviceInfo *deviceInfo;
793
794 numDevices = Pa_GetDeviceCount();
795 if (numDevices < 0) {
796 return 0;
797 }
798 for (i = 0; i < numDevices; i++) {
799 deviceInfo = Pa_GetDeviceInfo(i);
800 NOTICA
801 ("Found PORTAUDIO device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
802 CELLIAX_P_LOG, i, deviceInfo->name, deviceInfo->maxInputChannels,
803 deviceInfo->maxOutputChannels);
804 }
805
806 return numDevices;
807 }
808
celliax_portaudio_init(struct celliax_pvt * p)809 int celliax_portaudio_init(struct celliax_pvt *p)
810 {
811 PaError err;
812 int c;
813 PaStreamParameters inputParameters, outputParameters;
814 int numdevices;
815 const PaDeviceInfo *deviceInfo;
816
817 #ifndef GIOVA48
818 setenv("PA_ALSA_PLUGHW", "1", 1);
819 #endif // GIOVA48
820
821 err = Pa_Initialize();
822 if (err != paNoError)
823 return err;
824
825 numdevices = celliax_portaudio_devlist(p);
826
827 if (p->portaudiocindex > (numdevices - 1)) {
828 ERRORA("Portaudio Capture id=%d is out of range: valid id are from 0 to %d\n",
829 CELLIAX_P_LOG, p->portaudiocindex, (numdevices - 1));
830 return -1;
831 }
832
833 if (p->portaudiopindex > (numdevices - 1)) {
834 ERRORA("Portaudio Playback id=%d is out of range: valid id are from 0 to %d\n",
835 CELLIAX_P_LOG, p->portaudiopindex, (numdevices - 1));
836 return -1;
837 }
838 //inputParameters.device = 0;
839 if (p->portaudiocindex != -1) {
840 inputParameters.device = p->portaudiocindex;
841 } else {
842 inputParameters.device = Pa_GetDefaultInputDevice();
843 }
844 deviceInfo = Pa_GetDeviceInfo(inputParameters.device);
845 NOTICA
846 ("Using INPUT PORTAUDIO device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
847 CELLIAX_P_LOG, inputParameters.device, deviceInfo->name,
848 deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
849 if (deviceInfo->maxInputChannels == 0) {
850 ERRORA
851 ("No INPUT channels on device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
852 CELLIAX_P_LOG, inputParameters.device, deviceInfo->name,
853 deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
854 return -1;
855 }
856 inputParameters.channelCount = 1;
857 inputParameters.sampleFormat = paInt16;
858 //inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultHighInputLatency;
859 inputParameters.suggestedLatency = 0.1;
860 inputParameters.hostApiSpecificStreamInfo = NULL;
861
862 //outputParameters.device = 3;
863 if (p->portaudiopindex != -1) {
864 outputParameters.device = p->portaudiopindex;
865 } else {
866 outputParameters.device = Pa_GetDefaultOutputDevice();
867 }
868 deviceInfo = Pa_GetDeviceInfo(outputParameters.device);
869 NOTICA
870 ("Using OUTPUT PORTAUDIO device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
871 CELLIAX_P_LOG, outputParameters.device, deviceInfo->name,
872 deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
873 if (deviceInfo->maxOutputChannels == 0) {
874 ERRORA
875 ("No OUTPUT channels on device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
876 CELLIAX_P_LOG, inputParameters.device, deviceInfo->name,
877 deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
878 return -1;
879 }
880 #ifndef GIOVA48
881 outputParameters.channelCount = 1;
882 #else // GIOVA48
883 outputParameters.channelCount = 2;
884 #endif // GIOVA48
885 outputParameters.sampleFormat = paInt16;
886 //outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency;
887 outputParameters.suggestedLatency = 0.1;
888 outputParameters.hostApiSpecificStreamInfo = NULL;
889
890 /* build the pipe that will be polled on by pbx */
891 c = pipe(p->audiopipe);
892 if (c) {
893 ERRORA("Unable to create audio pipe\n", CELLIAX_P_LOG);
894 return -1;
895 }
896 fcntl(p->audiopipe[0], F_SETFL, O_NONBLOCK);
897 fcntl(p->audiopipe[1], F_SETFL, O_NONBLOCK);
898
899 err =
900 #ifndef GIOVA48
901 OpenAudioStream(&p->stream, &inputParameters, &outputParameters, 8000,
902 paDitherOff | paClipOff, SAMPLES_PER_FRAME, p->audiopipe[1],
903 &p->speexecho, &p->speexpreprocess, &p->owner);
904
905 #else // GIOVA48
906 OpenAudioStream(&p->stream, &inputParameters, &outputParameters, 48000,
907 paDitherOff | paClipOff, SAMPLES_PER_FRAME, p->audiopipe[1],
908 &p->speexecho, &p->speexpreprocess, &p->owner);
909
910 #endif // GIOVA48
911 if (err != paNoError) {
912 ERRORA("Unable to open audio stream: %s\n", CELLIAX_P_LOG, Pa_GetErrorText(err));
913 return -1;
914 }
915
916 /* the pipe is our audio fd for pbx to poll on */
917 p->celliax_sound_capt_fd = p->audiopipe[0];
918
919 return 0;
920 }
921
celliax_portaudio_write(struct celliax_pvt * p,struct ast_frame * f)922 int celliax_portaudio_write(struct celliax_pvt *p, struct ast_frame *f)
923 {
924 int samples;
925 #ifdef GIOVA48
926 //short buf[CELLIAX_FRAME_SIZE * 2];
927 short buf[3840];
928 short *buf2;
929
930 //ERRORA("1 f->datalen=: %d\n", CELLIAX_P_LOG, f->datalen);
931
932 memset(buf, '\0', CELLIAX_FRAME_SIZE * 2);
933
934 buf2 = f->data;
935
936 int i = 0, a = 0;
937
938 for (i = 0; i < f->datalen / sizeof(short); i++) {
939 //stereo, 2 chan 48 -> mono 8
940 buf[a] = buf2[i];
941 a++;
942 buf[a] = buf2[i];
943 a++;
944 buf[a] = buf2[i];
945 a++;
946 buf[a] = buf2[i];
947 a++;
948 buf[a] = buf2[i];
949 a++;
950 buf[a] = buf2[i];
951 a++;
952 buf[a] = buf2[i];
953 a++;
954 buf[a] = buf2[i];
955 a++;
956 buf[a] = buf2[i];
957 a++;
958 buf[a] = buf2[i];
959 a++;
960 buf[a] = buf2[i];
961 a++;
962 buf[a] = buf2[i];
963 a++;
964 /*
965 */
966 }
967 f->data = &buf;
968 f->datalen = f->datalen * 6;
969 //ERRORA("2 f->datalen=: %d\n", CELLIAX_P_LOG, f->datalen);
970 //f->datalen = f->datalen;
971 #endif // GIOVA48
972
973 #ifdef ASTERISK_VERSION_1_6_0_1
974 samples =
975 WriteAudioStream(p->stream, (short *) f->data.ptr,
976 (int) (f->datalen / sizeof(short)));
977 #else
978 samples =
979 WriteAudioStream(p->stream, (short *) f->data, (int) (f->datalen / sizeof(short)));
980 #endif /* ASTERISK_VERSION_1_6_0_1 */
981
982 if (samples != (int) (f->datalen / sizeof(short)))
983 ERRORA("WriteAudioStream wrote: %d of %d\n", CELLIAX_P_LOG, samples,
984 (int) (f->datalen / sizeof(short)));
985
986 return 0;
987 }
988
celliax_portaudio_read(struct celliax_pvt * p)989 struct ast_frame *celliax_portaudio_read(struct celliax_pvt *p)
990 {
991 static struct ast_frame f;
992 static short __buf[CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
993 short *buf;
994 static short __buf2[CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
995 short *buf2;
996 int samples;
997 char c;
998
999 memset(__buf, '\0', (CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2));
1000
1001 buf = __buf + AST_FRIENDLY_OFFSET / 2;
1002
1003 memset(__buf2, '\0', (CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2));
1004
1005 buf2 = __buf2 + AST_FRIENDLY_OFFSET / 2;
1006
1007 f.frametype = AST_FRAME_NULL;
1008 f.subclass = 0;
1009 f.samples = 0;
1010 f.datalen = 0;
1011
1012 #ifdef ASTERISK_VERSION_1_6_0_1
1013 f.data.ptr = NULL;
1014 #else
1015 f.data = NULL;
1016 #endif /* ASTERISK_VERSION_1_6_0_1 */
1017 f.offset = 0;
1018 f.src = celliax_type;
1019 f.mallocd = 0;
1020 f.delivery.tv_sec = 0;
1021 f.delivery.tv_usec = 0;
1022
1023 if ((samples = ReadAudioStream(p->stream, buf, SAMPLES_PER_FRAME)) == 0) {
1024 //do nothing
1025 } else {
1026 #ifdef GIOVA48
1027 int i = 0, a = 0;
1028
1029 samples = samples / 6;
1030 for (i = 0; i < samples; i++) {
1031 buf2[i] = buf[a];
1032 a = a + 6; //mono, 1 chan 48 -> 8
1033 }
1034 buf = buf2;
1035
1036 /* A real frame */
1037 f.frametype = AST_FRAME_VOICE;
1038 f.subclass = AST_FORMAT_SLINEAR;
1039 f.samples = CELLIAX_FRAME_SIZE / 6;
1040 f.datalen = CELLIAX_FRAME_SIZE * 2 / 6;
1041 #else // GIOVA48
1042 /* A real frame */
1043 f.frametype = AST_FRAME_VOICE;
1044 f.subclass = AST_FORMAT_SLINEAR;
1045 f.samples = CELLIAX_FRAME_SIZE;
1046 f.datalen = CELLIAX_FRAME_SIZE * 2;
1047 #endif // GIOVA48
1048
1049 #ifdef ASTERISK_VERSION_1_6_0_1
1050 f.data.ptr = buf;
1051 #else
1052 f.data = buf;
1053 #endif /* ASTERISK_VERSION_1_6_0_1 */
1054 f.offset = AST_FRIENDLY_OFFSET;
1055 f.src = celliax_type;
1056 f.mallocd = 0;
1057 }
1058
1059 read(p->audiopipe[0], &c, 1);
1060
1061 return &f;
1062 }
1063
celliax_portaudio_shutdown(struct celliax_pvt * p)1064 int celliax_portaudio_shutdown(struct celliax_pvt *p)
1065 {
1066 PaError err;
1067
1068 err = CloseAudioStream(p->stream);
1069
1070 if (err != paNoError)
1071 ERRORA("not able to CloseAudioStream\n", CELLIAX_P_LOG);
1072
1073 Pa_Terminate();
1074 return 0;
1075 }
1076 #endif // CELLIAX_PORTAUDIO
1077
celliax_serial_sync_AT(struct celliax_pvt * p)1078 int celliax_serial_sync_AT(struct celliax_pvt *p)
1079 {
1080 usleep(10000); /* 10msec */
1081 time(&p->celliax_serial_synced_timestamp);
1082 return 0;
1083 }
1084
celliax_serial_getstatus_AT(struct celliax_pvt * p)1085 int celliax_serial_getstatus_AT(struct celliax_pvt *p)
1086 {
1087 int res;
1088
1089 if (p->owner) {
1090 if (p->owner->_state != AST_STATE_UP && p->owner->_state != AST_STATE_DOWN) {
1091 DEBUGA_AT("No getstatus, we're neither UP nor DOWN\n", CELLIAX_P_LOG);
1092 return 0;
1093 }
1094 }
1095
1096 PUSHA_UNLOCKA(&p->controldev_lock);
1097 LOKKA(&p->controldev_lock);
1098 res = celliax_serial_write_AT_ack(p, "AT");
1099 if (res) {
1100 ERRORA("AT was not acknowledged, continuing but maybe there is a problem\n",
1101 CELLIAX_P_LOG);
1102 }
1103 usleep(1000);
1104
1105 if (strlen(p->at_query_battchg)) {
1106 res =
1107 celliax_serial_write_AT_expect(p, p->at_query_battchg, p->at_query_battchg_expect);
1108 if (res) {
1109 WARNINGA("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
1110 p->at_query_battchg, p->at_query_battchg_expect);
1111 }
1112 usleep(1000);
1113 }
1114
1115 if (strlen(p->at_query_signal)) {
1116 res =
1117 celliax_serial_write_AT_expect(p, p->at_query_signal, p->at_query_signal_expect);
1118 if (res) {
1119 WARNINGA("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
1120 p->at_query_signal, p->at_query_signal_expect);
1121 }
1122 usleep(1000);
1123 }
1124 //FIXME all the following commands in config!
1125
1126 if (p->sms_cnmi_not_supported) {
1127 res = celliax_serial_write_AT_ack(p, "AT+MMGL=\"HEADER ONLY\"");
1128 if (res) {
1129 WARNINGA
1130 ("%s does not get %s from the modem, maybe a long msg is incoming. If this cellmodem is not a Motorola, you are arriving here because your cellmodem do not supports CNMI kind of incoming SMS alert; please let it know to the developers of Celliax. If this cellmodem is a Motorola and this message keeps repeating, and you cannot correctly receive SMSs from this interface, please manually clean all messages from the cellmodem/SIM. Continuing.\n",
1131 CELLIAX_P_LOG, "AT+MMGL=\"HEADER ONLY\"", "OK");
1132 } else {
1133 usleep(1000);
1134 if (p->unread_sms_msg_id) {
1135 char at_command[256];
1136
1137 if (p->no_ucs2 == 0) {
1138 res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"UCS2\"");
1139 if (res) {
1140 ERRORA
1141 ("AT+CSCS=\"UCS2\" (set TE messages to ucs2) do not got OK from the phone\n",
1142 CELLIAX_P_LOG);
1143 memset(p->sms_message, 0, sizeof(p->sms_message));
1144 }
1145 }
1146
1147 memset(at_command, 0, sizeof(at_command));
1148 sprintf(at_command, "AT+CMGR=%d", p->unread_sms_msg_id);
1149 memset(p->sms_message, 0, sizeof(p->sms_message));
1150
1151 p->reading_sms_msg = 1;
1152 res = celliax_serial_write_AT_ack(p, at_command);
1153 p->reading_sms_msg = 0;
1154 if (res) {
1155 ERRORA
1156 ("AT+CMGR (read SMS) do not got OK from the phone, message sent was:|||%s|||\n",
1157 CELLIAX_P_LOG, at_command);
1158 }
1159 res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"GSM\"");
1160 if (res) {
1161 ERRORA
1162 ("AT+CSCS=\"GSM\" (set TE messages to GSM) do not got OK from the phone\n",
1163 CELLIAX_P_LOG);
1164 }
1165 memset(at_command, 0, sizeof(at_command));
1166 sprintf(at_command, "AT+CMGD=%d", p->unread_sms_msg_id); /* delete the message */
1167 p->unread_sms_msg_id = 0;
1168 res = celliax_serial_write_AT_ack(p, at_command);
1169 if (res) {
1170 ERRORA
1171 ("AT+CMGD (Delete SMS) do not got OK from the phone, message sent was:|||%s|||\n",
1172 CELLIAX_P_LOG, at_command);
1173 }
1174
1175 if (strlen(p->sms_message)) {
1176
1177 manager_event(EVENT_FLAG_SYSTEM, "CELLIAXincomingsms",
1178 "Interface: %s\r\nSMS_Message: %s\r\n", p->name, p->sms_message);
1179
1180 if (strlen(p->sms_receiving_program)) {
1181 int fd1[2];
1182 pid_t pid1;
1183 char *arg1[] = { p->sms_receiving_program, (char *) NULL };
1184 int i;
1185
1186 NOTICA("incoming SMS message:>>>%s<<<\n", CELLIAX_P_LOG, p->sms_message);
1187 pipe(fd1);
1188 pid1 = switch_fork();
1189
1190 if (pid1 == 0) { //child
1191 int err;
1192
1193 dup2(fd1[0], 0); // Connect stdin to pipe output
1194 close(fd1[1]); // close input pipe side
1195 setsid(); //session id
1196 err = execvp(arg1[0], arg1); //exec our program, with stdin connected to pipe output
1197 if (err) {
1198 ERRORA
1199 ("'sms_receiving_program' is set in config file to '%s', and it gave us back this error: %d, (%s). SMS received was:---%s---\n",
1200 CELLIAX_P_LOG, p->sms_receiving_program, err, strerror(errno),
1201 p->sms_message);
1202 }
1203 close(fd1[0]); // close output pipe side
1204 } //starting here continue the parent
1205 close(fd1[0]); // close output pipe side
1206 // write the msg on the pipe input
1207 for (i = 0; i < strlen(p->sms_message); i++) {
1208 write(fd1[1], &p->sms_message[i], 1);
1209 }
1210 close(fd1[1]); // close pipe input, let our program know we've finished
1211 } else {
1212 ERRORA
1213 ("got SMS incoming message, but 'sms_receiving_program' is not set in config file. SMS received was:---%s---\n",
1214 CELLIAX_P_LOG, p->sms_message);
1215 }
1216 }
1217 #if 1 //is this one needed? maybe it can interrupt an incoming call that is just to announce itself
1218 if (p->phone_callflow == CALLFLOW_CALL_IDLE
1219 && p->interface_state == AST_STATE_DOWN && p->owner == NULL) {
1220 /* we're not in a call, neither calling */
1221 res = celliax_serial_write_AT_ack(p, "AT+CKPD=\"EEE\"");
1222 if (res) {
1223 ERRORA
1224 ("AT+CKPD=\"EEE\" (cellphone screen back to user) do not got OK from the phone\n",
1225 CELLIAX_P_LOG);
1226 }
1227 }
1228 #endif
1229 }
1230 }
1231 }
1232
1233 UNLOCKA(&p->controldev_lock);
1234 POPPA_UNLOCKA(&p->controldev_lock);
1235 return 0;
1236 }
1237
celliax_serial_read_AT(struct celliax_pvt * p,int look_for_ack,int timeout_usec,int timeout_sec,const char * expected_string,int expect_crlf)1238 int celliax_serial_read_AT(struct celliax_pvt *p, int look_for_ack, int timeout_usec,
1239 int timeout_sec, const char *expected_string, int expect_crlf)
1240 {
1241 int select_err;
1242 int res;
1243 fd_set read_fds;
1244 struct timeval timeout;
1245 char tmp_answer[AT_BUFSIZ];
1246 char tmp_answer2[AT_BUFSIZ];
1247 char *tmp_answer_ptr;
1248 char *last_line_ptr;
1249 int i = 0;
1250 int read_count = 0;
1251 int la_counter = 0;
1252 int at_ack = -1;
1253 int la_read = 0;
1254
1255 FD_ZERO(&read_fds);
1256 FD_SET(p->controldevfd, &read_fds);
1257
1258 //NOTICA (" INSIDE this celliax_serial_device %s \n", CELLIAX_P_LOG, p->controldevice_name);
1259 tmp_answer_ptr = tmp_answer;
1260 memset(tmp_answer, 0, sizeof(char) * AT_BUFSIZ);
1261
1262 timeout.tv_sec = timeout_sec;
1263 timeout.tv_usec = timeout_usec;
1264 PUSHA_UNLOCKA(&p->controldev_lock);
1265 LOKKA(&p->controldev_lock);
1266
1267 while ((select_err = select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
1268 timeout.tv_sec = timeout_sec; //reset the timeout, linux modify it
1269 timeout.tv_usec = timeout_usec; //reset the timeout, linux modify it
1270 read_count =
1271 read(p->controldevfd, tmp_answer_ptr, AT_BUFSIZ - (tmp_answer_ptr - tmp_answer));
1272
1273 if (read_count == 0) {
1274 ERRORA
1275 ("read 0 bytes!!! Nenormalno! Marking this celliax_serial_device %s as dead, andif it is owned by a channel, hanging up. Maybe the phone is stuck, switched off, power down or battery exhausted\n",
1276 CELLIAX_P_LOG, p->controldevice_name);
1277 p->controldev_dead = 1;
1278 close(p->controldevfd);
1279 UNLOCKA(&p->controldev_lock);
1280 if (p->owner) {
1281 p->owner->hangupcause = AST_CAUSE_FAILURE;
1282 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1283 }
1284 return -1;
1285 }
1286
1287 if (option_debug > 90) {
1288 //DEBUGA_AT("1 read %d bytes, --|%s|--\n", CELLIAX_P_LOG, read_count, tmp_answer_ptr);
1289 //DEBUGA_AT("2 read %d bytes, --|%s|--\n", CELLIAX_P_LOG, read_count, tmp_answer);
1290 }
1291 tmp_answer_ptr = tmp_answer_ptr + read_count;
1292
1293 char *token_ptr;
1294
1295 la_counter = 0;
1296 memset(tmp_answer2, 0, sizeof(char) * AT_BUFSIZ);
1297 strcpy(tmp_answer2, tmp_answer);
1298 if ((token_ptr = strtok(tmp_answer2, "\n\r"))) {
1299 last_line_ptr = token_ptr;
1300 strncpy(p->line_array.result[la_counter], token_ptr, AT_MESG_MAX_LENGTH);
1301 if (strlen(token_ptr) > AT_MESG_MAX_LENGTH) {
1302 WARNINGA
1303 ("AT mesg longer than buffer, original message was: |%s|, in buffer only: |%s|\n",
1304 CELLIAX_P_LOG, token_ptr, p->line_array.result[la_counter]);
1305 }
1306 la_counter++;
1307 while ((token_ptr = strtok(NULL, "\n\r"))) {
1308 last_line_ptr = token_ptr;
1309 strncpy(p->line_array.result[la_counter], token_ptr, AT_MESG_MAX_LENGTH);
1310 if (strlen(token_ptr) > AT_MESG_MAX_LENGTH) {
1311 WARNINGA
1312 ("AT mesg longer than buffer, original message was: |%s|, in buffer only: |%s|\n",
1313 CELLIAX_P_LOG, token_ptr, p->line_array.result[la_counter]);
1314 }
1315 la_counter++;
1316 }
1317 } else {
1318 last_line_ptr = tmp_answer;
1319 }
1320
1321 if (expected_string && !expect_crlf) {
1322 DEBUGA_AT
1323 ("last_line_ptr=|%s|, expected_string=|%s|, expect_crlf=%d, memcmp(last_line_ptr, expected_string, strlen(expected_string)) = %d\n",
1324 CELLIAX_P_LOG, last_line_ptr, expected_string, expect_crlf, memcmp(last_line_ptr,
1325 expected_string,
1326 strlen
1327 (expected_string)));
1328 }
1329
1330 if (expected_string && !expect_crlf
1331 && !memcmp(last_line_ptr, expected_string, strlen(expected_string))
1332 ) {
1333 strncpy(p->line_array.result[la_counter], last_line_ptr, AT_MESG_MAX_LENGTH);
1334 // match expected string -> accept it withtout CRLF
1335 la_counter++;
1336
1337 }
1338 /* if the last line read was not a complete line, we'll read the rest in the future */
1339 else if (tmp_answer[strlen(tmp_answer) - 1] != '\r'
1340 && tmp_answer[strlen(tmp_answer) - 1] != '\n')
1341 la_counter--;
1342
1343 /* let's list the complete lines read so far, without re-listing the lines that has yet been listed */
1344 if (option_debug > 1) {
1345 for (i = la_read; i < la_counter; i++)
1346 DEBUGA_AT("Read line %d: |%s|\n", CELLIAX_P_LOG, i, p->line_array.result[i]);
1347 }
1348
1349 /* let's interpret the complete lines read so far (WITHOUT looking for OK, ERROR, and EXPECTED_STRING), without re-interpreting the lines that has been yet interpreted, so we're sure we don't miss anything */
1350 for (i = la_read; i < la_counter; i++) {
1351
1352 if ((strcmp(p->line_array.result[i], "RING") == 0)) {
1353 /* with first RING we wait for callid */
1354 gettimeofday(&(p->ringtime), NULL);
1355 /* give CALLID (+CLIP) a chance, wait for the next RING before answering */
1356 if (p->phone_callflow == CALLFLOW_INCOMING_RING) {
1357 /* we're at the second ring, set the interface state, will be answered by celliax_do_monitor */
1358 DEBUGA_AT("|%s| got second RING\n", CELLIAX_P_LOG, p->line_array.result[i]);
1359 p->interface_state = AST_STATE_RING;
1360 } else {
1361 /* we're at the first ring, so there is no CALLID yet thus clean the previous one
1362 just in case we don't receive the caller identification in this new call */
1363 memset(p->callid_name, 0, sizeof(p->callid_name));
1364 memset(p->callid_number, 0, sizeof(p->callid_number));
1365 /* only send AT+CLCC? if the device previously reported its support */
1366 if (p->at_has_clcc != 0) {
1367 /* we're at the first ring, try to get CALLID (with +CLCC) */
1368 DEBUGA_AT("|%s| got first RING, sending AT+CLCC?\n", CELLIAX_P_LOG,
1369 p->line_array.result[i]);
1370 res = celliax_serial_write_AT_noack(p, "AT+CLCC?");
1371 if (res) {
1372 ERRORA("AT+CLCC? (call list) was not correctly sent to the phone\n",
1373 CELLIAX_P_LOG);
1374 }
1375 } else {
1376 DEBUGA_AT("|%s| got first RING, but not sending AT+CLCC? as this device "
1377 "seems not to support\n", CELLIAX_P_LOG, p->line_array.result[i]);
1378 }
1379 }
1380 p->phone_callflow = CALLFLOW_INCOMING_RING;
1381 }
1382
1383 if ((strncmp(p->line_array.result[i], "+CLCC", 5) == 0)) {
1384 /* with clcc we wait for clip */
1385 memset(p->callid_name, 0, sizeof(p->callid_name));
1386 memset(p->callid_number, 0, sizeof(p->callid_number));
1387 int commacount = 0;
1388 int a = 0;
1389 int b = 0;
1390 int c = 0;
1391
1392 for (a = 0; a < strlen(p->line_array.result[i]); a++) {
1393
1394 if (p->line_array.result[i][a] == ',') {
1395 commacount++;
1396 }
1397 if (commacount == 5) {
1398 if (p->line_array.result[i][a] != ',' && p->line_array.result[i][a] != '"') {
1399 p->callid_number[b] = p->line_array.result[i][a];
1400 b++;
1401 }
1402 }
1403 if (commacount == 7) {
1404 if (p->line_array.result[i][a] != ',' && p->line_array.result[i][a] != '"') {
1405 p->callid_name[c] = p->line_array.result[i][a];
1406 c++;
1407 }
1408 }
1409 }
1410
1411 p->phone_callflow = CALLFLOW_INCOMING_RING;
1412 DEBUGA_AT("|%s| CLCC CALLID: name is %s, number is %s\n", CELLIAX_P_LOG,
1413 p->line_array.result[i],
1414 p->callid_name[0] ? p->callid_name : "not available",
1415 p->callid_number[0] ? p->callid_number : "not available");
1416 }
1417
1418 if ((strncmp(p->line_array.result[i], "+CLIP", 5) == 0)) {
1419 /* with CLIP, we want to answer right away */
1420 memset(p->callid_name, 0, sizeof(p->callid_name));
1421 memset(p->callid_number, 0, sizeof(p->callid_number));
1422
1423 int commacount = 0;
1424 int a = 0;
1425 int b = 0;
1426 int c = 0;
1427
1428 for (a = 7; a < strlen(p->line_array.result[i]); a++) {
1429 if (p->line_array.result[i][a] == ',') {
1430 commacount++;
1431 }
1432 if (commacount == 0) {
1433 if (p->line_array.result[i][a] != ',' && p->line_array.result[i][a] != '"') {
1434 p->callid_number[b] = p->line_array.result[i][a];
1435 b++;
1436 }
1437 }
1438 if (commacount == 4) {
1439 if (p->line_array.result[i][a] != ',' && p->line_array.result[i][a] != '"') {
1440 p->callid_name[c] = p->line_array.result[i][a];
1441 c++;
1442 }
1443 }
1444 }
1445
1446 if (p->interface_state != AST_STATE_RING) {
1447 gettimeofday(&(p->call_incoming_time), NULL);
1448 DEBUGA_AT("AST_STATE_RING call_incoming_time.tv_sec=%ld\n",
1449 CELLIAX_P_LOG, p->call_incoming_time.tv_sec);
1450
1451 }
1452
1453 p->interface_state = AST_STATE_RING;
1454 p->phone_callflow = CALLFLOW_INCOMING_RING;
1455 DEBUGA_AT("|%s| CLIP INCOMING CALLID: name is %s, number is %s\n", CELLIAX_P_LOG,
1456 p->line_array.result[i],
1457 p->callid_name[0] != 1 ? p->callid_name : "not available",
1458 p->callid_number[0] ? p->callid_number : "not available");
1459 }
1460
1461 if ((strcmp(p->line_array.result[i], "BUSY") == 0)) {
1462 p->phone_callflow = CALLFLOW_CALL_LINEBUSY;
1463 if (option_debug > 1)
1464 DEBUGA_AT("|%s| CALLFLOW_CALL_LINEBUSY\n", CELLIAX_P_LOG,
1465 p->line_array.result[i]);
1466 if (p->interface_state != AST_STATE_DOWN && p->owner) {
1467 ast_setstate(p->owner, AST_STATE_BUSY);
1468 celliax_queue_control(p->owner, AST_CONTROL_BUSY);
1469 } else {
1470 ERRORA("Why BUSY now?\n", CELLIAX_P_LOG);
1471 }
1472 }
1473 if ((strcmp(p->line_array.result[i], "NO ANSWER") == 0)) {
1474 p->phone_callflow = CALLFLOW_CALL_NOANSWER;
1475 if (option_debug > 1)
1476 DEBUGA_AT("|%s| CALLFLOW_CALL_NOANSWER\n", CELLIAX_P_LOG,
1477 p->line_array.result[i]);
1478 if (p->interface_state != AST_STATE_DOWN && p->owner) {
1479 p->owner->hangupcause = AST_CAUSE_NO_ANSWER;
1480 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1481 } else {
1482 ERRORA("Why NO ANSWER now?\n", CELLIAX_P_LOG);
1483 }
1484 }
1485 if ((strcmp(p->line_array.result[i], "NO CARRIER") == 0)) {
1486 if (p->phone_callflow != CALLFLOW_CALL_HANGUP_REQUESTED) {
1487 p->phone_callflow = CALLFLOW_CALL_NOCARRIER;
1488 if (option_debug > 1)
1489 DEBUGA_AT("|%s| CALLFLOW_CALL_NOCARRIER\n", CELLIAX_P_LOG,
1490 p->line_array.result[i]);
1491 p->control_to_send = 0;
1492 usleep(20000);
1493 if (p->interface_state != AST_STATE_DOWN && p->owner) {
1494 p->owner->hangupcause = AST_CAUSE_FAILURE;
1495 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1496 } else {
1497 ERRORA("Why NO CARRIER now?\n", CELLIAX_P_LOG);
1498 }
1499 }
1500 }
1501
1502 if ((strncmp(p->line_array.result[i], "+CBC:", 5) == 0)) {
1503 int power_supply, battery_strenght, err;
1504
1505 power_supply = battery_strenght = 0;
1506
1507 err =
1508 sscanf(&p->line_array.result[i][6], "%d,%d", &power_supply, &battery_strenght);
1509 if (err < 2) {
1510 DEBUGA_AT("|%s| is not formatted as: |+CBC: xx,yy| now trying |+CBC:xx,yy|\n",
1511 CELLIAX_P_LOG, p->line_array.result[i]);
1512
1513 err =
1514 sscanf(&p->line_array.result[i][5], "%d,%d", &power_supply,
1515 &battery_strenght);
1516 DEBUGA_AT("|%s| +CBC: Powered by %s, battery strenght=%d\n", CELLIAX_P_LOG,
1517 p->line_array.result[i], power_supply ? "power supply" : "battery",
1518 battery_strenght);
1519
1520 }
1521
1522 if (err < 2) {
1523 DEBUGA_AT("|%s| is not formatted as: |+CBC:xx,yy| giving up\n", CELLIAX_P_LOG,
1524 p->line_array.result[i]);
1525 }
1526
1527 else {
1528 if (option_debug > 1)
1529 DEBUGA_AT("|%s| +CBC: Powered by %s, battery strenght=%d\n", CELLIAX_P_LOG,
1530 p->line_array.result[i], power_supply ? "power supply" : "battery",
1531 battery_strenght);
1532 if (!power_supply) {
1533 if (battery_strenght < 10) {
1534 ERRORA("|%s| BATTERY ALMOST EXHAUSTED\n", CELLIAX_P_LOG,
1535 p->line_array.result[i]);
1536 } else if (battery_strenght < 20) {
1537 WARNINGA("|%s| BATTERY LOW\n", CELLIAX_P_LOG, p->line_array.result[i]);
1538
1539 }
1540
1541 }
1542 }
1543
1544 }
1545
1546 if ((strncmp(p->line_array.result[i], "+CSQ:", 5) == 0)) {
1547 int signal_quality, ber, err;
1548
1549 signal_quality = ber = 0;
1550
1551 err = sscanf(&p->line_array.result[i][6], "%d,%d", &signal_quality, &ber);
1552 if (option_debug > 1)
1553 DEBUGA_AT("|%s| +CSQ: Signal Quality: %d, Error Rate=%d\n", CELLIAX_P_LOG,
1554 p->line_array.result[i], signal_quality, ber);
1555 if (err < 2) {
1556 ERRORA("|%s| is not formatted as: |+CSQ: xx,yy|\n", CELLIAX_P_LOG,
1557 p->line_array.result[i]);
1558 } else {
1559 if (signal_quality < 11 || signal_quality == 99) {
1560 WARNINGA
1561 ("|%s| CELLPHONE GETS ALMOST NO SIGNAL, consider to move it or additional antenna\n",
1562 CELLIAX_P_LOG, p->line_array.result[i]);
1563 } else if (signal_quality < 15) {
1564 WARNINGA("|%s| CELLPHONE GETS SIGNAL LOW\n", CELLIAX_P_LOG,
1565 p->line_array.result[i]);
1566
1567 }
1568
1569 }
1570
1571 }
1572 if ((strncmp(p->line_array.result[i], "+CMGW:", 6) == 0)) {
1573 int err;
1574
1575 err = sscanf(&p->line_array.result[i][7], "%s", p->at_cmgw);
1576 DEBUGA_AT("|%s| +CMGW: %s\n", CELLIAX_P_LOG, p->line_array.result[i], p->at_cmgw);
1577 if (err < 1) {
1578 ERRORA("|%s| is not formatted as: |+CMGW: xxxx|\n", CELLIAX_P_LOG,
1579 p->line_array.result[i]);
1580 }
1581
1582 }
1583
1584 /* at_call_* are unsolicited messages sent by the modem to signal us about call processing activity and events */
1585 if ((strcmp(p->line_array.result[i], p->at_call_idle) == 0)) {
1586 p->phone_callflow = CALLFLOW_CALL_IDLE;
1587 if (option_debug > 1)
1588 DEBUGA_AT("|%s| CALLFLOW_CALL_IDLE\n", CELLIAX_P_LOG, p->line_array.result[i]);
1589 if (p->interface_state != AST_STATE_DOWN && p->owner) {
1590 DEBUGA_AT("just received a remote HANGUP\n", CELLIAX_P_LOG);
1591 p->owner->hangupcause = AST_CAUSE_NORMAL;
1592 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1593 DEBUGA_AT("just sent AST_CONTROL_HANGUP\n", CELLIAX_P_LOG);
1594 }
1595 }
1596
1597 if ((strcmp(p->line_array.result[i], p->at_call_incoming) == 0)) {
1598
1599 //char list_command[64];
1600
1601 if (option_debug > 1)
1602 DEBUGA_AT("|%s| CALLFLOW_CALL_INCOMING\n", CELLIAX_P_LOG,
1603 p->line_array.result[i]);
1604
1605 if (p->phone_callflow != CALLFLOW_CALL_INCOMING
1606 && p->phone_callflow != CALLFLOW_INCOMING_RING) {
1607 //mark the time of CALLFLOW_CALL_INCOMING
1608 gettimeofday(&(p->call_incoming_time), NULL);
1609 p->phone_callflow = CALLFLOW_CALL_INCOMING;
1610 DEBUGA_AT("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld\n",
1611 CELLIAX_P_LOG, p->call_incoming_time.tv_sec);
1612
1613 }
1614 }
1615
1616 if ((strcmp(p->line_array.result[i], p->at_call_active) == 0)) {
1617 p->phone_callflow = CALLFLOW_CALL_ACTIVE;
1618 if (option_debug > 1)
1619 DEBUGA_AT("|%s| CALLFLOW_CALL_ACTIVE\n", CELLIAX_P_LOG,
1620 p->line_array.result[i]);
1621
1622 if (p->owner && p->interface_state == CALLFLOW_CALL_DIALING) {
1623 DEBUGA_PBX("just received a remote ANSWER\n", CELLIAX_P_LOG);
1624 if (p->owner->_state != AST_STATE_UP) {
1625 celliax_queue_control(p->owner, AST_CONTROL_RINGING);
1626 DEBUGA_PBX("just sent AST_CONTROL_RINGING\n", CELLIAX_P_LOG);
1627 DEBUGA_PBX("going to send AST_CONTROL_ANSWER\n", CELLIAX_P_LOG);
1628 celliax_queue_control(p->owner, AST_CONTROL_ANSWER);
1629 DEBUGA_PBX("just sent AST_CONTROL_ANSWER\n", CELLIAX_P_LOG);
1630 }
1631 } else {
1632 }
1633 p->interface_state = AST_STATE_UP;
1634 DEBUGA_PBX("just interface_state UP\n", CELLIAX_P_LOG);
1635 }
1636
1637 if ((strcmp(p->line_array.result[i], p->at_call_calling) == 0)) {
1638 p->phone_callflow = CALLFLOW_CALL_DIALING;
1639 if (option_debug > 1)
1640 DEBUGA_AT("|%s| CALLFLOW_CALL_DIALING\n", CELLIAX_P_LOG,
1641 p->line_array.result[i]);
1642 }
1643 if ((strcmp(p->line_array.result[i], p->at_call_failed) == 0)) {
1644 p->phone_callflow = CALLFLOW_CALL_FAILED;
1645 if (option_debug > 1)
1646 DEBUGA_AT("|%s| CALLFLOW_CALL_FAILED\n", CELLIAX_P_LOG,
1647 p->line_array.result[i]);
1648 if (p->interface_state != AST_STATE_DOWN && p->owner) {
1649 p->owner->hangupcause = AST_CAUSE_FAILURE;
1650 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1651 }
1652 }
1653
1654 if ((strncmp(p->line_array.result[i], "+CSCA:", 6) == 0)) { //TODO SMS FIXME in config!
1655 if (option_debug > 1)
1656 DEBUGA_AT("|%s| +CSCA: Message Center Address!\n", CELLIAX_P_LOG,
1657 p->line_array.result[i]);
1658 }
1659
1660 if ((strncmp(p->line_array.result[i], "+CMGF:", 6) == 0)) { //TODO SMS FIXME in config!
1661 if (option_debug > 1)
1662 DEBUGA_AT("|%s| +CMGF: Message Format!\n", CELLIAX_P_LOG,
1663 p->line_array.result[i]);
1664 }
1665
1666 if ((strncmp(p->line_array.result[i], "+CMTI:", 6) == 0)) { //TODO SMS FIXME in config!
1667 int err;
1668 int pos;
1669
1670 //FIXME all the following commands in config!
1671 if (option_debug)
1672 DEBUGA_AT("|%s| +CMTI: Incoming SMS!\n", CELLIAX_P_LOG,
1673 p->line_array.result[i]);
1674
1675 err = sscanf(&p->line_array.result[i][12], "%d", &pos);
1676 if (err < 1) {
1677 ERRORA("|%s| is not formatted as: |+CMTI: \"MT\",xx|\n", CELLIAX_P_LOG,
1678 p->line_array.result[i]);
1679 } else {
1680 DEBUGA_AT("|%s| +CMTI: Incoming SMS in position: %d!\n", CELLIAX_P_LOG,
1681 p->line_array.result[i], pos);
1682 p->unread_sms_msg_id = pos;
1683 usleep(1000);
1684
1685 if (p->unread_sms_msg_id) {
1686 char at_command[256];
1687
1688 if (p->no_ucs2 == 0) {
1689 res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"UCS2\"");
1690 if (res) {
1691 ERRORA
1692 ("AT+CSCS=\"UCS2\" (set TE messages to ucs2) do not got OK from the phone, continuing\n",
1693 CELLIAX_P_LOG);
1694 //memset(p->sms_message, 0, sizeof(p->sms_message));
1695 }
1696 }
1697
1698 memset(at_command, 0, sizeof(at_command));
1699 sprintf(at_command, "AT+CMGR=%d", p->unread_sms_msg_id);
1700 memset(p->sms_message, 0, sizeof(p->sms_message));
1701
1702 p->reading_sms_msg = 1;
1703 res = celliax_serial_write_AT_ack(p, at_command);
1704 p->reading_sms_msg = 0;
1705 if (res) {
1706 ERRORA
1707 ("AT+CMGR (read SMS) do not got OK from the phone, message sent was:|||%s|||\n",
1708 CELLIAX_P_LOG, at_command);
1709 }
1710 res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"GSM\"");
1711 if (res) {
1712 ERRORA
1713 ("AT+CSCS=\"GSM\" (set TE messages to GSM) do not got OK from the phone\n",
1714 CELLIAX_P_LOG);
1715 }
1716 memset(at_command, 0, sizeof(at_command));
1717 sprintf(at_command, "AT+CMGD=%d", p->unread_sms_msg_id); /* delete the message */
1718 p->unread_sms_msg_id = 0;
1719 res = celliax_serial_write_AT_ack(p, at_command);
1720 if (res) {
1721 ERRORA
1722 ("AT+CMGD (Delete SMS) do not got OK from the phone, message sent was:|||%s|||\n",
1723 CELLIAX_P_LOG, at_command);
1724 }
1725
1726 if (strlen(p->sms_message)) {
1727 manager_event(EVENT_FLAG_SYSTEM, "CELLIAXincomingsms",
1728 "Interface: %s\r\nSMS_Message: %s\r\n", p->name,
1729 p->sms_message);
1730 if (strlen(p->sms_receiving_program)) {
1731 int fd1[2];
1732 pid_t pid1;
1733 char *arg1[] = { p->sms_receiving_program, (char *) NULL };
1734 int i;
1735
1736 NOTICA("incoming SMS message:>>>%s<<<\n", CELLIAX_P_LOG, p->sms_message);
1737 pipe(fd1);
1738 pid1 = switch_fork();
1739
1740 if (pid1 == 0) { //child
1741 int err;
1742
1743 dup2(fd1[0], 0); // Connect stdin to pipe output
1744 close(fd1[1]); // close input pipe side
1745 close(p->controldevfd);
1746 setsid(); //session id
1747 err = execvp(arg1[0], arg1); //exec our program, with stdin connected to pipe output
1748 if (err) {
1749 ERRORA
1750 ("'sms_receiving_program' is set in config file to '%s', and it gave us back this error: %d, (%s). SMS received was:---%s---\n",
1751 CELLIAX_P_LOG, p->sms_receiving_program, err, strerror(errno),
1752 p->sms_message);
1753 }
1754 close(fd1[0]); // close output pipe side
1755 }
1756 //starting here continue the parent
1757 close(fd1[0]); // close output pipe side
1758 // write the msg on the pipe input
1759 for (i = 0; i < strlen(p->sms_message); i++) {
1760 write(fd1[1], &p->sms_message[i], 1);
1761 }
1762 close(fd1[1]); // close pipe input, let our program know we've finished
1763 } else {
1764 ERRORA
1765 ("got SMS incoming message, but 'sms_receiving_program' is not set in config file. SMS received was:---%s---\n",
1766 CELLIAX_P_LOG, p->sms_message);
1767 }
1768 }
1769 #if 1 //is this one needed? maybe it can interrupt an incoming call that is just to announce itself
1770 if (p->phone_callflow == CALLFLOW_CALL_IDLE
1771 && p->interface_state == AST_STATE_DOWN && p->owner == NULL) {
1772 /* we're not in a call, neither calling */
1773 res = celliax_serial_write_AT_ack(p, "AT+CKPD=\"EEE\"");
1774 if (res) {
1775 ERRORA
1776 ("AT+CKPD=\"EEE\" (cellphone screen back to user) do not got OK from the phone\n",
1777 CELLIAX_P_LOG);
1778 }
1779 }
1780 #endif
1781 } //unread_msg_id
1782
1783 } //CMTI well formatted
1784
1785 } //CMTI
1786
1787 if ((strncmp(p->line_array.result[i], "+MMGL:", 6) == 0)) { //TODO MOTOROLA SMS FIXME in config!
1788 int err = 0;
1789 //int unread_msg_id=0;
1790
1791 if (option_debug)
1792 DEBUGA_AT("|%s| +MMGL: Listing Motorola SMSs!\n", CELLIAX_P_LOG,
1793 p->line_array.result[i]);
1794
1795 err = sscanf(&p->line_array.result[i][7], "%d", &p->unread_sms_msg_id);
1796 if (err < 1) {
1797 ERRORA("|%s| is not formatted as: |+MMGL: xx|\n", CELLIAX_P_LOG,
1798 p->line_array.result[i]);
1799 }
1800 }
1801 if ((strncmp(p->line_array.result[i], "+CMGL:", 6) == 0)) { //TODO SMS FIXME in config!
1802 if (option_debug)
1803 DEBUGA_AT("|%s| +CMGL: Listing SMSs!\n", CELLIAX_P_LOG,
1804 p->line_array.result[i]);
1805 }
1806 if ((strncmp(p->line_array.result[i], "+MMGR:", 6) == 0)) { //TODO MOTOROLA SMS FIXME in config!
1807 if (option_debug)
1808 DEBUGA_AT("|%s| +MMGR: Reading Motorola SMS!\n", CELLIAX_P_LOG,
1809 p->line_array.result[i]);
1810 if (p->reading_sms_msg)
1811 p->reading_sms_msg++;
1812 }
1813 if ((strncmp(p->line_array.result[i], "+CMGR: \"STO U", 13) == 0)) { //TODO SMS FIXME in config!
1814 if (option_debug)
1815 DEBUGA_AT("|%s| +CMGR: Reading stored UNSENT SMS!\n", CELLIAX_P_LOG,
1816 p->line_array.result[i]);
1817 } else if ((strncmp(p->line_array.result[i], "+CMGR: \"STO S", 13) == 0)) { //TODO SMS FIXME in config!
1818 if (option_debug)
1819 DEBUGA_AT("|%s| +CMGR: Reading stored SENT SMS!\n", CELLIAX_P_LOG,
1820 p->line_array.result[i]);
1821 } else if ((strncmp(p->line_array.result[i], "+CMGR: \"REC R", 13) == 0)) { //TODO SMS FIXME in config!
1822 if (option_debug)
1823 DEBUGA_AT("|%s| +CMGR: Reading received READ SMS!\n", CELLIAX_P_LOG,
1824 p->line_array.result[i]);
1825 } else if ((strncmp(p->line_array.result[i], "+CMGR: \"REC U", 13) == 0)) { //TODO SMS FIXME in config!
1826 if (option_debug)
1827 DEBUGA_AT("|%s| +CMGR: Reading received UNREAD SMS!\n", CELLIAX_P_LOG,
1828 p->line_array.result[i]);
1829 if (p->reading_sms_msg)
1830 p->reading_sms_msg++;
1831 }
1832
1833 if ((strcmp(p->line_array.result[i], "+MCST: 17") == 0)) { /* motorola call processing unsolicited messages */
1834 p->phone_callflow = CALLFLOW_CALL_INFLUX;
1835 if (option_debug > 1)
1836 DEBUGA_AT("|%s| CALLFLOW_CALL_INFLUX\n", CELLIAX_P_LOG,
1837 p->line_array.result[i]);
1838 }
1839
1840 if ((strcmp(p->line_array.result[i], "+MCST: 68") == 0)) { /* motorola call processing unsolicited messages */
1841 p->phone_callflow = CALLFLOW_CALL_NOSERVICE;
1842 if (option_debug > 1)
1843 DEBUGA_AT("|%s| CALLFLOW_CALL_NOSERVICE\n", CELLIAX_P_LOG,
1844 p->line_array.result[i]);
1845 if (p->interface_state != AST_STATE_DOWN && p->owner) {
1846 p->owner->hangupcause = AST_CAUSE_FAILURE;
1847 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1848 }
1849 }
1850 if ((strcmp(p->line_array.result[i], "+MCST: 70") == 0)) { /* motorola call processing unsolicited messages */
1851 p->phone_callflow = CALLFLOW_CALL_OUTGOINGRESTRICTED;
1852 if (option_debug > 1)
1853 DEBUGA_AT("|%s| CALLFLOW_CALL_OUTGOINGRESTRICTED\n", CELLIAX_P_LOG,
1854 p->line_array.result[i]);
1855 if (p->interface_state != AST_STATE_DOWN && p->owner) {
1856 p->owner->hangupcause = AST_CAUSE_FAILURE;
1857 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1858 }
1859 }
1860 if ((strcmp(p->line_array.result[i], "+MCST: 72") == 0)) { /* motorola call processing unsolicited messages */
1861 p->phone_callflow = CALLFLOW_CALL_SECURITYFAIL;
1862 if (option_debug > 1)
1863 DEBUGA_AT("|%s| CALLFLOW_CALL_SECURITYFAIL\n", CELLIAX_P_LOG,
1864 p->line_array.result[i]);
1865 if (p->interface_state != AST_STATE_DOWN && p->owner) {
1866 p->owner->hangupcause = AST_CAUSE_FAILURE;
1867 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1868 }
1869 }
1870
1871 if ((strncmp(p->line_array.result[i], "+CPBR", 5) == 0)) { /* phonebook stuff begins */
1872
1873 if (p->phonebook_querying) { /* probably phonebook struct begins */
1874 int err, first_entry, last_entry, number_lenght, text_lenght;
1875
1876 if (option_debug)
1877 DEBUGA_AT("phonebook struct: |%s|\n", CELLIAX_P_LOG, p->line_array.result[i]);
1878
1879 err =
1880 sscanf(&p->line_array.result[i][8], "%d-%d),%d,%d", &first_entry, &last_entry,
1881 &number_lenght, &text_lenght);
1882 if (err < 4) {
1883
1884 err =
1885 sscanf(&p->line_array.result[i][7], "%d-%d,%d,%d", &first_entry,
1886 &last_entry, &number_lenght, &text_lenght);
1887 }
1888
1889 if (err < 4) {
1890 ERRORA
1891 ("phonebook struct: |%s| is nor formatted as: |+CPBR: (1-750),40,14| neither as: |+CPBR: 1-750,40,14|\n",
1892 CELLIAX_P_LOG, p->line_array.result[i]);
1893 } else {
1894
1895 if (option_debug)
1896 DEBUGA_AT
1897 ("First entry: %d, last entry: %d, phone number max lenght: %d, text max lenght: %d\n",
1898 CELLIAX_P_LOG, first_entry, last_entry, number_lenght, text_lenght);
1899 p->phonebook_first_entry = first_entry;
1900 p->phonebook_last_entry = last_entry;
1901 p->phonebook_number_lenght = number_lenght;
1902 p->phonebook_text_lenght = text_lenght;
1903 }
1904
1905 } else { /* probably phonebook entry begins */
1906
1907 if (p->phonebook_listing) {
1908 int err, entry_id, entry_type;
1909
1910 char entry_number[256];
1911 char entry_text[256];
1912
1913 if (option_debug)
1914 DEBUGA_AT("phonebook entry: |%s|\n", CELLIAX_P_LOG,
1915 p->line_array.result[i]);
1916
1917 err =
1918 sscanf(&p->line_array.result[i][7], "%d,\"%255[0-9+]\",%d,\"%255[^\"]\"",
1919 &entry_id, entry_number, &entry_type, entry_text);
1920 if (err < 4) {
1921 ERRORA
1922 ("err=%d, phonebook entry: |%s| is not formatted as: |+CPBR: 504,\"+39025458068\",145,\"ciao a tutti\"|\n",
1923 CELLIAX_P_LOG, err, p->line_array.result[i]);
1924 } else {
1925 //TODO: sanitize entry_text
1926 if (option_debug)
1927 DEBUGA_AT("Number: %s, Text: %s, Type: %d\n", CELLIAX_P_LOG, entry_number,
1928 entry_text, entry_type);
1929 /* write entry in phonebook file */
1930 if (p->phonebook_writing_fp) {
1931 celliax_dir_entry_extension++;
1932
1933 fprintf(p->phonebook_writing_fp,
1934 "%s => ,%sSKO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcell=%s|phonebook_entry_owner=%s\n",
1935 entry_number, entry_text, "no",
1936 p->celliax_dir_entry_extension_prefix, "2",
1937 celliax_dir_entry_extension, "yes", "not_specified");
1938 fprintf(p->phonebook_writing_fp,
1939 "%s => ,%sDO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcell=%s|phonebook_entry_owner=%s\n",
1940 entry_number, entry_text, "no",
1941 p->celliax_dir_entry_extension_prefix, "3",
1942 celliax_dir_entry_extension, "yes", "not_specified");
1943 }
1944 }
1945
1946 }
1947
1948 if (p->phonebook_listing_received_calls) {
1949 int err, entry_id, entry_type;
1950
1951 char entry_number[256] = "";
1952 char entry_text[256] = "";
1953
1954 if (option_debug)
1955 DEBUGA_AT("phonebook entry: |%s|\n", CELLIAX_P_LOG,
1956 p->line_array.result[i]);
1957
1958 err =
1959 sscanf(&p->line_array.result[i][7], "%d,\"%255[0-9+]\",%d,\"%255[^\"]\"",
1960 &entry_id, entry_number, &entry_type, entry_text);
1961 if (err < 1) { //we match only on the progressive id, maybe the remote party has not sent its number, and/or there is no corresponding text entry in the phone directory
1962 ERRORA
1963 ("err=%d, phonebook entry: |%s| is not formatted as: |+CPBR: 504,\"+39025458068\",145,\"ciao a tutti\"|\n",
1964 CELLIAX_P_LOG, err, p->line_array.result[i]);
1965 } else {
1966 //TODO: sanitize entry_text
1967
1968 if (option_debug)
1969 DEBUGA_AT("Number: %s, Text: %s, Type: %d\n", CELLIAX_P_LOG, entry_number,
1970 entry_text, entry_type);
1971 memset(p->callid_name, 0, sizeof(p->callid_name));
1972 memset(p->callid_number, 0, sizeof(p->callid_number));
1973 strncpy(p->callid_name, entry_text, sizeof(p->callid_name));
1974 strncpy(p->callid_number, entry_number, sizeof(p->callid_number));
1975 if (option_debug)
1976 DEBUGA_AT("incoming callid: Text: %s, Number: %s\n", CELLIAX_P_LOG,
1977 p->callid_name, p->callid_number);
1978
1979 DEBUGA_AT("|%s| CPBR INCOMING CALLID: name is %s, number is %s\n",
1980 CELLIAX_P_LOG, p->line_array.result[i],
1981 p->callid_name[0] != 1 ? p->callid_name : "not available",
1982 p->callid_number[0] ? p->callid_number : "not available");
1983
1984 /* mark the time of RING */
1985 gettimeofday(&(p->ringtime), NULL);
1986 p->interface_state = AST_STATE_RING;
1987 p->phone_callflow = CALLFLOW_INCOMING_RING;
1988
1989 }
1990
1991 }
1992
1993 else {
1994 DEBUGA_AT("phonebook entry: |%s|\n", CELLIAX_P_LOG, p->line_array.result[i]);
1995
1996 }
1997 }
1998
1999 }
2000
2001 if ((strncmp(p->line_array.result[i], "*ECAV", 5) == 0) || (strncmp(p->line_array.result[i], "*ECAM", 5) == 0)) { /* sony-ericsson call processing unsolicited messages */
2002 int res, ccid, ccstatus, calltype, processid, exitcause, number, type;
2003 res = ccid = ccstatus = calltype = processid = exitcause = number = type = 0;
2004 res =
2005 sscanf(&p->line_array.result[i][6], "%d,%d,%d,%d,%d,%d,%d", &ccid, &ccstatus,
2006 &calltype, &processid, &exitcause, &number, &type);
2007 /* only changes the phone_callflow if enought parameters were parsed */
2008 if (res >= 3) {
2009 switch (ccstatus) {
2010 case 0:
2011 if (p->owner) {
2012 ast_setstate(p->owner, AST_STATE_DOWN);
2013 p->owner->hangupcause = AST_CAUSE_NORMAL;
2014 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
2015 }
2016 p->phone_callflow = CALLFLOW_CALL_IDLE;
2017 p->interface_state = AST_STATE_DOWN;
2018 if (option_debug > 1)
2019 DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: IDLE\n", CELLIAX_P_LOG,
2020 p->line_array.result[i]);
2021 break;
2022 case 1:
2023 if (option_debug > 1)
2024 DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: CALLING\n", CELLIAX_P_LOG,
2025 p->line_array.result[i]);
2026 break;
2027 case 2:
2028 if (p->owner) {
2029 ast_setstate(p->owner, AST_STATE_DIALING);
2030 }
2031 p->interface_state = CALLFLOW_CALL_DIALING;
2032 if (option_debug > 1)
2033 DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: CONNECTING\n", CELLIAX_P_LOG,
2034 p->line_array.result[i]);
2035 break;
2036 case 3:
2037 if (p->owner) {
2038 ast_setstate(p->owner, AST_STATE_UP);
2039 celliax_queue_control(p->owner, AST_CONTROL_ANSWER);
2040 }
2041 p->phone_callflow = CALLFLOW_CALL_ACTIVE;
2042 p->interface_state = AST_STATE_UP;
2043 if (option_debug > 1)
2044 DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: ACTIVE\n", CELLIAX_P_LOG,
2045 p->line_array.result[i]);
2046 break;
2047 case 4:
2048 if (option_debug > 1)
2049 DEBUGA_AT
2050 ("|%s| Sony-Ericsson *ECAM/*ECAV: don't know how to handle HOLD event\n",
2051 CELLIAX_P_LOG, p->line_array.result[i]);
2052 break;
2053 case 5:
2054 if (option_debug > 1)
2055 DEBUGA_AT
2056 ("|%s| Sony-Ericsson *ECAM/*ECAV: don't know how to handle WAITING event\n",
2057 CELLIAX_P_LOG, p->line_array.result[i]);
2058 break;
2059 case 6:
2060 if (option_debug > 1)
2061 DEBUGA_AT
2062 ("|%s| Sony-Ericsson *ECAM/*ECAV: don't know how to handle ALERTING event\n",
2063 CELLIAX_P_LOG, p->line_array.result[i]);
2064 break;
2065 case 7:
2066 if (p->owner) {
2067 ast_setstate(p->owner, AST_STATE_BUSY);
2068 celliax_queue_control(p->owner, AST_CONTROL_BUSY);
2069 }
2070 p->phone_callflow = CALLFLOW_CALL_LINEBUSY;
2071 p->interface_state = AST_STATE_BUSY;
2072 if (option_debug > 1)
2073 DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: BUSY\n", CELLIAX_P_LOG,
2074 p->line_array.result[i]);
2075 break;
2076 }
2077 } else {
2078 if (option_debug > 1)
2079 DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: could not parse parameters\n",
2080 CELLIAX_P_LOG, p->line_array.result[i]);
2081 }
2082
2083 }
2084
2085 /* at_indicator_* are unsolicited messages sent by the phone to signal us that some of its visual indicators on its screen has changed, based on CIND CMER ETSI docs */
2086 if ((strcmp(p->line_array.result[i], p->at_indicator_noservice_string) == 0)) {
2087 if (option_debug > 1)
2088 ERRORA("|%s| at_indicator_noservice_string\n", CELLIAX_P_LOG,
2089 p->line_array.result[i]);
2090 }
2091
2092 if ((strcmp(p->line_array.result[i], p->at_indicator_nosignal_string) == 0)) {
2093 if (option_debug > 1)
2094 ERRORA("|%s| at_indicator_nosignal_string\n", CELLIAX_P_LOG,
2095 p->line_array.result[i]);
2096 }
2097
2098 if ((strcmp(p->line_array.result[i], p->at_indicator_lowsignal_string) == 0)) {
2099 if (option_debug > 1)
2100 WARNINGA("|%s| at_indicator_lowsignal_string\n", CELLIAX_P_LOG,
2101 p->line_array.result[i]);
2102 }
2103
2104 if ((strcmp(p->line_array.result[i], p->at_indicator_lowbattchg_string) == 0)) {
2105 if (option_debug > 1)
2106 WARNINGA("|%s| at_indicator_lowbattchg_string\n", CELLIAX_P_LOG,
2107 p->line_array.result[i]);
2108 }
2109
2110 if ((strcmp(p->line_array.result[i], p->at_indicator_nobattchg_string) == 0)) {
2111 if (option_debug > 1)
2112 ERRORA("|%s| at_indicator_nobattchg_string\n", CELLIAX_P_LOG,
2113 p->line_array.result[i]);
2114 }
2115
2116 if ((strcmp(p->line_array.result[i], p->at_indicator_callactive_string) == 0)) {
2117 if (option_debug > 1)
2118 DEBUGA_AT("|%s| at_indicator_callactive_string\n", CELLIAX_P_LOG,
2119 p->line_array.result[i]);
2120 }
2121
2122 if ((strcmp(p->line_array.result[i], p->at_indicator_nocallactive_string) == 0)) {
2123 if (option_debug > 1)
2124 DEBUGA_AT("|%s| at_indicator_nocallactive_string\n", CELLIAX_P_LOG,
2125 p->line_array.result[i]);
2126 }
2127
2128 if ((strcmp(p->line_array.result[i], p->at_indicator_nocallsetup_string) == 0)) {
2129 if (option_debug > 1)
2130 DEBUGA_AT("|%s| at_indicator_nocallsetup_string\n", CELLIAX_P_LOG,
2131 p->line_array.result[i]);
2132 }
2133
2134 if ((strcmp(p->line_array.result[i], p->at_indicator_callsetupincoming_string) ==
2135 0)) {
2136 if (option_debug > 1)
2137 DEBUGA_AT("|%s| at_indicator_callsetupincoming_string\n", CELLIAX_P_LOG,
2138 p->line_array.result[i]);
2139 }
2140
2141 if ((strcmp(p->line_array.result[i], p->at_indicator_callsetupoutgoing_string) ==
2142 0)) {
2143 if (option_debug > 1)
2144 DEBUGA_AT("|%s| at_indicator_callsetupoutgoing_string\n", CELLIAX_P_LOG,
2145 p->line_array.result[i]);
2146 }
2147
2148 if ((strcmp(p->line_array.result[i], p->at_indicator_callsetupremoteringing_string)
2149 == 0)) {
2150 if (option_debug > 1)
2151 DEBUGA_AT("|%s| at_indicator_callsetupremoteringing_string\n", CELLIAX_P_LOG,
2152 p->line_array.result[i]);
2153 }
2154
2155 }
2156
2157 /* let's look for OK, ERROR and EXPECTED_STRING in the complete lines read so far, without re-looking at the lines that has been yet looked at */
2158 for (i = la_read; i < la_counter; i++) {
2159 if (expected_string) {
2160 if ((strncmp(p->line_array.result[i], expected_string, strlen(expected_string))
2161 == 0)) {
2162 if (option_debug > 1)
2163 DEBUGA_AT("|%s| got what EXPECTED\n", CELLIAX_P_LOG, p->line_array.result[i]);
2164 at_ack = AT_OK;
2165 }
2166 } else {
2167 //if ((strcmp(p->line_array.result[i], "OK") == 0)) {
2168 if ((strcmp(p->line_array.result[i], "OK") == 0) || (strcmp(p->line_array.result[i], "NO CARRIER") == 0) ) {
2169 if (option_debug > 1)
2170 DEBUGA_AT("got OK\n", CELLIAX_P_LOG);
2171 at_ack = AT_OK;
2172 }
2173 }
2174 if ((strcmp(p->line_array.result[i], "ERROR") == 0)) {
2175 if (option_debug > 1)
2176 DEBUGA_AT("got ERROR\n", CELLIAX_P_LOG);
2177 at_ack = AT_ERROR;
2178 }
2179
2180 /* if we are reading an sms message from memory, put the line into the sms buffer if the line is not "OK" or "ERROR" */
2181 if (p->reading_sms_msg > 1 && at_ack == -1) {
2182 int c;
2183 char sms_body[16000];
2184 int err;
2185
2186 if (strncmp(p->line_array.result[i], "+CMGR", 5) == 0) { /* we are reading the "header" of an SMS */
2187 char content[512];
2188 char content2[512];
2189
2190 memset(content, '\0', sizeof(content));
2191
2192 int inside_comma = 0;
2193 int inside_quote = 0;
2194 int d = 0;
2195
2196 for (c = 0; c < strlen(p->line_array.result[i]); c++) {
2197 if (p->line_array.result[i][c] == ','
2198 && p->line_array.result[i][c - 1] != '\\' && inside_quote == 0) {
2199 if (inside_comma) {
2200 inside_comma = 0;
2201 //NOTICA("inside_comma=%d, inside_quote=%d, we're at=%s\n", CELLIAX_P_LOG, inside_comma, inside_quote, &p->line_array.result[i][c]);
2202 } else {
2203 inside_comma = 1;
2204 //NOTICA("inside_comma=%d, inside_quote=%d, we're at=%s\n", CELLIAX_P_LOG, inside_comma, inside_quote, &p->line_array.result[i][c]);
2205 }
2206 }
2207 if (p->line_array.result[i][c] == '"'
2208 && p->line_array.result[i][c - 1] != '\\') {
2209 if (inside_quote) {
2210 inside_quote = 0;
2211 //ERRORA("END_CONTENT inside_comma=%d, inside_quote=%d, we're at=%s\n", CELLIAX_P_LOG, inside_comma, inside_quote, &p->line_array.result[i][c]);
2212 DEBUGA_AT("content=%s\n", CELLIAX_P_LOG, content);
2213
2214 strncat(p->sms_message, "---",
2215 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2216 strncat(p->sms_message, content,
2217 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2218 strncat(p->sms_message, "|||",
2219 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2220
2221 memset(content2, '\0', sizeof(content2));
2222 err = ucs2_to_utf8(p, content, content2, sizeof(content2));
2223
2224 strncat(p->sms_message, "---",
2225 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2226 if (!err)
2227 strncat(p->sms_message, content2,
2228 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2229 strncat(p->sms_message, "|||",
2230 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2231 memset(content, '\0', sizeof(content));
2232 d = 0;
2233 } else {
2234 inside_quote = 1;
2235 //WARNINGA("START_CONTENT inside_comma=%d, inside_quote=%d, we're at=%s\n", CELLIAX_P_LOG, inside_comma, inside_quote, &p->line_array.result[i][c]);
2236 }
2237 }
2238 if (inside_quote && p->line_array.result[i][c] != '"') {
2239
2240 content[d] = p->line_array.result[i][c];
2241 d++;
2242
2243 }
2244
2245 }
2246 } //it was the +CMGR answer from the cellphone
2247 else {
2248 strncat(p->sms_message, "---",
2249 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2250 strncat(p->sms_message, p->line_array.result[i],
2251 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2252 strncat(p->sms_message, "|||",
2253 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2254
2255 memset(sms_body, '\0', sizeof(sms_body));
2256 err = ucs2_to_utf8(p, p->line_array.result[i], sms_body, sizeof(sms_body));
2257
2258 strncat(p->sms_message, "---",
2259 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2260 if (!err)
2261 strncat(p->sms_message, sms_body,
2262 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2263 strncat(p->sms_message, "|||",
2264 ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2265
2266 DEBUGA_AT("sms_message=%s\n", CELLIAX_P_LOG, p->sms_message);
2267
2268 } //it was the UCS2 from cellphone
2269
2270 } //we were reading the SMS
2271
2272 }
2273
2274 la_read = la_counter;
2275
2276 if (look_for_ack && at_ack > -1)
2277 break;
2278
2279 if (la_counter > AT_MESG_MAX_LINES) {
2280 ERRORA("Too many lines in result (>%d). Stopping reader.\n", CELLIAX_P_LOG,
2281 AT_MESG_MAX_LINES);
2282 at_ack = AT_ERROR;
2283 break;
2284 }
2285 }
2286
2287 UNLOCKA(&p->controldev_lock);
2288 POPPA_UNLOCKA(&p->controldev_lock);
2289 if (select_err == -1) {
2290 ERRORA("select returned -1 on %s, setting controldev_dead, error was: %s\n",
2291 CELLIAX_P_LOG, p->controldevice_name, strerror(errno));
2292 p->controldev_dead = 1;
2293 close(p->controldevfd);
2294 if (p->owner)
2295 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
2296 return -1;
2297 }
2298
2299 if (p->phone_callflow == CALLFLOW_CALL_INCOMING && p->call_incoming_time.tv_sec) { //after three sec of CALLFLOW_CALL_INCOMING, we assume the phone is incapable of notifying RING (eg: motorola c350), so we try to answer
2300 char list_command[64];
2301 struct timeval call_incoming_timeout;
2302 gettimeofday(&call_incoming_timeout, NULL);
2303 call_incoming_timeout.tv_sec -= 3;
2304 DEBUGA_AT
2305 ("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n",
2306 CELLIAX_P_LOG, p->call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
2307 if (call_incoming_timeout.tv_sec > p->call_incoming_time.tv_sec) {
2308
2309 p->call_incoming_time.tv_sec = 0;
2310 p->call_incoming_time.tv_usec = 0;
2311 DEBUGA_AT
2312 ("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n",
2313 CELLIAX_P_LOG, p->call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
2314 res = celliax_serial_write_AT_ack(p, "AT+CPBS=RC");
2315 if (res) {
2316 ERRORA
2317 ("AT+CPBS=RC (select memory of received calls) was not answered by the phone\n",
2318 CELLIAX_P_LOG);
2319 }
2320 p->phonebook_querying = 1;
2321 res = celliax_serial_write_AT_ack(p, "AT+CPBR=?");
2322 if (res) {
2323 ERRORA
2324 ("AT+CPBS=RC (select memory of received calls) was not answered by the phone\n",
2325 CELLIAX_P_LOG);
2326 }
2327 p->phonebook_querying = 0;
2328 sprintf(list_command, "AT+CPBR=%d,%d", p->phonebook_first_entry,
2329 p->phonebook_last_entry);
2330 p->phonebook_listing_received_calls = 1;
2331 res = celliax_serial_write_AT_expect_longtime(p, list_command, "OK");
2332 if (res) {
2333 WARNINGA("AT+CPBR=%d,%d failed, continue\n", CELLIAX_P_LOG,
2334 p->phonebook_first_entry, p->phonebook_last_entry);
2335 }
2336 p->phonebook_listing_received_calls = 0;
2337 }
2338 }
2339
2340 if (p->phone_callflow == CALLFLOW_INCOMING_RING) {
2341 struct timeval call_incoming_timeout;
2342 gettimeofday(&call_incoming_timeout, NULL);
2343 call_incoming_timeout.tv_sec -= 10;
2344 DEBUGA_AT
2345 ("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n",
2346 CELLIAX_P_LOG, p->call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
2347 if (call_incoming_timeout.tv_sec > p->ringtime.tv_sec) {
2348 ERRORA("Ringing stopped and I have not answered. Why?\n", CELLIAX_P_LOG);
2349 DEBUGA_AT
2350 ("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n",
2351 CELLIAX_P_LOG, p->call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
2352 if (p->owner) {
2353 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
2354 p->owner->hangupcause = AST_CAUSE_FAILURE;
2355 }
2356 }
2357 }
2358 p->line_array.elemcount = la_counter;
2359 //NOTICA (" OUTSIDE this celliax_serial_device %s \n", CELLIAX_P_LOG, p->controldevice_name);
2360 if (look_for_ack)
2361 return at_ack;
2362 else
2363 return 0;
2364 }
2365
celliax_serial_write_AT(struct celliax_pvt * p,const char * data)2366 int celliax_serial_write_AT(struct celliax_pvt *p, const char *data)
2367 {
2368 int howmany;
2369 int i;
2370 int res;
2371 int count;
2372
2373 howmany = strlen(data);
2374
2375 for (i = 0; i < howmany; i++) {
2376 res = write(p->controldevfd, &data[i], 1);
2377
2378 if (res != 1) {
2379 DEBUGA_AT("Error sending (%.1s): %d (%s)\n", CELLIAX_P_LOG, &data[i], res,
2380 strerror(errno));
2381 usleep(100000);
2382 for (count = 0; count < 10; count++) {
2383 res = write(p->controldevfd, &data[i], 1);
2384 if (res == 1) {
2385 DEBUGA_AT("Successfully RE-sent (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i],
2386 count, res, strerror(errno));
2387 break;
2388 } else
2389 DEBUGA_AT("Error RE-sending (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i],
2390 count, res, strerror(errno));
2391 usleep(100000);
2392
2393 }
2394 if (res != 1) {
2395 ERRORA("Error RE-sending (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i], count,
2396 res, strerror(errno));
2397 return -1;
2398 }
2399 }
2400 if (option_debug > 1)
2401 DEBUGA_AT("sent data... (%.1s)\n", CELLIAX_P_LOG, &data[i]);
2402 usleep(1000); /* release the cpu */
2403 }
2404
2405 res = write(p->controldevfd, "\r", 1);
2406
2407 if (res != 1) {
2408 DEBUGA_AT("Error sending (carriage return): %d (%s)\n", CELLIAX_P_LOG, res,
2409 strerror(errno));
2410 usleep(100000);
2411 for (count = 0; count < 10; count++) {
2412 res = write(p->controldevfd, "\r", 1);
2413
2414 if (res == 1) {
2415 DEBUGA_AT("Successfully RE-sent carriage return: %d %d (%s)\n", CELLIAX_P_LOG,
2416 count, res, strerror(errno));
2417 break;
2418 } else
2419 DEBUGA_AT("Error RE-sending (carriage return): %d %d (%s)\n", CELLIAX_P_LOG,
2420 count, res, strerror(errno));
2421 usleep(100000);
2422
2423 }
2424 if (res != 1) {
2425 ERRORA("Error RE-sending (carriage return): %d %d (%s)\n", CELLIAX_P_LOG, count,
2426 res, strerror(errno));
2427 return -1;
2428 }
2429 }
2430 if (option_debug > 1)
2431 DEBUGA_AT("sent (carriage return)\n", CELLIAX_P_LOG);
2432 usleep(1000); /* release the cpu */
2433
2434 return howmany;
2435 }
2436
celliax_serial_write_AT_nocr(struct celliax_pvt * p,const char * data)2437 int celliax_serial_write_AT_nocr(struct celliax_pvt *p, const char *data)
2438 {
2439 int howmany;
2440 int i;
2441 int res;
2442 int count;
2443
2444 howmany = strlen(data);
2445
2446 for (i = 0; i < howmany; i++) {
2447 res = write(p->controldevfd, &data[i], 1);
2448
2449 if (res != 1) {
2450 DEBUGA_AT("Error sending (%.1s): %d (%s)\n", CELLIAX_P_LOG, &data[i], res,
2451 strerror(errno));
2452 usleep(100000);
2453 for (count = 0; count < 10; count++) {
2454 res = write(p->controldevfd, &data[i], 1);
2455 if (res == 1)
2456 break;
2457 else
2458 DEBUGA_AT("Error RE-sending (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i],
2459 count, res, strerror(errno));
2460 usleep(100000);
2461
2462 }
2463 if (res != 1) {
2464 ERRORA("Error RE-sending (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i], count,
2465 res, strerror(errno));
2466 return -1;
2467 }
2468 }
2469 if (option_debug > 1)
2470 DEBUGA_AT("sent data... (%.1s)\n", CELLIAX_P_LOG, &data[i]);
2471 usleep(1000); /* release the cpu */
2472 }
2473
2474 usleep(1000); /* release the cpu */
2475
2476 return howmany;
2477 }
2478
celliax_serial_write_AT_noack(struct celliax_pvt * p,const char * data)2479 int celliax_serial_write_AT_noack(struct celliax_pvt *p, const char *data)
2480 {
2481
2482 if (option_debug > 1)
2483 DEBUGA_AT("celliax_serial_write_AT_noack: %s\n", CELLIAX_P_LOG, data);
2484
2485 PUSHA_UNLOCKA(&p->controldev_lock);
2486 LOKKA(&p->controldev_lock);
2487 if (celliax_serial_write_AT(p, data) != strlen(data)) {
2488
2489 ERRORA("Error sending data... (%s)\n", CELLIAX_P_LOG, strerror(errno));
2490 UNLOCKA(&p->controldev_lock);
2491 return -1;
2492 }
2493 UNLOCKA(&p->controldev_lock);
2494 POPPA_UNLOCKA(&p->controldev_lock);
2495
2496 return 0;
2497 }
2498
celliax_serial_write_AT_ack(struct celliax_pvt * p,const char * data)2499 int celliax_serial_write_AT_ack(struct celliax_pvt *p, const char *data)
2500 {
2501 int at_result = AT_ERROR;
2502
2503 PUSHA_UNLOCKA(&p->controldev_lock);
2504 LOKKA(&p->controldev_lock);
2505 if (option_debug > 1)
2506 DEBUGA_AT("sending: %s\n", CELLIAX_P_LOG, data);
2507 if (celliax_serial_write_AT(p, data) != strlen(data)) {
2508 ERRORA("Error sending data... (%s) \n", CELLIAX_P_LOG, strerror(errno));
2509 UNLOCKA(&p->controldev_lock);
2510 return -1;
2511 }
2512
2513 at_result = celliax_serial_read_AT(p, 1, 500000, 2, NULL, 1); // 2.5 sec timeout
2514 UNLOCKA(&p->controldev_lock);
2515 POPPA_UNLOCKA(&p->controldev_lock);
2516
2517 return at_result;
2518
2519 }
2520
celliax_serial_write_AT_ack_nocr_longtime(struct celliax_pvt * p,const char * data)2521 int celliax_serial_write_AT_ack_nocr_longtime(struct celliax_pvt *p, const char *data)
2522 {
2523 int at_result = AT_ERROR;
2524
2525 PUSHA_UNLOCKA(&p->controldev_lock);
2526 LOKKA(&p->controldev_lock);
2527 if (option_debug > 1)
2528 DEBUGA_AT("sending: %s\n", CELLIAX_P_LOG, data);
2529 if (celliax_serial_write_AT_nocr(p, data) != strlen(data)) {
2530 ERRORA("Error sending data... (%s) \n", CELLIAX_P_LOG, strerror(errno));
2531 UNLOCKA(&p->controldev_lock);
2532 return -1;
2533 }
2534
2535 at_result = celliax_serial_read_AT(p, 1, 500000, 20, NULL, 1); // 20.5 sec timeout
2536 UNLOCKA(&p->controldev_lock);
2537 POPPA_UNLOCKA(&p->controldev_lock);
2538
2539 return at_result;
2540
2541 }
2542
celliax_serial_write_AT_expect1(struct celliax_pvt * p,const char * data,const char * expected_string,int expect_crlf,int seconds)2543 int celliax_serial_write_AT_expect1(struct celliax_pvt *p, const char *data,
2544 const char *expected_string, int expect_crlf,
2545 int seconds)
2546 {
2547 int at_result = AT_ERROR;
2548
2549 PUSHA_UNLOCKA(&p->controldev_lock);
2550 LOKKA(&p->controldev_lock);
2551 if (option_debug > 1)
2552 DEBUGA_AT("sending: %s, expecting: %s\n", CELLIAX_P_LOG, data, expected_string);
2553 if (celliax_serial_write_AT(p, data) != strlen(data)) {
2554 ERRORA("Error sending data... (%s) \n", CELLIAX_P_LOG, strerror(errno));
2555 UNLOCKA(&p->controldev_lock);
2556 return -1;
2557 }
2558
2559 at_result = celliax_serial_read_AT(p, 1, 500000, seconds, expected_string, expect_crlf); // 20.5 sec timeout, used for querying the SIM and sending SMSs
2560 UNLOCKA(&p->controldev_lock);
2561 POPPA_UNLOCKA(&p->controldev_lock);
2562
2563 return at_result;
2564
2565 }
2566
celliax_serial_AT_expect(struct celliax_pvt * p,const char * expected_string,int expect_crlf,int seconds)2567 int celliax_serial_AT_expect(struct celliax_pvt *p, const char *expected_string,
2568 int expect_crlf, int seconds)
2569 {
2570 int at_result = AT_ERROR;
2571
2572 PUSHA_UNLOCKA(&p->controldev_lock);
2573 LOKKA(&p->controldev_lock);
2574 if (option_debug > 1)
2575 DEBUGA_AT("expecting: %s\n", CELLIAX_P_LOG, expected_string);
2576
2577 at_result = celliax_serial_read_AT(p, 1, 500000, seconds, expected_string, expect_crlf); // 20.5 sec timeout, used for querying the SIM and sending SMSs
2578 UNLOCKA(&p->controldev_lock);
2579 POPPA_UNLOCKA(&p->controldev_lock);
2580
2581 return at_result;
2582
2583 }
2584
celliax_serial_answer_AT(struct celliax_pvt * p)2585 int celliax_serial_answer_AT(struct celliax_pvt *p)
2586 {
2587 int res;
2588
2589 res = celliax_serial_write_AT_expect(p, p->at_answer, p->at_answer_expect);
2590 if (res) {
2591 DEBUGA_AT
2592 ("at_answer command failed, command used: %s, expecting: %s, trying with AT+CKPD=\"S\"\n",
2593 CELLIAX_P_LOG, p->at_answer, p->at_answer_expect);
2594
2595 res = celliax_serial_write_AT_ack(p, "AT+CKPD=\"S\"");
2596 if (res) {
2597 ERRORA("at_answer command failed, command used: 'AT+CKPD=\"S\"', giving up\n",
2598 CELLIAX_P_LOG);
2599 return -1;
2600 }
2601 }
2602 //p->interface_state = AST_STATE_UP;
2603 //p->phone_callflow = CALLFLOW_CALL_ACTIVE;
2604 DEBUGA_AT("AT: call answered\n", CELLIAX_P_LOG);
2605 return 0;
2606 }
2607
celliax_serial_hangup_AT(struct celliax_pvt * p)2608 int celliax_serial_hangup_AT(struct celliax_pvt *p)
2609 {
2610 int res;
2611
2612 if (p->interface_state != AST_STATE_DOWN) {
2613 res = celliax_serial_write_AT_expect(p, p->at_hangup, p->at_hangup_expect);
2614 if (res) {
2615 DEBUGA_AT
2616 ("at_hangup command failed, command used: %s, trying to use AT+CKPD=\"EEE\"\n",
2617 CELLIAX_P_LOG, p->at_hangup);
2618 res = celliax_serial_write_AT_ack(p, "AT+CKPD=\"EEE\"");
2619 if (res) {
2620 ERRORA("at_hangup command failed, command used: 'AT+CKPD=\"EEE\"'\n",
2621 CELLIAX_P_LOG);
2622 return -1;
2623 }
2624 }
2625 }
2626 p->interface_state = AST_STATE_DOWN;
2627 p->phone_callflow = CALLFLOW_CALL_IDLE;
2628 return 0;
2629 }
2630
celliax_serial_config_AT(struct celliax_pvt * p)2631 int celliax_serial_config_AT(struct celliax_pvt *p)
2632 {
2633 int res;
2634
2635 /* initial_pause? */
2636 if (p->at_initial_pause) {
2637 DEBUGA_AT("sleeping for %d usec\n", CELLIAX_P_LOG, p->at_initial_pause);
2638 usleep(p->at_initial_pause);
2639 }
2640
2641 /* go until first empty preinit string, or last preinit string */
2642 while (1) {
2643
2644 if (strlen(p->at_preinit_1)) {
2645 res = celliax_serial_write_AT_expect(p, p->at_preinit_1, p->at_preinit_1_expect);
2646 if (res) {
2647 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2648 p->at_preinit_1, p->at_preinit_1_expect);
2649 }
2650 } else {
2651 break;
2652 }
2653
2654 if (strlen(p->at_preinit_2)) {
2655 res = celliax_serial_write_AT_expect(p, p->at_preinit_2, p->at_preinit_2_expect);
2656 if (res) {
2657 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2658 p->at_preinit_2, p->at_preinit_2_expect);
2659 }
2660 } else {
2661 break;
2662 }
2663
2664 if (strlen(p->at_preinit_3)) {
2665 res = celliax_serial_write_AT_expect(p, p->at_preinit_3, p->at_preinit_3_expect);
2666 if (res) {
2667 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2668 p->at_preinit_3, p->at_preinit_3_expect);
2669 }
2670 } else {
2671 break;
2672 }
2673
2674 if (strlen(p->at_preinit_4)) {
2675 res = celliax_serial_write_AT_expect(p, p->at_preinit_4, p->at_preinit_4_expect);
2676 if (res) {
2677 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2678 p->at_preinit_4, p->at_preinit_4_expect);
2679 }
2680 } else {
2681 break;
2682 }
2683
2684 if (strlen(p->at_preinit_5)) {
2685 res = celliax_serial_write_AT_expect(p, p->at_preinit_5, p->at_preinit_5_expect);
2686 if (res) {
2687 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2688 p->at_preinit_5, p->at_preinit_5_expect);
2689 }
2690 } else {
2691 break;
2692 }
2693
2694 break;
2695 }
2696
2697 /* after_preinit_pause? */
2698 if (p->at_after_preinit_pause) {
2699 DEBUGA_AT("sleeping for %d usec\n", CELLIAX_P_LOG, p->at_after_preinit_pause);
2700 usleep(p->at_after_preinit_pause);
2701 }
2702
2703 /* phone, brother, art you alive? */
2704 res = celliax_serial_write_AT_ack(p, "AT");
2705 if (res) {
2706 ERRORA("no response to AT\n", CELLIAX_P_LOG);
2707 return -1;
2708 }
2709 /* for motorola, bring it back to "normal" mode if it happens to be in another mode */
2710 res = celliax_serial_write_AT_ack(p, "AT+mode=0");
2711 if (res) {
2712 DEBUGA_AT("AT+mode=0 does not get OK from the phone. If it is NOT Motorola,"
2713 " no problem.\n", CELLIAX_P_LOG);
2714 }
2715 usleep(50000);
2716 /* for motorola end */
2717
2718 /* reset AT configuration to phone default */
2719 res = celliax_serial_write_AT_ack(p, "ATZ");
2720 if (res) {
2721 DEBUGA_AT("ATZ failed\n", CELLIAX_P_LOG);
2722 }
2723
2724 /* disable AT command echo */
2725 res = celliax_serial_write_AT_ack(p, "ATE0");
2726 if (res) {
2727 DEBUGA_AT("ATE0 failed\n", CELLIAX_P_LOG);
2728 }
2729
2730 /* disable extended error reporting */
2731 res = celliax_serial_write_AT_ack(p, "AT+CMEE=0");
2732 if (res) {
2733 DEBUGA_AT("AT+CMEE failed\n", CELLIAX_P_LOG);
2734 }
2735
2736 /* various phone manufacturer identifier */
2737 char at_command[5];
2738 int i;
2739 for (i = 0; i < 10; i++) {
2740 memset(at_command, 0, sizeof(at_command));
2741 sprintf(at_command, "ATI%d", i);
2742 res = celliax_serial_write_AT_ack(p, at_command);
2743 if (res) {
2744 DEBUGA_AT("ATI%d command failed, continue\n", CELLIAX_P_LOG, i);
2745 }
2746 }
2747
2748 /* phone manufacturer */
2749 res = celliax_serial_write_AT_ack(p, "AT+CGMI");
2750 if (res) {
2751 DEBUGA_AT("AT+CGMI failed\n", CELLIAX_P_LOG);
2752 }
2753
2754 /* phone model */
2755 res = celliax_serial_write_AT_ack(p, "AT+CGMM");
2756 if (res) {
2757 DEBUGA_AT("AT+CGMM failed\n", CELLIAX_P_LOG);
2758 }
2759
2760 res = celliax_serial_write_AT_ack(p, "AT+CGSN");
2761 if (res) {
2762 DEBUGA_AT("AT+CGSN failed\n", CELLIAX_P_LOG);
2763 }
2764
2765 /* this take a lot of time to complete on devices with slow serial link (eg.: 9600bps) */
2766 #if 0
2767 /* ask for the list of supported AT commands, useful to implement new models and debugging */
2768 res = celliax_serial_write_AT_ack(p, "AT+CLAC");
2769 if (res) {
2770 DEBUGA_AT("AT+CLAC failed, continue\n", CELLIAX_P_LOG);
2771 }
2772 #endif
2773 /* signal incoming SMS with a +CMTI unsolicited msg */
2774 res = celliax_serial_write_AT_ack(p, "AT+CNMI=3,1,0,0,0");
2775 if (res) {
2776 DEBUGA_AT("AT+CNMI=3,1,0,0,0 failed, continue\n", CELLIAX_P_LOG);
2777 p->sms_cnmi_not_supported = 1;
2778 p->celliax_serial_sync_period = 30;
2779 }
2780 /* what is the Message Center address (number) to which the SMS has to be sent? */
2781 res = celliax_serial_write_AT_ack(p, "AT+CSCA?");
2782 if (res) {
2783 DEBUGA_AT("AT+CSCA? failed, continue\n", CELLIAX_P_LOG);
2784 }
2785 /* what is the Message Format of SMSs? */
2786 res = celliax_serial_write_AT_ack(p, "AT+CMGF?");
2787 if (res) {
2788 DEBUGA_AT("AT+CMGF? failed, continue\n", CELLIAX_P_LOG);
2789 }
2790 res = celliax_serial_write_AT_ack(p, "AT+CMGF=1"); //TODO: support phones that only accept pdu mode
2791 if (res) {
2792 ERRORA("Error setting SMS sending mode to TEXT on the cellphone\n", CELLIAX_P_LOG);
2793 return RESULT_FAILURE;
2794 }
2795 /* what is the Charset of SMSs? */
2796 res = celliax_serial_write_AT_ack(p, "AT+CSCS?");
2797 if (res) {
2798 DEBUGA_AT("AT+CSCS? failed, continue\n", CELLIAX_P_LOG);
2799 }
2800
2801 p->no_ucs2 = 0;
2802 res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"UCS2\"");
2803 if (res) {
2804 WARNINGA
2805 ("AT+CSCS=\"UCS2\" (set TE messages to ucs2) do not got OK from the phone, let's try with 'GSM'\n",
2806 CELLIAX_P_LOG);
2807 p->no_ucs2 = 1;
2808 }
2809
2810 if (p->no_ucs2) {
2811 res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"GSM\"");
2812 if (res) {
2813 WARNINGA("AT+CSCS=\"GSM\" (set TE messages to GSM) do not got OK from the phone\n",
2814 CELLIAX_P_LOG);
2815 }
2816 //res = celliax_serial_write_AT_ack(p, "AT+CSMP=17,167,0,16"); //"flash", class 0 sms 7 bit
2817 res = celliax_serial_write_AT_ack(p, "AT+CSMP=17,167,0,0"); //normal, 7 bit message
2818 if (res) {
2819 WARNINGA("AT+CSMP do not got OK from the phone, continuing\n", CELLIAX_P_LOG);
2820 }
2821 } else {
2822 //res = celliax_serial_write_AT_ack(p, "AT+CSMP=17,167,0,20"); //"flash", class 0 sms 16 bit unicode
2823 res = celliax_serial_write_AT_ack(p, "AT+CSMP=17,167,0,8"); //unicode, 16 bit message
2824 if (res) {
2825 WARNINGA("AT+CSMP do not got OK from the phone, continuing\n", CELLIAX_P_LOG);
2826 }
2827 }
2828
2829 /* is the unsolicited reporting of mobile equipment event supported? */
2830 res = celliax_serial_write_AT_ack(p, "AT+CMER=?");
2831 if (res) {
2832 DEBUGA_AT("AT+CMER=? failed, continue\n", CELLIAX_P_LOG);
2833 }
2834 /* request unsolicited reporting of mobile equipment indicators' events, to be screened by categories reported by +CIND=? */
2835 res = celliax_serial_write_AT_ack(p, "AT+CMER=3,0,0,1");
2836 if (res) {
2837 DEBUGA_AT("AT+CMER=? failed, continue\n", CELLIAX_P_LOG);
2838 }
2839
2840 /* is the solicited reporting of mobile equipment indications supported? */
2841
2842 res = celliax_serial_write_AT_ack(p, "AT+CIND=?");
2843 if (res) {
2844 DEBUGA_AT("AT+CIND=? failed, continue\n", CELLIAX_P_LOG);
2845 }
2846
2847 /* is the unsolicited reporting of call monitoring supported? sony-ericsson specific */
2848 res = celliax_serial_write_AT_ack(p, "AT*ECAM=?");
2849 if (res) {
2850 DEBUGA_AT("AT*ECAM=? failed, continue\n", CELLIAX_P_LOG);
2851 }
2852 /* enable the unsolicited reporting of call monitoring. sony-ericsson specific */
2853 res = celliax_serial_write_AT_ack(p, "AT*ECAM=1");
2854 if (res) {
2855 DEBUGA_AT("AT*ECAM=1 failed, continue\n", CELLIAX_P_LOG);
2856 p->at_has_ecam = 0;
2857 } else {
2858 p->at_has_ecam = 1;
2859 }
2860
2861 /* disable unsolicited signaling of call list */
2862 res = celliax_serial_write_AT_ack(p, "AT+CLCC=0");
2863 if (res) {
2864 DEBUGA_AT("AT+CLCC=0 failed, continue\n", CELLIAX_P_LOG);
2865 p->at_has_clcc = 0;
2866 } else {
2867 p->at_has_clcc = 1;
2868 }
2869
2870 /* give unsolicited caller id when incoming call */
2871 res = celliax_serial_write_AT_ack(p, "AT+CLIP=1");
2872 if (res) {
2873 DEBUGA_AT("AT+CLIP failed, continue\n", CELLIAX_P_LOG);
2874 }
2875 /* for motorola */
2876 res = celliax_serial_write_AT_ack(p, "AT+MCST=1"); /* motorola call control codes
2877 (to know when call is disconnected (they
2878 don't give you "no carrier") */
2879 if (res) {
2880 DEBUGA_AT("AT+MCST=1 does not get OK from the phone. If it is NOT Motorola,"
2881 " no problem.\n", CELLIAX_P_LOG);
2882 }
2883 /* for motorola end */
2884
2885 /* go until first empty postinit string, or last postinit string */
2886 while (1) {
2887
2888 if (strlen(p->at_postinit_1)) {
2889 res = celliax_serial_write_AT_expect(p, p->at_postinit_1, p->at_postinit_1_expect);
2890 if (res) {
2891 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2892 p->at_postinit_1, p->at_postinit_1_expect);
2893 }
2894 } else {
2895 break;
2896 }
2897
2898 if (strlen(p->at_postinit_2)) {
2899 res = celliax_serial_write_AT_expect(p, p->at_postinit_2, p->at_postinit_2_expect);
2900 if (res) {
2901 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2902 p->at_postinit_2, p->at_postinit_2_expect);
2903 }
2904 } else {
2905 break;
2906 }
2907
2908 if (strlen(p->at_postinit_3)) {
2909 res = celliax_serial_write_AT_expect(p, p->at_postinit_3, p->at_postinit_3_expect);
2910 if (res) {
2911 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2912 p->at_postinit_3, p->at_postinit_3_expect);
2913 }
2914 } else {
2915 break;
2916 }
2917
2918 if (strlen(p->at_postinit_4)) {
2919 res = celliax_serial_write_AT_expect(p, p->at_postinit_4, p->at_postinit_4_expect);
2920 if (res) {
2921 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2922 p->at_postinit_4, p->at_postinit_4_expect);
2923 }
2924 } else {
2925 break;
2926 }
2927
2928 if (strlen(p->at_postinit_5)) {
2929 res = celliax_serial_write_AT_expect(p, p->at_postinit_5, p->at_postinit_5_expect);
2930 if (res) {
2931 DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2932 p->at_postinit_5, p->at_postinit_5_expect);
2933 }
2934 } else {
2935 break;
2936 }
2937
2938 break;
2939 }
2940
2941 return 0;
2942 }
2943
celliax_serial_call_AT(struct celliax_pvt * p,char * dstr)2944 int celliax_serial_call_AT(struct celliax_pvt *p, char *dstr)
2945 {
2946 int res;
2947 char at_command[256];
2948
2949 if (option_debug)
2950 DEBUGA_PBX("Dialing %s\n", CELLIAX_P_LOG, dstr);
2951 memset(at_command, 0, sizeof(at_command));
2952 p->phone_callflow = CALLFLOW_CALL_DIALING;
2953 p->interface_state = AST_STATE_DIALING;
2954 ast_uri_decode(dstr);
2955 size_t fixdstr = strspn(dstr, AST_DIGIT_ANYDIG);
2956 if (fixdstr == 0) {
2957 ERRORA("dial command failed because of invalid dial number. dial string was: %s\n",
2958 CELLIAX_P_LOG, dstr);
2959 return -1;
2960 }
2961 dstr[fixdstr] = '\0';
2962 sprintf(at_command, "%s%s%s", p->at_dial_pre_number, dstr, p->at_dial_post_number);
2963 res = celliax_serial_write_AT_expect(p, at_command, p->at_dial_expect);
2964 if (res) {
2965 ERRORA("dial command failed, dial string was: %s\n", CELLIAX_P_LOG, at_command);
2966 return -1;
2967 }
2968 // jet - early audio
2969 if (p->at_early_audio) {
2970 ast_queue_control(p->owner, AST_CONTROL_ANSWER);
2971 }
2972
2973 return 0;
2974 }
2975
celliax_console_at(int fd,int argc,char * argv[])2976 int celliax_console_at(int fd, int argc, char *argv[])
2977 {
2978 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
2979 char at_cmd[1024];
2980 int i, a, c;
2981
2982 if (argc == 1)
2983 return RESULT_SHOWUSAGE;
2984 if (!p) {
2985 ast_cli(fd,
2986 "No \"current\" console for celliax_at, please enter 'help celliax_console'\n");
2987 return RESULT_SUCCESS;
2988 }
2989 if (p->controldevprotocol != PROTOCOL_AT) {
2990 ast_cli(fd,
2991 "The \"current\" console is not connected to an 'AT modem' (cellphone)\n");
2992 return RESULT_SUCCESS;
2993 }
2994
2995 memset(at_cmd, 0, sizeof(at_cmd));
2996 c = 0;
2997 for (i = 1; i < argc; i++) {
2998 for (a = 0; a < strlen(argv[i]); a++) {
2999 at_cmd[c] = argv[i][a];
3000 c++;
3001 if (c == 1022)
3002 break;
3003 }
3004 if (i != argc - 1) {
3005 at_cmd[c] = ' ';
3006 c++;
3007 }
3008 if (c == 1023)
3009 break;
3010 }
3011 celliax_serial_write_AT_noack(p, at_cmd);
3012 return RESULT_SUCCESS;
3013 }
3014
3015 #ifdef ASTERISK_VERSION_1_2
celliax_manager_sendsms(struct mansession * s,struct message * m)3016 int celliax_manager_sendsms(struct mansession *s, struct message *m)
3017 #endif //ASTERISK_VERSION_1_2
3018 #ifdef ASTERISK_VERSION_1_4
3019 int celliax_manager_sendsms(struct mansession *s, const struct message *m)
3020 #endif //ASTERISK_VERSION_1_4
3021 {
3022 int ret;
3023 char command[512];
3024 const char *interfacename = astman_get_header(m, "Interface");
3025 const char *destinationnumber = astman_get_header(m, "Number");
3026 const char *text = astman_get_header(m, "Text");
3027 const char *action_id = astman_get_header(m, "ActionID");
3028
3029 if (ast_strlen_zero(interfacename)) {
3030 astman_send_error(s, m, "Interface: missing.\n");
3031 return 0;
3032 }
3033 if (ast_strlen_zero(destinationnumber)) {
3034 astman_send_error(s, m, "Number: missing.\n");
3035 return 0;
3036 }
3037 if (ast_strlen_zero(text)) {
3038 astman_send_error(s, m, "Text: missing.\n");
3039 return 0;
3040 }
3041 if (ast_strlen_zero(action_id)) {
3042 astman_send_error(s, m, "ActionID: missing.\n");
3043 return 0;
3044 }
3045
3046 memset(command, 0, sizeof(command));
3047
3048 sprintf(command, "%s/%s|%s|", interfacename, destinationnumber, text);
3049
3050 ret = celliax_sendsms(NULL, (void *) &command);
3051
3052 #ifndef ASTERISK_VERSION_1_4
3053 if (!ret) {
3054 ast_cli(s->fd, "Response: Success\r\n");
3055 if (!ast_strlen_zero(action_id))
3056 ast_cli(s->fd, "ActionID: %s\r\n", action_id);
3057 ast_cli(s->fd, "\r\n");
3058 return RESULT_SUCCESS;
3059 } else {
3060 ast_cli(s->fd, "Response: Error\r\n");
3061 if (!ast_strlen_zero(action_id))
3062 ast_cli(s->fd, "ActionID: %s\r\n", action_id);
3063 ast_cli(s->fd, "Message: celliax_manager_sendsms failed\r\n");
3064 ast_cli(s->fd, "\r\n");
3065 return 0;
3066 }
3067 #else /* ASTERISK_VERSION_1_4 */
3068 if (!ret) {
3069 astman_append(s, "Response: Success\r\n");
3070 if (!ast_strlen_zero(action_id))
3071 astman_append(s, "ActionID: %s\r\n", action_id);
3072 astman_append(s, "\r\n");
3073 return RESULT_SUCCESS;
3074 } else {
3075 astman_append(s, "Response: Error\r\n");
3076 if (!ast_strlen_zero(action_id))
3077 astman_append(s, "ActionID: %s\r\n", action_id);
3078 astman_append(s, "Message: celliax_manager_sendsms failed\r\n");
3079 astman_append(s, "\r\n");
3080 return 0;
3081 }
3082 #endif /* ASTERISK_VERSION_1_4 */
3083
3084 return RESULT_SUCCESS; //never reached
3085 }
3086
ucs2_to_utf8(struct celliax_pvt * p,char * ucs2_in,char * utf8_out,size_t outbytesleft)3087 int ucs2_to_utf8(struct celliax_pvt *p, char *ucs2_in, char *utf8_out,
3088 size_t outbytesleft)
3089 {
3090 char converted[16000];
3091 iconv_t iconv_format;
3092 int iconv_res;
3093 char *outbuf;
3094 char *inbuf;
3095 size_t inbytesleft;
3096 int c;
3097 char stringa[5];
3098 double hexnum;
3099 int i = 0;
3100
3101 memset(converted, '\0', sizeof(converted));
3102
3103 DEBUGA_AT("ucs2_in=%s\n", CELLIAX_P_LOG, ucs2_in);
3104 /* cicopet */
3105 for (c = 0; c < strlen(ucs2_in); c++) {
3106 sprintf(stringa, "0x%c%c", ucs2_in[c], ucs2_in[c + 1]);
3107 c++;
3108 hexnum = strtod(stringa, NULL);
3109 converted[i] = hexnum;
3110 i++;
3111 }
3112
3113 outbuf = utf8_out;
3114 inbuf = converted;
3115
3116 iconv_format = iconv_open("UTF8", "UCS-2BE");
3117 if (iconv_format == (iconv_t) - 1) {
3118 ERRORA("error: %s\n", CELLIAX_P_LOG, strerror(errno));
3119 return -1;
3120 }
3121
3122 inbytesleft = i;
3123 iconv_res = iconv(iconv_format, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
3124 if (iconv_res == (size_t) - 1) {
3125 DEBUGA_AT("ciao in=%s, inleft=%d, out=%s, outleft=%d, converted=%s, utf8_out=%s\n",
3126 CELLIAX_P_LOG, inbuf, inbytesleft, outbuf, outbytesleft, converted,
3127 utf8_out);
3128 DEBUGA_AT("error: %s %d\n", CELLIAX_P_LOG, strerror(errno), errno);
3129 return -1;
3130 }
3131 DEBUGA_AT
3132 ("iconv_res=%d, in=%s, inleft=%d, out=%s, outleft=%d, converted=%s, utf8_out=%s\n",
3133 CELLIAX_P_LOG, iconv_res, inbuf, inbytesleft, outbuf, outbytesleft, converted,
3134 utf8_out);
3135 iconv_close(iconv_format);
3136
3137 return 0;
3138 }
3139
utf_to_ucs2(struct celliax_pvt * p,char * utf_in,size_t inbytesleft,char * ucs2_out,size_t outbytesleft)3140 int utf_to_ucs2(struct celliax_pvt *p, char *utf_in, size_t inbytesleft, char *ucs2_out,
3141 size_t outbytesleft)
3142 {
3143 /* cicopet */
3144 iconv_t iconv_format;
3145 int iconv_res;
3146 char *outbuf;
3147 char *inbuf;
3148 char converted[16000];
3149 int i;
3150 char stringa[16];
3151 char stringa2[16];
3152
3153 memset(converted, '\0', sizeof(converted));
3154
3155 outbuf = converted;
3156 inbuf = utf_in;
3157
3158 iconv_format = iconv_open("UCS-2BE", "UTF8");
3159 if (iconv_format == (iconv_t) - 1) {
3160 ERRORA("error: %s\n", CELLIAX_P_LOG, strerror(errno));
3161 return -1;
3162 }
3163 outbytesleft = 16000;
3164
3165 DEBUGA_AT("in=%s, inleft=%d, out=%s, outleft=%d, utf_in=%s, converted=%s\n",
3166 CELLIAX_P_LOG, inbuf, inbytesleft, outbuf, outbytesleft, utf_in, converted);
3167 iconv_res = iconv(iconv_format, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
3168 if (iconv_res == (size_t) - 1) {
3169 ERRORA("error: %s %d\n", CELLIAX_P_LOG, strerror(errno), errno);
3170 return -1;
3171 }
3172 DEBUGA_AT
3173 ("iconv_res=%d, in=%s, inleft=%d, out=%s, outleft=%d, utf_in=%s, converted=%s\n",
3174 CELLIAX_P_LOG, iconv_res, inbuf, inbytesleft, outbuf, outbytesleft, utf_in,
3175 converted);
3176 iconv_close(iconv_format);
3177
3178 for (i = 0; i < 16000 - outbytesleft; i++) {
3179 memset(stringa, '\0', sizeof(stringa));
3180 memset(stringa2, '\0', sizeof(stringa2));
3181 sprintf(stringa, "%02X", converted[i]);
3182 DEBUGA_AT("character is |%02X|\n", CELLIAX_P_LOG, converted[i]);
3183 stringa2[0] = stringa[strlen(stringa) - 2];
3184 stringa2[1] = stringa[strlen(stringa) - 1];
3185 strncat(ucs2_out, stringa2, ((outbytesleft - strlen(ucs2_out)) - 1)); //add the received line to the buffer
3186 DEBUGA_AT("stringa=%s, stringa2=%s, ucs2_out=%s\n", CELLIAX_P_LOG, stringa, stringa2,
3187 ucs2_out);
3188 }
3189 return 0;
3190 }
3191
celliax_sendsms(struct ast_channel * c,void * data)3192 int celliax_sendsms(struct ast_channel *c, void *data)
3193 {
3194 char *idest = data;
3195 char rdest[256];
3196 struct celliax_pvt *p = NULL;
3197 char *device;
3198 char *dest;
3199 char *text;
3200 char *stringp = NULL;
3201 int found = 0;
3202 int failed = 0;
3203
3204 strncpy(rdest, idest, sizeof(rdest) - 1);
3205 ast_log(LOG_DEBUG, "CelliaxSendsms: %s\n", rdest);
3206 ast_log(LOG_DEBUG, "START\n");
3207 /* we can use celliax_request to get the channel, but celliax_request would look for onowned channels, and probably we can send SMSs while a call is ongoing
3208 *
3209 */
3210
3211 stringp = rdest;
3212 device = strsep(&stringp, "/");
3213 dest = strsep(&stringp, "|");
3214 text = strsep(&stringp, "|");
3215
3216 if (!device) {
3217 ast_log(LOG_ERROR,
3218 "CelliaxSendsms app do not recognize '%s'. Requires a destination with slashes (interfacename/destinationnumber, TEXT)\n",
3219 idest);
3220 return -1;
3221 }
3222
3223 if (!dest) {
3224 ast_log(LOG_ERROR,
3225 "CelliaxSendsms app do not recognize '%s'. Requires a destination with slashes (interfacename/destinationnumber, TEXT)\n",
3226 idest);
3227 return -1;
3228 }
3229
3230 if (!text) {
3231 ast_log(LOG_ERROR,
3232 "CelliaxSendsms app do not recognize '%s'. Requires a destination with slashes (interfacename/destinationnumber, TEXT)\n",
3233 idest);
3234 return -1;
3235 }
3236
3237 ast_log(LOG_DEBUG, "interfacename:%s, destinationnumber:%s, text:%s\n", device, dest,
3238 text);
3239
3240 /* lock the interfaces' list */
3241 LOKKA(&celliax_iflock);
3242 /* make a pointer to the first interface in the interfaces list */
3243 p = celliax_iflist;
3244 /* Search for the requested interface and verify if is unowned */
3245 //TODO implement groups a la chan_zap
3246 while (p) {
3247 size_t length = strlen(p->name);
3248 /* is this the requested interface? */
3249 if (strncmp(device, p->name, length) == 0) {
3250 /* this is the requested interface! */
3251 if (option_debug)
3252 DEBUGA_AT("FOUND! interfacename:%s, destinationnumber:%s, text:%s, p->name=%s\n",
3253 CELLIAX_P_LOG, device, dest, text, p->name);
3254 found = 1;
3255 break;
3256
3257 }
3258 /* not yet found, next please */
3259 p = p->next;
3260 }
3261 /* unlock the interfaces' list */
3262 UNLOCKA(&celliax_iflock);
3263
3264 if (!found) {
3265 ast_log(LOG_ERROR, "Interface '%s' requested by CelliaxSendsms NOT FOUND\n", device);
3266 return RESULT_FAILURE;
3267 }
3268
3269 if (p->controldevprotocol != PROTOCOL_AT) {
3270 ERRORA("CelliaxSendsms supports only AT command cellphones at the moment :-( !\n",
3271 CELLIAX_P_LOG);
3272 return RESULT_FAILURE;
3273 }
3274
3275 if (p->controldevprotocol == PROTOCOL_AT) {
3276 int err = 0;
3277 char smscommand[16000];
3278 memset(smscommand, '\0', sizeof(smscommand));
3279
3280 PUSHA_UNLOCKA(&p->controldev_lock);
3281 LOKKA(&p->controldev_lock);
3282
3283 if (p->no_ucs2) {
3284 sprintf(smscommand, "AT+CMGS=\"%s\"", dest); //TODO: support phones that only accept pdu mode
3285 } else {
3286 char dest2[1048];
3287
3288 err = celliax_serial_write_AT_ack(p, "AT+CSCS=\"UCS2\"");
3289 if (err) {
3290 ERRORA
3291 ("AT+CSCS=\"UCS2\" (set TE messages to ucs2) do not got OK from the phone\n",
3292 CELLIAX_P_LOG);
3293 }
3294
3295 memset(dest2, '\0', sizeof(dest2));
3296 utf_to_ucs2(p, dest, strlen(dest), dest2, sizeof(dest2));
3297 sprintf(smscommand, "AT+CMGS=\"%s\"", dest2); //TODO: support phones that only accept pdu mode
3298 }
3299 //TODO: support phones that only accept pdu mode
3300 //TODO would be better to lock controldev here
3301 err = celliax_serial_write_AT_noack(p, smscommand);
3302 if (err) {
3303 ERRORA("Error sending SMS\n", CELLIAX_P_LOG);
3304 failed = 1;
3305 goto uscita;
3306 }
3307 err = celliax_serial_AT_expect(p, "> ", 0, 1); // wait 1.5s for the prompt, no crlf
3308 #if 1
3309 if (err) {
3310 DEBUGA_AT
3311 ("Error or timeout getting prompt '> ' for sending sms directly to the remote party. BTW, seems that we cannot do that with Motorola c350, so we'll write to cellphone memory, then send from memory\n",
3312 CELLIAX_P_LOG);
3313
3314 err = celliax_serial_write_AT_ack(p, "ATE1"); //motorola (at least c350) do not echo the '>' prompt when in ATE0... go figure!!!!
3315 if (err) {
3316 ERRORA("Error activating echo from modem\n", CELLIAX_P_LOG);
3317 }
3318 p->at_cmgw[0] = '\0';
3319 sprintf(smscommand, "AT+CMGW=\"%s\"", dest); //TODO: support phones that only accept pdu mode
3320 err = celliax_serial_write_AT_noack(p, smscommand);
3321 if (err) {
3322 ERRORA("Error writing SMS destination to the cellphone memory\n", CELLIAX_P_LOG);
3323 failed = 1;
3324 goto uscita;
3325 }
3326 err = celliax_serial_AT_expect(p, "> ", 0, 1); // wait 1.5s for the prompt, no crlf
3327 if (err) {
3328 ERRORA
3329 ("Error or timeout getting prompt '> ' for writing sms text in cellphone memory\n",
3330 CELLIAX_P_LOG);
3331 failed = 1;
3332 goto uscita;
3333 }
3334 }
3335 #endif
3336
3337 //sprintf(text,"ciao 123 belè новости לק ראת ﺎﻠﺠﻤﻋﺓ 人大"); //let's test the beauty of utf
3338 memset(smscommand, '\0', sizeof(smscommand));
3339 if (p->no_ucs2) {
3340 sprintf(smscommand, "%s", text);
3341 } else {
3342 utf_to_ucs2(p, text, strlen(text), smscommand, sizeof(smscommand));
3343 }
3344
3345 smscommand[strlen(smscommand)] = 0x1A;
3346 DEBUGA_AT("smscommand len is: %d, text is:|||%s|||\n", CELLIAX_P_LOG,
3347 strlen(smscommand), smscommand);
3348
3349 err = celliax_serial_write_AT_ack_nocr_longtime(p, smscommand);
3350 //TODO would be better to unlock controldev here
3351 if (err) {
3352 ERRORA("Error writing SMS text to the cellphone memory\n", CELLIAX_P_LOG);
3353 //return RESULT_FAILURE;
3354 failed = 1;
3355 goto uscita;
3356 }
3357 if (p->at_cmgw[0]) {
3358 sprintf(smscommand, "AT+CMSS=%s", p->at_cmgw);
3359 err = celliax_serial_write_AT_expect_longtime(p, smscommand, "OK");
3360 if (err) {
3361 ERRORA("Error sending SMS from the cellphone memory\n", CELLIAX_P_LOG);
3362 //return RESULT_FAILURE;
3363 failed = 1;
3364 goto uscita;
3365 }
3366
3367 err = celliax_serial_write_AT_ack(p, "ATE0"); //motorola (at least c350) do not echo the '>' prompt when in ATE0... go figure!!!!
3368 if (err) {
3369 ERRORA("Error de-activating echo from modem\n", CELLIAX_P_LOG);
3370 }
3371 }
3372 uscita:
3373 usleep(1000);
3374
3375 if (p->at_cmgw[0]) {
3376
3377 /* let's see what we've sent, just for check TODO: Motorola it's not reliable! Motorola c350 tells that all was sent, but is not true! It just sends how much it fits into one SMS FIXME: need an algorithm to calculate how many ucs2 chars fits into an SMS. It make difference based, probably, on the GSM alphabet translation, or so */
3378 sprintf(smscommand, "AT+CMGR=%s", p->at_cmgw);
3379 err = celliax_serial_write_AT_ack(p, smscommand);
3380 if (err) {
3381 ERRORA("Error reading SMS back from the cellphone memory\n", CELLIAX_P_LOG);
3382 }
3383
3384 /* let's delete from cellphone memory what we've sent */
3385 sprintf(smscommand, "AT+CMGD=%s", p->at_cmgw);
3386 err = celliax_serial_write_AT_ack(p, smscommand);
3387 if (err) {
3388 ERRORA("Error deleting SMS from the cellphone memory\n", CELLIAX_P_LOG);
3389 }
3390
3391 p->at_cmgw[0] = '\0';
3392 }
3393 //usleep(500000); //.5 secs
3394 UNLOCKA(&p->controldev_lock);
3395 POPPA_UNLOCKA(&p->controldev_lock);
3396 }
3397
3398 ast_log(LOG_DEBUG, "FINISH\n");
3399 if (failed)
3400 return -1;
3401 else
3402 return RESULT_SUCCESS;
3403 }
3404
3405 #ifdef CELLIAX_DIR
3406 /* For simplicity, I'm keeping the format compatible with the voicemail config,
3407 but i'm open to suggestions for isolating it */
3408 #define CELLIAX_DIR_CONFIG "directoriax.conf"
3409
3410 /* How many digits to read in */
3411 #define CELLIAX_DIR_NUMDIGITS 3
3412
celliax_dir_realtime(char * context)3413 struct ast_config *celliax_dir_realtime(char *context)
3414 {
3415 //TODO: all the realtime stuff has to be re-made
3416 struct ast_config *cfg;
3417 struct celliax_pvt *p = NULL;
3418 #ifdef ASTERISK_VERSION_1_6_0
3419 struct ast_flags config_flags = { 0 };
3420 #endif /* ASTERISK_VERSION_1_6_0 */
3421
3422 /* Load flat file config. */
3423 #ifdef ASTERISK_VERSION_1_6_0
3424 cfg = ast_config_load(CELLIAX_DIR_CONFIG, config_flags);
3425 #else
3426 cfg = ast_config_load(CELLIAX_DIR_CONFIG);
3427 #endif /* ASTERISK_VERSION_1_6_0 */
3428
3429 if (!cfg) {
3430 /* Loading config failed. */
3431 WARNINGA
3432 ("Loading directoriax.conf config file failed. It's not necessary, continuing.\n",
3433 CELLIAX_P_LOG);
3434 return NULL;
3435 }
3436 return cfg;
3437 }
3438
celliax_dir_convert(char * lastname)3439 static char *celliax_dir_convert(char *lastname)
3440 {
3441 char *tmp;
3442 int lcount = 0;
3443 tmp = malloc(CELLIAX_DIR_NUMDIGITS + 1);
3444 if (tmp) {
3445 while ((*lastname > 32) && lcount < CELLIAX_DIR_NUMDIGITS) {
3446 switch (toupper(*lastname)) {
3447 case '1':
3448 tmp[lcount++] = '1';
3449 break;
3450 case '2':
3451 case 'A':
3452 case 'B':
3453 case 'C':
3454 tmp[lcount++] = '2';
3455 break;
3456 case '3':
3457 case 'D':
3458 case 'E':
3459 case 'F':
3460 tmp[lcount++] = '3';
3461 break;
3462 case '4':
3463 case 'G':
3464 case 'H':
3465 case 'I':
3466 tmp[lcount++] = '4';
3467 break;
3468 case '5':
3469 case 'J':
3470 case 'K':
3471 case 'L':
3472 tmp[lcount++] = '5';
3473 break;
3474 case '6':
3475 case 'M':
3476 case 'N':
3477 case 'O':
3478 tmp[lcount++] = '6';
3479 break;
3480 case '7':
3481 case 'P':
3482 case 'Q':
3483 case 'R':
3484 case 'S':
3485 tmp[lcount++] = '7';
3486 break;
3487 case '8':
3488 case 'T':
3489 case 'U':
3490 case 'V':
3491 tmp[lcount++] = '8';
3492 break;
3493 case '9':
3494 case 'W':
3495 case 'X':
3496 case 'Y':
3497 case 'Z':
3498 tmp[lcount++] = '9';
3499 break;
3500 }
3501 lastname++;
3502 }
3503 tmp[lcount] = '\0';
3504 }
3505 return tmp;
3506 }
3507
celliax_console_celliax_dir_export(int fd,int argc,char * argv[])3508 int celliax_console_celliax_dir_export(int fd, int argc, char *argv[])
3509 {
3510 struct ast_config *cfg;
3511
3512 struct ast_variable *v;
3513 char *start, *pos, *stringp, *space, *options = NULL, *conv = NULL;
3514 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
3515 char *context = "default";
3516 char *s;
3517 char *var, *value;
3518 int fromcell = 0;
3519 int fromskype = 0;
3520 char name[256] = "";
3521 char phonebook_direct_calling_ext[7] = "";
3522 char write_entry_command[256] = "";
3523 char entry_number[256] = "";
3524 char entry_text[256] = "";
3525 char final_entry_text[256] = "";
3526 int res;
3527 int tocell = 0;
3528 #ifdef CELLIAX_LIBCSV
3529 int tocsv = 0;
3530 int tovcf = 0;
3531 #endif /* CELLIAX_LIBCSV */
3532
3533 if (argc < 3 || argc > 4)
3534 return RESULT_SHOWUSAGE;
3535 if (!p) {
3536 ast_cli(fd, "No \"current\" console ???, please enter 'help celliax_console'\n");
3537 return RESULT_SUCCESS;
3538 }
3539
3540 if (!strcasecmp(argv[1], "tocell"))
3541 tocell = 1;
3542 #ifdef CELLIAX_LIBCSV
3543 else if (!strcasecmp(argv[1], "tocsv"))
3544 tocsv = 1;
3545 else if (!strcasecmp(argv[1], "tovcf"))
3546 tovcf = 1;
3547 #endif /* CELLIAX_LIBCSV */
3548 else {
3549 ast_cli(fd,
3550 #ifdef CELLIAX_LIBCSV
3551 "\n\nYou have neither specified 'tocell' nor 'tocsv'\n\n");
3552 #else /* CELLIAX_LIBCSV */
3553 "\n\nYou have not specified 'tocell'\n\n");
3554 #endif /* CELLIAX_LIBCSV */
3555 return RESULT_SHOWUSAGE;
3556 }
3557 if (tocell)
3558 if (p->controldevprotocol != PROTOCOL_AT) {
3559 ast_cli(fd,
3560 "Exporting to the cellphone phonebook is currently supported only on \"AT\" cellphones :( !\n");
3561 return RESULT_SUCCESS;
3562 }
3563 #ifdef CELLIAX_LIBCSV
3564 if (tocsv || tovcf)
3565 if (argc != 4) {
3566 ast_cli(fd, "\n\nYou have to specify a filename with 'tocsv'\n\n");
3567 return RESULT_SHOWUSAGE;
3568 }
3569 #endif /* CELLIAX_LIBCSV */
3570
3571 if (option_debug)
3572 NOTICA("celliax_cellphonenumber is: %s\n", CELLIAX_P_LOG, argv[2]);
3573
3574 #ifdef CELLIAX_LIBCSV
3575 if (tocsv) {
3576 if (option_debug)
3577 NOTICA("filename is: %s\n", CELLIAX_P_LOG, argv[3]);
3578 //ast_cli(fd, "\n\nnot yet implemented :P \n");
3579 //return RESULT_SUCCESS;
3580 }
3581 if (tovcf) {
3582 if (option_debug)
3583 NOTICA("filename is: %s\n", CELLIAX_P_LOG, argv[3]);
3584 ast_cli(fd, "\n\nnot yet implemented :P \n");
3585 return RESULT_SUCCESS;
3586 }
3587 #endif /* CELLIAX_LIBCSV */
3588
3589 cfg = celliax_dir_realtime(context);
3590 if (!cfg) {
3591 return -1;
3592 }
3593
3594 if (tocell) {
3595 /* which phonebook to use, use the SIM */
3596 res = celliax_serial_write_AT_ack(p, "AT+CPBS=SM");
3597 if (res) {
3598 WARNINGA("AT+CPBS=SM failed, continue\n", CELLIAX_P_LOG);
3599 }
3600 /* which phonebook to use, trying to use phone, not SIM */
3601 res = celliax_serial_write_AT_ack(p, "AT+CPBS=ME");
3602 if (res) {
3603 WARNINGA("AT+CPBS=ME failed, continue\n", CELLIAX_P_LOG);
3604 }
3605 /* retrieve the fields lenght in the selected phonebook */
3606 p->phonebook_querying = 1;
3607 res = celliax_serial_write_AT_ack(p, "AT+CPBR=?");
3608 if (res) {
3609 WARNINGA("AT+CPBR=? failed, continue\n", CELLIAX_P_LOG);
3610 }
3611 p->phonebook_querying = 0;
3612
3613 v = ast_variable_browse(cfg, context);
3614 /* Find all candidate extensions */
3615 while (v) {
3616 /* Find a candidate extension */
3617 start = strdup(v->value);
3618 if (strcasestr(start, "fromcell=yes")) {
3619 fromcell = 1;
3620 fromskype = 0;
3621
3622 }
3623 if (strcasestr(start, "fromskype=yes")) {
3624 fromcell = 0;
3625 fromskype = 1;
3626
3627 }
3628
3629 if (start && !strcasestr(start, "hidefromdir=yes")) {
3630 memset(name, 0, sizeof(name));
3631 memset(phonebook_direct_calling_ext, 0, sizeof(phonebook_direct_calling_ext));
3632 memset(write_entry_command, 0, sizeof(write_entry_command));
3633 memset(entry_number, 0, sizeof(entry_number));
3634 memset(entry_text, 0, sizeof(entry_text));
3635 memset(final_entry_text, 0, sizeof(final_entry_text));
3636
3637 DEBUGA_AT("v->name=%s\n", CELLIAX_P_LOG, v->name);
3638 DEBUGA_AT("v->value=%s\n", CELLIAX_P_LOG, v->value);
3639
3640 stringp = start;
3641 strsep(&stringp, ",");
3642 pos = strsep(&stringp, ",");
3643 if (pos) {
3644 ast_copy_string(name, pos, sizeof(name));
3645 if (strchr(pos, ' ')) {
3646 space = strchr(pos, ' ');
3647 *space = '\0';
3648 }
3649 if (pos) {
3650 conv = celliax_dir_convert(pos);
3651 DEBUGA_AT("<pos=>%s<conv=>%s<\n", CELLIAX_P_LOG, pos, conv);
3652
3653 options = strdup(v->value);
3654 strsep(&options, ",");
3655 strsep(&options, ",");
3656 strsep(&options, ",");
3657 strsep(&options, ",");
3658 DEBUGA_AT("options=%s\n", CELLIAX_P_LOG, options);
3659
3660 while ((s = strsep(&options, "|"))) {
3661 value = s;
3662 if ((var = strsep(&value, "=")) && value) {
3663 DEBUGA_AT("var=%s value=%s\n", CELLIAX_P_LOG, var, value);
3664 if (!strcmp(var, "phonebook_direct_calling_ext"))
3665 strncpy(phonebook_direct_calling_ext, value, 6);
3666 }
3667 }
3668
3669 res =
3670 snprintf(entry_number, p->phonebook_number_lenght + 1, "%s%s%d%s%s",
3671 argv[2], "p", p->celliax_dir_prefix, "p",
3672 phonebook_direct_calling_ext);
3673 if (res == (p->phonebook_number_lenght + 1)
3674 || res > (p->phonebook_number_lenght + 1)) {
3675 ERRORA("entry_number truncated, was: '%s%s%d%s%s', now is: '%s'\n",
3676 CELLIAX_P_LOG, argv[2], "p", p->celliax_dir_prefix, "p",
3677 phonebook_direct_calling_ext, entry_number);
3678 //FIXME: abort ???
3679
3680 }
3681
3682 res = snprintf(final_entry_text, p->phonebook_text_lenght + 1, "%s", name); //FIXME result not checked
3683
3684 res =
3685 snprintf(write_entry_command, sizeof(write_entry_command) - 1,
3686 "AT+CPBW=,\"%s\",,\"%s\"", entry_number, final_entry_text);
3687 if (res == (sizeof(write_entry_command) - 1)
3688 || res > (sizeof(write_entry_command) - 1)) {
3689 WARNINGA
3690 ("write_entry_command truncated, was supposed: 'AT+CPBW=,\"%s\",,\"%s\"', now is: '%s'\n",
3691 CELLIAX_P_LOG, entry_number, final_entry_text, write_entry_command);
3692 }
3693 //if (option_debug)
3694 NOTICA("%s\n", CELLIAX_P_LOG, write_entry_command);
3695 }
3696 }
3697 if (conv)
3698 free(conv);
3699 if (start)
3700 free(start);
3701 if (options)
3702 free(options);
3703 }
3704 v = v->next;
3705 }
3706 }
3707 #ifdef CELLIAX_LIBCSV
3708 if (tocsv) {
3709
3710 v = ast_variable_browse(cfg, context);
3711 /* Find all candidate extensions */
3712 while (v) {
3713 /* Find a candidate extension */
3714 start = strdup(v->value);
3715 if (strcasestr(start, "fromcell=yes")) {
3716 fromcell = 1;
3717 fromskype = 0;
3718
3719 }
3720 if (strcasestr(start, "fromskype=yes")) {
3721 fromcell = 0;
3722 fromskype = 1;
3723
3724 }
3725
3726 if (start && !strcasestr(start, "hidefromdir=yes")) {
3727 memset(name, 0, sizeof(name));
3728 memset(phonebook_direct_calling_ext, 0, sizeof(phonebook_direct_calling_ext));
3729 memset(write_entry_command, 0, sizeof(write_entry_command));
3730 memset(entry_number, 0, sizeof(entry_number));
3731 memset(entry_text, 0, sizeof(entry_text));
3732 memset(final_entry_text, 0, sizeof(final_entry_text));
3733
3734 DEBUGA_AT("v->name=%s\n", CELLIAX_P_LOG, v->name);
3735 DEBUGA_AT("v->value=%s\n", CELLIAX_P_LOG, v->value);
3736
3737 stringp = start;
3738 strsep(&stringp, ",");
3739 pos = strsep(&stringp, ",");
3740 if (pos) {
3741 ast_copy_string(name, pos, sizeof(name));
3742 if (strchr(pos, ' ')) {
3743 space = strchr(pos, ' ');
3744 *space = '\0';
3745 }
3746 if (pos) {
3747 conv = celliax_dir_convert(pos);
3748 DEBUGA_AT("<pos=>%s<conv=>%s<\n", CELLIAX_P_LOG, pos, conv);
3749
3750 options = strdup(v->value);
3751 strsep(&options, ",");
3752 strsep(&options, ",");
3753 strsep(&options, ",");
3754 strsep(&options, ",");
3755 DEBUGA_AT("options=%s\n", CELLIAX_P_LOG, options);
3756
3757 while ((s = strsep(&options, "|"))) {
3758 value = s;
3759 if ((var = strsep(&value, "=")) && value) {
3760 DEBUGA_AT("var=%s value=%s\n", CELLIAX_P_LOG, var, value);
3761 if (!strcmp(var, "phonebook_direct_calling_ext"))
3762 strncpy(phonebook_direct_calling_ext, value, 6);
3763 }
3764 }
3765
3766 //FIXME choose a logic for fields maximum lenght
3767 res =
3768 snprintf(entry_number, sizeof(entry_number) - 1, "%s%s%d%s%s", argv[2], "p",
3769 p->celliax_dir_prefix, "p", phonebook_direct_calling_ext);
3770 if (res == (sizeof(entry_number) - 1)
3771 || res > (sizeof(entry_number) - 1)) {
3772 ERRORA("entry_number truncated, was: '%s%s%d%s%s', now is: '%s'\n",
3773 CELLIAX_P_LOG, argv[2], "p", p->celliax_dir_prefix, "p",
3774 phonebook_direct_calling_ext, entry_number);
3775 //FIXME: abort ???
3776
3777 }
3778
3779 res = snprintf(final_entry_text, sizeof(final_entry_text) - 1, "%s", name); //FIXME result not checked
3780
3781 int i, a;
3782
3783 a = 0;
3784 for (i = 0; i < p->csv_complete_name_pos - 1; i++) {
3785 if (p->csv_separator_is_semicolon)
3786 write_entry_command[a] = ';';
3787 else
3788 write_entry_command[a] = ',';
3789 a++;
3790 }
3791 //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3792
3793 write_entry_command[a] = '"';
3794 a++;
3795 //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3796 for (i = 0; i < strlen(final_entry_text); i++) {
3797 write_entry_command[a] = final_entry_text[i];
3798 a++;
3799 }
3800 //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3801 write_entry_command[a] = '"';
3802 a++;
3803 //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3804 for (i = 0; i < (p->csv_business_phone_pos - p->csv_complete_name_pos); i++) {
3805 if (p->csv_separator_is_semicolon)
3806 write_entry_command[a] = ';';
3807 else
3808 write_entry_command[a] = ',';
3809 a++;
3810 }
3811
3812 //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3813
3814 write_entry_command[a] = '"';
3815 a++;
3816 //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3817 for (i = 0; i < strlen(entry_number); i++) {
3818 write_entry_command[a] = entry_number[i];
3819 a++;
3820 }
3821 //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3822 write_entry_command[a] = '"';
3823 a++;
3824 //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3825
3826 if (option_debug)
3827 NOTICA("%s\n", CELLIAX_P_LOG, write_entry_command);
3828 }
3829 }
3830 if (conv)
3831 free(conv);
3832 if (start)
3833 free(start);
3834 if (options)
3835 free(options);
3836 }
3837 v = v->next;
3838 }
3839
3840 }
3841 if (tovcf) {
3842 //TODO implementation here
3843 }
3844 #endif /* CELLIAX_LIBCSV */
3845 ast_config_destroy(cfg);
3846 return 0;
3847 }
3848
3849 #ifdef CELLIAX_LIBCSV
3850
celliax_cb1(char * s,size_t len,void * data)3851 void celliax_cb1(char *s, size_t len, void *data)
3852 {
3853 struct celliax_pvt *p = data;
3854 char field_content[256];
3855
3856 p->csv_fields++;
3857 memset(field_content, 0, sizeof(field_content));
3858 strncpy(field_content, s,
3859 sizeof(field_content) > (len + 1) ? len : (sizeof(field_content) - 1));
3860 if (p->csv_fields == p->csv_complete_name_pos) {
3861 strncpy(p->csv_complete_name, field_content, sizeof(p->csv_complete_name) - 1);
3862 }
3863 if (p->csv_fields == p->csv_email_pos) {
3864 strncpy(p->csv_email, field_content, sizeof(p->csv_email) - 1);
3865 }
3866 if (p->csv_fields == p->csv_home_phone_pos) {
3867 strncpy(p->csv_home_phone, field_content, sizeof(p->csv_home_phone) - 1);
3868 }
3869 if (p->csv_fields == p->csv_mobile_phone_pos) {
3870 strncpy(p->csv_mobile_phone, field_content, sizeof(p->csv_mobile_phone) - 1);
3871 }
3872 if (p->csv_fields == p->csv_business_phone_pos) {
3873 strncpy(p->csv_business_phone, field_content, sizeof(p->csv_business_phone) - 1);
3874 }
3875 }
3876
celliax_cb2(char c,void * data)3877 void celliax_cb2(char c, void *data)
3878 {
3879 struct celliax_pvt *p = data;
3880
3881 p->csv_rows++;
3882 p->csv_fields = 0;
3883
3884 if (p->csv_first_row_is_title && p->csv_rows == 1) {
3885 //do nothing
3886 } else {
3887 if (strlen(p->csv_complete_name)) {
3888 if (option_debug)
3889 NOTICA
3890 ("ROW %d ENDED, complete_name=%s, email=%s, home_phone=%s, mobile_phone=%s, business_phone=%s\n",
3891 CELLIAX_P_LOG, p->csv_rows,
3892 strlen(p->csv_complete_name) ? p->csv_complete_name : "N/A",
3893 strlen(p->csv_email) ? p->csv_email : "N/A",
3894 strlen(p->csv_home_phone) ? p->csv_home_phone : "N/A",
3895 strlen(p->csv_mobile_phone) ? p->csv_mobile_phone : "N/A",
3896 strlen(p->csv_business_phone) ? p->csv_business_phone : "N/A");
3897 }
3898
3899 /* write entries in phonebook file */
3900 if (p->phonebook_writing_fp) {
3901 celliax_dir_entry_extension++;
3902
3903 if (strlen(p->csv_complete_name)) {
3904 /* let's start with home_phone */
3905 if (strlen(p->csv_home_phone)) {
3906 fprintf(p->phonebook_writing_fp,
3907 "%s => ,%s %sSKO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3908 p->csv_home_phone, p->csv_complete_name, "HOME", "no",
3909 p->celliax_dir_entry_extension_prefix, "2", celliax_dir_entry_extension,
3910 "yes", "not_specified");
3911 fprintf(p->phonebook_writing_fp,
3912 "%s => ,%s %sDO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3913 p->csv_home_phone, p->csv_complete_name, "HOME", "no",
3914 p->celliax_dir_entry_extension_prefix, "3", celliax_dir_entry_extension,
3915 "yes", "not_specified");
3916 }
3917
3918 /* now business_phone */
3919 if (strlen(p->csv_business_phone)) {
3920 fprintf(p->phonebook_writing_fp,
3921 "%s => ,%s %sSKO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3922 p->csv_business_phone, p->csv_complete_name, "BIZ", "no",
3923 p->celliax_dir_entry_extension_prefix, "2", celliax_dir_entry_extension,
3924 "yes", "not_specified");
3925 fprintf(p->phonebook_writing_fp,
3926 "%s => ,%s %sDO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3927 p->csv_business_phone, p->csv_complete_name, "BIZ", "no",
3928 p->celliax_dir_entry_extension_prefix, "3", celliax_dir_entry_extension,
3929 "yes", "not_specified");
3930 }
3931
3932 /* let's end with mobile_phone */
3933 if (strlen(p->csv_mobile_phone)) {
3934 fprintf(p->phonebook_writing_fp,
3935 "%s => ,%s %sSKO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3936 p->csv_mobile_phone, p->csv_complete_name, "CELL", "no",
3937 p->celliax_dir_entry_extension_prefix, "2", celliax_dir_entry_extension,
3938 "yes", "not_specified");
3939 fprintf(p->phonebook_writing_fp,
3940 "%s => ,%s %sDO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3941 p->csv_mobile_phone, p->csv_complete_name, "CELL", "no",
3942 p->celliax_dir_entry_extension_prefix, "3", celliax_dir_entry_extension,
3943 "yes", "not_specified");
3944 }
3945 }
3946
3947 }
3948
3949 }
3950 }
3951
3952 #endif /* CELLIAX_LIBCSV */
3953
celliax_console_celliax_dir_import(int fd,int argc,char * argv[])3954 int celliax_console_celliax_dir_import(int fd, int argc, char *argv[])
3955 {
3956 int res;
3957 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
3958 char list_command[64];
3959 char fn[256];
3960 char date[256] = "";
3961 time_t t;
3962 char *configfile = CELLIAX_DIR_CONFIG;
3963 int add_to_celliax_dir_conf = 1;
3964 //int fromskype = 0;
3965 int fromcell = 0;
3966 #ifdef CELLIAX_LIBCSV
3967 int fromcsv = 0;
3968 int fromvcf = 0;
3969 #endif /* CELLIAX_LIBCSV */
3970
3971 if (argc < 3 || argc > 4)
3972 return RESULT_SHOWUSAGE;
3973 if (!p) {
3974 ast_cli(fd, "No \"current\" console ???, please enter 'help celliax_console'\n");
3975 return RESULT_SUCCESS;
3976 }
3977
3978 if (!strcasecmp(argv[1], "add"))
3979 add_to_celliax_dir_conf = 1;
3980 else if (!strcasecmp(argv[1], "replace"))
3981 add_to_celliax_dir_conf = 0;
3982 else {
3983 ast_cli(fd, "\n\nYou have neither specified 'add' nor 'replace'\n\n");
3984 return RESULT_SHOWUSAGE;
3985 }
3986
3987 //if (!strcasecmp(argv[2], "fromskype"))
3988 //fromskype = 1;
3989 //else
3990
3991 if (!strcasecmp(argv[2], "fromcell"))
3992 fromcell = 1;
3993 #ifdef CELLIAX_LIBCSV
3994 else if (!strcasecmp(argv[2], "fromcsv"))
3995 fromcsv = 1;
3996 else if (!strcasecmp(argv[2], "fromvcf"))
3997 fromvcf = 1;
3998 #endif /* CELLIAX_LIBCSV */
3999 else {
4000 ast_cli(fd, "\n\nYou have neither specified 'fromcell' neither 'fromcsv'\n\n");
4001 return RESULT_SHOWUSAGE;
4002 }
4003
4004 #ifdef CELLIAX_LIBCSV
4005 if (fromcsv || fromvcf)
4006 if (argc != 4) {
4007 ast_cli(fd,
4008 "\n\nYou have to specify a filename with 'fromcsv' or with 'fromvcf'\n\n");
4009 return RESULT_SHOWUSAGE;
4010 }
4011 #endif /* CELLIAX_LIBCSV */
4012 if (fromcell)
4013 if (p->controldevprotocol != PROTOCOL_AT) {
4014 ast_cli(fd,
4015 "Importing from cellphone is currently supported only on \"AT\" cellphones :( !\n");
4016 //fclose(p->phonebook_writing_fp);
4017 //celliax_dir_create_extensions();
4018 return RESULT_SUCCESS;
4019 }
4020
4021 if (fromcell)
4022 if (argc != 3) {
4023 ast_cli(fd, "\n\nYou don't have to specify a filename with 'fromcell'\n\n");
4024 return RESULT_SHOWUSAGE;
4025 }
4026 #ifdef CELLIAX_LIBCSV
4027 if (fromvcf) {
4028 if (option_debug)
4029 NOTICA("filename is: %s\n", CELLIAX_P_LOG, argv[3]);
4030 ast_cli(fd, "\n\nnot yet implemented :P \n");
4031 return RESULT_SUCCESS;
4032 }
4033 #endif /* CELLIAX_LIBCSV */
4034
4035 /*******************************************************************************************/
4036
4037 if (configfile[0] == '/') {
4038 ast_copy_string(fn, configfile, sizeof(fn));
4039 } else {
4040 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
4041 }
4042 if (option_debug)
4043 NOTICA("Opening '%s'\n", CELLIAX_P_LOG, fn);
4044 time(&t);
4045 ast_copy_string(date, ctime(&t), sizeof(date));
4046
4047 if (add_to_celliax_dir_conf)
4048 p->phonebook_writing_fp = fopen(fn, "a+");
4049 else
4050 p->phonebook_writing_fp = fopen(fn, "w+");
4051
4052 if (p->phonebook_writing_fp) {
4053 if (add_to_celliax_dir_conf) {
4054 if (option_debug)
4055 NOTICA("Opened '%s' for appending \n", CELLIAX_P_LOG, fn);
4056 fprintf(p->phonebook_writing_fp, ";!\n");
4057 fprintf(p->phonebook_writing_fp, ";! Update Date: %s", date);
4058 fprintf(p->phonebook_writing_fp, ";! Updated by: %s, %d\n", __FILE__, __LINE__);
4059 fprintf(p->phonebook_writing_fp, ";!\n");
4060 } else {
4061 if (option_debug)
4062 NOTICA("Opened '%s' for writing \n", CELLIAX_P_LOG, fn);
4063 fprintf(p->phonebook_writing_fp, ";!\n");
4064 fprintf(p->phonebook_writing_fp, ";! Automatically generated configuration file\n");
4065 fprintf(p->phonebook_writing_fp, ";! Filename: %s (%s)\n", configfile, fn);
4066 fprintf(p->phonebook_writing_fp, ";! Creation Date: %s", date);
4067 fprintf(p->phonebook_writing_fp, ";! Generated by: %s, %d\n", __FILE__, __LINE__);
4068 fprintf(p->phonebook_writing_fp, ";!\n");
4069 fprintf(p->phonebook_writing_fp, "[general]\n\n");
4070 fprintf(p->phonebook_writing_fp, "[default]\n");
4071 }
4072
4073 #ifdef CELLIAX_LIBCSV
4074 //FIXME: if add_to_celliax_dir_conf parse the "old" config file, so to have the correct next entry id-exten
4075 if (fromcsv) {
4076 if (option_debug)
4077 NOTICA("filename is: %s\n", CELLIAX_P_LOG, argv[3]);
4078
4079 /************************/
4080 FILE *fp;
4081 struct csv_parser *csvp;
4082 char buf[1024];
4083 size_t bytes_read;
4084 unsigned char options = 0;
4085
4086 p->csv_rows = 0;
4087 p->csv_fields = 0;
4088
4089 if (p->csv_separator_is_semicolon) {
4090 if (csv_init(&csvp, options | CSV_USE_SEMICOLON_SEPARATOR) != 0) {
4091 ERRORA("Failed to initialize csv parser\n", CELLIAX_P_LOG);
4092 return RESULT_SUCCESS;
4093 }
4094 } else {
4095 if (csv_init(&csvp, options) != 0) {
4096 ERRORA("Failed to initialize csv parser\n", CELLIAX_P_LOG);
4097 return RESULT_SUCCESS;
4098 }
4099
4100 }
4101
4102 fp = fopen(argv[3], "rb");
4103 if (!fp) {
4104 ERRORA("Failed to open %s: %s\n", CELLIAX_P_LOG, argv[3], strerror(errno));
4105 return RESULT_SUCCESS;
4106 }
4107 while ((bytes_read = fread(buf, 1, 1024, fp)) > 0) {
4108 if (csv_parse(csvp, buf, bytes_read, celliax_cb1, celliax_cb2, p) != bytes_read) {
4109 ERRORA("Error while parsing file: %s\n", CELLIAX_P_LOG,
4110 csv_strerror(csv_error(csvp)));
4111 }
4112 }
4113
4114 csv_fini(csvp, celliax_cb1, celliax_cb2, p);
4115
4116 if (ferror(fp)) {
4117 ERRORA("Error while reading file %s\n", CELLIAX_P_LOG, argv[3]);
4118 fclose(fp);
4119 return RESULT_SUCCESS;
4120 }
4121
4122 fclose(fp);
4123 if (option_debug)
4124 NOTICA("%s: %d fields, %d rows\n", CELLIAX_P_LOG, argv[3], p->csv_fields,
4125 p->csv_rows);
4126
4127 csv_free(csvp);
4128
4129 /**************************/
4130 }
4131 #endif /* CELLIAX_LIBCSV */
4132
4133 /*******************************************************************************************/
4134 //if (fromskype) {
4135 //ast_cli(fd,
4136 //"Skype not supported in celliax_dir. Load chan_skypiax and use skypiax_dir!\n");
4137 //}
4138
4139 /*******************************************************************************************/
4140 if (fromcell) {
4141 /* which phonebook to use, use the SIM */
4142 res = celliax_serial_write_AT_ack(p, "AT+CPBS=SM");
4143 if (res) {
4144 WARNINGA("AT+CPBS=SM failed, continue\n", CELLIAX_P_LOG);
4145 }
4146 /* which phonebook to use, trying to use combined phone+SIM */
4147 res = celliax_serial_write_AT_ack(p, "AT+CPBS=MT");
4148 if (res) {
4149 WARNINGA("AT+CPBS=MT failed, continue\n", CELLIAX_P_LOG);
4150 }
4151 /* How many entries in phonebook */
4152 p->phonebook_querying = 1;
4153 res = celliax_serial_write_AT_ack(p, "AT+CPBR=?");
4154 if (res) {
4155 WARNINGA("AT+CPBR=? failed, continue\n", CELLIAX_P_LOG);
4156 }
4157 p->phonebook_querying = 0;
4158 /* list entries in phonebook, give the SIM the time to answer */
4159 WARNINGA
4160 ("About to querying the cellphone phonebook, if the SIM do not answer may stuck here for 20 seconds... Don't worry.\n",
4161 CELLIAX_P_LOG);
4162 sprintf(list_command, "AT+CPBR=%d,%d", p->phonebook_first_entry,
4163 p->phonebook_last_entry);
4164 p->phonebook_listing = 1;
4165 res = celliax_serial_write_AT_expect_longtime(p, list_command, "OK");
4166 if (res) {
4167 WARNINGA("AT+CPBR=%d,%d failed, continue\n", CELLIAX_P_LOG,
4168 p->phonebook_first_entry, p->phonebook_last_entry);
4169 }
4170 p->phonebook_listing = 0;
4171 }
4172 /*******************************************************************************************/
4173 #ifdef CELLIAX_LIBCSV
4174 if (fromvcf) {
4175 //TODO implementation here
4176 }
4177 #endif /* CELLIAX_LIBCSV */
4178
4179 } else {
4180 ast_cli(fd, "\n\nfailed to open the directoriax.conf configuration file: %s\n", fn);
4181 ERRORA("failed to open the directoriax.conf configuration file: %s\n", CELLIAX_P_LOG,
4182 fn);
4183 return RESULT_FAILURE;
4184 }
4185
4186 fclose(p->phonebook_writing_fp);
4187 //celliax_dir_create_extensions();
4188
4189 return RESULT_SUCCESS;
4190 }
4191
4192 #endif /* CELLIAX_DIR */
4193
4194 #ifdef CELLIAX_FBUS2
4195
celliax_serial_getstatus_FBUS2(struct celliax_pvt * p)4196 int celliax_serial_getstatus_FBUS2(struct celliax_pvt *p)
4197 {
4198 unsigned char MsgBuffer[7];
4199 int res;
4200 int how_many_reads = 0;
4201
4202 PUSHA_UNLOCKA(&p->controldev_lock);
4203 LOKKA(&p->controldev_lock);
4204
4205 MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4206 MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4207 MsgBuffer[2] = 0x00;
4208 MsgBuffer[3] = 0x03;
4209 MsgBuffer[4] = 0x00;
4210 MsgBuffer[5] = FBUS2_IS_LAST_FRAME;
4211 MsgBuffer[6] = celliax_serial_get_seqnum_FBUS2(p);
4212
4213 if (option_debug > 1)
4214 DEBUGA_FBUS2("asking model, outseqnum %.2X \n", CELLIAX_P_LOG, MsgBuffer[6]);
4215 celliax_serial_write_FBUS2(p, MsgBuffer, 7, FBUS2_TYPE_MODEL_ASK);
4216 usleep(1000);
4217 res = celliax_serial_read_FBUS2(p); //we don't have no monitor neither do_controldev_thread
4218 if (res == -1) {
4219 ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4220 UNLOCKA(&p->controldev_lock);
4221 return -1;
4222 }
4223 while (res != MsgBuffer[6] && res != FBUS2_TYPE_MODEL_ANSWER) {
4224 usleep(1000);
4225 res = celliax_serial_read_FBUS2(p);
4226 how_many_reads++;
4227 if (res == -1) {
4228 ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4229 UNLOCKA(&p->controldev_lock);
4230 return -1;
4231 }
4232 if (how_many_reads > 10) {
4233 ERRORA("no expected results in %d celliax_serial_read_FBUS2\n", CELLIAX_P_LOG,
4234 how_many_reads);
4235 UNLOCKA(&p->controldev_lock);
4236 return -1;
4237 }
4238 }
4239
4240 UNLOCKA(&p->controldev_lock);
4241 POPPA_UNLOCKA(&p->controldev_lock);
4242 return 0;
4243 }
4244
celliax_serial_sync_FBUS2(struct celliax_pvt * p)4245 int celliax_serial_sync_FBUS2(struct celliax_pvt *p)
4246 {
4247 unsigned char initc = 0x55; /* FBUS2 initialization char */
4248 int c, rt;
4249 PUSHA_UNLOCKA(&p->controldev_lock);
4250 LOKKA(&p->controldev_lock);
4251 /* init the link (sync receive uart) */
4252 for (c = 0; c < 55; c++) { /* 55 times */
4253 usleep(10000);
4254 rt = write(p->controldevfd, &initc, 1);
4255 if (rt != 1) {
4256 ERRORA("serial error: %s", CELLIAX_P_LOG, strerror(errno));
4257 UNLOCKA(&p->controldev_lock);
4258 return -1;
4259 }
4260 }
4261 time(&p->celliax_serial_synced_timestamp);
4262 UNLOCKA(&p->controldev_lock);
4263 POPPA_UNLOCKA(&p->controldev_lock);
4264 return 0;
4265 }
4266
celliax_serial_answer_FBUS2(struct celliax_pvt * p)4267 int celliax_serial_answer_FBUS2(struct celliax_pvt *p)
4268 {
4269 unsigned char MsgBuffer[6];
4270
4271 celliax_serial_security_command_FBUS2(p);
4272
4273 MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4274 MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4275 MsgBuffer[2] = FBUS2_SECURIY_CALL_COMMANDS;
4276 MsgBuffer[3] = FBUS2_SECURIY_CALL_COMMAND_ANSWER;
4277 MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4278 MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4279 if (option_debug > 1)
4280 DEBUGA_FBUS2("celliax_serial_answer_FBUS2, outseqnum %.2X \n", CELLIAX_P_LOG,
4281 MsgBuffer[5]);
4282 celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4283 DEBUGA_FBUS2("FBUS2: sent commands to answer the call\n", CELLIAX_P_LOG);
4284 p->interface_state = AST_STATE_UP; //FIXME
4285
4286 return 0;
4287 }
4288
celliax_serial_call_FBUS2(struct celliax_pvt * p,char * dstr)4289 int celliax_serial_call_FBUS2(struct celliax_pvt *p, char *dstr)
4290 {
4291 unsigned char MsgBufferNum[255];
4292 int i;
4293
4294 celliax_serial_security_command_FBUS2(p);
4295
4296 MsgBufferNum[0] = FBUS2_COMMAND_BYTE_1;
4297 MsgBufferNum[1] = FBUS2_COMMAND_BYTE_2;
4298 MsgBufferNum[2] = FBUS2_SECURIY_CALL_COMMANDS;
4299 MsgBufferNum[3] = FBUS2_SECURIY_CALL_COMMAND_CALL;
4300 for (i = 0; i < strlen(dstr); i++) {
4301 MsgBufferNum[4 + i] = dstr[i];
4302 }
4303 MsgBufferNum[4 + strlen(dstr)] = 0x00; /* required by FBUS2 prot */
4304 MsgBufferNum[4 + strlen(dstr) + 1] = FBUS2_IS_LAST_FRAME;
4305 MsgBufferNum[4 + strlen(dstr) + 2] = celliax_serial_get_seqnum_FBUS2(p);
4306 if (option_debug > 1)
4307 DEBUGA_FBUS2("celliax_serial_call_FBUS2, outseqnum %.2X \n", CELLIAX_P_LOG,
4308 MsgBufferNum[4 + strlen(dstr) + 2]);
4309 celliax_serial_write_FBUS2(p, MsgBufferNum, 5 + strlen(dstr) + 2, FBUS2_TYPE_SECURITY);
4310
4311 p->phone_callflow = CALLFLOW_CALL_DIALING;
4312 p->interface_state = AST_STATE_DIALING;
4313 if (option_debug)
4314 DEBUGA_FBUS2("FBUS2: sent commands to call\n", CELLIAX_P_LOG);
4315 return 0;
4316 }
4317
celliax_serial_hangup_FBUS2(struct celliax_pvt * p)4318 int celliax_serial_hangup_FBUS2(struct celliax_pvt *p)
4319 {
4320 unsigned char MsgBuffer[6];
4321
4322 if (p->interface_state != AST_STATE_DOWN) {
4323 celliax_serial_security_command_FBUS2(p);
4324
4325 MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4326 MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4327 MsgBuffer[2] = FBUS2_SECURIY_CALL_COMMANDS;
4328 MsgBuffer[3] = FBUS2_SECURIY_CALL_COMMAND_RELEASE;
4329 MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4330 MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4331
4332 if (option_debug > 1)
4333 DEBUGA_FBUS2("celliax_serial_hangup_FBUS2, outseqnum %.2X \n", CELLIAX_P_LOG,
4334 MsgBuffer[5]);
4335 celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4336
4337 DEBUGA_FBUS2("FBUS2: sent commands to hangup the call\n", CELLIAX_P_LOG);
4338
4339 }
4340 p->interface_state = AST_STATE_DOWN; //FIXME
4341 p->phone_callflow = CALLFLOW_CALL_IDLE; //FIXME
4342 return 0;
4343 }
4344
celliax_serial_config_FBUS2(struct celliax_pvt * p)4345 int celliax_serial_config_FBUS2(struct celliax_pvt *p)
4346 {
4347 unsigned char MsgBuffer[6];
4348 int res;
4349 int how_many_reads = 0;
4350
4351 MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4352 MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4353 MsgBuffer[2] = FBUS2_SECURIY_EXTENDED_COMMANDS;
4354 MsgBuffer[3] = FBUS2_SECURIY_EXTENDED_COMMAND_ON;
4355 MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4356 MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4357
4358 if (option_debug > 1)
4359 DEBUGA_FBUS2("activating security commands for getting IMEI, outseqnum %.2X \n",
4360 CELLIAX_P_LOG, MsgBuffer[5]);
4361 celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4362 res = celliax_serial_read_FBUS2(p); //we don't have no monitor neither do_controldev_thread
4363 if (res == -1) {
4364 ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4365 return -1;
4366 }
4367 while (res != MsgBuffer[5] && res != FBUS2_SECURIY_EXTENDED_COMMAND_ON) {
4368 usleep(1000);
4369 res = celliax_serial_read_FBUS2(p);
4370 how_many_reads++;
4371 if (res == -1) {
4372 ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4373 return -1;
4374 }
4375 if (how_many_reads > 10) {
4376 ERRORA("no expected results in %d celliax_serial_read_FBUS2\n", CELLIAX_P_LOG,
4377 how_many_reads);
4378 return -1;
4379 }
4380 }
4381
4382 MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4383 MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4384 MsgBuffer[2] = FBUS2_SECURIY_IMEI_COMMANDS;
4385 MsgBuffer[3] = FBUS2_SECURIY_IMEI_COMMAND_GET;
4386 MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4387 MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4388 if (option_debug > 1)
4389 DEBUGA_FBUS2("celliax_serial_get_IMEI_init_FBUS2, outseqnum %.2X \n", CELLIAX_P_LOG,
4390 MsgBuffer[5]);
4391 celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4392 res = celliax_serial_read_FBUS2(p); //we don't have no monitor neither do_controldev_thread
4393 if (res == -1) {
4394 ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4395 return -1;
4396 }
4397 how_many_reads = 0;
4398 while (res != MsgBuffer[5] && res != CALLFLOW_GOT_IMEI) {
4399 usleep(1000);
4400 res = celliax_serial_read_FBUS2(p);
4401 how_many_reads++;
4402 if (res == -1) {
4403 ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4404 return -1;
4405 }
4406 if (how_many_reads > 10) {
4407 ERRORA("no expected results in %d celliax_serial_read_FBUS2\n", CELLIAX_P_LOG,
4408 how_many_reads);
4409 //FIXME return -1;
4410 return 0;
4411 }
4412 }
4413
4414 if (option_debug > 1)
4415 DEBUGA_FBUS2("xxxxx GOT IMEI xxxxx res=%d %.2X \n", CELLIAX_P_LOG, res, res);
4416
4417 return 0;
4418 }
4419
celliax_serial_get_seqnum_FBUS2(struct celliax_pvt * p)4420 int celliax_serial_get_seqnum_FBUS2(struct celliax_pvt *p)
4421 {
4422 if (p->seqnumfbus > FBUS2_SEQNUM_MAX || p->seqnumfbus < FBUS2_SEQNUM_MIN) {
4423 ERRORA("p->seqnumfbus: %2.X\n", CELLIAX_P_LOG, p->seqnumfbus);
4424 p->seqnumfbus = FBUS2_SEQNUM_MIN;
4425 }
4426
4427 if (p->seqnumfbus == FBUS2_SEQNUM_MAX) {
4428 p->seqnumfbus = FBUS2_SEQNUM_MIN;
4429 } else {
4430 p->seqnumfbus++;
4431 }
4432 if (option_debug > 10)
4433 DEBUGA_FBUS2("sqnum: %2.X\n", CELLIAX_P_LOG, p->seqnumfbus);
4434 return p->seqnumfbus;
4435 }
4436
celliax_serial_security_command_FBUS2(struct celliax_pvt * p)4437 int celliax_serial_security_command_FBUS2(struct celliax_pvt *p)
4438 {
4439 unsigned char MsgBuffer[6];
4440
4441 MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4442 MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4443 MsgBuffer[2] = FBUS2_SECURIY_EXTENDED_COMMANDS;
4444 MsgBuffer[3] = FBUS2_SECURIY_EXTENDED_COMMAND_ON;
4445 MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4446 MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4447
4448 if (option_debug > 1)
4449 DEBUGA_FBUS2("activating security commands, outseqnum %.2X \n", CELLIAX_P_LOG,
4450 MsgBuffer[5]);
4451 celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4452 return 0;
4453 }
4454
4455 /*!
4456 * \brief Write on the serial port for all the FBUS2 (old Nokia) functions
4457 * \param p celliax_pvt
4458 * \param len lenght of buffer2
4459 * \param buffer2 chars to be written
4460 *
4461 * Write on the serial port for all the FBUS2 (old Nokia) functions
4462 *
4463 * \return the number of chars written on the serial,
4464 * that can be different from len (or negative) in case of errors.
4465 */
celliax_serial_send_FBUS2(struct celliax_pvt * p,int len,unsigned char * mesg_ptr)4466 int celliax_serial_send_FBUS2(struct celliax_pvt *p, int len, unsigned char *mesg_ptr)
4467 {
4468 int ret;
4469 size_t actual = 0;
4470 unsigned char *mesg_ptr2 = mesg_ptr;
4471 PUSHA_UNLOCKA(&p->controldev_lock);
4472 LOKKA(&p->controldev_lock);
4473 do {
4474 ret = write(p->controldevfd, mesg_ptr, len - actual);
4475 if (ret < 0 && errno == EAGAIN)
4476 continue;
4477 if (ret < 0) {
4478 if (actual != len)
4479 ERRORA("celliax_serial_write error: %s", CELLIAX_P_LOG, strerror(errno));
4480 UNLOCKA(&p->controldev_lock);
4481 return -1;
4482 }
4483 actual += ret;
4484 mesg_ptr += ret;
4485 usleep(10000);
4486 } while (actual < len);
4487
4488 UNLOCKA(&p->controldev_lock);
4489 POPPA_UNLOCKA(&p->controldev_lock);
4490 if (option_debug > 10) {
4491 int i;
4492 char debug_buf[1024];
4493 char *debug_buf_pos;
4494
4495 memset(debug_buf, 0, 1024);
4496 debug_buf_pos = debug_buf;
4497
4498 for (i = 0; i < len; i++) {
4499 debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", mesg_ptr2[i]);
4500 if (debug_buf_pos > ((char *) &debug_buf + 1000))
4501 break;
4502 }
4503 DEBUGA_FBUS2("%s was sent down the wire\n", CELLIAX_P_LOG, debug_buf);
4504 }
4505
4506 return 0;
4507 }
4508
4509 /*!
4510 * \brief Flags as acknowledged an FBUS2 message previously sent
4511 * \param p celliax_pvt
4512 * \param seqnum identifier of the message to be acknowledged
4513 *
4514 * Called upon receiving an FBUS2 acknoledgement message, browse the fbus2_outgoing_list
4515 * looking for the seqnum sent FBUS2 message, and flags it as acknowledged.
4516 * (if an outgoing FBUS2 message is not aknowledged by the cellphone in a while,
4517 * it will be retransmitted)
4518 *
4519 * \return 0 on error, 1 otherwise
4520 */
celliax_serial_list_acknowledge_FBUS2(struct celliax_pvt * p,int seqnum)4521 int celliax_serial_list_acknowledge_FBUS2(struct celliax_pvt *p, int seqnum)
4522 {
4523 struct fbus2_msg *ptr;
4524
4525 ptr = p->fbus2_outgoing_list;
4526 if (ptr == NULL) {
4527 ERRORA("fbus2_outgoing_list is NULL ?\n", CELLIAX_P_LOG);
4528 return -1;
4529 }
4530 PUSHA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4531 LOKKA(&p->fbus2_outgoing_list_lock);
4532 while (ptr->next != NULL)
4533 ptr = ptr->next;
4534 while (ptr->acknowledged == 0) {
4535 if (ptr->seqnum == seqnum) {
4536 ptr->acknowledged = 1;
4537 if (option_debug > 1)
4538 DEBUGA_FBUS2("Acknowledgment to %.2X\n", CELLIAX_P_LOG, seqnum);
4539
4540 DEBUGA_FBUS2("PREFREE OUTGOING list:\n", CELLIAX_P_LOG);
4541 celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4542 if (ptr->previous) {
4543 if (ptr->next) {
4544 ptr->previous->next = ptr->next;
4545 } else {
4546 ptr->previous->next = NULL;
4547 }
4548 }
4549 if (ptr->next) {
4550 if (ptr->previous) {
4551 ptr->next->previous = ptr->previous;
4552 } else {
4553 ptr->next->previous = NULL;
4554 }
4555 }
4556
4557 if ((NULL == ptr->next) && (NULL == ptr->previous)) { /* bug catched by Wojciech Andralojc */
4558 if (option_debug > 1)
4559 DEBUGA_FBUS2("FREEING LAST\n", CELLIAX_P_LOG);
4560 p->fbus2_outgoing_list = NULL;
4561 p->fbus2_outgoing_list = celliax_serial_list_init_FBUS2(p);
4562 }
4563
4564 free(ptr);
4565 DEBUGA_FBUS2("POSTFREE OUTGOING list:\n", CELLIAX_P_LOG);
4566 celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4567
4568 break;
4569 }
4570 if (ptr->previous != NULL) {
4571 ptr = ptr->previous;
4572 } else {
4573 ERRORA
4574 ("The phone sent us an acknowledgement referring to a msg with a seqnum that is not in our sent list: %.2X\n",
4575 CELLIAX_P_LOG, seqnum);
4576 break;
4577 }
4578 }
4579 UNLOCKA(&p->fbus2_outgoing_list_lock);
4580 POPPA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4581 return 0;
4582 }
4583
4584 /*!
4585 * \brief Sends an FBUS2 message or resends it if it was not acknowledged
4586 * \param p celliax_pvt
4587 *
4588 * Called by celliax_serial_read_FBUS2, browse the fbus2_outgoing_list looking for FBUS2 messages to be sent,
4589 * or for FBUS2 messages previously sent but not yet acknoledged.
4590 * (if an outgoing FBUS2 message is not aknowledged by the cellphone in a while,
4591 * it will be retransmitted)
4592 *
4593 * \return 0 on error, 1 otherwise
4594 */
celliax_serial_send_if_time_FBUS2(struct celliax_pvt * p)4595 int celliax_serial_send_if_time_FBUS2(struct celliax_pvt *p)
4596 {
4597 struct fbus2_msg *ptr;
4598 struct timeval tv;
4599 struct timezone tz;
4600
4601 gettimeofday(&tv, &tz);
4602 ptr = p->fbus2_outgoing_list;
4603 if (ptr == NULL) {
4604 ERRORA("fbus2_outgoing_list is NULL ?\n", CELLIAX_P_LOG);
4605 return -1;
4606 }
4607 while (ptr->next != NULL) {
4608 WARNINGA("fbus2_outgoing_list->next is not null ?\n", CELLIAX_P_LOG);
4609 ptr = ptr->next; //FIXME what to do?
4610 }
4611 while (ptr->sent == 0 && ptr->acknowledged == 0) {
4612 if (ptr->previous != NULL) {
4613 ptr = ptr->previous;
4614 } else
4615 break;
4616 }
4617 while (ptr->sent == 1 && ptr->acknowledged == 0) {
4618 if (ptr->previous != NULL) {
4619 ptr = ptr->previous;
4620 } else
4621 break;
4622 }
4623 if (ptr->sent == 1 && ptr->acknowledged == 1) {
4624 if (ptr->next != NULL) {
4625 ptr = ptr->next;
4626 }
4627 }
4628 if (ptr->sent == 1 && ptr->acknowledged == 0 && ptr->msg > 0) {
4629 if ((tv.tv_sec * 1000 + tv.tv_usec / 1000) >
4630 ((ptr->tv_sec * 1000 + ptr->tv_usec / 1000) + 1000)) {
4631
4632 PUSHA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4633 LOKKA(&p->fbus2_outgoing_list_lock);
4634
4635 if (ptr->sent == 1 && ptr->acknowledged == 0 && ptr->msg > 0) { //retest, maybe has been changed?
4636 if ((tv.tv_sec * 1000 + tv.tv_usec / 1000) > ((ptr->tv_sec * 1000 + ptr->tv_usec / 1000) + 1000)) { //retest, maybe has been changed?
4637
4638 if (option_debug > 1)
4639 DEBUGA_FBUS2("RESEND %.2X, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
4640 ptr->seqnum,
4641 ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
4642 (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)),
4643 ptr->how_many_sent);
4644 if (ptr->how_many_sent > 9) {
4645 ERRORA("RESEND %.2X, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
4646 ptr->seqnum,
4647 ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
4648 (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)), ptr->how_many_sent);
4649
4650 UNLOCKA(&p->fbus2_outgoing_list_lock);
4651 return -1;
4652 }
4653
4654 celliax_serial_send_FBUS2(p, ptr->len, ptr->buffer);
4655 if (ptr->buffer[3] == FBUS2_ACK_BYTE) {
4656 if (option_debug > 1)
4657 DEBUGA_FBUS2("RESEND ACK, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
4658 ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
4659 (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)),
4660 ptr->how_many_sent);
4661 ptr->acknowledged = 1;
4662 ptr->msg = FBUS2_OUTGOING_ACK;
4663 }
4664 ptr->tv_sec = tv.tv_sec;
4665 ptr->tv_usec = tv.tv_usec;
4666 ptr->sent = 1;
4667 ptr->how_many_sent++;
4668 if (option_debug > 1) {
4669 DEBUGA_FBUS2("OUTGOING list:\n", CELLIAX_P_LOG);
4670 celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4671 DEBUGA_FBUS2("OUTGOING list END\n", CELLIAX_P_LOG);
4672 }
4673
4674 }
4675 }
4676
4677 UNLOCKA(&p->fbus2_outgoing_list_lock);
4678 POPPA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4679 }
4680 }
4681 if (ptr->sent == 0 && ptr->acknowledged == 0 && ptr->msg > 0) {
4682
4683 PUSHA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4684 LOKKA(&p->fbus2_outgoing_list_lock);
4685
4686 if (ptr->sent == 0 && ptr->acknowledged == 0 && ptr->msg > 0) { //retest, maybe has been changed?
4687
4688 if (option_debug > 1)
4689 DEBUGA_FBUS2("SENDING 1st TIME %.2X\n", CELLIAX_P_LOG, ptr->seqnum);
4690 celliax_serial_send_FBUS2(p, ptr->len, ptr->buffer);
4691 if (ptr->buffer[3] == FBUS2_ACK_BYTE) {
4692 if (option_debug > 1)
4693 DEBUGA_FBUS2("SENDING 1st TIME ACK\n", CELLIAX_P_LOG);
4694 ptr->acknowledged = 1;
4695 ptr->msg = FBUS2_OUTGOING_ACK;
4696 }
4697 ptr->tv_sec = tv.tv_sec;
4698 ptr->tv_usec = tv.tv_usec;
4699 ptr->sent = 1;
4700 ptr->how_many_sent++;
4701 if (option_debug > 1) {
4702 DEBUGA_FBUS2("OUTGOING list:\n", CELLIAX_P_LOG);
4703 celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4704 DEBUGA_FBUS2("OUTGOING list END\n", CELLIAX_P_LOG);
4705 }
4706
4707 }
4708
4709 UNLOCKA(&p->fbus2_outgoing_list_lock);
4710 POPPA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4711
4712 }
4713 return 0;
4714 }
4715
celliax_serial_write_FBUS2(struct celliax_pvt * p,unsigned char * MsgBuffer,int MsgLength,unsigned char MsgType)4716 int celliax_serial_write_FBUS2(struct celliax_pvt *p, unsigned char *MsgBuffer,
4717 int MsgLength, unsigned char MsgType)
4718 {
4719 unsigned char buffer2[FBUS2_MAX_TRANSMIT_LENGTH + 10];
4720 unsigned char checksum = 0;
4721 int i, len;
4722 struct timeval tv;
4723 struct timezone tz;
4724
4725 buffer2[0] = FBUS2_SERIAL_FRAME_ID;
4726 buffer2[1] = FBUS2_DEVICE_PHONE; /* destination */
4727 buffer2[2] = FBUS2_DEVICE_PC; /* source */
4728 buffer2[3] = MsgType;
4729 buffer2[4] = 0x00; /* required by protocol */
4730 buffer2[5] = MsgLength;
4731
4732 memcpy(buffer2 + 6, MsgBuffer, MsgLength);
4733 len = MsgLength + 6;
4734
4735 /* Odd messages require additional padding 0x00 byte */
4736 if (MsgLength % 2)
4737 buffer2[len++] = 0x00; /* optional PaddingByte */
4738
4739 checksum = 0;
4740 for (i = 0; i < len; i += 2)
4741 checksum ^= buffer2[i];
4742 buffer2[len++] = checksum; /* ChkSum1 */
4743
4744 checksum = 0;
4745 for (i = 1; i < len; i += 2)
4746 checksum ^= buffer2[i];
4747 buffer2[len++] = checksum; /* ChkSum2 */
4748
4749 if (option_debug > 10) {
4750 int i;
4751 char debug_buf[1024];
4752 char *debug_buf_pos;
4753
4754 memset(debug_buf, 0, 1024);
4755 debug_buf_pos = debug_buf;
4756
4757 for (i = 0; i < len; i++) {
4758 debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", buffer2[i]);
4759 if (debug_buf_pos > (char *) (&debug_buf + 1000))
4760 break;
4761 }
4762 if (buffer2[3] == FBUS2_ACK_BYTE) {
4763 DEBUGA_FBUS2("%s to be written, ACK\n", CELLIAX_P_LOG, debug_buf);
4764 } else {
4765 DEBUGA_FBUS2("%s to be written\n", CELLIAX_P_LOG, debug_buf);
4766 }
4767 }
4768
4769 gettimeofday(&tv, &tz);
4770
4771 if (buffer2[3] != FBUS2_ACK_BYTE) {
4772 p->fbus2_outgoing_list = celliax_serial_list_init_FBUS2(p);
4773 p->fbus2_outgoing_list->msg = 11;
4774
4775 p->fbus2_outgoing_list->len = len;
4776 for (i = 0; i < len; i++) {
4777 p->fbus2_outgoing_list->buffer[i] = buffer2[i];
4778 }
4779 p->fbus2_outgoing_list->seqnum = MsgBuffer[MsgLength - 1];
4780 if (option_debug > 1) {
4781 DEBUGA_FBUS2("OUTGOING LIST seqnum is %2.X\n", CELLIAX_P_LOG,
4782 MsgBuffer[MsgLength - 1]);
4783
4784 DEBUGA_FBUS2("OUTGOING list:\n", CELLIAX_P_LOG);
4785 celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4786 DEBUGA_FBUS2("OUTGOING list END\n", CELLIAX_P_LOG);
4787 }
4788 } else {
4789 usleep(100);
4790 celliax_serial_send_FBUS2(p, len, buffer2);
4791 }
4792
4793 return 0;
4794 }
4795
celliax_serial_send_ack_FBUS2(struct celliax_pvt * p,unsigned char MsgType,unsigned char MsgSequence)4796 int celliax_serial_send_ack_FBUS2(struct celliax_pvt *p, unsigned char MsgType,
4797 unsigned char MsgSequence)
4798 {
4799 unsigned char buffer2[2];
4800
4801 buffer2[0] = MsgType;
4802 buffer2[1] = (MsgSequence - FBUS2_SEQNUM_MIN);
4803
4804 if (option_debug > 1)
4805 DEBUGA_FBUS2("SENDING ACK to %2.X, seqack %2.X \n", CELLIAX_P_LOG, MsgSequence,
4806 (MsgSequence - FBUS2_SEQNUM_MIN));
4807 /* Sending to phone */
4808 return celliax_serial_write_FBUS2(p, buffer2, 2, FBUS2_ACK_BYTE);
4809 }
4810
celliax_serial_list_init_FBUS2(struct celliax_pvt * p)4811 struct fbus2_msg *celliax_serial_list_init_FBUS2(struct celliax_pvt *p)
4812 {
4813 struct fbus2_msg *list;
4814 list = p->fbus2_outgoing_list;
4815
4816 PUSHA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4817 LOKKA(&p->fbus2_outgoing_list_lock);
4818 if (list == NULL) {
4819 list = malloc(sizeof(*(list)));
4820 list->msg = 0;
4821 list->seqnum = 0;
4822 list->len = 0;
4823 list->acknowledged = 0;
4824 list->how_many_sent = 0;
4825 list->sent = 0;
4826 list->tv_sec = 0;
4827 list->tv_usec = 0;
4828 list->next = NULL;
4829 list->previous = NULL;
4830 }
4831 if (list->msg != 0) {
4832 struct fbus2_msg *new;
4833 new = malloc(sizeof(*new));
4834 new->msg = 0;
4835 new->seqnum = 0;
4836 new->len = 0;
4837 new->acknowledged = 0;
4838 new->how_many_sent = 0;
4839 new->sent = 0;
4840 new->tv_sec = 0;
4841 new->tv_usec = 0;
4842 new->next = NULL;
4843 new->previous = list;
4844 list->next = new;
4845 list = new;
4846 }
4847 UNLOCKA(&p->fbus2_outgoing_list_lock);
4848 POPPA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4849 return list;
4850 }
4851
celliax_serial_list_print_FBUS2(struct celliax_pvt * p,struct fbus2_msg * list)4852 int celliax_serial_list_print_FBUS2(struct celliax_pvt *p, struct fbus2_msg *list)
4853 {
4854 struct fbus2_msg *ptr;
4855 ptr = list;
4856 while (ptr) {
4857 if (option_debug > 3)
4858 DEBUGA_FBUS2
4859 ("PTR msg is: %d, seqnum is %.2X, tv_sec is %d, tv_usec is %d, acknowledged is: %d,"
4860 " sent is:%d, how_many_sent is: %d\n", CELLIAX_P_LOG, ptr->msg, ptr->seqnum,
4861 ptr->tv_sec, ptr->tv_usec, ptr->acknowledged, ptr->sent, ptr->how_many_sent);
4862 ptr = ptr->previous;
4863 }
4864 return 0;
4865 }
4866
celliax_serial_read_FBUS2(struct celliax_pvt * p)4867 int celliax_serial_read_FBUS2(struct celliax_pvt *p)
4868 {
4869 int read_count;
4870 int select_err;
4871 fd_set read_fds;
4872 struct timeval timeout;
4873 int fbus_mesg = 0;
4874 int i;
4875
4876 FD_ZERO(&read_fds);
4877 FD_SET(p->controldevfd, &read_fds);
4878 timeout.tv_sec = 0;
4879 timeout.tv_usec = 50000;
4880
4881 if ((select_err = select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
4882 timeout.tv_sec = 0; //reset the timeout, linux modify it
4883 timeout.tv_usec = 50000; //reset the timeout, linux modify it
4884 PUSHA_UNLOCKA(&p->controldev_lock);
4885 LOKKA(&p->controldev_lock);
4886 while ((select_err =
4887 select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
4888 gettimeofday(&p->fbus2_list_tv, &p->fbus2_list_tz);
4889 read_count = read(p->controldevfd, p->rxm, 255);
4890
4891 if (read_count == 0) {
4892 ERRORA
4893 ("read 0 bytes!!! Nenormalno! Marking this celliax_serial_device %s as dead, andif it is owned by a channel, hanging up. Maybe the phone is stuck, switched off, power down or battery exhausted\n",
4894 CELLIAX_P_LOG, p->controldevice_name);
4895 p->controldev_dead = 1;
4896 close(p->controldevfd);
4897 UNLOCKA(&p->controldev_lock);
4898 if (p->owner) {
4899 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
4900 p->owner->hangupcause = AST_CAUSE_FAILURE;
4901 }
4902 return -1;
4903 }
4904 if (option_debug > 10) {
4905 int c;
4906 char debug_buf[1024];
4907 char *debug_buf_pos;
4908
4909 memset(debug_buf, 0, 1024);
4910 debug_buf_pos = debug_buf;
4911 for (c = 0; c < read_count; c++) {
4912 debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", p->rxm[c]);
4913 if (debug_buf_pos > (char *) (&debug_buf + 1000))
4914 break;
4915 }
4916 DEBUGA_FBUS2("%s READ AT seconds=%ld usec=%6ld read_count=%d\n", CELLIAX_P_LOG,
4917 debug_buf, p->fbus2_list_tv.tv_sec, p->fbus2_list_tv.tv_usec,
4918 read_count);
4919 }
4920
4921 for (i = 0; i < read_count; i++) {
4922 if (p->rxm[i] == FBUS2_DEVICE_PHONE && p->rxm[i - 1] == FBUS2_DEVICE_PC
4923 && p->rxm[i - 2] == FBUS2_SERIAL_FRAME_ID) {
4924 /* if we have identified the start of an fbus2 frame sent to us by the phone */
4925 /* clean the array, copy into it the beginning of the frame, move the counter in the array after the last byte copied */
4926 memset(p->array, 0, 255);
4927 p->array[0] = FBUS2_SERIAL_FRAME_ID;
4928 p->array[1] = FBUS2_DEVICE_PC;
4929 p->arraycounter = 2;
4930 }
4931 if (p->rxm[i] == FBUS2_SERIAL_FRAME_ID && read_count == 1) { /* quick hack to try to identify the lone char
4932 at the beginning a frame, often returned by
4933 ark3116 based datacables */
4934 /* if we have identified the start of an fbus2 frame sent to us by the phone */
4935 /* clean the array, copy into it the beginning of the frame, move the counter in the array after the last byte copied */
4936 memset(p->array, 0, 255);
4937 p->arraycounter = 0;
4938 }
4939
4940 /* continue copying into the array, until... */
4941 p->array[p->arraycounter] = p->rxm[i];
4942 /* we reach the end of the incoming frame, its lenght is in the p->array[5] byte, plus overhead */
4943 if (p->arraycounter == p->array[5] + 7) {
4944 /* start categorizing frames */
4945 int seqnum;
4946 int known = 0;
4947
4948 /* ACK frames are always of lenght 10, without padding */
4949 seqnum = p->array[p->arraycounter - 2];
4950 /* first step in categorizing frames, look at the general kind of frame, in p->array[3] */
4951 switch (p->array[3]) {
4952 /****************************************************************/
4953 case FBUS2_ACK_BYTE:
4954 /* this is an ACKnowledgement frame sent to us in reply to an item we sent, take note we were ACKnowledged, no need to resend the item */
4955 if (option_debug > 1)
4956 DEBUGA_FBUS2("INCOMING ACK, seqack %.2X \n", CELLIAX_P_LOG, seqnum);
4957 if (seqnum == 0x80) { /* reset */
4958 seqnum = 0x00;
4959 DEBUGA_FBUS2
4960 ("seqack was 0x80, interpreting as 0x00, first acknowledgement (session begin?) of our first sent item 0x40\n",
4961 CELLIAX_P_LOG);
4962 }
4963 /* an ACK frame has the same seqnum as the item it acknowledge, minus 0x40, so here we obtain the seqnum of the item that has been ACKnowledged */
4964 fbus_mesg = seqnum + FBUS2_SEQNUM_MIN;
4965 /* take note that the item sent was ACKnowledged, so no need to resend it */
4966 celliax_serial_list_acknowledge_FBUS2(p, fbus_mesg);
4967 /* this frame has been categorized, bail out from the loop */
4968 known = 1;
4969 break;
4970 /****************************************************************/
4971 case FBUS2_TYPE_CALL_DIVERT:
4972 if (option_debug > 1)
4973 DEBUGA_FBUS2("CALL DIVERT SIGNALING seqnum %.2X \n", CELLIAX_P_LOG, seqnum);
4974 fbus_mesg = FBUS2_TYPE_CALL_DIVERT;
4975 /* this signal us that we have some settings in line divert, let's use it as activation of the line when we call */
4976 if (p->interface_state == AST_STATE_DIALING) {
4977 p->interface_state = AST_STATE_UP;
4978 p->phone_callflow = CALLFLOW_CALL_ACTIVE;
4979 ast_setstate(p->owner, AST_STATE_RINGING);
4980 celliax_queue_control(p->owner, AST_CONTROL_ANSWER);
4981 if (option_debug)
4982 DEBUGA_FBUS2
4983 ("call is active, I know it's not yet true, but 3310 do not give us remote answer signaling\n",
4984 CELLIAX_P_LOG);
4985 }
4986 /* this frame has been categorized, bail out from the loop */
4987 known = 1;
4988 break;
4989
4990 /****************************************************************/
4991 /* this kind of frames is an answer to "ask model" actions */
4992 case FBUS2_TYPE_MODEL_ANSWER:
4993 if (1) {
4994 int newline = 0;
4995 int c = i = 0;
4996 unsigned char model[10];
4997 for (i = 10; i < p->arraycounter; i++) {
4998 if (p->array[i] == '\n')
4999 newline++;
5000 if (newline == 2) {
5001 if (p->array[i] != '\n') {
5002 model[c] = p->array[i];
5003 c++;
5004 }
5005 }
5006 if (newline == 3) {
5007 break;
5008 }
5009 if (c == 9)
5010 break;
5011 }
5012 model[c] = '\0';
5013 DEBUGA_FBUS2("FBUS2 PHONE MODEL is: %s, inseqnum %.2X \n", CELLIAX_P_LOG,
5014 model, seqnum);
5015 }
5016 known = 1;
5017 fbus_mesg = FBUS2_TYPE_MODEL_ANSWER;
5018 break;
5019 /****************************************************************/
5020 /* this kind of frames is an answer to "security enabled" actions */
5021 case FBUS2_TYPE_SECURITY:
5022 switch (p->array[8]) {
5023 /* this subkind of frames is an answer to "security enabled" CALL actions */
5024 case FBUS2_SECURIY_CALL_COMMANDS:
5025 switch (p->array[9]) {
5026 /* this sub-subkind of frames tell us that we answered the call */
5027 case FBUS2_SECURIY_CALL_COMMAND_ANSWER:
5028 p->interface_state = AST_STATE_UP;
5029 p->phone_callflow = CALLFLOW_CALL_ACTIVE;
5030
5031 /* set the channel state to UP, we've answered */
5032 if (ast_setstate(p->owner, AST_STATE_UP)) {
5033 ERRORA("ast_setstate failed, BAD\n", CELLIAX_P_LOG);
5034 }
5035
5036 if (option_debug > 1)
5037 DEBUGA_FBUS2("ANSWERED CALL, inseqnum %.2X \n", CELLIAX_P_LOG, seqnum);
5038 known = 1;
5039 break;
5040 /* this sub-subkind of frames tell us that we released the call */
5041 case FBUS2_SECURIY_CALL_COMMAND_RELEASE:
5042 p->interface_state = AST_STATE_DOWN;
5043 p->phone_callflow = CALLFLOW_CALL_IDLE;
5044 if (option_debug > 1)
5045 DEBUGA_FBUS2("RELEASED CALL, inseqnum %.2X \n", CELLIAX_P_LOG, seqnum);
5046 fbus_mesg = CALLFLOW_CALL_RELEASED;
5047 known = 1;
5048 break;
5049 }
5050 break;
5051 /* this subkind of frames is an answer to "enable security commands" action */
5052 case FBUS2_SECURIY_EXTENDED_COMMANDS:
5053 if (option_debug > 1)
5054 DEBUGA_FBUS2("SECURITY EXTENDED COMMANDS ON, inseqnum %.2X \n",
5055 CELLIAX_P_LOG, seqnum);
5056 fbus_mesg = FBUS2_SECURIY_EXTENDED_COMMAND_ON;
5057 known = 1;
5058 break;
5059 /* this subkind of frames is an answer to "get IMEI" action */
5060 case FBUS2_SECURIY_IMEI_COMMANDS:
5061 if (option_debug > 1)
5062 DEBUGA_FBUS2("CALLFLOW_GOT_IMEI, inseqnum %.2X \n", CELLIAX_P_LOG,
5063 seqnum);
5064 fbus_mesg = CALLFLOW_GOT_IMEI;
5065 known = 1;
5066 break;
5067 }
5068 break;
5069 /****************************************************************/
5070 /* this kind of frames is about SMSs */
5071 case FBUS2_TYPE_SMS:
5072 switch (p->array[9]) {
5073 /* this subkind of frames is about an INCOMING SMS */
5074 case FBUS2_SMS_INCOMING:
5075 if (option_debug > 1)
5076 DEBUGA_FBUS2("SMS, inseqnum %.2X \n", CELLIAX_P_LOG, seqnum);
5077 known = 1;
5078 break;
5079 }
5080 break;
5081 /****************************************************************/
5082 /* this kind of frames is about PHONE CALLs */
5083 case FBUS2_TYPE_CALL:
5084 switch (p->array[9]) {
5085 int a;
5086 /* this subkind of frame is about the CALL has been HUNGUP */
5087 case FBUS2_CALL_HANGUP:
5088 p->interface_state = AST_STATE_DOWN;
5089 p->phone_callflow = CALLFLOW_CALL_IDLE;
5090 if (option_debug > 1)
5091 DEBUGA_FBUS2("REMOTE PARTY HANG UP, inseqnum %.2X \n", CELLIAX_P_LOG,
5092 seqnum);
5093 fbus_mesg = CALLFLOW_INCOMING_HANGUP;
5094 known = 1;
5095 break;
5096 /* this subkind of frame is about the remote CALLID (not signaled by 3310) */
5097 case FBUS2_CALL_CALLID:
5098 if (option_debug > 1)
5099 DEBUGA_FBUS2("CALLID, inseqnum %.2X \n", CELLIAX_P_LOG, seqnum);
5100 memset(p->callid_name, 0, sizeof(p->callid_name));
5101 memset(p->callid_number, 0, sizeof(p->callid_number));
5102 for (a = 0; a < p->array[12]; a++) {
5103 p->callid_number[a] = p->array[12 + a + 1];
5104 }
5105 for (a = 0; a < p->array[12 + 1 + p->array[12]] + 1; a++) {
5106 p->callid_name[a] = p->array[12 + 1 + a + p->array[12] + 1];
5107 }
5108 if (option_debug > 1)
5109 DEBUGA_FBUS2("CALLFLOW_INCOMING_CALLID: name is %s, number is %s\n",
5110 CELLIAX_P_LOG,
5111 p->callid_name[0] != 1 ? p->callid_name : "not available",
5112 p->callid_number[0] ? p->callid_number : "not available");
5113 fbus_mesg = CALLFLOW_INCOMING_CALLID;
5114 p->phone_callflow = CALLFLOW_INCOMING_RING;
5115 p->interface_state = AST_STATE_RING;
5116 known = 1;
5117 break;
5118 }
5119 break;
5120 /****************************************************************/
5121 /* this kind of frames is about NETWORK STATUS */
5122 case FBUS2_TYPE_NETWORK_STATUS:
5123 switch (p->array[9]) {
5124 /* this subkind of frames is NETWORK STATUS REGISTERED */
5125 case FBUS2_NETWORK_STATUS_REGISTERED:
5126 if (option_debug > 1)
5127 DEBUGA_FBUS2("NETWORK STATUS REGISTERED, inseqnum %.2X \n", CELLIAX_P_LOG,
5128 seqnum);
5129 if (p->callid_name[0] == 0 && p->owner
5130 && p->interface_state != AST_STATE_DOWN) {
5131 p->interface_state = AST_STATE_DOWN;
5132 p->phone_callflow = CALLFLOW_CALL_IDLE;
5133 if (option_debug)
5134 NOTICA("We think we are using a nokia3310, so NETWORK STATUS REGISTERED"
5135 " is interpreted as REMOTE PARTY HANG UP during a call, because"
5136 " Nokia 3310 give no hint about remote hangup. Nokia 3310"
5137 " does not signal the CALLID, while other nokias at least put"
5138 " callid_name[0]=1 (also if no callid was transmitted by remote"
5139 " party), we use this lack of CALLID as a sign of 3310nness."
5140 " Outside a call, or when CALLID has been signaled, NETWORK STATUS"
5141 " REGISTERED is ignored.\n", CELLIAX_P_LOG);
5142 fbus_mesg = CALLFLOW_INCOMING_HANGUP;
5143 }
5144 known = 1;
5145 break;
5146 }
5147 break;
5148 /****************************************************************/
5149 /* this kind of frames is about CALL STATUS */
5150 case FBUS2_TYPE_CALL_STATUS:
5151 switch (p->array[12]) {
5152 /* this subkind of frames is about CALL STATUS OFF */
5153 case FBUS2_CALL_STATUS_OFF:
5154 p->interface_state = AST_STATE_DOWN;
5155 p->phone_callflow = CALLFLOW_CALL_IDLE;
5156 if (option_debug > 1)
5157 DEBUGA_FBUS2("STATUS call in progress OFF, inseqnum %.2X \n",
5158 CELLIAX_P_LOG, seqnum);
5159 fbus_mesg = CALLFLOW_INCOMING_HANGUP;
5160 known = 1;
5161 break;
5162 /* this subkind of frames is about CALL STATUS ON */
5163 case FBUS2_CALL_STATUS_ON:
5164 if (option_debug > 1)
5165 DEBUGA_FBUS2("STATUS call in progress ON, inseqnum %.2X \n",
5166 CELLIAX_P_LOG, seqnum);
5167 known = 1;
5168 break;
5169 }
5170 /****************************************************************/
5171 break;
5172 }
5173
5174 /* categorization of frame is ended, if it has not been recognized, whine */
5175 if (!known) {
5176 WARNINGA("FBUS2 MSG UNKNOWN, inseqnum %.2X\n", CELLIAX_P_LOG, seqnum);
5177 }
5178
5179 /* let's print our frame */
5180 if (option_debug > 1) {
5181 int i;
5182 char debug_buf[1024];
5183 char *debug_buf_pos;
5184
5185 memset(debug_buf, 0, 1024);
5186 debug_buf_pos = debug_buf;
5187 for (i = 0; i < p->arraycounter + 1; i++) {
5188 debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", p->array[i]);
5189 if (debug_buf_pos > (char *) (&debug_buf + 1000))
5190 break;
5191 }
5192 DEBUGA_FBUS2("%s is the RECEIVED FRAME inseqnum %.2X\n", CELLIAX_P_LOG,
5193 debug_buf, seqnum);
5194 }
5195
5196 /* if the frame we received is not an ACK frame, let's ACKnowledge it */
5197 if (p->array[0] == FBUS2_SERIAL_FRAME_ID && p->array[3] != FBUS2_ACK_BYTE) {
5198 celliax_serial_send_ack_FBUS2(p, p->array[3], seqnum);
5199 }
5200 }
5201 p->arraycounter++;
5202 }
5203 }
5204 UNLOCKA(&p->controldev_lock);
5205 POPPA_UNLOCKA(&p->controldev_lock);
5206 }
5207 /* oooops, select returned error, got a kill/cancel or problems with the serial file descriptor */
5208 if (select_err == -1) {
5209 if (errno != EINTR) {
5210 ERRORA
5211 ("select returned -1 on %s, marking controldev as dead, errno was: %d, error was: %s\n",
5212 CELLIAX_P_LOG, p->controldevice_name, errno, strerror(errno));
5213 p->controldev_dead = 1;
5214 close(p->controldevfd);
5215 if (p->owner)
5216 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
5217 return -1;
5218 } else {
5219 WARNINGA("select returned -1 on %s, errno was: %d, EINTR, error was: %s\n",
5220 CELLIAX_P_LOG, p->controldevice_name, errno, strerror(errno));
5221 return 0;
5222 }
5223 }
5224 /* OK, reading done, let's browse the list of pending frames to be sent, and act on it */
5225 if (celliax_serial_send_if_time_FBUS2(p)) {
5226 ERRORA("celliax_serial_send_if_time_FBUS2 failed!\n", CELLIAX_P_LOG);
5227 return -1;
5228 }
5229
5230 if (fbus_mesg == CALLFLOW_INCOMING_HANGUP) {
5231 if (p->owner) {
5232 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
5233 DEBUGA_FBUS2("phone call ended\n", CELLIAX_P_LOG);
5234 }
5235 }
5236
5237 return fbus_mesg; //FIXME breaks the convention of returning 0 on success
5238 }
5239
5240 #endif /* CELLIAX_FBUS2 */
5241
5242 #ifdef CELLIAX_CVM
5243
celliax_serial_sync_CVM_BUSMAIL(struct celliax_pvt * p)5244 int celliax_serial_sync_CVM_BUSMAIL(struct celliax_pvt *p)
5245 {
5246 usleep(1000); /* 1msec */
5247 time(&p->celliax_serial_synced_timestamp);
5248 return 0;
5249 }
5250
celliax_serial_answer_CVM_BUSMAIL(struct celliax_pvt * p)5251 int celliax_serial_answer_CVM_BUSMAIL(struct celliax_pvt *p)
5252 {
5253 if (AST_STATE_RING == p->interface_state) {
5254 DEBUGA_CVM("Sending commands to answer an incomming call...\n", CELLIAX_P_LOG);
5255 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_CONNECT_REQ, 0, NULL);
5256
5257 } else {
5258 DEBUGA_CVM
5259 ("SKIPPING Sending commands to answer an incomming call, because: !AST_STATE_RING\n",
5260 CELLIAX_P_LOG);
5261 }
5262
5263 return 0;
5264 }
5265
celliax_serial_call_CVM_BUSMAIL(struct celliax_pvt * p,char * dstr)5266 int celliax_serial_call_CVM_BUSMAIL(struct celliax_pvt *p, char *dstr)
5267 {
5268 unsigned char bCallType = 0x01; /* INTERNAL */
5269
5270 unsigned char DialReqBuff[2];
5271
5272 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_SETUP_REQ, sizeof(bCallType),
5273 &bCallType);
5274
5275 while (AST_STATE_DOWN == p->interface_state) {
5276 usleep(10000); //10msec
5277 }
5278
5279 if (AST_STATE_DIALING == p->interface_state) {
5280 /* as for now, we only support internal calls */
5281 /* "0" - call speaker phone */
5282 /* "1" - call handset #1 */
5283 /* "2" - call handset #2 */
5284 /* ... */
5285
5286 DialReqBuff[0] = 1; /* number of digits to send */
5287 DialReqBuff[1] = dstr[0]; /* digit to send */
5288
5289 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_KEYPAD_REQ, 2, DialReqBuff);
5290 }
5291
5292 if (option_debug)
5293 NOTICA("CVM_BUSMAIL: sent commands to call\n", CELLIAX_P_LOG);
5294 return 0;
5295 }
5296
celliax_serial_hangup_CVM_BUSMAIL(struct celliax_pvt * p)5297 int celliax_serial_hangup_CVM_BUSMAIL(struct celliax_pvt *p)
5298 {
5299 unsigned char bReason = 0x0; /* Normal hang-up */
5300
5301 if (p->interface_state != AST_STATE_DOWN) {
5302 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_RELEASE_REQ, sizeof(bReason),
5303 &bReason);
5304
5305 DEBUGA_CVM("CVM_BUSMAIL: sent commands to hangup the call\n", CELLIAX_P_LOG);
5306
5307 } else {
5308 DEBUGA_CVM("CVM_BUSMAIL: sent commands to hangup skipped because: AST_STATE_DOWN\n",
5309 CELLIAX_P_LOG);
5310 }
5311
5312 return 0;
5313 }
5314
celliax_serial_config_CVM_BUSMAIL(struct celliax_pvt * p)5315 int celliax_serial_config_CVM_BUSMAIL(struct celliax_pvt *p)
5316 {
5317 int res;
5318 int how_many_reads = 0;
5319 unsigned char SubcriptionNo = p->cvm_subsc_no;
5320 unsigned char RegistartionData[5];
5321
5322 p->cvm_lock_state = CVM_UNKNOWN_LOCK_STATE;
5323 p->cvm_register_state = CVM_UNKNOWN_REGISTER_STATE;
5324
5325 PUSHA_UNLOCKA(&p->controldev_lock);
5326 CVM_LOKKA(&p->controldev_lock);
5327
5328 if (option_debug > 1)
5329 DEBUGA_CVM("Try to init communication with CVM...\n", CELLIAX_P_LOG);
5330
5331 /* CVM after reset sends SABM CTRL frame, let's assume that CVM already sent it, that's the reply... */
5332 celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p,
5333 BUSMAIL_HEADER_CTRL_FRAME |
5334 BUSMAIL_HEADER_CTRL_UN_FRAME |
5335 BUSMAIL_HEADER_UNID_SABM);
5336 /* usleep(10000); *//* 10ms */
5337
5338 /* Now we are sending SABM CTRL frame, if CVM is out there, it should reply... */
5339 celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p,
5340 BUSMAIL_HEADER_CTRL_FRAME |
5341 BUSMAIL_HEADER_CTRL_UN_FRAME |
5342 BUSMAIL_HEADER_UNID_SABM |
5343 (BUSMAIL_HEADER_PF_BIT_MASK & 0xFF));
5344 // usleep(1000);
5345
5346 res = celliax_serial_read_CVM_BUSMAIL(p); //we don't have no monitor neither do_controldev_thread
5347
5348 DEBUGA_CVM("celliax_serial_read_CVM_BUSMAIL res= %X, expected %X\n", CELLIAX_P_LOG, res,
5349 (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_UN_FRAME |
5350 BUSMAIL_HEADER_SABM));
5351
5352 if (res == -1) {
5353 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5354 CVM_UNLOCKA(&p->controldev_lock);
5355 return -1;
5356 }
5357
5358 how_many_reads = 0;
5359
5360 while ((res & 0xF0) !=
5361 (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_UN_FRAME | BUSMAIL_HEADER_SABM))
5362 {
5363
5364 usleep(1000);
5365 res = celliax_serial_read_CVM_BUSMAIL(p);
5366 how_many_reads++;
5367
5368 if (res == -1) {
5369 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5370 CVM_UNLOCKA(&p->controldev_lock);
5371 return -1;
5372 }
5373
5374 if (how_many_reads > 10) {
5375 ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG,
5376 how_many_reads);
5377
5378 ERRORA("Unable to initialize cmmunication with CVM...\n", CELLIAX_P_LOG);
5379
5380 CVM_UNLOCKA(&p->controldev_lock);
5381 return -1;
5382 }
5383 }
5384
5385 DEBUGA_CVM("Communication with CVM initialized successfully...\n", CELLIAX_P_LOG);
5386
5387 DEBUGA_CVM("Attempt to lock to FP...\n", CELLIAX_P_LOG);
5388
5389 /* Try to connect to FP, try to lock to FP, maybe we registered with it in the past... */
5390 /* CVM can hold up to 2 subscriptions in its EEPROM, celliax.conf contains number we should try */
5391 /* eg. cvm_subscription_no = 1 */
5392
5393 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_LOCK_REQ, sizeof(SubcriptionNo),
5394 &SubcriptionNo);
5395
5396 usleep(10000);
5397
5398 res = celliax_serial_read_CVM_BUSMAIL(p); //we don't have no monitor neither do_controldev_thread
5399
5400 if (res == -1) {
5401 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5402 CVM_UNLOCKA(&p->controldev_lock);
5403 return -1;
5404 }
5405
5406 how_many_reads = 0;
5407
5408 while (CVM_UNKNOWN_LOCK_STATE == p->cvm_lock_state) {
5409
5410 /*
5411 if (0 == (how_many_reads % 10))
5412 {
5413 DEBUGA_CVM("Attempt to lock to FP... %d\n", CELLIAX_P_LOG, how_many_reads/10 );
5414 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_LOCK_REQ, sizeof(SubcriptionNo) ,&SubcriptionNo);
5415 }
5416 */
5417
5418 usleep(100000);
5419
5420 res = celliax_serial_read_CVM_BUSMAIL(p);
5421 how_many_reads++;
5422
5423 if (res == -1) {
5424 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5425 CVM_UNLOCKA(&p->controldev_lock);
5426 return -1;
5427 }
5428
5429 if (how_many_reads > 50) {
5430 ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG,
5431 how_many_reads);
5432
5433 ERRORA("Unable to lock to FP...\n", CELLIAX_P_LOG);
5434 break;
5435 }
5436 }
5437
5438 if (CVM_LOCKED_TO_FP == p->cvm_lock_state) {
5439 DEBUGA_CVM("CVM locked to FP successfully...\n", CELLIAX_P_LOG);
5440 } else {
5441 DEBUGA_CVM("Lock to FP failed, Attempt to register to FP...\n", CELLIAX_P_LOG);
5442
5443 RegistartionData[0] = SubcriptionNo;
5444 RegistartionData[1] = 0xFF;
5445 RegistartionData[2] = 0xFF;
5446
5447 if (1 == SubcriptionNo) {
5448 RegistartionData[3] =
5449 (((p->cvm_subsc_1_pin[3] - 0x30) & 0x0F) << 4) | ((p->cvm_subsc_1_pin[2] -
5450 0x30) & 0x0F);
5451 RegistartionData[4] =
5452 (((p->cvm_subsc_1_pin[1] - 0x30) & 0x0F) << 4) | ((p->cvm_subsc_1_pin[0] -
5453 0x30) & 0x0F);
5454 } else {
5455 RegistartionData[3] =
5456 (((p->cvm_subsc_2_pin[3] - 0x30) & 0x0F) << 4) | ((p->cvm_subsc_2_pin[2] -
5457 0x30) & 0x0F);
5458 RegistartionData[4] =
5459 (((p->cvm_subsc_2_pin[1] - 0x30) & 0x0F) << 4) | ((p->cvm_subsc_2_pin[0] -
5460 0x30) & 0x0F);
5461 }
5462
5463 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ACCESS_RIGHTS_REQ,
5464 sizeof(RegistartionData),
5465 RegistartionData);
5466
5467 usleep(100000);
5468
5469 res = celliax_serial_read_CVM_BUSMAIL(p); //we don't have no monitor neither do_controldev_thread
5470
5471 if (res == -1) {
5472 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5473 CVM_UNLOCKA(&p->controldev_lock);
5474 return -1;
5475 }
5476
5477 how_many_reads = 0;
5478
5479 while (CVM_UNKNOWN_REGISTER_STATE == p->cvm_register_state) {
5480
5481 if (0 == (how_many_reads % 50)) {
5482 DEBUGA_CVM("Attempt to register to FP... %d\n", CELLIAX_P_LOG,
5483 how_many_reads / 10);
5484 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ACCESS_RIGHTS_REQ,
5485 sizeof(RegistartionData),
5486 RegistartionData);
5487 }
5488
5489 /* up to 5 minutes for registration.... */
5490 usleep(1000000);
5491 res = celliax_serial_read_CVM_BUSMAIL(p);
5492 how_many_reads++;
5493
5494 if (res == -1) {
5495 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5496 CVM_UNLOCKA(&p->controldev_lock);
5497 return -1;
5498 }
5499
5500 if (how_many_reads > 300) {
5501 ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n",
5502 CELLIAX_P_LOG, how_many_reads);
5503
5504 ERRORA("Unable to communication with CVM...\n", CELLIAX_P_LOG);
5505
5506 CVM_UNLOCKA(&p->controldev_lock);
5507 return -1;
5508 }
5509 }
5510
5511 if (CVM_REGISTERED_TO_FP != p->cvm_register_state) {
5512 ERRORA("Unable to register to FP...\n", CELLIAX_P_LOG);
5513
5514 CVM_UNLOCKA(&p->controldev_lock);
5515 return -1;
5516
5517 } else {
5518 DEBUGA_CVM("CVM registered to FP successfully...\n", CELLIAX_P_LOG);
5519 DEBUGA_CVM("Attempt to lock to FP...\n", CELLIAX_P_LOG);
5520
5521 /* Try to connect to FP, try to lock to FP, maybe we registered with it in the past... */
5522 /* CVM can hold up to 2 subscriptions in its EEPROM, celliax.conf contains number we should try */
5523 /* eg. cvm_subscription_no = 1 */
5524
5525 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_LOCK_REQ,
5526 sizeof(SubcriptionNo), &SubcriptionNo);
5527
5528 usleep(10000);
5529
5530 res = celliax_serial_read_CVM_BUSMAIL(p); //we don't have no monitor neither do_controldev_thread
5531
5532 if (res == -1) {
5533 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5534 CVM_UNLOCKA(&p->controldev_lock);
5535 return -1;
5536 }
5537
5538 how_many_reads = 0;
5539
5540 while (CVM_UNKNOWN_LOCK_STATE == p->cvm_lock_state) {
5541
5542 if (0 == (how_many_reads % 10)) {
5543 DEBUGA_CVM("Attempt to lock to FP... %d\n", CELLIAX_P_LOG, how_many_reads / 10);
5544 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ACCESS_RIGHTS_REQ,
5545 sizeof(RegistartionData),
5546 RegistartionData);
5547 }
5548
5549 usleep(10000);
5550 res = celliax_serial_read_CVM_BUSMAIL(p);
5551 how_many_reads++;
5552
5553 if (res == -1) {
5554 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5555 CVM_UNLOCKA(&p->controldev_lock);
5556 return -1;
5557 }
5558
5559 if (how_many_reads > 100) {
5560 ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n",
5561 CELLIAX_P_LOG, how_many_reads);
5562
5563 ERRORA("Unable to communication with CVM...\n", CELLIAX_P_LOG);
5564
5565 CVM_UNLOCKA(&p->controldev_lock);
5566 return -1;
5567 }
5568 }
5569
5570 if (CVM_LOCKED_TO_FP != p->cvm_lock_state) {
5571 ERRORA("Unable to lock to FP...\n", CELLIAX_P_LOG);
5572
5573 CVM_UNLOCKA(&p->controldev_lock);
5574 return -1;
5575 } else {
5576 DEBUGA_CVM("CVM locked to FP successfully...\n", CELLIAX_P_LOG);
5577 }
5578 }
5579 }
5580
5581 usleep(100000);
5582
5583 CVM_UNLOCKA(&p->controldev_lock);
5584 POPPA_UNLOCKA(&p->controldev_lock);
5585 return 0;
5586
5587 }
5588
celliax_serial_read_CVM_BUSMAIL(struct celliax_pvt * p)5589 int celliax_serial_read_CVM_BUSMAIL(struct celliax_pvt *p)
5590 {
5591 int read_count;
5592 int select_err;
5593 fd_set read_fds;
5594 struct timeval timeout;
5595 int cvm_busmail_mesg = 0;
5596 unsigned char busmail_crc = 0;
5597 unsigned char MsgCrc = 0;
5598 unsigned char MsgHeader = 0;
5599 unsigned char MsgTxSeqNo = 0;
5600 unsigned char MsgRxSeqNo = 0;
5601 unsigned char MsgTaskId = 0;
5602 unsigned char MsgProgId = 0;
5603 unsigned char MsgPrimitiveLSB = 0;
5604 unsigned char MsgPrimitiveMSB = 0;
5605 unsigned int MsgPrimitive = 0;
5606
5607 int i = 0;
5608
5609 FD_ZERO(&read_fds);
5610 FD_SET(p->controldevfd, &read_fds);
5611 timeout.tv_sec = 0;
5612 timeout.tv_usec = 10000;
5613
5614 if ((select_err = select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
5615 timeout.tv_sec = 0; //reset the timeout, linux modify it
5616 timeout.tv_usec = 10000; //reset the timeout, linux modify it
5617 PUSHA_UNLOCKA(&p->controldev_lock);
5618 CVM_LOKKA(&p->controldev_lock);
5619
5620 while ((select_err =
5621 select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
5622 gettimeofday(&p->cvm_busmail_list_tv, &p->cvm_busmail_list_tz);
5623 read_count = read(p->controldevfd, p->rxm, 255);
5624
5625 if (read_count == 0) {
5626 ERRORA
5627 ("read 0 bytes!!! Nenormalno! Marking this celliax_serial_device %s as dead, andif it is owned by a channel, hanging up. Maybe the CVM is stuck, switched off or power down.\n",
5628 CELLIAX_P_LOG, p->controldevice_name);
5629
5630 p->controldev_dead = 1;
5631 close(p->controldevfd);
5632 CVM_UNLOCKA(&p->controldev_lock);
5633
5634 if (p->owner)
5635 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
5636 return -1;
5637 }
5638
5639 if (option_debug > 10) {
5640 char debug_buf[1024];
5641 char *debug_buf_pos;
5642
5643 memset(debug_buf, 0, 1024);
5644 debug_buf_pos = debug_buf;
5645 for (i = 0; i < read_count; i++) {
5646 debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", p->rxm[i]);
5647 if (debug_buf_pos > (char *) (&debug_buf + 1000))
5648 break;
5649 }
5650
5651 DEBUGA_CVM("%s READ AT seconds=%ld usec=%6ld read_count=%d\n", CELLIAX_P_LOG,
5652 debug_buf, p->cvm_busmail_list_tv.tv_sec,
5653 p->cvm_busmail_list_tv.tv_usec, read_count);
5654 }
5655
5656 for (i = 0; i < read_count; i++) {
5657 if (p->rxm[i] == BUSMAIL_SOF) {
5658 /* if we have identified the start of an busmail frame sent to us by the CVM */
5659 /* clean the array, copy into it the beginning of the frame, move the counter in the array after the last byte copied */
5660 memset(p->array, 0, 255);
5661 p->array[0] = p->rxm[i];
5662 p->arraycounter = 1;
5663 }
5664
5665 /* buffer overload protection */
5666 if (255 == p->arraycounter) {
5667 p->arraycounter = 1;
5668 }
5669
5670 /* continue copying into the array, until... */
5671 p->array[p->arraycounter - 1] = p->rxm[i];
5672
5673 /* we reach the end of the incoming frame, its lenght is in the p->array[BUSMAIL_OFFSET_LEN_LSB] byte, plus overhead */
5674 if (p->arraycounter == p->array[BUSMAIL_OFFSET_LEN_LSB] + 4) {
5675
5676 tcflush(p->controldevfd, TCIFLUSH); /* PL2303HX bug? */
5677 /* start categorizing frames */
5678
5679 if (option_debug > 10) {
5680 char debug_buf[1024];
5681 char *debug_buf_pos;
5682
5683 memset(debug_buf, 0, 1024);
5684 debug_buf_pos = debug_buf;
5685
5686 for (i = 0; i < p->arraycounter; i++) {
5687 debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", p->array[i]);
5688 if (debug_buf_pos > (char *) (&debug_buf + 1000))
5689 break;
5690 }
5691
5692 DEBUGA_CVM("%s was received, Starting to categorize this frame\n",
5693 CELLIAX_P_LOG, debug_buf);
5694 }
5695
5696 int known = 0;
5697 int j = 0;
5698
5699 busmail_crc = 0;
5700 MsgCrc = p->array[p->arraycounter - 1];
5701
5702 busmail_crc = (unsigned char) (p->array[BUSMAIL_OFFSET_HEADER] + busmail_crc);
5703
5704 for (j = BUSMAIL_OFFSET_MAIL; j < (p->arraycounter - 1); j++) {
5705 busmail_crc = (unsigned char) (p->array[j] + busmail_crc);
5706 }
5707
5708 if (busmail_crc != MsgCrc) {
5709 WARNINGA("BUSMAIL MSG CRC FAILED!, MsgCrc %.2X, calcd %.2X, dropping frame\n",
5710 CELLIAX_P_LOG, MsgCrc, busmail_crc);
5711 } else {
5712 /* first step in categorizing frames, look at the general kind of frame, in p->array[BUSMAIL_OFFSET_HEADER] */
5713 if (option_debug > 1)
5714 DEBUGA_CVM("BUSMAIL MSG CRC, MsgCrc %.2X, calcd %.2X...\n", CELLIAX_P_LOG,
5715 MsgCrc, busmail_crc);
5716
5717 MsgHeader = p->array[BUSMAIL_OFFSET_HEADER];
5718 cvm_busmail_mesg = MsgHeader;
5719
5720 switch (MsgHeader & BUSMAIL_HEADER_IC_BIT_MASK) {
5721 case BUSMAIL_HEADER_INFO_FRAME:
5722 /* analyzis of frame header */
5723 MsgTxSeqNo = ((MsgHeader & BUSMAIL_HEADER_TXSEQ_MASK) >> 4);
5724 MsgRxSeqNo = ((MsgHeader & BUSMAIL_HEADER_RXSEQ_MASK));
5725
5726 if (option_debug > 1)
5727 DEBUGA_CVM("BUSMAIL_HEADER_INFO_FRAME TxSeq %X, RxSeq %X\n",
5728 CELLIAX_P_LOG, MsgTxSeqNo, MsgRxSeqNo);
5729
5730 if (((p->busmail_rxseq_cvm_last + 1) & 0x7) != MsgTxSeqNo) {
5731 /* some CVM frames are missing, TxSeq of this frame is higher then expected */
5732 /* reject, I expected p->busmail_rxseq_cvm_last + 1, resend it to me, please */
5733
5734 WARNINGA("CVM TxSeq %X, does not match expected value %X\n",
5735 CELLIAX_P_LOG, MsgTxSeqNo,
5736 (p->busmail_rxseq_cvm_last + 1) & 0x7);
5737
5738 // celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_REJ);
5739
5740 if (((p->busmail_rxseq_cvm_last) & 0x7) == MsgTxSeqNo) {
5741
5742 WARNINGA
5743 ("It looks like our ACK to this frame was MIA :), lets ACK the frame one more time...\n",
5744 CELLIAX_P_LOG);
5745
5746 /* if the frame we received informs us that other side is waiting for ACK, let's ACK it */
5747 /* even if it is unknown to us */
5748 if (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_PF_BIT_MASK) {
5749 if (BUSMAIL_HEADER_SABM ==
5750 (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SABM_MASK)) {
5751 celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, (unsigned char)
5752 (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_UN_FRAME | BUSMAIL_HEADER_UNID_SABM));
5753 } else {
5754 celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, (unsigned char)
5755 (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_RR));
5756 }
5757 }
5758 }
5759
5760 break;
5761 } else {
5762 /* we expected packet with this seq no. */
5763 /* CVM ACKed our frames with info frame */
5764 celliax_serial_list_acknowledge_CVM_BUSMAIL(p, MsgRxSeqNo);
5765
5766 /* save it but limit it to 3 bits only (valid values: 0-7) */
5767 p->busmail_rxseq_cvm_last = MsgTxSeqNo;
5768 p->busmail_rxseq_cvm_last &= 0x7;
5769
5770 /* if the frame we received informs us that other side is waiting for ACK, let's ACK it */
5771 /* even if it is unknown to us */
5772 if (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_PF_BIT_MASK) {
5773 if (BUSMAIL_HEADER_SABM ==
5774 (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SABM_MASK)) {
5775 celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, (unsigned char)
5776 (BUSMAIL_HEADER_CTRL_FRAME
5777 |
5778 BUSMAIL_HEADER_CTRL_UN_FRAME
5779 |
5780 BUSMAIL_HEADER_UNID_SABM));
5781 } else {
5782 celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, (unsigned char)
5783 (BUSMAIL_HEADER_CTRL_FRAME
5784 |
5785 BUSMAIL_HEADER_CTRL_SU_FRAME
5786 |
5787 BUSMAIL_HEADER_SUID_RR));
5788 }
5789 }
5790
5791 }
5792
5793 /* frame header OK, let's see what's inside mail field */
5794 MsgTaskId = p->array[BUSMAIL_OFFSET_MAIL_TASK_ID];
5795 MsgProgId = p->array[BUSMAIL_OFFSET_MAIL_PROGRAM_ID];
5796 MsgPrimitiveLSB = p->array[BUSMAIL_OFFSET_MAIL_PRIMITIVE_LSB];
5797 MsgPrimitiveMSB = p->array[BUSMAIL_OFFSET_MAIL_PRIMITIVE_MSB];
5798 MsgPrimitive = MsgPrimitiveMSB << 8 | MsgPrimitiveLSB;
5799
5800 if (option_debug > 1)
5801 DEBUGA_CVM
5802 ("BUSMAIL_HEADER_INFO_FRAME ProgId %X, TaskId %X, Primitive %X %X\n",
5803 CELLIAX_P_LOG, MsgProgId, MsgTaskId, MsgPrimitiveMSB, MsgPrimitiveLSB);
5804
5805 switch (MsgPrimitive) {
5806
5807 case API_PP_ACCESS_RIGHTS_REJ:
5808 /* FP rejected our registration... */
5809 WARNINGA("API_PP_ACCESS_RIGHTS_REJ, FP rejected our registration...\n",
5810 CELLIAX_P_LOG);
5811
5812 p->cvm_register_state = CVM_UNREGISTERED_TO_FP;
5813 p->cvm_lock_state = CVM_UNKNOWN_LOCK_STATE;
5814 known = 1;
5815 break;
5816
5817 case API_PP_ACCESS_RIGHTS_CFM:
5818 /* FP accepted our registration... */
5819 if (option_debug > 1)
5820 DEBUGA_CVM
5821 ("API_PP_ACCESS_RIGHTS_CFM, FP accepted our registration...\n",
5822 CELLIAX_P_LOG);
5823
5824 p->cvm_register_state = CVM_REGISTERED_TO_FP;
5825 p->cvm_lock_state = CVM_UNKNOWN_LOCK_STATE;
5826 p->cvm_handset_no = p->array[BUSMAIL_OFFSET_MAIL_PARAMS + 0];
5827 p->cvm_fp_is_cvm = p->array[BUSMAIL_OFFSET_MAIL_PARAMS + 1];
5828
5829 if (option_debug > 1)
5830 DEBUGA_CVM
5831 ("API_PP_ACCESS_RIGHTS_CFM, FP accepted our registration, Our handset no. is %d, CVM? %X\n",
5832 CELLIAX_P_LOG, p->cvm_handset_no, p->cvm_fp_is_cvm);
5833
5834 known = 1;
5835 break;
5836
5837 case API_PP_LOCKED_IND:
5838 /* CVM is connected to FP */
5839 if (option_debug > 1)
5840 DEBUGA_CVM("API_PP_LOCKED_IND, Connection to FP completed...\n",
5841 CELLIAX_P_LOG);
5842
5843 p->cvm_register_state = CVM_REGISTERED_TO_FP;
5844 p->cvm_lock_state = CVM_LOCKED_TO_FP;
5845 known = 1;
5846 break;
5847
5848 case API_PP_UNLOCKED_IND:
5849 /* CVM is unlocked with FP, Out of service */
5850 WARNINGA
5851 ("API_PP_UNLOCKED_IND, CVM is unlocked with FP, Out of service !!!\n",
5852 CELLIAX_P_LOG);
5853
5854 p->cvm_lock_state = CVM_UNLOCKED_TO_FP;
5855 known = 1;
5856 break;
5857
5858 case API_PP_SETUP_ACK_IND:
5859 /* Outgoing call, connection to FP established, FP is waiting for a number to dial */
5860 if (option_debug > 1)
5861 DEBUGA_CVM
5862 ("API_PP_SETUP_ACK_IND, connection to FP established, FP is waiting for a numer to dial...\n",
5863 CELLIAX_P_LOG);
5864
5865 if (AST_STATE_DOWN == p->interface_state) {
5866 p->interface_state = AST_STATE_DIALING;
5867 }
5868
5869 known = 1;
5870 break;
5871
5872 case API_PP_ALERT_IND:
5873 /* Outgoing call, Remote end is ringing */
5874 if (option_debug > 1)
5875 DEBUGA_CVM("API_PP_ALERT_IND, remote end is ringing...\n",
5876 CELLIAX_P_LOG);
5877
5878 if (AST_STATE_DIALING == p->interface_state) {
5879 p->interface_state = AST_STATE_RINGING;
5880 }
5881
5882 known = 1;
5883 break;
5884
5885 case API_PP_CONNECT_IND:
5886 /* Outgoing call, the remote end answered our call */
5887 if (option_debug > 1)
5888 DEBUGA_CVM("API_PP_CONNECT_IND, our call was answered...\n",
5889 CELLIAX_P_LOG);
5890
5891 if (AST_STATE_RINGING == p->interface_state) {
5892
5893 /* let's open audio and have a chat */
5894 celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_OPEN_REQ, 0,
5895 NULL);
5896
5897 unsigned char volume = (unsigned char) p->cvm_volume_level;
5898 celliax_serial_send_info_frame_CVM_BUSMAIL(p,
5899 CVM_PP_AUDIO_SET_VOLUME_REQ,
5900 sizeof(volume), &volume);
5901
5902 /* let's unmute mic and have a chat */
5903 celliax_serial_send_info_frame_CVM_BUSMAIL(p,
5904 CVM_PP_AUDIO_UNMUTE_MIC_REQ,
5905 0, NULL);
5906
5907 /* let's switch to headset, because we fried normal output.... */
5908 /* unsigned char headset_on = (unsigned char) 1;
5909 celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_HS_PLUG_IND, sizeof(headset_on), &headset_on);
5910 */
5911 p->interface_state = AST_STATE_UP;
5912 ast_setstate(p->owner, AST_STATE_RINGING);
5913 celliax_queue_control(p->owner, AST_CONTROL_ANSWER);
5914 }
5915
5916 known = 1;
5917 break;
5918
5919 case API_PP_REJECT_IND:
5920 /* Outgoing/Incoming call, FP rejected our connection... */
5921 if (option_debug > 1)
5922 DEBUGA_CVM
5923 ("API_PP_REJECT_IND, FP or ther PP rejected our connection...\n",
5924 CELLIAX_P_LOG);
5925
5926 if (AST_STATE_RING == p->interface_state && p->owner) {
5927 /* Attempt to answer incoming call rejected by FP or PP */
5928 if (option_debug > 1)
5929 DEBUGA_CVM("Was it PAGE_ALL CALL, that we should not answered?\n",
5930 CELLIAX_P_LOG);
5931
5932 p->interface_state = AST_STATE_DOWN;
5933 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
5934
5935 } else if (AST_STATE_DOWN != p->interface_state && p->owner) {
5936 /* Outgoing call rejected by other PP or FP */
5937 p->interface_state = AST_STATE_BUSY;
5938 ast_setstate(p->owner, AST_STATE_BUSY);
5939 celliax_queue_control(p->owner, AST_CONTROL_BUSY);
5940 }
5941
5942 known = 1;
5943 break;
5944
5945 case API_PP_SIGNAL_ON_IND:
5946 /* Ringback, ignore it... */
5947 if (option_debug > 1)
5948 DEBUGA_CVM("API_PP_SIGNAL_ON_IND, Ringback, ignore it...\n",
5949 CELLIAX_P_LOG);
5950
5951 known = 1;
5952 break;
5953
5954 case API_PP_SIGNAL_OFF_IND:
5955 /* Ringback, ignore it... */
5956 if (option_debug > 1)
5957 DEBUGA_CVM("API_PP_SIGNAL_OFF_IND, Ringback, ignore it...\n",
5958 CELLIAX_P_LOG);
5959
5960 known = 1;
5961 break;
5962
5963 case API_PP_SETUP_IND:
5964 /* Incoming call, Somebody is calling us */
5965
5966 if (option_debug > 1)
5967 DEBUGA_CVM("API_PP_SETUP_IND, somebody is calling us...\n",
5968 CELLIAX_P_LOG);
5969
5970 if (AST_STATE_DOWN == p->interface_state) {
5971
5972 if (API_PP_SETUP_IND_CALL_INT ==
5973 p->array[BUSMAIL_OFFSET_MAIL_PARAMS +
5974 API_PP_SETUP_IND_CALL_TYPE_OFFSET]) {
5975 DEBUGA_CVM("INTERNAL CALL, receive it...\n", CELLIAX_P_LOG);
5976
5977 p->interface_state = AST_STATE_RING;
5978
5979 /* inform calling end, that we know about his call, and that we are alerting */
5980 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ALERT_REQ, 0,
5981 NULL);
5982
5983 /* let's open audio before valid mac, to remove noise... */
5984 celliax_serial_send_info_frame_CVM_BUSMAIL(p,
5985 CVM_PP_AUDIO_OPEN_ADPCM_OFF_REQ,
5986 0, NULL);
5987
5988 } else {
5989 DEBUGA_CVM("NOT an INTERNAL CALL, CALL TYPE %X, just ignore it...\n",
5990 CELLIAX_P_LOG,
5991 p->array[BUSMAIL_OFFSET_MAIL_PARAMS +
5992 API_PP_SETUP_IND_CALL_TYPE_OFFSET]);
5993
5994 /* inform calling end, that we know about his call, and that we are alerting OR not :) */
5995 /* probably it is needed so FP does not remove us from PP list :) */
5996 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ALERT_REQ, 0,
5997 NULL);
5998 }
5999
6000 } else {
6001 WARNINGA
6002 ("Ignore incoming call, Wrong interface state, current state %X\n",
6003 CELLIAX_P_LOG, p->interface_state);
6004 }
6005
6006 known = 1;
6007 break;
6008
6009 case API_PP_ALERT_OFF_IND:
6010 /* Incoming call, We should stop alerting about incoming call... */
6011 if (option_debug > 1)
6012 DEBUGA_CVM
6013 ("API_PP_ALERT_OFF_IND, Ringback, stop alerting about incoming call...\n",
6014 CELLIAX_P_LOG);
6015
6016 known = 1;
6017 break;
6018
6019 case API_PP_ALERT_ON_IND:
6020 /* Incoming call, We should stop alerting about incoming call... */
6021 if (option_debug > 1)
6022 DEBUGA_CVM
6023 ("API_PP_ALERT_ON_IND, Ringback, start alerting about incoming call...\n",
6024 CELLIAX_P_LOG);
6025 /*
6026 if (AST_STATE_DOWN == p->interface_state) {
6027 DEBUGA_CVM("Somebody is calling us, we see a PP_ALERT_ON_IND, receive it...\n", CELLIAX_P_LOG);
6028 p->interface_state = AST_STATE_RING;
6029 }
6030 */
6031 known = 1;
6032 break;
6033
6034 case API_PP_CONNECT_CFM:
6035 /* Incoming call, Confirmation for request to answer incoming call... */
6036 if (option_debug > 1)
6037 DEBUGA_CVM
6038 ("API_PP_CONNECT_CFM, Confirmation for request to answer incoming call...\n",
6039 CELLIAX_P_LOG);
6040
6041 if (AST_STATE_RING == p->interface_state && p->owner) {
6042
6043 p->interface_state = AST_STATE_UP;
6044 ast_setstate(p->owner, AST_STATE_UP);
6045
6046 /* let's open audio and have a chat */
6047 // celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_OPEN_ADPCM_OFF_REQ, 0, NULL);
6048
6049 /* let's open audio and have a chat */
6050 celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_OPEN_REQ, 0,
6051 NULL);
6052
6053 unsigned char volume = (unsigned char) p->cvm_volume_level;
6054 celliax_serial_send_info_frame_CVM_BUSMAIL(p,
6055 CVM_PP_AUDIO_SET_VOLUME_REQ,
6056 sizeof(volume), &volume);
6057
6058 /* let's unmute mic and have a chat */
6059 celliax_serial_send_info_frame_CVM_BUSMAIL(p,
6060 CVM_PP_AUDIO_UNMUTE_MIC_REQ,
6061 0, NULL);
6062
6063 /* let's switch to headset, because we fried normal output.... */
6064 /* unsigned char headset_on = (unsigned char) 1;
6065 celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_HS_PLUG_IND, sizeof(headset_on), &headset_on);
6066 */
6067 } else {
6068 WARNINGA
6069 ("Ignore connection cfm, Wrong interface state, current state %X\n",
6070 CELLIAX_P_LOG, p->interface_state);
6071 }
6072
6073 known = 1;
6074 break;
6075
6076 case API_PP_RELEASE_CFM:
6077 /* Confirmation for request to hangup a call... */
6078 if (option_debug > 1)
6079 DEBUGA_CVM
6080 ("API_PP_RELEASE_CFM, Confirmation for request to hangup a call..\n",
6081 CELLIAX_P_LOG);
6082
6083 if (AST_STATE_UP == p->interface_state) {
6084 /* let's close audio */
6085 celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_CLOSE_REQ, 0,
6086 NULL);
6087
6088 /* let's unmute mic and have a chat */
6089 celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_MUTE_MIC_REQ,
6090 0, NULL);
6091 }
6092
6093 p->interface_state = AST_STATE_DOWN;
6094
6095 known = 1;
6096 break;
6097
6098 case API_PP_RELEASE_IND:
6099 /* FP releases connection to CVM... */
6100 if (option_debug > 1)
6101 DEBUGA_CVM("API_PP_RELEASE_IND, FP releases connection to CVM...\n",
6102 CELLIAX_P_LOG);
6103
6104 if (AST_STATE_UP == p->interface_state && p->owner) {
6105 /* let's close audio */
6106 celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_CLOSE_REQ, 0,
6107 NULL);
6108 p->interface_state = AST_STATE_DOWN;
6109 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
6110
6111 } else if (AST_STATE_RING == p->interface_state && p->owner) {
6112 /* workaround for PAGE ALL CALL, FIXME!!!! */
6113 if (option_debug > 1)
6114 DEBUGA_CVM("WAS IT A PAGE ALL ???...\n", CELLIAX_P_LOG);
6115
6116 p->interface_state = AST_STATE_UP;
6117 usleep(100000);
6118
6119 p->interface_state = AST_STATE_DOWN;
6120 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
6121 }
6122
6123 /* we need to ACK release */
6124 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_RELEASE_RES, 0,
6125 NULL);
6126
6127 known = 1;
6128 break;
6129
6130 case API_PP_READ_RSSI_CFM:
6131 if (option_debug > 1)
6132 DEBUGA_CVM("API_PP_READ_RSSI_CFM, RSSI readout...\n", CELLIAX_P_LOG);
6133
6134 p->cvm_rssi = p->array[BUSMAIL_OFFSET_MAIL_PARAMS + 0];
6135 int rssi_percent = p->cvm_rssi * 100 / 0x3F;
6136 if (option_debug > 1)
6137 DEBUGA_CVM("RSSI is %X, %d%%...\n", CELLIAX_P_LOG, p->cvm_rssi,
6138 rssi_percent);
6139
6140 known = 1;
6141 break;
6142 default:
6143 WARNINGA("UNKNOWN MsgPrimitive!!! %X\n", CELLIAX_P_LOG, MsgPrimitive);
6144 break;
6145 }
6146
6147 break;
6148
6149 case BUSMAIL_HEADER_CTRL_FRAME:
6150 if (option_debug > 1)
6151 DEBUGA_CVM("BUSMAIL_HEADER_CTRL_FRAME\n", CELLIAX_P_LOG);
6152
6153 switch (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SU_BIT_MASK) {
6154 case BUSMAIL_HEADER_CTRL_SU_FRAME:
6155 if (option_debug > 1)
6156 DEBUGA_CVM("BUSMAIL_HEADER_CTRL_SU_FRAME\n", CELLIAX_P_LOG);
6157
6158 switch (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SUID_MASK) {
6159 case BUSMAIL_HEADER_SUID_REJ:
6160 /* CVM Reject, CVM missed one of our packets, it will be resend, do nothing */
6161 MsgRxSeqNo =
6162 ((p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK));
6163
6164 if (option_debug > 1)
6165 DEBUGA_CVM("BUSMAIL_HEADER_SUID_REJ, RxSeq %X\n", CELLIAX_P_LOG,
6166 MsgRxSeqNo);
6167
6168 /* Even that it is CVM Reject packet, it still ACKs some packets */
6169 celliax_serial_list_acknowledge_CVM_BUSMAIL(p, MsgRxSeqNo);
6170
6171 known = 1;
6172 break;
6173 case BUSMAIL_HEADER_SUID_RNR:
6174 /* CVM Receiver Not Ready, answer to packet that we sent, do nothing, it will be resend later */
6175 MsgRxSeqNo =
6176 ((p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK));
6177
6178 if (option_debug > 1)
6179 DEBUGA_CVM("BUSMAIL_HEADER_SUID_RNR, RxSeq %X\n", CELLIAX_P_LOG,
6180 MsgRxSeqNo);
6181
6182 known = 1;
6183 break;
6184 case BUSMAIL_HEADER_SUID_RR:
6185 /* CVM ACKs our packets */
6186 MsgRxSeqNo =
6187 ((p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK));
6188
6189 if (option_debug > 1)
6190 DEBUGA_CVM("BUSMAIL_HEADER_SUID_RR, RxSeq %X\n", CELLIAX_P_LOG,
6191 MsgRxSeqNo);
6192
6193 /* CVM ACKed our frames with RR frame */
6194 celliax_serial_list_acknowledge_CVM_BUSMAIL(p, MsgRxSeqNo);
6195
6196 known = 1;
6197 break;
6198
6199 default:
6200 WARNINGA("BUSMAIL_HEADER_SUID_UNKNOWN!!!\n", CELLIAX_P_LOG);
6201 break;
6202 }
6203 break;
6204
6205 case BUSMAIL_HEADER_CTRL_UN_FRAME:
6206 if (option_debug > 1)
6207 DEBUGA_CVM("BUSMAIL_HEADER_CTRL_UN_FRAME\n", CELLIAX_P_LOG);
6208
6209 switch (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_UNID_MASK) {
6210
6211 case BUSMAIL_HEADER_UNID_SABM:
6212 if (option_debug > 1)
6213 DEBUGA_CVM("BUSMAIL_HEADER_UNID_SABM\n", CELLIAX_P_LOG);
6214 /* reset seq counters */
6215 p->busmail_txseq_celliax_last = 0xFF;
6216 p->busmail_rxseq_cvm_last = 0xFF;
6217
6218 celliax_serial_lists_free_CVM_BUSMAIL(p);
6219 /* if needed, reply will be send by code at the end of switch statements */
6220 known = 1;
6221 break;
6222
6223 default:
6224 WARNINGA("BUSMAIL_HEADER_UNID_UNKNOWN!!!\n", CELLIAX_P_LOG);
6225 break;
6226 }
6227 break;
6228
6229 default:
6230 WARNINGA("BUSMAIL_HEADER_CTRL_UNKNOWN!!!\n", CELLIAX_P_LOG);
6231 break;
6232 }
6233 break;
6234
6235 default:
6236 WARNINGA("BUSMAIL_HEADER_UNKNOWN!!!\n", CELLIAX_P_LOG);
6237 break;
6238 }
6239
6240 }
6241
6242 /* categorization of frame is ended, if it has not been recognized, whine */
6243 if (!known) {
6244 WARNINGA("BUSMAIL MSG UNKNOWN or REJECTED!\n", CELLIAX_P_LOG);
6245 }
6246 }
6247 p->arraycounter++;
6248 }
6249 }
6250 CVM_UNLOCKA(&p->controldev_lock);
6251 POPPA_UNLOCKA(&p->controldev_lock);
6252 }
6253
6254 /* oooops, select returned error, got a kill/cancel or problems with the serial file descriptor */
6255 if (select_err == -1) {
6256 if (errno != EINTR) {
6257 ERRORA
6258 ("select returned -1 on %s, marking controldev as dead, errno was: %d, error was: %s\n",
6259 CELLIAX_P_LOG, p->controldevice_name, errno, strerror(errno));
6260
6261 p->controldev_dead = 1;
6262 close(p->controldevfd);
6263
6264 if (p->owner)
6265 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
6266 return -1;
6267
6268 } else {
6269 WARNINGA("select returned -1 on %s, errno was: %d, EINTR, error was: %s\n",
6270 CELLIAX_P_LOG, p->controldevice_name, errno, strerror(errno));
6271 return 0;
6272 }
6273 }
6274 /* OK, reading done, let's browse the list of pending frames to be sent, and act on it */
6275 if (celliax_serial_send_if_time_CVM_BUSMAIL(p)) {
6276 ERRORA("celliax_serial_send_if_time_CVM_BUSMAIL failed!\n", CELLIAX_P_LOG);
6277 return -1;
6278 }
6279
6280 return cvm_busmail_mesg; //FIXME breaks the convention of returning 0 on success
6281 }
6282
celliax_serial_getstatus_CVM_BUSMAIL(struct celliax_pvt * p)6283 int celliax_serial_getstatus_CVM_BUSMAIL(struct celliax_pvt *p)
6284 {
6285 int res;
6286 int how_many_reads = 0;
6287
6288 PUSHA_UNLOCKA(&p->controldev_lock);
6289 CVM_LOKKA(&p->controldev_lock);
6290
6291 if (option_debug > 1)
6292 DEBUGA_CVM("Sending RR CTRL frame wit PF bit set\n", CELLIAX_P_LOG);
6293
6294 /* this ctrl frame can be used as low level keep alive */
6295 celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p,
6296 BUSMAIL_HEADER_CTRL_FRAME |
6297 BUSMAIL_HEADER_CTRL_SU_FRAME |
6298 BUSMAIL_HEADER_SUID_RR |
6299 (BUSMAIL_HEADER_PF_BIT_MASK & 0xFF));
6300
6301 //usleep(1000);
6302
6303 res = celliax_serial_read_CVM_BUSMAIL(p); //we don't have no monitor neither do_controldev_thread
6304
6305 if (res == -1) {
6306 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
6307 CVM_UNLOCKA(&p->controldev_lock);
6308 return -1;
6309 }
6310
6311 while ((res & 0xF0) !=
6312 (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME |
6313 BUSMAIL_HEADER_SUID_RR)) {
6314
6315 usleep(1000);
6316 res = celliax_serial_read_CVM_BUSMAIL(p);
6317 how_many_reads++;
6318
6319 if (res == -1) {
6320 ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
6321 CVM_UNLOCKA(&p->controldev_lock);
6322 return -1;
6323 }
6324
6325 if (how_many_reads > 10) {
6326 ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG,
6327 how_many_reads);
6328 CVM_UNLOCKA(&p->controldev_lock);
6329 return -1;
6330 }
6331 }
6332
6333 //celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_READ_RSSI_REQ, 0, NULL);
6334
6335 CVM_UNLOCKA(&p->controldev_lock);
6336 POPPA_UNLOCKA(&p->controldev_lock);
6337
6338 return 0;
6339
6340 }
6341
6342 /*!
6343 * \brief Write on the serial port for all the CVM_BUSMAIL functions
6344 * \param p celliax_pvt
6345 * \param len lenght of buffer2
6346 * \param buffer2 chars to be written
6347 *
6348 * Write on the serial port for all the CVM_BUSMAIL functions
6349 *
6350 * \return the number of chars written on the serial,
6351 * that can be different from len (or negative) in case of errors.
6352 */
celliax_serial_send_CVM_BUSMAIL(struct celliax_pvt * p,int len,unsigned char * mesg_ptr)6353 int celliax_serial_send_CVM_BUSMAIL(struct celliax_pvt *p, int len,
6354 unsigned char *mesg_ptr)
6355 {
6356 int ret;
6357 size_t actual = 0;
6358 unsigned char *mesg_ptr2 = mesg_ptr;
6359 PUSHA_UNLOCKA(&p->controldev_lock);
6360 CVM_LOKKA(&p->controldev_lock);
6361 do {
6362 ret = write(p->controldevfd, mesg_ptr, len - actual);
6363 if (ret < 0 && errno == EAGAIN)
6364 continue;
6365 if (ret < 0) {
6366 if (actual != len)
6367 ERRORA("celliax_serial_write error: %s", CELLIAX_P_LOG, strerror(errno));
6368 CVM_UNLOCKA(&p->controldev_lock);
6369 return -1;
6370 }
6371 actual += ret;
6372 mesg_ptr += ret;
6373 usleep(10000);
6374 // usleep(p->cvm_celliax_serial_delay*1000);
6375 } while (actual < len);
6376
6377 usleep(p->cvm_celliax_serial_delay * 1000);
6378
6379 // tcdrain(p->controldevfd);
6380
6381 CVM_UNLOCKA(&p->controldev_lock);
6382 POPPA_UNLOCKA(&p->controldev_lock);
6383
6384 if (option_debug > 10) {
6385 int i;
6386 char debug_buf[1024];
6387 char *debug_buf_pos;
6388
6389 memset(debug_buf, 0, 1024);
6390 debug_buf_pos = debug_buf;
6391
6392 for (i = 0; i < len; i++) {
6393 debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", mesg_ptr2[i]);
6394 if (debug_buf_pos > ((char *) &debug_buf + 1000))
6395 break;
6396 }
6397 DEBUGA_CVM("%s was sent down the wire\n", CELLIAX_P_LOG, debug_buf);
6398 }
6399
6400 return 0;
6401 }
6402
6403 /*!
6404 * \brief Flags as acknowledged an BUSMAIL message previously sent
6405 * \param p celliax_pvt
6406 * \param seqnum identifier of the message to be acknowledged
6407 *
6408 * Called upon receiving an BUSMAIL acknoledgement message, browse the cvm_busmail_outgoing_list
6409 * looking for the seqnum sent BUSMAIL message, and flags it as acknowledged.
6410 * (if an outgoing BUSMAIL message is not aknowledged by the cellphone in a while,
6411 * it will be retransmitted)
6412 *
6413 * \return 0 on error, 1 otherwise
6414 */
celliax_serial_list_acknowledge_CVM_BUSMAIL(struct celliax_pvt * p,unsigned char AckTxSeqNo)6415 int celliax_serial_list_acknowledge_CVM_BUSMAIL(struct celliax_pvt *p,
6416 unsigned char AckTxSeqNo)
6417 {
6418 struct cvm_busmail_msg *ptr = NULL;
6419 struct cvm_busmail_msg *old = NULL;
6420
6421 unsigned char MsgTxSeqNo;
6422 unsigned char MsgRxSeqNo;
6423
6424 ptr = p->cvm_busmail_outgoing_list;
6425
6426 if (ptr == NULL) {
6427 ERRORA("cvm_busmail_outgoing_list is NULL ?\n", CELLIAX_P_LOG);
6428 return -1;
6429 }
6430
6431 PUSHA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6432 CVM_LOKKA(&p->cvm_busmail_outgoing_list_lock);
6433 /*
6434 DEBUGA_CVM("PREFREE OUTGOING list:\n", CELLIAX_P_LOG);
6435 celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6436 */
6437 while (ptr->next != NULL)
6438 ptr = ptr->next;
6439
6440 while (ptr) {
6441
6442 if ((1 == ptr->valid) && (0 == ptr->acknowledged) && (0 != ptr->sent)) {
6443 MsgTxSeqNo =
6444 ((ptr->busmail_msg_buffer[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_TXSEQ_MASK) >>
6445 4);
6446 MsgRxSeqNo =
6447 ((ptr->busmail_msg_buffer[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK));
6448
6449 /*
6450 if (option_debug > 1)
6451 DEBUGA_CVM("OUTGOING LIST TxSeq is %X, RxSeq is %X\n", CELLIAX_P_LOG, MsgTxSeqNo, MsgRxSeqNo);
6452 */
6453 unsigned char TxToAck = 0;
6454
6455 if (0 == AckTxSeqNo) {
6456 TxToAck = 7;
6457 } else {
6458 TxToAck = AckTxSeqNo - 1;
6459 }
6460
6461 if (MsgTxSeqNo <= TxToAck) {
6462
6463 if (option_debug > 1)
6464 DEBUGA_CVM("Msg with TxSeq=%X ACKed with CvmRxSeq=%X\n", CELLIAX_P_LOG,
6465 MsgTxSeqNo, AckTxSeqNo);
6466
6467 old = ptr;
6468 old->acknowledged = 1;
6469 old->valid = 0;
6470 ptr = old->previous;
6471
6472 if (old->previous) {
6473 if (old->next) {
6474 old->previous->next = old->next;
6475 } else {
6476 old->previous->next = NULL;
6477 }
6478 }
6479
6480 if (old->next) {
6481 if (old->previous) {
6482 old->next->previous = old->previous;
6483 } else {
6484 old->next->previous = NULL;
6485 }
6486 }
6487
6488 if ((NULL == old->next) && (NULL == old->previous)) {
6489 if (option_debug > 1) {
6490 DEBUGA_CVM("FREEING LAST\n", CELLIAX_P_LOG);
6491 }
6492
6493 p->cvm_busmail_outgoing_list = NULL;
6494 p->cvm_busmail_outgoing_list = celliax_serial_list_init_CVM_BUSMAIL(p);
6495 }
6496
6497 /*
6498 if (option_debug > 1)
6499 DEBUGA_CVM("FREEING TxSeq is %X, RxSeq is %X\n", CELLIAX_P_LOG, MsgTxSeqNo, MsgRxSeqNo);
6500 */
6501
6502 free(old);
6503
6504 } else {
6505 ptr = ptr->previous;
6506 }
6507
6508 } else {
6509 ptr = ptr->previous;
6510 }
6511 }
6512
6513 /*
6514 DEBUGA_CVM("POSTFREE OUTGOING list:\n", CELLIAX_P_LOG);
6515 celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6516 */
6517
6518 CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6519 POPPA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6520 return 0;
6521 }
6522
6523 /*!
6524 * \brief Sends an FBUS2 message or resends it if it was not acknowledged
6525 * \param p celliax_pvt
6526 *
6527 * Called by celliax_serial_read_CVM_BUSMAIL, browse the fbus2_outgoing_list looking for FBUS2 messages to be sent,
6528 * or for FBUS2 messages previously sent but not yet acknoledged.
6529 * (if an outgoing FBUS2 message is not aknowledged by the cellphone in a while,
6530 * it will be retransmitted)
6531 *
6532 * \return 0 on error, 1 otherwise
6533 */
celliax_serial_send_if_time_CVM_BUSMAIL(struct celliax_pvt * p)6534 int celliax_serial_send_if_time_CVM_BUSMAIL(struct celliax_pvt *p)
6535 {
6536 struct cvm_busmail_msg *ptr;
6537 struct timeval tv;
6538 struct timezone tz;
6539
6540 gettimeofday(&tv, &tz);
6541 ptr = p->cvm_busmail_outgoing_list;
6542
6543 if (ptr == NULL) {
6544 /* ERRORA("cvm_busmail_outgoing_list is NULL ?\n", CELLIAX_P_LOG); */
6545 WARNINGA("cvm_busmail_outgoing_list is NULL, nothing to send...\n", CELLIAX_P_LOG);
6546
6547 /* return -1; */
6548 return 0;
6549
6550 }
6551
6552 while (ptr->next != NULL) {
6553 WARNINGA("cvm_busmail_outgoing_list->next is not null ?\n", CELLIAX_P_LOG);
6554 ptr = ptr->next; //FIXME what to do?
6555 }
6556
6557 while (ptr->sent == 0 && ptr->acknowledged == 0) {
6558 if (ptr->previous != NULL) {
6559 ptr = ptr->previous;
6560 } else
6561 break;
6562 }
6563
6564 while (ptr->sent == 1 && ptr->acknowledged == 0) {
6565 if (ptr->previous != NULL) {
6566 ptr = ptr->previous;
6567 } else
6568 break;
6569 }
6570
6571 if (ptr->sent == 1 && ptr->acknowledged == 1) {
6572 if (ptr->next != NULL) {
6573 ptr = ptr->next;
6574 }
6575 }
6576
6577 if (ptr->sent == 1 && ptr->acknowledged == 0 && ptr->valid == 1) {
6578 if ((tv.tv_sec * 1000 + tv.tv_usec / 1000) >
6579 ((ptr->tv_sec * 1000 + ptr->tv_usec / 1000) + 1000)) {
6580
6581 PUSHA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6582 CVM_LOKKA(&p->cvm_busmail_outgoing_list_lock);
6583
6584 if (ptr->sent == 1 && ptr->acknowledged == 0 && ptr->valid == 1) { //retest, maybe has been changed?
6585 if ((tv.tv_sec * 1000 + tv.tv_usec / 1000) > ((ptr->tv_sec * 1000 + ptr->tv_usec / 1000) + 1000)) { //retest, maybe has been changed?
6586
6587 if (option_debug > 1)
6588 DEBUGA_CVM("RESEND TxSeq=%X, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
6589 ptr->txseqno,
6590 ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
6591 (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)), ptr->how_many_sent);
6592
6593 if (ptr->how_many_sent > 9) {
6594 ERRORA("RESEND TxSeq=%X, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
6595 ptr->txseqno,
6596 ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
6597 (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)), ptr->how_many_sent);
6598
6599 CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6600 return -1;
6601 }
6602
6603 celliax_serial_send_CVM_BUSMAIL(p, ptr->busmail_msg_len,
6604 ptr->busmail_msg_buffer);
6605
6606 ptr->tv_sec = tv.tv_sec;
6607 ptr->tv_usec = tv.tv_usec;
6608 ptr->sent = 1;
6609 ptr->how_many_sent++;
6610 /*
6611 if (option_debug > 1) {
6612 DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6613 celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6614 DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG);
6615 }
6616 */
6617 }
6618 }
6619
6620 CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6621 POPPA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6622 }
6623 }
6624
6625 if (ptr->sent == 0 && ptr->acknowledged == 0 && ptr->valid == 1) {
6626
6627 PUSHA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6628 CVM_LOKKA(&p->cvm_busmail_outgoing_list_lock);
6629
6630 if (ptr->sent == 0 && ptr->acknowledged == 0 && ptr->valid == 1) { //retest, maybe has been changed?
6631
6632 if (option_debug > 1)
6633 DEBUGA_CVM("SENDING 1st TIME TxSeq=%X\n", CELLIAX_P_LOG, ptr->txseqno);
6634
6635 celliax_serial_send_CVM_BUSMAIL(p, ptr->busmail_msg_len, ptr->busmail_msg_buffer);
6636
6637 ptr->tv_sec = tv.tv_sec;
6638 ptr->tv_usec = tv.tv_usec;
6639 ptr->sent = 1;
6640 ptr->how_many_sent++;
6641 /*
6642 if (option_debug > 1) {
6643 DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6644 celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6645 DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG);
6646 }
6647 */
6648 }
6649
6650 CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6651 POPPA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6652
6653 }
6654 return 0;
6655 }
6656
celliax_serial_write_CVM_BUSMAIL(struct celliax_pvt * p,struct cvm_busmail_frame * busmail_frame)6657 int celliax_serial_write_CVM_BUSMAIL(struct celliax_pvt *p,
6658 struct cvm_busmail_frame *busmail_frame)
6659 {
6660 unsigned char buffer2[BUSMAIL_MAX_FRAME_LENGTH];
6661 int i = 0;
6662 int len = 0;
6663 unsigned int busmail_len_total = 0;
6664
6665 busmail_frame->busmail_sof = BUSMAIL_SOF;
6666 busmail_frame->busmail_crc = 0;
6667
6668 /* because of Rx Tx SEQ HEADER fields problem, update when these fields are filled with correct data
6669 busmail_frame->busmail_crc = (unsigned char)(busmail_frame->busmail_header + busmail_frame->busmail_crc);
6670 */
6671
6672 buffer2[BUSMAIL_OFFSET_SOF] = busmail_frame->busmail_sof;
6673 buffer2[BUSMAIL_OFFSET_HEADER] = busmail_frame->busmail_header;
6674
6675 if ((buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_IC_BIT_MASK) ==
6676 BUSMAIL_HEADER_INFO_FRAME) {
6677 len =
6678 BUSMAIL_OFFSET_MAIL_PARAMS + busmail_frame->busmail_mail_params_buffer_len +
6679 sizeof(busmail_frame->busmail_crc);
6680 busmail_len_total =
6681 busmail_frame->busmail_mail_params_buffer_len +
6682 sizeof(busmail_frame->busmail_header)
6683 + sizeof(busmail_frame->busmail_mail_program_id) +
6684 sizeof(busmail_frame->busmail_mail_task_id) + 2;
6685
6686 if (option_debug > 1)
6687 DEBUGA_CVM("INFO frame to send\n", CELLIAX_P_LOG);
6688
6689 buffer2[BUSMAIL_OFFSET_MAIL_PROGRAM_ID] = busmail_frame->busmail_mail_program_id;
6690 buffer2[BUSMAIL_OFFSET_MAIL_TASK_ID] = busmail_frame->busmail_mail_task_id;
6691 buffer2[BUSMAIL_OFFSET_MAIL_PRIMITIVE_LSB] =
6692 busmail_frame->busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_LSB];
6693 buffer2[BUSMAIL_OFFSET_MAIL_PRIMITIVE_MSB] =
6694 busmail_frame->busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_MSB];
6695
6696 if (busmail_frame->busmail_mail_params_buffer_len) {
6697 memcpy(buffer2 + BUSMAIL_OFFSET_MAIL_PARAMS,
6698 busmail_frame->busmail_mail_params_buffer,
6699 busmail_frame->busmail_mail_params_buffer_len);
6700 }
6701
6702 for (i = 0; i < busmail_frame->busmail_mail_params_buffer_len; i++) {
6703 busmail_frame->busmail_crc =
6704 (unsigned char) (busmail_frame->busmail_mail_params_buffer[i] +
6705 busmail_frame->busmail_crc);
6706 }
6707
6708 busmail_frame->busmail_crc += busmail_frame->busmail_mail_program_id;
6709 busmail_frame->busmail_crc += busmail_frame->busmail_mail_task_id;
6710 busmail_frame->busmail_crc +=
6711 busmail_frame->busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_LSB];
6712 busmail_frame->busmail_crc +=
6713 busmail_frame->busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_MSB];
6714 } else {
6715 busmail_len_total = sizeof(busmail_frame->busmail_header);
6716 len = BUSMAIL_OFFSET_MAIL + sizeof(busmail_frame->busmail_crc);
6717
6718 if (option_debug > 1)
6719 DEBUGA_CVM("CTRL frame to send\n", CELLIAX_P_LOG);
6720 }
6721
6722 /*
6723 DEBUGA_CVM("Its len=%d\n", CELLIAX_P_LOG, len);
6724 */
6725
6726 busmail_frame->busmail_len[BUSMAIL_LEN_LSB] =
6727 (unsigned char) (busmail_len_total & 0xFF);
6728 busmail_frame->busmail_len[BUSMAIL_LEN_MSB] = (unsigned char) (busmail_len_total >> 8);
6729 buffer2[BUSMAIL_OFFSET_LEN_MSB] = busmail_frame->busmail_len[BUSMAIL_LEN_MSB];
6730 buffer2[BUSMAIL_OFFSET_LEN_LSB] = busmail_frame->busmail_len[BUSMAIL_LEN_LSB];
6731
6732 /*
6733 buffer2[len-1] = busmail_frame->busmail_crc;
6734 */
6735 buffer2[len - 1] = 0xFF;
6736
6737 if ((buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_IC_BIT_MASK) ==
6738 BUSMAIL_HEADER_INFO_FRAME) {
6739 /* if it is INFO frame, queue it */
6740
6741 /* update TxSeq and RxSeq bits */
6742 /* clear TxSeq and RxSeq bits */
6743 buffer2[BUSMAIL_OFFSET_HEADER] &=
6744 ~(BUSMAIL_HEADER_RXSEQ_MASK | BUSMAIL_HEADER_TXSEQ_MASK);
6745
6746 buffer2[BUSMAIL_OFFSET_HEADER] |=
6747 (p->busmail_rxseq_cvm_last + 1) & BUSMAIL_HEADER_RXSEQ_MASK;
6748
6749 p->busmail_txseq_celliax_last++;
6750 p->busmail_txseq_celliax_last &= 0x07;
6751
6752 buffer2[BUSMAIL_OFFSET_HEADER] |=
6753 ((p->busmail_txseq_celliax_last) << 4) & BUSMAIL_HEADER_TXSEQ_MASK;
6754
6755 /* update CRC */
6756 busmail_frame->busmail_crc += buffer2[BUSMAIL_OFFSET_HEADER];
6757 buffer2[len - 1] = busmail_frame->busmail_crc;
6758
6759 p->cvm_busmail_outgoing_list = celliax_serial_list_init_CVM_BUSMAIL(p);
6760 p->cvm_busmail_outgoing_list->busmail_msg_len = len;
6761
6762 for (i = 0; i < len; i++) {
6763 p->cvm_busmail_outgoing_list->busmail_msg_buffer[i] = buffer2[i];
6764 }
6765
6766 if (option_debug > 10) {
6767 char debug_buf[1024];
6768 char *debug_buf_pos;
6769
6770 memset(debug_buf, 0, 1024);
6771 debug_buf_pos = debug_buf;
6772
6773 for (i = 0; i < len; i++) {
6774 debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", buffer2[i]);
6775 if (debug_buf_pos > (char *) (&debug_buf + 1000))
6776 break;
6777 }
6778
6779 if (option_debug > 1)
6780 DEBUGA_CVM("INFO: %s was prepared to send\n", CELLIAX_P_LOG, debug_buf);
6781 }
6782
6783 if (option_debug > 1) {
6784 DEBUGA_CVM("OUTGOING INFO Frame TxSeq is %X, RxSeq is %X\n", CELLIAX_P_LOG,
6785 (buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_TXSEQ_MASK) >> 4,
6786 buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK);
6787 /*
6788 DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6789 celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6790 DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG); */
6791 }
6792 p->cvm_busmail_outgoing_list->txseqno =
6793 (unsigned char) (buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_TXSEQ_MASK) >> 4;
6794 p->cvm_busmail_outgoing_list->valid = 1; /* ready to send (?) */
6795
6796 } else {
6797 /* if it is CTRL frame, send it straight to the wire */
6798 if (BUSMAIL_HEADER_SABM !=
6799 (buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SABM_MASK)) {
6800 /*SABM ctrl frames have no RxSeq bits */
6801
6802 buffer2[BUSMAIL_OFFSET_HEADER] &= ~BUSMAIL_HEADER_RXSEQ_MASK;
6803
6804 if (BUSMAIL_HEADER_REJ ==
6805 (buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_REJ_MASK)) {
6806
6807 if (option_debug > 1)
6808 DEBUGA_CVM("CTRL REJ frame...\n", CELLIAX_P_LOG);
6809
6810 if (0xFF != p->busmail_rxseq_cvm_last) {
6811 buffer2[BUSMAIL_OFFSET_HEADER] |=
6812 (p->busmail_rxseq_cvm_last + 1) & BUSMAIL_HEADER_RXSEQ_MASK;
6813 } else {
6814 if (option_debug > 1)
6815 DEBUGA_CVM
6816 ("Skipping sending REJ, because we just cleared RxSeq counter, and probably it was a packet that is invalid now...\n",
6817 CELLIAX_P_LOG);
6818 return 0;
6819 }
6820
6821 } else {
6822 buffer2[BUSMAIL_OFFSET_HEADER] |=
6823 (p->busmail_rxseq_cvm_last + 1) & BUSMAIL_HEADER_RXSEQ_MASK;
6824 }
6825 }
6826
6827 /* update CRC */
6828 busmail_frame->busmail_crc += buffer2[BUSMAIL_OFFSET_HEADER];
6829 buffer2[len - 1] = busmail_frame->busmail_crc;
6830
6831 if (option_debug > 10) {
6832 char debug_buf[1024];
6833 char *debug_buf_pos;
6834
6835 memset(debug_buf, 0, 1024);
6836 debug_buf_pos = debug_buf;
6837
6838 for (i = 0; i < len; i++) {
6839 debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", buffer2[i]);
6840 if (debug_buf_pos > (char *) (&debug_buf + 1000))
6841 break;
6842 }
6843
6844 if (option_debug > 1)
6845 DEBUGA_CVM("CTRL: %s was prepared to send\n", CELLIAX_P_LOG, debug_buf);
6846 }
6847 // usleep(100);
6848 celliax_serial_send_CVM_BUSMAIL(p, len, buffer2);
6849 }
6850
6851 return 0;
6852 }
6853
celliax_serial_send_ctrl_frame_CVM_BUSMAIL(struct celliax_pvt * p,unsigned char FrameType)6854 int celliax_serial_send_ctrl_frame_CVM_BUSMAIL(struct celliax_pvt *p,
6855 unsigned char FrameType)
6856 {
6857 /*FrameType parameter is really a busmail header with info neeeded to tell the frame type to send */
6858 struct cvm_busmail_frame busmail_frame;
6859
6860 switch (FrameType & 0xF0) {
6861 /* only higher nibble is important for us, do not take PF bit into considration */
6862
6863 case BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_RR:
6864 case BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_REJ:
6865 case BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_RNR:
6866 case BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_UN_FRAME | BUSMAIL_HEADER_UNID_SABM:
6867
6868 busmail_frame.busmail_header =
6869 (FrameType & 0xF8);
6870
6871 break;
6872
6873 default:
6874 WARNINGA("UNKNOWN CTRL TYPE specified, sending nothing!!!\n", CELLIAX_P_LOG);
6875 return -1;
6876 break;
6877 }
6878
6879 busmail_frame.busmail_mail_params_buffer_len = 0;
6880
6881 /* Sending to CVM */
6882 return celliax_serial_write_CVM_BUSMAIL(p, &busmail_frame);
6883 }
6884
celliax_serial_send_info_frame_CVM_BUSMAIL(struct celliax_pvt * p,int FrameType,unsigned char ParamsLen,unsigned char * Params)6885 int celliax_serial_send_info_frame_CVM_BUSMAIL(struct celliax_pvt *p, int FrameType,
6886 unsigned char ParamsLen,
6887 unsigned char *Params)
6888 {
6889 /*FrameType parameter is really a Primitive ID */
6890 struct cvm_busmail_frame busmail_frame;
6891 int i = 0;
6892 busmail_frame.busmail_header =
6893 (BUSMAIL_HEADER_PF_BIT_MASK & 0xFF) | BUSMAIL_HEADER_INFO_FRAME;
6894
6895 busmail_frame.busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_LSB] = FrameType & 0xFF;
6896 busmail_frame.busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_MSB] =
6897 (FrameType >> 8) & 0xFF;
6898
6899 busmail_frame.busmail_mail_program_id = BUSMAIL_MAIL_PROGRAM_ID;
6900 busmail_frame.busmail_mail_task_id = BUSMAIL_MAIL_TASK_ID;
6901
6902 for (i = 0; i < ParamsLen; i++) {
6903 busmail_frame.busmail_mail_params_buffer[i] = Params[i];
6904 }
6905
6906 busmail_frame.busmail_mail_params_buffer_len = ParamsLen;
6907
6908 /* Sending to CVM */
6909 return celliax_serial_write_CVM_BUSMAIL(p, &busmail_frame);
6910 }
6911
celliax_serial_lists_free_CVM_BUSMAIL(struct celliax_pvt * p)6912 int celliax_serial_lists_free_CVM_BUSMAIL(struct celliax_pvt *p)
6913 {
6914 struct cvm_busmail_msg *ptr, *prev;
6915 /*
6916 if (option_debug > 1) {
6917 DEBUGA_CVM("START FREEING OUTGOING\n", CELLIAX_P_LOG);
6918 DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6919 celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6920 DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG);
6921 }
6922 */
6923 ptr = p->cvm_busmail_outgoing_list;
6924
6925 if (ptr) {
6926 while (ptr->next != NULL)
6927 ptr = ptr->next;
6928
6929 while (ptr->previous != NULL) {
6930
6931 if (option_debug > 1)
6932 DEBUGA_CVM("FREED \n", CELLIAX_P_LOG);
6933
6934 prev = ptr->previous;
6935 free(ptr);
6936 ptr = prev;
6937 }
6938
6939 free(ptr);
6940 }
6941
6942 if (option_debug > 1)
6943 DEBUGA_CVM("LAST FREED \n", CELLIAX_P_LOG);
6944
6945 p->cvm_busmail_outgoing_list = NULL;
6946 p->cvm_busmail_outgoing_list = celliax_serial_list_init_CVM_BUSMAIL(p);
6947
6948 if (option_debug > 1) {
6949 DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6950 celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6951 DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG);
6952 DEBUGA_CVM("STARTING FREE INGOING\n", CELLIAX_P_LOG);
6953 }
6954
6955 return 0;
6956 }
6957
celliax_serial_list_init_CVM_BUSMAIL(struct celliax_pvt * p)6958 struct cvm_busmail_msg *celliax_serial_list_init_CVM_BUSMAIL(struct celliax_pvt *p)
6959 {
6960 struct cvm_busmail_msg *list;
6961 list = p->cvm_busmail_outgoing_list;
6962
6963 PUSHA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6964 CVM_LOKKA(&p->cvm_busmail_outgoing_list_lock);
6965
6966 if (list == NULL) {
6967 list = malloc(sizeof(*(list)));
6968 list->valid = 0;
6969 list->busmail_msg_len = 0;
6970 list->acknowledged = 0;
6971 list->how_many_sent = 0;
6972 list->sent = 0;
6973 list->tv_sec = 0;
6974 list->tv_usec = 0;
6975 list->next = NULL;
6976 list->previous = NULL;
6977 }
6978
6979 if (list->valid != 0) {
6980 struct cvm_busmail_msg *new;
6981 new = malloc(sizeof(*new));
6982 new->valid = 0;
6983 new->busmail_msg_len = 0;
6984 new->acknowledged = 0;
6985 new->how_many_sent = 0;
6986 new->sent = 0;
6987 new->tv_sec = 0;
6988 new->tv_usec = 0;
6989 new->next = NULL;
6990 new->previous = list;
6991 list->next = new;
6992 list = new;
6993 }
6994
6995 CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6996 POPPA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6997
6998 return list;
6999 }
7000
celliax_serial_list_print_CVM_BUSMAIL(struct celliax_pvt * p,struct cvm_busmail_msg * list)7001 int celliax_serial_list_print_CVM_BUSMAIL(struct celliax_pvt *p,
7002 struct cvm_busmail_msg *list)
7003 {
7004 struct cvm_busmail_msg *ptr;
7005 ptr = list;
7006
7007 if (ptr) {
7008 while (ptr->next != NULL)
7009 ptr = ptr->next;
7010
7011 while (ptr) {
7012
7013 if (option_debug > 3)
7014 DEBUGA_CVM
7015 ("PTR msg is: %d, seqnum is %.2X, tv_sec is %d, tv_usec is %d, acknowledged is: %d,"
7016 " sent is:%d, how_many_sent is: %d\n", CELLIAX_P_LOG, ptr->valid,
7017 /*ptr->seqnum */ 44,
7018 ptr->tv_sec, ptr->tv_usec, ptr->acknowledged, ptr->sent, ptr->how_many_sent);
7019
7020 ptr = ptr->previous;
7021 }
7022 }
7023
7024 return 0;
7025 }
7026
7027 #endif /* CELLIAX_CVM */
7028