1 /*******************************************************************************
2 * Copyright (c) 2014 IBM Corp.
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * and Eclipse Distribution License v1.0 which accompany this distribution.
7 *
8 * The Eclipse Public License is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 * and the Eclipse Distribution License is available at
11 * http://www.eclipse.org/org/documents/edl-v10.php.
12 *
13 * Contributors:
14 * Ian Craggs - initial API and implementation and/or initial documentation
15 * Sergio R. Caprile - port to the bare metal environment and serial media specifics
16 *******************************************************************************/
17
18 /** By the way, this is a nice bare bones example, easier to expand to whatever non-OS
19 media you might have */
20
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include "transport.h"
27
28 /**
29 This simple low-level implementation assumes a single connection for a single thread. Thus, single static
30 variables are used for that connection.
31 On other scenarios, you might want to put all these variables into a structure and index via the 'sock'
32 parameter, as some functions show in the comments
33 The blocking rx function is not supported.
34 If you plan on writing one, take into account that the current implementation of
35 MQTTPacket_read() has a function pointer for a function call to get the data to a buffer, but no provisions
36 to know the caller or other indicator (the socket id): int (*getfn)(unsigned char*, int)
37 */
38 static transport_iofunctions_t *io = NULL;
39 static unsigned char *from = NULL; // to keep track of data sending
40 static int howmany; // ditto
41
42
transport_sendPacketBuffernb_start(int sock,unsigned char * buf,int buflen)43 void transport_sendPacketBuffernb_start(int sock, unsigned char* buf, int buflen)
44 {
45 from = buf; // from[sock] or mystruct[sock].from
46 howmany = buflen; // myhowmany[sock] or mystruct[sock].howmany
47 }
48
transport_sendPacketBuffernb(int sock)49 int transport_sendPacketBuffernb(int sock)
50 {
51 transport_iofunctions_t *myio = io; // io[sock] or mystruct[sock].io
52 int len;
53
54 /* you should have called open() with a valid pointer to a valid struct and
55 called sendPacketBuffernb_start with a valid buffer, before calling this */
56 assert((myio != NULL) && (myio->send != NULL) && (from != NULL));
57 if((len = myio->send(from, howmany)) > 0){
58 from += len;
59 if((howmany -= len) <= 0){
60 return TRANSPORT_DONE;
61 }
62 } else if(len < 0){
63 return TRANSPORT_ERROR;
64 }
65 return TRANSPORT_AGAIN;
66 }
67
transport_sendPacketBuffer(int sock,unsigned char * buf,int buflen)68 int transport_sendPacketBuffer(int sock, unsigned char* buf, int buflen)
69 {
70 int rc;
71
72 transport_sendPacketBuffernb_start(sock, buf, buflen);
73 while((rc=transport_sendPacketBuffernb(sock)) == TRANSPORT_AGAIN){
74 /* this is unlikely to loop forever unless there is a hardware problem */
75 }
76 if(rc == TRANSPORT_DONE){
77 return buflen;
78 }
79 return TRANSPORT_ERROR;
80 }
81
82
transport_getdata(unsigned char * buf,int count)83 int transport_getdata(unsigned char* buf, int count)
84 {
85 assert(0); /* This function is NOT supported, it is just here to tease you */
86 return TRANSPORT_ERROR; /* nah, it is here for similarity with other transport examples */
87 }
88
transport_getdatanb(void * sck,unsigned char * buf,int count)89 int transport_getdatanb(void *sck, unsigned char* buf, int count)
90 {
91 //int sock = *((int *)sck); /* sck: pointer to whatever the system may use to identify the transport */
92 transport_iofunctions_t *myio = io; // io[sock] or mystruct[sock].io
93 int len;
94
95 /* you should have called open() with a valid pointer to a valid struct before calling this */
96 assert((myio != NULL) && (myio->recv != NULL));
97 /* this call will return immediately if no bytes, or return whatever outstanding bytes we have,
98 upto count */
99 if((len = myio->recv(buf, count)) >= 0)
100 return len;
101 return TRANSPORT_ERROR;
102 }
103
104 /**
105 return >=0 for a connection descriptor, <0 for an error code
106 */
transport_open(transport_iofunctions_t * thisio)107 int transport_open(transport_iofunctions_t *thisio)
108 {
109 int idx=0; // for multiple connections, you might, basically turn myio into myio[MAX_CONNECTIONS],
110
111 //if((idx=assignidx()) >= MAX_CONNECTIONS) // somehow assign an index,
112 // return TRANSPORT_ERROR;
113 io = thisio; // store myio[idx] = thisio, or mystruct[idx].io = thisio,
114 return idx; // and return the index used
115 }
116
transport_close(int sock)117 int transport_close(int sock)
118 {
119 int rc=TRANSPORT_DONE;
120
121 return rc;
122 }
123