GTK basics : learning from sources - gtk

I am new at programming Gtk gnome linux C application, and I am trying to learn from some source reagind and online gnome documentation but I can't do it because this is in my opinion very poor and bad. I have a problem understanding this following source: after creating a GObject of GApplication type, how can this main function call other parts of programs? (This is from gedit source) I learnt that GApplication doesn't include any pointer to some code.
/*
* gedit.c
* This file is part of gedit
*
* Copyright (C) 2005 - Paolo Maggi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "gedit-app.h"
#ifdef OS_OSX
#include "gedit-app-osx.h"
#else
#ifdef G_OS_WIN32
#include "gedit-app-win32.h"
#else
#include "gedit-app-x11.h"
#endif
#endif
#include <glib.h>
#include <locale.h>
#include <libintl.h>
#include "gedit-dirs.h"
#include "gedit-debug.h"
#ifdef G_OS_WIN32
#include <gmodule.h>
static GModule *libgedit_dll = NULL;
/* This code must live in gedit.exe, not in libgedit.dll, since the whole
* point is to find and load libgedit.dll.
*/
static gboolean
gedit_w32_load_private_dll (void)
{
gchar *dllpath;
gchar *prefix;
prefix = g_win32_get_package_installation_directory_of_module (NULL);
if (prefix != NULL)
{
/* Instead of g_module_open () it may be possible to do any of the
* following:
* A) Change PATH to "${dllpath}/lib/gedit;$PATH"
* B) Call SetDllDirectory ("${dllpath}/lib/gedit")
* C) Call AddDllDirectory ("${dllpath}/lib/gedit")
* But since we only have one library, and its name is known, may as well
* use gmodule.
*/
dllpath = g_build_filename (prefix, "lib", "gedit", "libgedit.dll", NULL);
g_free (prefix);
libgedit_dll = g_module_open (dllpath, 0);
if (libgedit_dll == NULL)
{
g_printerr ("Failed to load '%s': %s\n",
dllpath, g_module_error ());
}
g_free (dllpath);
}
if (libgedit_dll == NULL)
{
libgedit_dll = g_module_open ("libgedit.dll", 0);
if (libgedit_dll == NULL)
{
g_printerr ("Failed to load 'libgedit.dll': %s\n",
g_module_error ());
}
}
return (libgedit_dll != NULL);
}
static void
gedit_w32_unload_private_dll (void)
{
if (libgedit_dll)
{
g_module_close (libgedit_dll);
libgedit_dll = NULL;
}
}
#endif
int
main (int argc, char *argv[])
{
GType type;
GeditApp *app;
gint status;
const gchar *dir;
#ifdef OS_OSX
type = GEDIT_TYPE_APP_OSX;
#else
#ifdef G_OS_WIN32
if (!gedit_w32_load_private_dll ())
{
return 1;
}
type = GEDIT_TYPE_APP_WIN32;
#else
type = GEDIT_TYPE_APP_X11;
#endif
#endif
/* NOTE: we should not make any calls to the gedit api before the
* private library is loaded */
gedit_dirs_init ();
/* Setup locale/gettext */
setlocale (LC_ALL, "");
dir = gedit_dirs_get_gedit_locale_dir ();
bindtextdomain (GETTEXT_PACKAGE, dir);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
app = g_object_new (type,
"application-id", "org.gnome.gedit",
"flags", G_APPLICATION_HANDLES_COMMAND_LINE | G_APPLICATION_HANDLES_OPEN,
NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
/* Break reference cycles caused by the PeasExtensionSet
* for GeditAppActivatable which holds a ref on the GeditApp
*/
g_object_run_dispose (G_OBJECT (app));
g_object_add_weak_pointer (G_OBJECT (app), (gpointer *) &app);
g_object_unref (app);
if (app != NULL)
{
gedit_debug_message (DEBUG_APP, "Leaking with %i refs",
G_OBJECT (app)->ref_count);
}
#ifdef G_OS_WIN32
gedit_w32_unload_private_dll ();
#endif
return status;
}
/* ex:set ts=8 noet: */

Related

How to encapsulate library handle in Perl XS

I wanted to send/receive MQTT messages from Perl. For various reasons (MQTT 5 support, TLS) I don't want to use existing Perl libraries. So I tried to create XS bindings to Paho MQTT C Library. I somehow adapted provided example to link Perl module to Paho library using relly basic Perl XS:
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <MQTTClient.h>
#define CLIENTID "ExampleClientPub"
#define QOS 1
#define TIMEOUT 10000L
MODULE = paho PACKAGE = paho
int
mqtt_connect_and_send (server_address, username, topic, payload)
char * server_address
char * username
char * topic
char * payload
CODE:
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message msg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
int rc;
/* connect to server */
MQTTClient_create(&client, server_address, CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = username;
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
/* didn't connect */
die("Failed to connect, return code %d", rc);
}
/* fill in message data and send it */
msg.payload = payload;
msg.payloadlen = strlen(payload);
msg.qos = QOS;
msg.retained = 0;
MQTTClient_publishMessage(client, topic, &msg, &token);
rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);
/* shutdown connection */
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
if (rc != MQTTCLIENT_SUCCESS) {
/* didn't send the message */
die("Failed to send message, return code %d", rc);
}
RETVAL = 1;
OUTPUT:
RETVAL
This is working OK. But now I want to split function mqtt_connect_and_send to 3 functions: mqtt_connect, mqtt_send_message, mqtt_disconnect. And my question is - how to do this? How to create a handle (client in my case) in XS in one function, return it to Perl to somehow store it in a scalar and use that handle in ahother XS function to be used to send more messages? I want to be able to do this in Perl:
my $client = paho::mqtt_connect($server_spec, $username, $password, $more_opts);
$success = paho::mqtt_send($client, $data, $message_opts);
# ... more of mqtt_send's
paho::mqtt_disconnect($server)
I tried to set RETVAL RETVAL = &client or mXPUSHu(&client) but that I didn't get anywhere with that. Can you point me to some example how to get client to Perl and then back to XS to be used again?
Thank you.
Here is an example of how you can return the client as a perl object:
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h" // allow the module to be built using older versions of Perl
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <MQTTClient.h>
#define CLIENTID "ExampleClientPub"
#define QOS 1
#define TIMEOUT 10000L
UV get_hash_uv(HV *hash, const char *key) {
#define get_hash_uv(a,b) get_hash_uv(aTHX_ a,b)
SV * key_sv = newSVpv (key, strlen (key));
UV value;
if (hv_exists_ent (hash, key_sv, 0)) {
HE *he = hv_fetch_ent (hash, key_sv, 0, 0);
SV *val = HeVAL (he);
STRLEN val_length;
char * val_pv = SvPV (val, val_length);
if (SvIOK (val)) {
value = SvUV (val);
}
else {
croak("Value of hash key '%s' is not a number", key);
}
}
else {
croak("The hash key for '%s' doesn't exist", key);
}
return value;
}
MODULE = Paho PACKAGE = Paho
PROTOTYPES: DISABLE
SV *
mqtt_connect(server_address, username)
char *server_address
char *username
CODE:
int rc;
MQTTClient client; // void *
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_create(&client, server_address, CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = username;
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
MQTTClient_destroy(&client);
croak("Failed to connect, return code %d", rc);
}
HV *hash = newHV();
SV *self = newRV_noinc( (SV *)hash );
SV *sv = newSVuv(PTR2IV(client));
hv_store (hash, "client", strlen ("client"), sv, 0);
RETVAL = sv_bless(self, gv_stashpv( "Paho::Client", GV_ADD ) );
OUTPUT:
RETVAL
MODULE = Paho PACKAGE = Paho::Client
void
DESTROY(self)
SV *self
CODE:
MQTTClient client; // void *
HV *hv = (HV *) SvRV(self);
UV addr = get_hash_uv(hv, "client");
client = (MQTTClient ) INT2PTR(SV*, addr);
MQTTClient_destroy(&client);
printf("Paho::Client destroy\n");
I am not able to test this yet, because I do not have good values for the input parameters server_address and username. Please provide data that we can test with.
There's no point in building a hash unless you want the class to be extensible.[1] As such, Håkon Hægland's solution can be simplified by returning a scalar-based object. Doing so is quite common for XS-based classes.
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h" // allow the module to be built using older versions of Perl
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <MQTTClient.h>
#define CLIENTID "ExampleClientPub"
#define QOS 1
#define TIMEOUT 10000L
MODULE = paho PACKAGE = paho
PROTOTYPES: DISABLE
SV *
mqtt_connect(server_address, username)
char *server_address
char *username
CODE:
int rc;
MQTTClient client; // void *
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_create(&client, server_address, CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = username;
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
MQTTClient_destroy(&client);
croak("Failed to connect, return code %d", rc);
}
SV *sv = newSVuv(PTR2IV(client));
SV *self = newRV_noinc(sv);
RETVAL = sv_bless(self, gv_stashpv("Paho::Client", GV_ADD));
OUTPUT:
RETVAL
void
DESTROY(self)
SV *self
CODE:
MQTTClient client; // void *
client = INT2PTR(MQTTClient, SvUV(SvRV(self)));
MQTTClient_destroy(&client);
printf("Paho::Client destroy\n");
It can still be extended using the inside-out object technique. And of course, it can still be wrapped.

Same S-Function used twice, one works one doesn't

I have a simulink model and I made a simple s-function block to add to my model and it works.
The catch if if I copy or use that same s-function twice in my model, when I run it only the last s-function called will do what it's supposed to do, the other will output a 0.
#define S_FUNCTION_NAME DivByZero
#define S_FUNCTION_LEVEL 2
#define NUMBER_OF_INPUTS 1
#define NUMBER_OF_OUTPUTS 1
#include "DivByZero.h"
#include "mex.h"
#if !defined(MATLAB_MEX_FILE)
/*
* This file cannot be used directly
*/
# error This_file_can_be_used_only_during_simulation_inside_Simulink
#endif
float32 DivByZeroInput;
float32 DivByZeroOutput;
const void * inputPorts[NUMBER_OF_INPUTS];
const void * outputPorts[NUMBER_OF_OUTPUTS];
static void mdlInitializeSizes(SimStruct *S)
{
uint8 i;
ssSetNumSFcnParams(S, 0);
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S))
{
return; /* Parameter mismatch reported by the Simulink engine */
}
if (!ssSetNumInputPorts(S, NUMBER_OF_INPUTS)) return;
ssSetInputPortWidth(S, 0, 1);
ssSetInputPortDataType(S, 0, SS_SINGLE);
for (i = 0; i < NUMBER_OF_INPUTS; i++)
{
ssSetInputPortDirectFeedThrough(S, i, 1); /* Set direct feedthrough flag */
ssSetInputPortRequiredContiguous(S, i, 1); /*direct input signal access*/
}
if (!ssSetNumOutputPorts(S, NUMBER_OF_OUTPUTS)) return;
ssSetOutputPortWidth(S, 0, 1);
ssSetOutputPortDataType(S, 0, SS_SINGLE);
/* Set Sample Time */
ssSetNumSampleTimes(S, 1);
/* Specify the sim state compliance to be same as a built-in block */
ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
ssSetOptions(S, SS_OPTION_ALLOW_PORT_SAMPLE_TIME_IN_TRIGSS);
ssSupportsMultipleExecInstances(S, true); //set so the s-function can be used in a for each subsystem block
}
static void mdlInitializeSampleTimes(SimStruct *S)
{
/* Inherits sample time from the driving block */
ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
}
#define MDL_START
#if defined(MDL_START)
static void mdlStart(SimStruct *S)
{
uint8 i;
/* Save Input ports */
for (i = 0; i < NUMBER_OF_INPUTS; i++)
{
inputPorts[i] = ssGetInputPortSignal(S, i);
}
/* Save Output ports */
for (i = 0; i < NUMBER_OF_OUTPUTS; i++)
{
outputPorts[i] = ssGetOutputPortRealSignal(S, i);
}
}
#endif
static void mdlOutputs(SimStruct *S, int_T tid)
{
memcpy(&DivByZeroInput, inputPorts[0], sizeof(DivByZeroInput));//gets the input port info
if (fabs(DivByZeroInput) > 0.00001f)
{
DivByZeroOutput = DivByZeroInput;
}
else
{
if (DivByZeroInput >= 0.0f)
{
DivByZeroOutput = 0.00001f;
}
else
{
DivByZeroOutput= -0.00001f;
}
}
memcpy(outputPorts[0], &DivByZeroOutput, sizeof(DivByZeroOutput));//sets the output port
}
static void mdlTerminate(SimStruct *S)
{
/* MODEL TERMINATE */
}
/* END OF TEMPLATE */
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
The s-function is supposed to provide a simple division by zero protection as you can see from the code.
In the image below, if I delete S-Function1, S-Function will then work as intended.
I tried putting it in a library block and just put 2 library blocks and I got the same result
You are defining these variables:
float32 DivByZeroInput;
float32 DivByZeroOutput;
const void * inputPorts[NUMBER_OF_INPUTS];
const void * outputPorts[NUMBER_OF_OUTPUTS];
These variables are shared across both instances, which means both S-Functions write to the same output addresses.
Side note: Do you really have to use an S-Function? Creating the same from a few native simulink blocks is probably much easier.

How to use Boost library 1.55.0 to create a shared memory using a matlab application

I'm trying to use boost library 1.55.0 to create a shared memory.I have a example.cpp file which creates boost shared memory. Mexing of this file is successful,but throws the following exception while debugging "MATLAB.exe has triggered a breakpoint".Is this exception because of the version of the boost being incompatible with the matlab version? How to resolve this
`/* File : sfun_counter_cpp.cpp
* Abstract:
*
* Example of an C++ S-function which stores an C++ object in
* the pointers vector PWork.
*
* Copyright 1990-2000 The MathWorks, Inc.
*
*/
#include "iostream"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
typedef struct
{
int outGate;
unsigned int outPin;
int inGate;
unsigned int inPin;
} wire;
typedef struct
{
unsigned int gateType;
unsigned int inPins;
unsigned int outPins;
std::vector<wire> inWires;
std::vector<wire> outWires;
} gate;
std::vector<gate> gates;
wire wiredata;
gate gatedata;
class counter {
double x;
public:
counter() {
x = 0.0;
}
double output(void) {
x = x + 1.0;
return x;
}
};
#ifdef __cplusplus
extern "C" { // use the C fcn-call standard for all functions
#endif // defined within this scope
#define S_FUNCTION_LEVEL 2
#define S_FUNCTION_NAME sfun_counter_cpp
/*
* Need to include simstruc.h for the definition of the SimStruct and
* its associated macro definitions.
*/
#include "simstruc.h"
/*====================*
* S-function methods *
*====================*/
/* Function: mdlInitializeSizes ===============================================
* Abstract:
* The sizes information is used by Simulink to determine the S-function
* block's characteristics (number of inputs, outputs, states, etc.).
*/
static void mdlInitializeSizes(SimStruct *S)
{
/* See sfuntmpl_doc.c for more details on the macros below */
ssSetNumSFcnParams(S, 1); /* Number of expected parameters */
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
/* Return if number of expected != number of actual parameters */
return;
}
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 0);
if (!ssSetNumInputPorts(S, 0)) return;
if (!ssSetNumOutputPorts(S, 1)) return;
ssSetOutputPortWidth(S, 0, 1);
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 1); // reserve element in the pointers vector
ssSetNumModes(S, 0); // to store a C++ object
ssSetNumNonsampledZCs(S, 0);
ssSetOptions(S, 0);
}
/* Function: mdlInitializeSampleTimes
=========================================
* Abstract:
* This function is used to specify the sample time(s) for your
* S-function. You must register the same number of sample times as
* specified in ssSetNumSampleTimes.
*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, mxGetScalar(ssGetSFcnParam(S, 0)));
ssSetOffsetTime(S, 0, 0.0);
}
#define MDL_START /* Change to #undef to remove function */
#if defined(MDL_START)
/* Function: mdlStart
=======================================================
* Abstract:
* This function is called once at start of model execution. If you
* have states that should be initialized once, this is the place
* to do it.
*/
static void mdlStart(SimStruct *S)
{
ssGetPWork(S)[0] = (void *) new counter; // store new C++ object in
the
} // pointers vector
#endif /* MDL_START */
/* Function: mdlOutputs =======================================================
* Abstract:
* In this function, you compute the outputs of your S-function
* block. Generally outputs are placed in the output vector, ssGetY(S).
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
using namespace boost::interprocess;
counter *c = (counter *) ssGetPWork(S)[0]; // retrieve C++ object from
shared_memory_object::remove("MySharedMemory");
//create the shared memory
managed_shared_memory segment(create_only, "MySharedMemory", 65536);
//create the allocators for the struct elements to be accessed as
vectors
typedef allocator<gate,
managed_shared_memory::segment_manager>gate_alloc;
typedef allocator<wire,
managed_shared_memory::segment_manager>inwire_alloc;
typedef allocator<wire,
managed_shared_memory::segment_manager>outwire_alloc;
//create a boost vector with an associated allocator to it
typedef vector<gate, gate_alloc>gate_vec;
typedef vector<wire, inwire_alloc>inwire_vec;
typedef vector<wire, outwire_alloc>outwire_vec;
//Initialize shared memory STL-compatible allocator
const gate_alloc alloc_inst(segment.get_segment_manager());
const inwire_alloc alloc_inst1(segment.get_segment_manager());
const outwire_alloc alloc_inst2(segment.get_segment_manager());
//construct the segment for pushing the data into it
gate_vec *gate_data = segment.construct<gate_vec>("gatedata")
(alloc_inst);
inwire_vec *inwire_data = segment.construct<inwire_vec>("inwiredata")
(alloc_inst1);
outwire_vec *outwire_data = segment.construct<outwire_vec>
("outwiredata")
(alloc_inst2);
//push the data into the vectors
wiredata.inGate = 10;
wiredata.inPin = 2;
wiredata.outGate = 1;
wiredata.outPin = 3;
inwire_data->push_back(wiredata);
outwire_data->push_back(wiredata);
gatedata.gateType = 1;
gatedata.inPins = 2;
gatedata.outPins = 3;
gate_data->push_back(gatedata);
real_T *y = ssGetOutputPortRealSignal(S,0); // the pointers vector
and use
y[0] = c->output(); // member functions of
the
} // object
/* Function: mdlTerminate
=====================================================
* Abstract:
* In this function, you should perform any actions that are necessary
* at the termination of a simulation. For example, if memory was
* allocated in mdlStart, this is the place to free it.
*/
static void mdlTerminate(SimStruct *S)
{
counter *c = (counter *) ssGetPWork(S)[0]; // retrieve and destroy C++
delete c; // object in the
termination
} // function
/*======================================================*
* See sfuntmpl_doc.c for the optional S-function methods *
*======================================================*/
/*=============================*
* Required S-function trailer *
*=============================*/
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file?*/
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
#ifdef __cplusplus
} // end of extern "C" scope
#endif
`
this is the sfunction which I have to mex , debug and run .Though the mexing of the above code snippet is successful ,it throws an exception "MATLAB.exe has triggered a breakpoint" while debugging.
I can give you an example. Unfortunately I cannot test it with windows, but I have tested it on a UNIX system. The main idea is the same. In this case it is shared memory from an external binary to a Matlab mex function.
The external binary is:
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
using namespace boost::interprocess;
const std::string payload("SHARED MEMORY CONTENT");
int main(void) {
shared_memory_object shm(open_or_create, "memory4mat" ,read_write);
shm.truncate(payload.size());
mapped_region mem(shm, read_write);
std::memcpy(mem.get_address(), payload.c_str(), mem.get_size());
do {
std::cout << '\n' << "Press a key to continue...";
} while (std::cin.get() != '\n');
shared_memory_object::remove("memory4mat");
return 0;
}
while the mex function is:
#include "mex.hpp"
#include "mexAdapter.hpp"
#include "MatlabDataArray.hpp"
#include <string>
#include <cstdlib>
#include "boost/interprocess/shared_memory_object.hpp"
#include "boost/interprocess/mapped_region.hpp"
using namespace boost::interprocess;
class MexFunction : public matlab::mex::Function {
public:
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
matlab::data::ArrayFactory factory;
shared_memory_object shm(open_only, "memory4mat", read_only);
mapped_region mem(shm, read_only);
std::string payload(static_cast<const char *>(mem.get_address()), mem.get_size());
outputs[0] = factory.createCharArray(payload);
outputs[1] = factory.createScalar<int16_t>(mem.get_size());
}
};
it uses the C++ Interface and Data API for Matlab. To compile the two example you need to add the boost include directory as compiler options (shared memory is a header only feature in boost).
The external binary create a shared memory that contains the string "SHARED MEMORY CONTENT", and waits an enter from the user to remove the shared memory object.
The mex files opens the shared memory if exist (if the shared memory do not exist an error is reported and handled in Matlab, which is one of the reasons why I prefer C++ api) and copy its content in a Matlab char array. The function returns two values, the first is the content of the shared memory, the second is the length of the shared memory (the mapper uses all the memory, set with truncate).
This simple example uses only basic features and should work on Unix and Windows system, but again I cannot test on win.
A more complete example
Let's try with a more complete example about shared memories and Matlab Mex files. Let us write a very simple external binary that allows us to create/delete/read/write a shared memory. This binary has a lot of stuff hardcoded for simplicity, such as the name of the memory file ("shmem"):
// File: share_server.cpp
// g++ share_server.cpp -o share_server
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
using namespace boost::interprocess;
static const std::size_t size = 20;
static const std::size_t wsize = 15;
static const char name[6] = "shmem";
static const char input[wsize] = "write in share";
char output[size];
inline void printHelp() {
std::cout << "Options:" << std::endl;
std::cout << " n) open a new 'shmem' memory" << std::endl;
std::cout << " d) delete a 'shmem' memory" << std::endl;
std::cout << " r) read from 'shmem' memory" << std::endl;
std::cout << " w) write to 'shmem' memory" << std::endl;
std::cout << " x) Exit" << std::endl;
}
inline void cmd_createShare() {
try {
shared_memory_object sm(create_only, name, read_write);
sm.truncate(size);
std::cout << "Shared object created" << std::endl;
} catch(std::exception & e) {
std::cout << "Create Error :: " << e.what() << std::endl;
}
}
inline void cmd_deleteShare() {
try {
shared_memory_object::remove(name);
std::cout << "Shared object deletetd" << std::endl;
} catch(std::exception & e) {
std::cout << "Delete Error:: " << e.what() << std::endl;
}
}
inline void cmd_readShare() {
try {
shared_memory_object sm(open_only, name, read_only);
mapped_region sh_mem(sm, read_only);
std::string ret(static_cast<const char *>(sh_mem.get_address()), sh_mem.get_size());
std::cout << ret << std::endl;
} catch(std::exception & e) {
std::cout << "Read Error:: " << e.what() << std::endl;
}
}
inline void cmd_writeShare() {
try {
shared_memory_object sm(open_only, name, read_write);
mapped_region sh_mem(sm, read_write);
std::memcpy(sh_mem.get_address(), input, wsize);
std::cout << "Write completed" << std::endl;
} catch(std::exception & e) {
std::cout << "Read Error:: " << e.what() << std::endl;
}
}
we can write 3 mex files (using the C++ api) in order to interact with the shared memory. The first one, the simplest, reads the content of the shared memory as a string and returns it to the Matlab workspace. The interface in Matlab syntax is something like:
function [value, read_size] = read_share(share_name)
...
end
and the C++ implementation is the following:
// File: read_share.cpp
#include "mex.hpp"
#include "mexAdapter.hpp"
#include "MatlabDataArray.hpp"
#include <string>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <exception>
#include "boost/interprocess/shared_memory_object.hpp"
#include "boost/interprocess/mapped_region.hpp"
using namespace boost::interprocess;
using namespace matlab::data;
class MexFunction : public matlab::mex::Function {
private:
std::shared_ptr<matlab::engine::MATLABEngine> engine;
ArrayFactory factory;
void throwError(std::string errorMessage) {
engine->feval(matlab::engine::convertUTF8StringToUTF16String("error"),
0, std::vector<Array>({ factory.createScalar(errorMessage) }));
}
uint64_t read_shared_memory(const std::string & name, std::string & ret_value) {
try {
shared_memory_object sm(open_only, name.c_str(), read_only);
mapped_region sh_mem(sm, read_only);
ret_value += std::string(static_cast<const char *>(sh_mem.get_address()), sh_mem.get_size());
return ret_value.size();
} catch(std::exception & e) {
throwError(std::string("Reading error: ") + std::string(e.what()));
}
return 0;
}
void checkArguments(matlab::mex::ArgumentList inputs, matlab::mex::ArgumentList outputs) {
if (inputs.size() != 1)
throwError("Input must be of size 1");
if (inputs[0].getType() != ArrayType::CHAR)
throwError("First element must be a matlab char array");
if (outputs.size() > 2)
throwError("Too many outputs (required 1)");
}
public:
MexFunction() {
engine = getEngine();
}
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
checkArguments(inputs, outputs);
const CharArray name_array = std::move(inputs[0]);
std::string name = name_array.toAscii();
std::string ret_string("");
uint64_t ret_size = read_shared_memory(name, ret_string);
outputs[0] = factory.createScalar(ret_string);
outputs[1] = factory.createScalar<uint64_t>(ret_size);
}
};
The second mex file is the write operation. It takes two input: the name of the shared memory and the string to write inside the memory. The mex checks the maximum size of the shared memory and stores no more than the available space. The function returns the bytes written in the The interface for the write function is something like:
function written_size = write_share(share_name, string)
...
end
and the implementation is:
// File: write_share.cpp
#include "mex.hpp"
#include "mexAdapter.hpp"
#include "MatlabDataArray.hpp"
#include <string>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <exception>
#include "boost/interprocess/shared_memory_object.hpp"
#include "boost/interprocess/mapped_region.hpp"
using namespace boost::interprocess;
using namespace matlab::data;
class MexFunction : public matlab::mex::Function {
private:
std::shared_ptr<matlab::engine::MATLABEngine> engine;
ArrayFactory factory;
void throwError(std::string errorMessage) {
engine->feval(matlab::engine::convertUTF8StringToUTF16String("error"),
0, std::vector<Array>({ factory.createScalar(errorMessage) }));
}
uint64_t write_shared_memory(const std::string & name, const std::string & value) {
try {
shared_memory_object sm(open_only, name.c_str(), read_write);
mapped_region sh_mem(sm, read_write);
uint64_t size = std::min(value.size(), sh_mem.get_size());
std::memcpy(sh_mem.get_address(), value.c_str(), size);
return size;
} catch(std::exception & e) {
throwError(std::string("Reading error: ") + std::string(e.what()));
}
return 0;
}
void checkArguments(matlab::mex::ArgumentList inputs, matlab::mex::ArgumentList outputs) {
if (inputs.size() != 2)
throwError("Input must be of size 2");
if (inputs[0].getType() != ArrayType::CHAR)
throwError("First element must be a matlab char array");
if (inputs[1].getType() != ArrayType::CHAR)
throwError("Second element must be a matlab char array to save");
if (outputs.size() > 1)
throwError("Too many outputs (required 1)");
}
public:
MexFunction() {
engine = getEngine();
}
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
checkArguments(inputs, outputs);
const CharArray name_array = std::move(inputs[0]);
std::string name = name_array.toAscii();
const CharArray value_array = std::move(inputs[1]);
std::string value = value_array.toAscii();
uint64_t written = write_shared_memory(name, value);
outputs[0] = factory.createScalar<uint64_t>(written);
}
};
The last mex is the most complex and handles the creation and deletion of the shared memory. You will notice the presence of a destructor that handles the removal of shared memory when the mex is unloaded from Matlab. The interface takes a command in the form of "create" or "delete", a string with the name of the share and the size of the shared memory for creation (it must be an unsigned int - uint16(...)). The function returns the size of the shared memory (it should be equal to size):
function size_shmem = menage_mex(command, share_name, uint16(size))
...
end
the implementation is the following:
// File: menage_share.cpp
#include "mex.hpp"
#include "mexAdapter.hpp"
#include "MatlabDataArray.hpp"
#include <string>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <exception>
#include "boost/interprocess/shared_memory_object.hpp"
#include "boost/interprocess/mapped_region.hpp"
using namespace boost::interprocess;
using namespace matlab::data;
class MexFunction : public matlab::mex::Function {
private:
std::shared_ptr<matlab::engine::MATLABEngine> engine;
ArrayFactory factory;
std::vector<std::string> pool;
void throwError(std::string errorMessage) {
engine->feval(matlab::engine::convertUTF8StringToUTF16String("error"),
0, std::vector<Array>({ factory.createScalar(errorMessage) }));
}
uint64_t run_command(const std::string & cmd, const std::string & name, uint64_t size) {
if (cmd == "create")
return create_shared_memory(name, size);
if (cmd == "delete")
return delete_shared_memory(name, size);
throwError("The command is unknown");
return 0;
}
uint64_t create_shared_memory(const std::string & name, uint64_t size) {
bool in_pool = false;
for (const auto & el : pool) {
if (el == name) {
in_pool = true;
break;
}
}
if (in_pool) {
try {
shared_memory_object sm(open_only, name.c_str(), read_only);
mapped_region sm_reg(sm, read_only);
if (sm_reg.get_size() != size)
throwError("Memory already exist and it is of different size");
return 0;
} catch (std::exception & e) {
throwError(std::string("Cannot open existing shared memory (maybe already open?) :: ") + std::string(e.what()));
}
} else {
try {
shared_memory_object sm(create_only, name.c_str(), read_write);
sm.truncate(size);
pool.push_back(name);
return size;
} catch (std::exception & e) {
throwError(std::string("Cannot create shared memory [" + name + "] (maybe already open?) :: ") + std::string(e.what()));
}
}
return 0;
}
uint64_t delete_shared_memory(const std::string & name, uint64_t size) {
std::size_t in_pool = 0;
for (const auto & el : pool) {
if (el == name)
break;
in_pool++;
}
if (in_pool < pool.size()) {
shared_memory_object::remove(name.c_str());
pool.erase(pool.begin() + in_pool);
} else {
throwError("Shared memory [" + name + "] is not handled by this mex");
}
return 0;
}
void checkArguments(matlab::mex::ArgumentList inputs, matlab::mex::ArgumentList outputs) {
if (inputs.size() != 3)
throwError("Input must be of size 3");
if (inputs[0].getType() != ArrayType::CHAR)
throwError("First element must be a matlab char array");
if (inputs[1].getType() != ArrayType::CHAR)
throwError("Second element must be amatlab char array");
if (inputs[2].getType() != ArrayType::UINT64)
throwError("Third element must be a single uint64 integer");
if (outputs.size() > 1)
throwError("Too many outputs (required 1)");
}
void inputArguments(std::string & cmd, std::string & name, uint64_t & size, matlab::mex::ArgumentList inputs) {
const CharArray cmd_array = std::move(inputs[0]);
const CharArray name_array = std::move(inputs[1]);
const TypedArray<uint64_t> size_array = std::move(inputs[2]);
cmd = cmd_array.toAscii();
name = name_array.toAscii();
size = size_array[0];
}
public:
MexFunction() {
pool.clear();
engine = getEngine();
}
~MexFunction() {
for (const auto & el : pool) {
shared_memory_object::remove(el.c_str());
}
}
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
checkArguments(inputs, outputs);
std::string cmd, name;
uint64_t size;
inputArguments(cmd, name, size, inputs);
uint64_t ret = run_command(cmd, name, size);
outputs[0] = factory.createScalar<uint64_t>(ret);
}
};
To compile the mex you can use the following script:
MEX_OPT = ['-I', '/path/to/boost'];
MEX_SRC = { ...
'menage_share.cpp', ...
'read_share.cpp', ...
'write_share.cpp' ...
};
for i = 1:length(MEX_SRC)
mex(MEX_OPT, MEX_SRC{i});
end
!g++ share_server.cpp -o share_server
and you can test them as follows:
(MATLAB) | (TERMINAL)
>> menage_share('create', 'shmem', uint64(20)) |
<< 20 |
>> write_share('shmem', 'Hello there') | $ ./share_server
<< 11 | ( ... help message ... )
| << r
| >> Hello there

How High the Pin of Parallel Port

/* Necessary includes for drivers */
#include <linux/init.h>
//#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/ioport.h>
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <asm/io.h> /* inb, outb */
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Nikunj");
/* Function declaration of parlelport.c */
int parlelport_open(struct inode *inode, struct file *filp);
int parlelport_release(struct inode *inode, struct file *filp);
ssize_t parlelport_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t parlelport_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void parlelport_exit(void);
int parlelport_init(void);
/* Structure that declares the common */
/* file access fcuntions */
struct file_operations parlelport_fops = {
read : parlelport_read,
write : parlelport_write,
open : parlelport_open,
release : parlelport_release
};
/* Driver global variables */
/* Major number */
int parlelport_major = 61;
/* Control variable for memory */
/* reservation of the parallel port*/
int port;
module_init(parlelport_init);
module_exit(parlelport_exit);
int parlelport_init(void)
{
int result;
/* Registering device */
result = register_chrdev(parlelport_major, "parlelport", &parlelport_fops);
if (result < 0)
{
printk("<1>parlelport: cannot obtain major number %d\n",parlelport_major);
return result;
}
/* Registering port */
port = check_region(0x378, 1);
if (port)
{
printk("<1>parlelport: cannot reserve 0x378\n");
result = port;
goto fail;
}
request_region(0x378, 1, "parlelport");
printk("<1>Inserting parlelport module\n");
return 0;
fail:
parlelport_exit();
return result;
}
void parlelport_exit(void)
{
/* Make major number free! */
unregister_chrdev(parlelport_major, "parlelport");
/* Make port free! */
if (!port)
{
release_region(0x378,1);
}
printk("<1>Removing parlelport module\n");
}
int parlelport_open(struct inode *inode, struct file *filp)
{
/* Success */
return 0;
}
int parlelport_release(struct inode *inode, struct file *filp)
{
/* Success */
return 0;
}
ssize_t parlelport_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
/* Buffer to read the device */
char parlelport_buffer;
/* Reading port */
parlelport_buffer = inb(0x378);
/* We transfer data to user space */
copy_to_user(buf,&parlelport_buffer,1);
/* We change the reading position as best suits */
if (*f_pos == 0)
{
*f_pos+=1;
return 1;
}
else
{
return 0;
}
}
ssize_t parlelport_write( struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
char *tmp;
/* Buffer writing to the device */
char parlelport_buffer;
tmp=buf+count-1;
copy_from_user(&parlelport_buffer,tmp,1);
/* Writing to the port */
outb(parlelport_buffer,0x378);
return 1;
}
this is the code of parallel port device driver and this is my first c code for that.
Please help me to solve the below problem
i have successfully compile the code and create the .ko file successfully and successfully load in the ubuntu 9.10 OS but thee is no high or low the pin so please help me
How you are checking answer?? After installed module do
dmesg
Actually you can not acquire region at 0x378. Because by default system allocate this one to parport0.
Do cat /proc/ioports so you will find that at 0x378 there is parport0.
You can directly write on that address (0x378), without using that checking and requesting.
My suggestion is that don't directly go in complex form. In write function just write
outb(0x378,1) and check (by inserting hardware having LEDs) LED on/off on data pins.

How to get the WIFI gateway address on the iPhone? [duplicate]

This question already has answers here:
How can I determine the default gateway on iPhone?
(5 answers)
Closed 5 years ago.
I need to get the gateway address of the wifi network I connect with the iPhone. Anyone knows how to get that ?
Just to clarify, I am looking for the information of this screen :
Thanks.
Add to your project route.h file from http://opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/net/route.h
Create getgateway.h
int getdefaultgateway(in_addr_t * addr);
Create getgateway.c
#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include "getgateway.h"
#include "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR
#include <net/route.h>
#define TypeEN "en1"
#else
#include "route.h"
#define TypeEN "en0"
#endif
#include <net/if.h>
#include <string.h>
#define CTL_NET 4 /* network, see socket.h */
#if defined(BSD) || defined(__APPLE__)
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
int getdefaultgateway(in_addr_t * addr)
{
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
NET_RT_FLAGS, RTF_GATEWAY};
size_t l;
char * buf, * p;
struct rt_msghdr * rt;
struct sockaddr * sa;
struct sockaddr * sa_tab[RTAX_MAX];
int i;
int r = -1;
if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
return -1;
}
if(l>0) {
buf = malloc(l);
if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
return -1;
}
for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
rt = (struct rt_msghdr *)p;
sa = (struct sockaddr *)(rt + 1);
for(i=0; i<RTAX_MAX; i++) {
if(rt->rtm_addrs & (1 << i)) {
sa_tab[i] = sa;
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
} else {
sa_tab[i] = NULL;
}
}
if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
&& sa_tab[RTAX_DST]->sa_family == AF_INET
&& sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
char ifName[128];
if_indextoname(rt->rtm_index,ifName);
if(strcmp(TypeEN,ifName)==0){
*addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
r = 0;
}
}
}
}
free(buf);
}
return r;
}
#endif
Through the following snippet, this example will be good work on the simulator and the devise.
#include "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR
#include <net/route.h>
#define TypeEN "en1"
#else
#include "route.h"
#define TypeEN "en0"
#endif
Use this code in your Objective C project
#import "getgateway.h"
#import <arpa/inet.h>
- (NSString *)getGatewayIP {
NSString *ipString = nil;
struct in_addr gatewayaddr;
int r = getdefaultgateway(&(gatewayaddr.s_addr));
if(r >= 0) {
ipString = [NSString stringWithFormat: #"%s",inet_ntoa(gatewayaddr)];
NSLog(#"default gateway : %#", ipString );
} else {
NSLog(#"getdefaultgateway() failed");
}
return ipString;
}
The following works for me, but a copy of route.h is required.
My general understanding is that this code queries and retrieves the systems routing table.
It uses its entries to determine the default route aka gateway ip
/* $Id: getgateway.c,v 1.6 2007/12/13 14:46:06 nanard Exp $ */
/* libnatpmp
* Copyright (c) 2007, Thomas BERNARD <miniupnp#free.fr>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include "getgateway.h"
#include "route.h"
#include <net/if.h>
#include <string.h>
#define CTL_NET 4 /* network, see socket.h */
#if defined(BSD) || defined(__APPLE__)
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
int getdefaultgateway(in_addr_t * addr)
{
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
NET_RT_FLAGS, RTF_GATEWAY};
size_t l;
char * buf, * p;
struct rt_msghdr * rt;
struct sockaddr * sa;
struct sockaddr * sa_tab[RTAX_MAX];
int i;
int r = -1;
if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
return -1;
}
if(l>0) {
buf = malloc(l);
if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
return -1;
}
for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
rt = (struct rt_msghdr *)p;
sa = (struct sockaddr *)(rt + 1);
for(i=0; i<RTAX_MAX; i++) {
if(rt->rtm_addrs & (1 << i)) {
sa_tab[i] = sa;
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
} else {
sa_tab[i] = NULL;
}
}
if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
&& sa_tab[RTAX_DST]->sa_family == AF_INET
&& sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
char ifName[128];
if_indextoname(rt->rtm_index,ifName);
if(strcmp("en0",ifName)==0){
*addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
r = 0;
}
}
}
}
free(buf);
}
return r;
}
#endif
After checking back with Apple, the SDK does not offer an easy way to do that. The hard way, if any, is to dig deep into the system or use a traceroute.
I filed a bug report, maybe they will add it in the future.
Take a look at the answers to Objective-C : How to fetch the router address?
Perhaps only tangentially related, but see the technique outlined in this blog post: http://blog.zachwaugh.com/post/309927273/programmatically-retrieving-ip-address-of-iphone
It obtains the IP address of the Wi-Fi interface, and might be a another jumping off point to finding another solution....
- (NSString *)getIPAddress
{
NSString *address = #"error";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL)
{
if(temp_addr->ifa_addr->sa_family == AF_INET)
{
// Check if interface is en0 which is the wifi connection on the iPhone
if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:#"en0"])
{
// Get NSString from C String
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
}
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
return address;
}