3 * AT chat library with GLib integration
5 * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
6 * Copyright (C) 2009 Trolltech ASA.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 #include "ringbuffer.h"
39 static const char *cmux_prefix[] = { "+CMUX:", NULL };
40 static const char *none_prefix[] = { NULL };
42 typedef struct _GAtMuxChannel GAtMuxChannel;
43 typedef struct _GAtMuxWatch GAtMuxWatch;
44 typedef void (*GAtMuxWriteFrame)(GAtMux *mux, guint8 dlc, guint8 control,
45 const guint8 *data, int len);
47 /* While 63 channels are theoretically possible, channel 62 and 63 is reserved
48 * by 27.010 for use as the beginning of frame and end of frame flags.
49 * Refer to Section 5.6 in 27.007
51 #define MAX_CHANNELS 61
53 #define MUX_CHANNEL_BUFFER_SIZE 4096
54 #define MUX_BUFFER_SIZE 4096
60 GIOCondition condition;
61 struct ring_buffer *buffer;
71 GIOCondition condition;
75 gint ref_count; /* Ref count */
76 guint read_watch; /* GSource read id, 0 if none */
77 guint write_watch; /* GSource write id, 0 if none */
78 GIOChannel *channel; /* main serial channel */
79 GAtDisconnectFunc user_disconnect; /* user disconnect func */
80 gpointer user_disconnect_data; /* user disconnect data */
81 GAtDebugFunc debugf; /* debugging output function */
82 gpointer debug_data; /* Data to pass to debug func */
83 GAtMuxChannel *dlcs[MAX_CHANNELS]; /* DLCs opened by the MUX */
84 guint8 newdata[BITMAP_SIZE]; /* Channels that got new data */
85 const GAtMuxDriver *driver; /* Driver functions */
86 void *driver_data; /* Driver data */
87 char buf[MUX_BUFFER_SIZE]; /* Buffer on the main mux */
88 int buf_used; /* Bytes of buf being used */
92 struct mux_setup_data {
96 GDestroyNotify destroy;
101 static inline void debug(GAtMux *mux, const char *format, ...)
106 if (mux->debugf == NULL)
109 va_start(ap, format);
111 if (vsnprintf(str, sizeof(str), format, ap) > 0)
112 mux->debugf(str, mux->debug_data);
117 static void dispatch_sources(GAtMuxChannel *channel, GIOCondition condition)
125 c = channel->sources;
128 gboolean destroy = FALSE;
132 debug(channel->mux, "checking source: %p", source);
134 if (condition & source->condition) {
135 gpointer user_data = NULL;
136 GSourceFunc callback = NULL;
137 GSourceCallbackFuncs *cb_funcs;
139 gboolean (*dispatch) (GSource *, GSourceFunc, gpointer);
141 debug(channel->mux, "dispatching source: %p", source);
143 dispatch = source->source.source_funcs->dispatch;
144 cb_funcs = source->source.callback_funcs;
145 cb_data = source->source.callback_data;
148 cb_funcs->ref(cb_data);
151 cb_funcs->get(cb_data, (GSource *) source,
152 &callback, &user_data);
154 destroy = !dispatch((GSource *) source, callback,
158 cb_funcs->unref(cb_data);
162 debug(channel->mux, "removing source: %p", source);
164 g_source_destroy((GSource *) source);
169 channel->sources = c->next;
181 static gboolean received_data(GIOChannel *channel, GIOCondition cond,
189 if (cond & G_IO_NVAL)
192 debug(mux, "received data");
195 status = g_io_channel_read_chars(mux->channel, mux->buf + mux->buf_used,
196 sizeof(mux->buf) - mux->buf_used,
199 mux->buf_used += bytes_read;
201 if (bytes_read > 0 && mux->driver->feed_data) {
204 memset(mux->newdata, 0, BITMAP_SIZE);
206 nread = mux->driver->feed_data(mux, mux->buf, mux->buf_used);
207 mux->buf_used -= nread;
209 if (mux->buf_used > 0)
210 memmove(mux->buf, mux->buf + nread, mux->buf_used);
212 for (i = 1; i <= MAX_CHANNELS; i++) {
216 if (!(mux->newdata[offset] & (1 << bit)))
219 debug(mux, "dispatching sources for channel: %p",
222 dispatch_sources(mux->dlcs[i-1], G_IO_IN);
226 if (cond & (G_IO_HUP | G_IO_ERR))
229 if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN)
232 if (mux->buf_used == sizeof(mux->buf))
238 static void write_watcher_destroy_notify(gpointer user_data)
240 GAtMux *mux = user_data;
242 mux->write_watch = 0;
245 static gboolean can_write_data(GIOChannel *chan, GIOCondition cond,
251 if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
254 debug(mux, "can write data");
256 for (dlc = 0; dlc < MAX_CHANNELS; dlc += 1) {
257 GAtMuxChannel *channel = mux->dlcs[dlc];
262 debug(mux, "checking channel for write: %p", channel);
264 if (channel->throttled)
267 debug(mux, "dispatching write sources: %p", channel);
269 dispatch_sources(channel, G_IO_OUT);
272 for (dlc = 0; dlc < MAX_CHANNELS; dlc += 1) {
273 GAtMuxChannel *channel = mux->dlcs[dlc];
280 if (channel->throttled)
283 for (l = channel->sources; l; l = l->next) {
286 if (source->condition & G_IO_OUT)
294 static void wakeup_writer(GAtMux *mux)
296 if (mux->write_watch != 0)
299 debug(mux, "waking up writer");
301 mux->write_watch = g_io_add_watch_full(mux->channel,
303 G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
305 write_watcher_destroy_notify);
308 int g_at_mux_raw_write(GAtMux *mux, const void *data, int towrite)
310 gssize count = towrite;
313 g_io_channel_write_chars(mux->channel, (gchar *) data,
314 count, &bytes_written, NULL);
316 return bytes_written;
319 void g_at_mux_feed_dlc_data(GAtMux *mux, guint8 dlc,
320 const void *data, int tofeed)
322 GAtMuxChannel *channel;
328 debug(mux, "deliver_data: dlc: %hu", dlc);
330 if (dlc < 1 || dlc > MAX_CHANNELS)
333 channel = mux->dlcs[dlc-1];
338 written = ring_buffer_write(channel->buffer, data, tofeed);
346 mux->newdata[offset] |= 1 << bit;
347 channel->condition |= G_IO_IN;
350 void g_at_mux_set_dlc_status(GAtMux *mux, guint8 dlc, int status)
352 GAtMuxChannel *channel;
354 debug(mux, "got status %d, for channel %hu", status, dlc);
356 if (dlc < 1 || dlc > MAX_CHANNELS)
359 channel = mux->dlcs[dlc-1];
363 if (status & G_AT_MUX_DLC_STATUS_RTR) {
366 mux->dlcs[dlc-1]->throttled = FALSE;
367 debug(mux, "setting throttled to FALSE");
369 for (l = mux->dlcs[dlc-1]->sources; l; l = l->next) {
370 GAtMuxWatch *source = l->data;
372 if (source->condition & G_IO_OUT) {
378 mux->dlcs[dlc-1]->throttled = TRUE;
381 void g_at_mux_set_data(GAtMux *mux, void *data)
386 mux->driver_data = data;
389 void *g_at_mux_get_data(GAtMux *mux)
394 return mux->driver_data;
397 static gboolean watch_check(GSource *source)
402 static gboolean watch_prepare(GSource *source, gint *timeout)
408 static gboolean watch_dispatch(GSource *source, GSourceFunc callback,
411 GIOFunc func = (GIOFunc) callback;
412 GAtMuxWatch *watch = (GAtMuxWatch *) source;
413 GAtMuxChannel *channel = (GAtMuxChannel *) watch->channel;
418 return func(watch->channel, channel->condition & watch->condition,
422 static void watch_finalize(GSource *source)
424 GAtMuxWatch *watch = (GAtMuxWatch *) source;
426 g_io_channel_unref(watch->channel);
429 static GSourceFuncs watch_funcs = {
436 static GIOStatus channel_read(GIOChannel *channel, gchar *buf, gsize count,
437 gsize *bytes_read, GError **err)
439 GAtMuxChannel *mux_channel = (GAtMuxChannel *) channel;
440 unsigned int avail = ring_buffer_len_no_wrap(mux_channel->buffer);
445 *bytes_read = ring_buffer_read(mux_channel->buffer, buf, avail);
447 if (*bytes_read == 0)
448 return G_IO_STATUS_AGAIN;
450 return G_IO_STATUS_NORMAL;
453 static GIOStatus channel_write(GIOChannel *channel, const gchar *buf,
454 gsize count, gsize *bytes_written, GError **err)
456 GAtMuxChannel *mux_channel = (GAtMuxChannel *) channel;
457 GAtMux *mux = mux_channel->mux;
459 if (mux->driver->write)
460 mux->driver->write(mux, mux_channel->dlc, buf, count);
461 *bytes_written = count;
463 return G_IO_STATUS_NORMAL;
466 static GIOStatus channel_seek(GIOChannel *channel, gint64 offset,
467 GSeekType type, GError **err)
469 return G_IO_STATUS_NORMAL;
472 static GIOStatus channel_close(GIOChannel *channel, GError **err)
474 GAtMuxChannel *mux_channel = (GAtMuxChannel *) channel;
475 GAtMux *mux = mux_channel->mux;
477 debug(mux, "closing channel: %d", mux_channel->dlc);
479 dispatch_sources(mux_channel, G_IO_NVAL);
481 if (mux->driver->close_dlc)
482 mux->driver->close_dlc(mux, mux_channel->dlc);
484 mux->dlcs[mux_channel->dlc - 1] = NULL;
486 return G_IO_STATUS_NORMAL;
489 static void channel_free(GIOChannel *channel)
491 GAtMuxChannel *mux_channel = (GAtMuxChannel *) channel;
493 ring_buffer_free(mux_channel->buffer);
498 static GSource *channel_create_watch(GIOChannel *channel,
499 GIOCondition condition)
503 GAtMuxChannel *dlc = (GAtMuxChannel *) channel;
504 GAtMux *mux = dlc->mux;
506 source = g_source_new(&watch_funcs, sizeof(GAtMuxWatch));
507 watch = (GAtMuxWatch *) source;
509 watch->channel = channel;
510 g_io_channel_ref(channel);
512 watch->condition = condition;
514 if ((watch->condition & G_IO_OUT) && dlc->throttled == FALSE)
517 debug(mux, "creating source: %p, channel: %p, writer: %d, reader: %d",
519 condition & G_IO_OUT,
520 condition & G_IO_IN);
522 dlc->sources = g_slist_prepend(dlc->sources, watch);
527 static GIOStatus channel_set_flags(GIOChannel *channel, GIOFlags flags,
530 return G_IO_STATUS_NORMAL;
533 static GIOFlags channel_get_flags(GIOChannel *channel)
540 static GIOFuncs channel_funcs = {
545 channel_create_watch,
551 GAtMux *g_at_mux_new(GIOChannel *channel, const GAtMuxDriver *driver)
558 mux = g_try_new0(GAtMux, 1);
563 mux->driver = driver;
564 mux->shutdown = TRUE;
566 mux->channel = channel;
567 g_io_channel_ref(channel);
569 g_io_channel_set_close_on_unref(channel, TRUE);
574 GAtMux *g_at_mux_ref(GAtMux *mux)
579 g_atomic_int_inc(&mux->ref_count);
584 void g_at_mux_unref(GAtMux *mux)
589 if (g_atomic_int_dec_and_test(&mux->ref_count)) {
590 g_at_mux_shutdown(mux);
592 g_io_channel_unref(mux->channel);
594 if (mux->driver->remove)
595 mux->driver->remove(mux);
601 gboolean g_at_mux_start(GAtMux *mux)
603 if (mux->channel == NULL)
606 if (mux->driver->startup == NULL)
609 if (mux->driver->startup(mux) == FALSE)
612 mux->read_watch = g_io_add_watch_full(mux->channel, G_PRIORITY_DEFAULT,
613 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
614 received_data, mux, NULL);
616 mux->shutdown = FALSE;
621 gboolean g_at_mux_shutdown(GAtMux *mux)
625 if (mux->shutdown == TRUE)
628 if (mux->channel == NULL)
631 if (mux->read_watch > 0)
632 g_source_remove(mux->read_watch);
634 for (i = 0; i < MAX_CHANNELS; i++) {
635 if (mux->dlcs[i] == NULL)
638 channel_close((GIOChannel *) mux->dlcs[i], NULL);
641 if (mux->driver->shutdown)
642 mux->driver->shutdown(mux);
644 mux->shutdown = TRUE;
649 gboolean g_at_mux_set_disconnect_function(GAtMux *mux,
650 GAtDisconnectFunc disconnect, gpointer user_data)
655 mux->user_disconnect = disconnect;
656 mux->user_disconnect_data = user_data;
661 gboolean g_at_mux_set_debug(GAtMux *mux, GAtDebugFunc func, gpointer user_data)
667 mux->debug_data = user_data;
672 GIOChannel *g_at_mux_create_channel(GAtMux *mux)
674 GAtMuxChannel *mux_channel;
678 for (i = 0; i < MAX_CHANNELS; i++) {
679 if (mux->dlcs[i] == NULL)
683 if (i == MAX_CHANNELS)
686 mux_channel = g_try_new0(GAtMuxChannel, 1);
687 if (mux_channel == NULL)
690 if (mux->driver->open_dlc)
691 mux->driver->open_dlc(mux, i+1);
693 channel = (GIOChannel *) mux_channel;
695 g_io_channel_init(channel);
696 channel->close_on_unref = TRUE;
697 channel->funcs = &channel_funcs;
699 channel->is_seekable = FALSE;
700 channel->is_readable = TRUE;
701 channel->is_writeable = TRUE;
703 channel->do_encode = FALSE;
705 mux_channel->mux = mux;
706 mux_channel->dlc = i+1;
707 mux_channel->buffer = ring_buffer_new(MUX_CHANNEL_BUFFER_SIZE);
708 mux_channel->throttled = FALSE;
710 mux->dlcs[i] = mux_channel;
712 debug(mux, "created channel %p, dlc: %d", channel, i+1);
717 static void msd_free(gpointer user_data)
719 struct mux_setup_data *msd = user_data;
722 g_at_chat_unref(msd->chat);
727 static void mux_setup_cb(gboolean ok, GAtResult *result, gpointer user_data)
729 struct mux_setup_data *msd = user_data;
737 channel = g_at_chat_get_channel(msd->chat);
738 channel = g_io_channel_ref(channel);
740 g_at_chat_unref(msd->chat);
743 flags = g_io_channel_get_flags(channel) | G_IO_FLAG_NONBLOCK;
744 g_io_channel_set_flags(channel, flags, NULL);
746 g_io_channel_set_encoding(channel, NULL, NULL);
747 g_io_channel_set_buffered(channel, FALSE);
750 mux = g_at_mux_new_gsm0710_basic(channel, msd->frame_size);
752 mux = g_at_mux_new_gsm0710_advanced(channel, msd->frame_size);
754 g_io_channel_unref(channel);
757 msd->func(mux, msd->user);
760 msd->destroy(msd->user);
763 static void mux_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
765 struct mux_setup_data *msd = user_data;
766 struct mux_setup_data *nmsd;
772 /* CMUX query not supported, abort */
776 g_at_result_iter_init(&iter, result);
778 if (!g_at_result_iter_next(&iter, "+CMUX:"))
782 if (!g_at_result_iter_open_list(&iter))
785 if (!g_at_result_iter_next_range(&iter, &min, &max))
788 if (!g_at_result_iter_close_list(&iter))
791 if (min <= 1 && 1 <= max)
793 else if (min <= 0 && 0 <= max)
799 if (!g_at_result_iter_open_list(&iter))
802 if (!g_at_result_iter_next_range(&iter, &min, &max))
805 if (!g_at_result_iter_close_list(&iter))
811 /* Speed, pick highest */
812 if (g_at_result_iter_open_list(&iter)) {
813 if (!g_at_result_iter_next_range(&iter, &min, &max))
816 if (!g_at_result_iter_close_list(&iter))
821 if (!g_at_result_iter_skip_next(&iter))
824 /* not available/used */
828 /* Frame size, pick defaults */
829 if (!g_at_result_iter_open_list(&iter))
832 if (!g_at_result_iter_next_range(&iter, &min, &max))
835 if (!g_at_result_iter_close_list(&iter))
838 if (msd->mode == 0) {
839 if (min > 31 || max < 31)
842 msd->frame_size = 31;
843 } else if (msd->mode == 1) {
844 if (min > 64 || max < 64)
847 msd->frame_size = 64;
851 nmsd = g_memdup(msd, sizeof(struct mux_setup_data));
852 g_at_chat_ref(nmsd->chat);
855 sprintf(buf, "AT+CMUX=%u,0,,%u", msd->mode, msd->frame_size);
857 sprintf(buf, "AT+CMUX=%u,0,%u,%u", msd->mode, speed,
860 if (g_at_chat_send(msd->chat, buf, none_prefix,
861 mux_setup_cb, nmsd, msd_free) > 0)
867 msd->func(NULL, msd->user);
870 msd->destroy(msd->user);
873 gboolean g_at_mux_setup_gsm0710(GAtChat *chat,
874 GAtMuxSetupFunc notify, gpointer user_data,
875 GDestroyNotify destroy)
877 struct mux_setup_data *msd;
885 msd = g_new0(struct mux_setup_data, 1);
887 msd->chat = g_at_chat_ref(chat);
889 msd->user = user_data;
890 msd->destroy = destroy;
892 if (g_at_chat_send(chat, "AT+CMUX=?", cmux_prefix,
893 mux_query_cb, msd, msd_free) > 0)
902 #define GSM0710_BUFFER_SIZE 4096
904 struct gsm0710_data {
908 /* Process an incoming GSM 07.10 packet */
909 static gboolean gsm0710_packet(GAtMux *mux, int dlc, guint8 control,
910 const unsigned char *data, int len,
911 GAtMuxWriteFrame write_frame)
913 if (control == 0xEF || control == 0x03) {
914 if (dlc >= 1 && dlc <= 63) {
915 g_at_mux_feed_dlc_data(mux, dlc, data, len);
920 /* An embedded command or response on channel 0 */
921 if (len >= 2 && data[0] == GSM0710_STATUS_SET) {
922 return gsm0710_packet(mux, dlc,
926 } else if (len >= 2 && data[0] == 0x43) {
927 /* Test command from other side - send the same bytes back */
928 unsigned char *resp = alloca(len);
929 memcpy(resp, data, len);
930 resp[0] = 0x41; /* Clear the C/R bit in the response */
931 write_frame(mux, 0, GSM0710_DATA, resp, len);
934 } else if (control == GSM0710_STATUS_ACK && dlc == 0) {
935 unsigned char resp[33];
937 /* Status change message */
939 /* Handle status changes on other channels */
940 dlc = ((data[0] & 0xFC) >> 2);
942 if (dlc >= 1 && dlc <= 63)
943 g_at_mux_set_dlc_status(mux, dlc, data[1]);
946 /* Send the response to the status change request to ACK it */
947 debug(mux, "received status line signal, sending response");
950 resp[0] = GSM0710_STATUS_ACK;
951 resp[1] = ((len << 1) | 0x01);
952 memcpy(resp + 2, data, len);
953 write_frame(mux, 0, GSM0710_DATA, resp, len + 2);
959 static void gsm0710_basic_write_frame(GAtMux *mux, guint8 dlc, guint8 control,
960 const guint8 *data, int towrite)
962 struct gsm0710_data *gd = g_at_mux_get_data(mux);
963 guint8 *frame = alloca(gd->frame_size + 7);
966 frame_size = gsm0710_basic_fill_frame(frame, dlc, control,
968 g_at_mux_raw_write(mux, frame, frame_size);
971 #define COMPOSE_STATUS_FRAME(data, dlc, status) \
973 data[0] = GSM0710_STATUS_SET; \
975 data[2] = ((dlc << 2) | 0x03); \
978 static void gsm0710_basic_remove(GAtMux *mux)
980 struct gsm0710_data *gd = g_at_mux_get_data(mux);
983 g_at_mux_set_data(mux, NULL);
986 static gboolean gsm0710_basic_startup(GAtMux *mux)
991 frame_size = gsm0710_basic_fill_frame(frame, 0, GSM0710_OPEN_CHANNEL,
993 g_at_mux_raw_write(mux, frame, frame_size);
998 static gboolean gsm0710_basic_shutdown(GAtMux *mux)
1003 frame_size = gsm0710_basic_fill_frame(frame, 0, GSM0710_CLOSE_CHANNEL,
1005 g_at_mux_raw_write(mux, frame, frame_size);
1010 static gboolean gsm0710_basic_open_dlc(GAtMux *mux, guint8 dlc)
1015 frame_size = gsm0710_basic_fill_frame(frame, dlc, GSM0710_OPEN_CHANNEL,
1017 g_at_mux_raw_write(mux, frame, frame_size);
1022 static gboolean gsm0710_basic_close_dlc(GAtMux *mux, guint8 dlc)
1027 frame_size = gsm0710_basic_fill_frame(frame, dlc, GSM0710_CLOSE_CHANNEL,
1029 g_at_mux_raw_write(mux, frame, frame_size);
1034 static int gsm0710_basic_feed_data(GAtMux *mux, void *data, int len)
1045 nread = gsm0710_basic_extract_frame(data, len, &dlc, &ctrl,
1046 &frame, &frame_len);
1055 gsm0710_packet(mux, dlc, ctrl, frame, frame_len,
1056 gsm0710_basic_write_frame);
1057 } while (nread > 0);
1062 static void gsm0710_basic_set_status(GAtMux *mux, guint8 dlc, guint8 status)
1064 struct gsm0710_data *gd = g_at_mux_get_data(mux);
1065 guint8 *frame = alloca(gd->frame_size + 7);
1068 COMPOSE_STATUS_FRAME(data, dlc, status);
1069 frame_size = gsm0710_basic_fill_frame(frame, 0, GSM0710_DATA, data, 4);
1070 g_at_mux_raw_write(mux, frame, frame_size);
1073 static void gsm0710_basic_write(GAtMux *mux, guint8 dlc,
1074 const void *data, int towrite)
1076 struct gsm0710_data *gd = g_at_mux_get_data(mux);
1077 guint8 *frame = alloca(gd->frame_size + 7);
1081 while (towrite > 0) {
1082 max = MIN(towrite, gd->frame_size);
1083 frame_size = gsm0710_basic_fill_frame(frame, dlc,
1084 GSM0710_DATA, data, max);
1085 g_at_mux_raw_write(mux, frame, frame_size);
1091 static GAtMuxDriver gsm0710_basic_driver = {
1092 .remove = gsm0710_basic_remove,
1093 .startup = gsm0710_basic_startup,
1094 .shutdown = gsm0710_basic_shutdown,
1095 .open_dlc = gsm0710_basic_open_dlc,
1096 .close_dlc = gsm0710_basic_close_dlc,
1097 .feed_data = gsm0710_basic_feed_data,
1098 .set_status = gsm0710_basic_set_status,
1099 .write = gsm0710_basic_write,
1102 GAtMux *g_at_mux_new_gsm0710_basic(GIOChannel *channel, int frame_size)
1105 struct gsm0710_data *gd;
1107 mux = g_at_mux_new(channel, &gsm0710_basic_driver);
1112 gd = g_new0(struct gsm0710_data, 1);
1113 gd->frame_size = frame_size;
1115 g_at_mux_set_data(mux, gd);
1120 static void gsm0710_advanced_write_frame(GAtMux *mux, guint8 dlc, guint8 control,
1121 const guint8 *data, int towrite)
1123 struct gsm0710_data *gd = g_at_mux_get_data(mux);
1124 guint8 *frame = alloca(gd->frame_size * 2 + 7);
1127 frame_size = gsm0710_advanced_fill_frame(frame, dlc, control,
1129 g_at_mux_raw_write(mux, frame, frame_size);
1132 static void gsm0710_advanced_remove(GAtMux *mux)
1134 struct gsm0710_data *gd = g_at_mux_get_data(mux);
1137 g_at_mux_set_data(mux, NULL);
1140 static gboolean gsm0710_advanced_startup(GAtMux *mux)
1142 guint8 frame[8]; /* Account for escapes */
1145 frame_size = gsm0710_advanced_fill_frame(frame, 0,
1146 GSM0710_OPEN_CHANNEL, NULL, 0);
1147 g_at_mux_raw_write(mux, frame, frame_size);
1152 static gboolean gsm0710_advanced_shutdown(GAtMux *mux)
1154 guint8 frame[8]; /* Account for escapes */
1157 frame_size = gsm0710_advanced_fill_frame(frame, 0,
1158 GSM0710_CLOSE_CHANNEL, NULL, 0);
1159 g_at_mux_raw_write(mux, frame, frame_size);
1164 static gboolean gsm0710_advanced_open_dlc(GAtMux *mux, guint8 dlc)
1166 guint8 frame[8]; /* Account for escapes */
1169 frame_size = gsm0710_advanced_fill_frame(frame, dlc,
1170 GSM0710_OPEN_CHANNEL, NULL, 0);
1171 g_at_mux_raw_write(mux, frame, frame_size);
1176 static gboolean gsm0710_advanced_close_dlc(GAtMux *mux, guint8 dlc)
1178 guint8 frame[8]; /* Account for escapes */
1181 frame_size = gsm0710_advanced_fill_frame(frame, dlc,
1182 GSM0710_CLOSE_CHANNEL, NULL, 0);
1183 g_at_mux_raw_write(mux, frame, frame_size);
1188 static int gsm0710_advanced_feed_data(GAtMux *mux, void *data, int len)
1199 nread = gsm0710_advanced_extract_frame(data, len, &dlc, &ctrl,
1200 &frame, &frame_len);
1209 gsm0710_packet(mux, dlc, ctrl, frame, frame_len,
1210 gsm0710_advanced_write_frame);
1211 } while (nread > 0);
1216 static void gsm0710_advanced_set_status(GAtMux *mux, guint8 dlc, guint8 status)
1218 struct gsm0710_data *gd = g_at_mux_get_data(mux);
1219 guint8 *frame = alloca(gd->frame_size * 2 + 7);
1222 COMPOSE_STATUS_FRAME(data, dlc, status);
1223 frame_size = gsm0710_advanced_fill_frame(frame, 0,
1224 GSM0710_DATA, data, 4);
1225 g_at_mux_raw_write(mux, frame, frame_size);
1228 static void gsm0710_advanced_write(GAtMux *mux, guint8 dlc,
1229 const void *data, int towrite)
1231 struct gsm0710_data *gd = g_at_mux_get_data(mux);
1232 guint8 *frame = alloca(gd->frame_size * 2 + 7);
1236 while (towrite > 0) {
1237 max = MIN(towrite, gd->frame_size);
1238 frame_size = gsm0710_advanced_fill_frame(frame, dlc,
1239 GSM0710_DATA, data, max);
1240 g_at_mux_raw_write(mux, frame, frame_size);
1246 static GAtMuxDriver gsm0710_advanced_driver = {
1247 .remove = gsm0710_advanced_remove,
1248 .startup = gsm0710_advanced_startup,
1249 .shutdown = gsm0710_advanced_shutdown,
1250 .open_dlc = gsm0710_advanced_open_dlc,
1251 .close_dlc = gsm0710_advanced_close_dlc,
1252 .feed_data = gsm0710_advanced_feed_data,
1253 .set_status = gsm0710_advanced_set_status,
1254 .write = gsm0710_advanced_write,
1257 GAtMux *g_at_mux_new_gsm0710_advanced(GIOChannel *channel, int frame_size)
1260 struct gsm0710_data *gd;
1262 mux = g_at_mux_new(channel, &gsm0710_advanced_driver);
1267 gd = g_new0(struct gsm0710_data, 1);
1268 gd->frame_size = frame_size;
1270 g_at_mux_set_data(mux, gd);