Frans Korhonen / Mbed 2 deprecated RMCIOS-Mbed

Dependencies:   mbed mbed-rtos EthernetInterface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_ethernet_channels.cpp Source File

mbed_ethernet_channels.cpp

00001 /* 
00002 RMCIOS - Reactive Multipurpose Control Input Output System
00003 Copyright (c) 2018 Frans Korhonen
00004 
00005 RMCIOS was originally developed at Institute for Atmospheric 
00006 and Earth System Research / Physics, Faculty of Science, 
00007 University of Helsinki, Finland
00008 
00009 Assistance, experience and feedback from following persons have been 
00010 critical for development of RMCIOS: Erkki Siivola, Juha Kangasluoma, 
00011 Lauri Ahonen, Ella Häkkinen, Pasi Aalto, Joonas Enroth, Runlong Cai, 
00012 Markku Kulmala and Tuukka Petäjä.
00013 
00014 This file is part of RMCIOS. This notice was encoded using utf-8.
00015 
00016 RMCIOS is free software: you can redistribute it and/or modify
00017 it under the terms of the GNU General Public License as published by
00018 the Free Software Foundation, either version 3 of the License, or
00019 (at your option) any later version.
00020 
00021 RMCIOS is distributed in the hope that it will be useful,
00022 but WITHOUT ANY WARRANTY; without even the implied warranty of
00023 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00024 GNU General Public License for more details.
00025 
00026 You should have received a copy of the GNU General Public Licenses
00027 along with RMCIOS.  If not, see <http://www.gnu.org/licenses/>.
00028 */
00029 
00030 #if DEVICE_ETHERNET == 1
00031 
00032 #include "EthernetInterface.h"
00033 #include "RMCIOS-functions.h"
00034 
00035 extern const struct context_rmcios *module_context ; 
00036 
00037 //////////////////////////////////////////////////////////////////////
00038 // Ethernet interface channel
00039 //////////////////////////////////////////////////////////////////////
00040 EthernetInterface enet ;
00041 EthernetInterface *eth=&enet ;
00042 char eth_configured=0;
00043 
00044 void ethernet_class_func(const struct context_rmcios *context, 
00045                          void *data, int id, int function,
00046                          enum type_rmcios paramtype,
00047                          union param_rmcios returnv, 
00048                          int num_params,union param_rmcios param)
00049 {
00050  int iplen ;
00051  int masklen ;
00052  int gwlen ;
00053  switch(function) 
00054  {
00055     case help_rmcios:
00056        return_string(context, paramtype,returnv,
00057              "help for ethernet interface channel\r\n"
00058              " setup eth # Configure ethernet with DHCP\r\n"
00059              " setup eth ip_addr ipmask gateway # Manual configuration\r\n"
00060              ) ;
00061        break ;
00062 
00063     case setup_rmcios :
00064        // Allocate ethernet interface.
00065        if(eth==NULL) eth = new EthernetInterface ;
00066        if(eth==NULL) break ;
00067        if(eth_configured==1) {
00068           return_string(context, paramtype,returnv,
00069                 "Ethernet can only be configured once.") ;
00070           break ;
00071        }
00072 
00073        if(num_params<3) {
00074           return_string(context, paramtype,returnv,
00075                 "Configuring ethernet with DHCP:") ;
00076           eth_configured=1;
00077           eth->init() ; // dhcp config
00078           eth->connect();
00079 
00080           return_string(context, paramtype,returnv,
00081                 "Ethernet configuration:\r\n") ;
00082           return_string(context, paramtype,returnv,"ip:");
00083           return_string(context, paramtype,returnv,eth->getIPAddress());
00084           return_string(context, paramtype,returnv,"\r\nipmask:");
00085           return_string(context, paramtype,returnv,eth->getNetworkMask());
00086           return_string(context, paramtype,returnv,"\r\ngateway:");
00087           return_string(context, paramtype,returnv,eth->getGateway());
00088           return_string(context, paramtype,returnv,"\r\n");
00089           break ;
00090        }
00091 
00092        iplen = param_string_length(context, paramtype, param, 0)+1;
00093        masklen = param_string_length(context, paramtype, param, 1)+1;
00094        gwlen = param_string_length(context, paramtype, param, 2)+1;
00095        {
00096 
00097           char ip[iplen] ;
00098           char ipmask[masklen] ;
00099           char gateway[gwlen] ;
00100           param_to_string(context, paramtype, param, 0, iplen, ip);
00101           param_to_string(context, paramtype, param, 1, masklen, ipmask);
00102           param_to_string(context, paramtype, param, 2, gwlen, gateway);
00103 
00104           printf("setup manual ip: %s %s %s\r\n", ip, ipmask, gateway) ;
00105           eth_configured=1;
00106           eth->init(ip,ipmask,gateway) ; // manual ip config
00107           eth->connect();
00108 
00109           return_string(context, paramtype,returnv,
00110                         "Ethernet configuration:\r\n") ;
00111           return_string(context, paramtype, returnv, "ip:");
00112           return_string(context, paramtype, returnv, eth->getIPAddress());
00113           return_string(context, paramtype, returnv, "\r\nipmask:");
00114           return_string(context, paramtype, returnv, eth->getNetworkMask());
00115           return_string(context, paramtype, returnv, "\r\ngateway:");
00116           return_string(context, paramtype, returnv, eth->getGateway());
00117           return_string(context, paramtype, returnv, "\r\n");
00118        }
00119        break ;
00120  }
00121 }
00122 
00123 ////////////////////////////////////////////////////////////////////////
00124 // TCP Client channel:
00125 ////////////////////////////////////////////////////////////////////////
00126 struct tcp_connection_data {
00127     char host[50] ;
00128     int port ;
00129     TCPSocketConnection socket;
00130     bool closed ;
00131 };
00132 
00133 void tcp_client_class_func(void* data,
00134                            const struct context_rmcios *context,
00135                            int id, 
00136                            int function,
00137                            enum type_rmcios paramtype,
00138                            union param_rmcios returnv, 
00139                            int num_params,
00140                            union param_rmcios param)
00141 {
00142     tcp_connection_data *p_data=(tcp_connection_data *)data ;
00143     int plen ;
00144     switch(function) {
00145         case help_rmcios:
00146            return_string(context, paramtype, returnv,
00147            "help for tcp client channel\r\n"
00148            " create tcp_client newname\r\n"
00149            " setup newname ip port #Open connection\r\n"
00150            " setup newname #Close connection\r\n"
00151            " write newname #Flush all buffers\r\n"
00152            " write newname data #Write data to the connection.\r\n"
00153            "       Reconnect if needed\r\n"
00154            " link newname channel # Link received data to channel\r\n"
00155            ) ;
00156             break ;
00157         case create_rmcios :
00158             if(num_params<1) break ;
00159             if(eth==NULL) break ;
00160             
00161             // allocate new data
00162             p_data= new struct tcp_connection_data; 
00163 
00164             // default values
00165             p_data->host[0]=0;
00166             p_data->port=0;
00167             p_data->closed=true ;
00168 
00169             create_channel_param(context, paramtype, param, 0, 
00170                                  (class_rmcios)tcp_client_class_func, p_data) ; 
00171                                  
00172             break ;
00173         case setup_rmcios :
00174             if(p_data==NULL) break ;
00175             if(num_params<1) { // Close connection
00176                 Thread::wait(500);
00177                 if(p_data==NULL) break ;
00178                 if(p_data->socket.is_connected()) p_data->socket.close();
00179                 break ;
00180             }
00181             if(num_params<2) break ;
00182             param_to_string(context, paramtype, param, 0, 
00183                             sizeof(p_data->host),p_data->host) ;
00184             p_data->port=param_to_int(context, paramtype,param,1) ;
00185             p_data->closed=true ;
00186             break ;
00187 
00188         case write_rmcios :
00189             if(p_data==NULL) break ;
00190             if(num_params<1) { // Close connection
00191                 Thread::wait(500);
00192                 if(p_data==NULL) break ;
00193                 if(p_data->socket.is_connected()) p_data->socket.close();
00194                 break ;
00195             }
00196 
00197             /// If socket is not open. Try 3 times to open connection:
00198             if(!p_data->socket.is_connected() || p_data->closed==true ) {
00199                 if(p_data->socket.connect(p_data->host,p_data->port)==0) {
00200                    p_data->closed=false ;
00201                 }
00202                 else p_data->closed=false ;
00203             }
00204             if(!p_data->socket.is_connected() || p_data->closed==true ) {
00205                 Thread::wait(200);
00206                 if(p_data->socket.connect(p_data->host,p_data->port)==0) {
00207                    p_data->closed=false ;
00208                 }
00209                 else p_data->closed=false ;
00210             }
00211             if(!p_data->socket.is_connected() || p_data->closed==true ) {
00212                 Thread::wait(200);
00213                 if(p_data->socket.connect(p_data->host,p_data->port)==0) {
00214                    p_data->closed=false ;
00215                 }
00216                 else p_data->closed=false ;
00217             }
00218 
00219             plen=param_buffer_alloc_size(context, paramtype,param,0) ;
00220             {
00221                 char buffer[plen] ;
00222                 int retry;
00223                 struct buffer_rmcios p ;
00224                 p=param_to_buffer(context, paramtype,param, 0, plen, buffer) ;
00225                 // retry 3 times
00226                 for(retry=0 ;
00227                     retry<3 && p_data->socket.send(p.data, p.length )<0 ;
00228                     retry++)
00229                 { 
00230                     Thread::wait(200);
00231                 }
00232                 Thread::wait(100);
00233             }
00234             break ;
00235     }
00236 }
00237 
00238 ///////////////////////////////////////////////////////
00239 // TCP server channel
00240 ////////////////////////////////////////////////////////
00241 struct tcpserver_data {
00242     int port ;
00243     TCPSocketServer socket ;
00244     TCPSocketConnection connection;
00245     int linked_channels ;
00246     char buffer[512] ;
00247     int id ;
00248 };
00249 
00250 //! Thread for handling udp reception.
00251 void tcpserver_thread(const void *param)
00252 {
00253     printf("tcp server thread created!\r\n") ;
00254     int n=0 ;
00255     struct tcpserver_data *pthis=(struct tcpserver_data *) param ;
00256     
00257     while(pthis->port==0) ;
00258     {
00259         Thread::wait(200);
00260     }
00261     
00262     pthis->socket.bind(pthis->port) ;
00263     pthis->socket.listen();
00264     
00265     while(1) {
00266         pthis->socket.accept( pthis->connection )  ;
00267         printf("connection accepted!\r\n") ;
00268         // receive command
00269         while( pthis->connection.is_connected() ) {
00270             n=pthis->connection.receive(pthis->buffer,sizeof( pthis->buffer)-1);
00271             if(n>0) {
00272                 if( pthis->linked_channels!=0) {
00273                    write_buffer(module_context, pthis->linked_channels,
00274                                 pthis->buffer,n,pthis->id) ;
00275                 } 
00276            }
00277         }
00278     }
00279 }
00280 
00281 void tcp_server_class_func(struct tcpserver_data *pthis, 
00282                            const struct context_rmcios *context,
00283                            int id, 
00284                            int function,
00285                            enum type_rmcios paramtype,
00286                            union param_rmcios returnv, 
00287                            int num_params,
00288                            union param_rmcios param)
00289 {
00290     int plen;
00291     switch(function) {
00292         case help_rmcios:
00293             return_string(context, paramtype, returnv, 
00294                           "TCP server channel\r\n"
00295                           "create tcpserver newname\r\n"
00296                           "setup newname port\r\n"
00297                           "write newname data\r\n"
00298                           "link newname channel\r\n"
00299                           );
00300             break;
00301 
00302         case create_rmcios :
00303             if(num_params<1) break ;
00304             pthis=  (struct tcpserver_data *) 
00305                     malloc(sizeof( struct tcpserver_data)) ; 
00306             
00307             pthis->port=0 ;
00308             pthis->buffer[0]=0;
00309             pthis->socket=TCPSocketServer();
00310             pthis->connection=TCPSocketConnection();
00311             
00312             pthis->id=create_channel_param(context, paramtype, param, 0,
00313                                            (class_rmcios)tcp_server_class_func,
00314                                            pthis); 
00315             pthis->linked_channels=linked_channels(context, pthis->id) ;
00316             break;
00317 
00318         case setup_rmcios :
00319             if(pthis==NULL) break ;
00320             if(num_params<1) {
00321                 if( !pthis->connection.is_connected() ){
00322                    pthis->connection.close() ;
00323                 }
00324                 break ;
00325             }
00326             pthis->port=param_to_integer(context, paramtype, param,0);
00327             
00328             // Start reception thread
00329             new Thread(tcpserver_thread, pthis);
00330             break;
00331 
00332         case write_rmcios :
00333             if(pthis==NULL) break ;
00334             if(num_params<1) break ;
00335             plen=param_buffer_alloc_size(context, paramtype, param, 0) ; 
00336             {
00337                 char buffer[plen] ; 
00338                 struct buffer_rmcios pbuffer ; 
00339                 pbuffer = param_to_buffer(context, paramtype,param, 0, 
00340                                           plen , buffer) ;
00341                 if(pthis->connection.send(pbuffer.data, pbuffer.length)<0){
00342                     return_int(context, paramtype, returnv, -1) ;
00343                     pthis->connection.close() ;
00344                 }
00345             }
00346             break;
00347     }
00348 }
00349 
00350 ///////////////////////////////////////////////////////
00351 // UDP server channel
00352 ////////////////////////////////////////////////////////
00353 struct udp_server_data {
00354     int id ;
00355     int port ;
00356     UDPSocket socket ;
00357     Endpoint client ;
00358     char txbuffer[100] ;
00359     char buffer[100] ;
00360     int linked_channel ;
00361 } ;
00362 
00363 //! Thread for handling udp reception.
00364 void udp_server_thread(const void *param)
00365 {
00366     //printf("udp thread created!\r\n") ;
00367     int n=0 ;
00368     struct udp_server_data *p_data=(struct udp_server_data *) param ;
00369     //printf("waiting for configuration:\r\n") ;
00370     while(p_data->port==0) ;
00371     {
00372         p_data->socket.bind(p_data->port) ;
00373         Thread::wait(200);
00374     }
00375     while(1) {
00376         // receive command
00377         n=p_data->socket.receiveFrom(p_data->client, p_data->buffer, 
00378                                      sizeof(p_data->buffer)-1 ) ;
00379         if(n>0) {
00380             if(p_data->linked_channel!=0){
00381                write_buffer(module_context, p_data->linked_channel, 
00382                             p_data->buffer, n, p_data->id) ;
00383             }
00384         }
00385     }
00386 }
00387 
00388 void udp_server_class_func(udp_server_data *p_data,  
00389                            const struct context_rmcios *context,
00390                            int id, 
00391                            int function,
00392                            enum type_rmcios paramtype,
00393                            union param_rmcios returnv, 
00394                            int num_params,union param_rmcios param)
00395 {
00396  switch(function) 
00397  {
00398     case help_rmcios :
00399        return_string(context, paramtype, returnv,
00400              "help for udp server channel\r\n"
00401              " create udp_server newname\r\n"
00402              " setup newname port \r\n"
00403              " write newname \r\n"
00404              "        # flush tansmit buffer)\r\n"
00405              " write newname data \r\n"
00406              "        # write data to tansmit buffer.\r\n"
00407              "        Flush buffer to ethernet when \\r encountered. \r\n"
00408              " link newname channel \r\n"
00409              "        # Link received data to channel\r\n"
00410              ) ;
00411 
00412        break ;
00413     case create_rmcios :
00414        if(num_params<1) break ;
00415        if(eth==NULL) break ;
00416        p_data= new struct udp_server_data ;
00417        if(p_data==NULL) break ;
00418 
00419        // Default values:
00420        p_data->port=0;
00421        p_data->buffer[0]=0;
00422        p_data->txbuffer[0]=0 ;
00423 
00424        // Create the channel
00425        p_data->id=create_channel_param(context, paramtype, param, 0, 
00426                                        (class_rmcios)udp_server_class_func, 
00427                                        p_data) ;
00428 
00429        p_data->linked_channel=linked_channels(context,p_data->id);
00430        break ;
00431     case setup_rmcios :
00432 
00433        if(p_data==NULL) break ;
00434        if(num_params<1) break ;
00435        else {
00436           p_data->port=param_to_int(context, paramtype, param, 0);
00437           new Thread(udp_server_thread, p_data);
00438        }
00439        break ;
00440 
00441     case write_rmcios :
00442        if(p_data==NULL) break ;
00443        if(num_params<1) { // flush buffer
00444           p_data->socket.sendTo(p_data->client, p_data->txbuffer, 
00445                                 strlen(p_data->txbuffer));
00446           p_data->txbuffer[0]=0 ;
00447           break ;
00448        }
00449 
00450        // collect data to buffer
00451        param_to_string(context, paramtype, param, 0, 
00452                        sizeof(p_data->txbuffer)-strlen(p_data->txbuffer), 
00453                        p_data->txbuffer+strlen(p_data->txbuffer)) ;
00454        break ;
00455  }
00456 }
00457 
00458 void init_mbed_ethernet_channels(const struct context_rmcios *context)
00459 {
00460     module_context=context ;
00461     create_channel_str(context, "eth",(class_rmcios)ethernet_class_func, NULL);
00462     create_channel_str(context, "udp_server",
00463                        (class_rmcios)udp_server_class_func, NULL ) ;
00464 
00465     // TCP Not usable. (Memory consumption issues.)
00466     // create_channel_str("tcp_client",(channel_func) tcp_client_class_func, 
00467     //                    NULL ) ;
00468     // create_channel_str("tcp_server",(channel_func) tcp_server_class_func, 
00469     //                    NULL ) ;
00470 }
00471 
00472 #endif //if DEVICE_ETHERNET == 1
00473 
00474