I am currently adding an I/O Expander PCF8574a in my device tree am335x-boneblack.dts. I have two I/O expander, one at 0x38 and another at 0x39.
The code below works fine for a single expander but if I add PCF8574a with address 0x39 in the similar manner, it shows an error.
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins_default>;
status = "okay";
clock-frequency = <400000>;
pcf8574a: pcf8574a#38 {
compatible = "nxp,pcf8574a";
reg = <0x38>;
gpio-controller;
#gpio-cells = <2>;
};
};
Error log :
"Duplicate label 'pcf8574a' on /ocp/i2c#4802a000/pcf8574a#39 and /ocp/i2c#4802a000/pcf8574a#38"
which I completely understand.
But I dont know how to add another node or say sub node to make this work. Any suggestions?
have you tried this
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins_default>;
status = "okay";
clock-frequency = <400000>;
pcf8574a_38: pcf8574a#38 {
compatible = "nxp,pcf8574a";
reg = <0x38>;
gpio-controller;
#gpio-cells = <2>;
};
pcf8574a_39: pcf8574a#39 {
compatible = "nxp,pcf8574a";
reg = <0x39>;
gpio-controller;
#gpio-cells = <2>;
};
};
I am using openwrt, initially, under /dev, there is only ttyO0 with is serial port for console. and I am using it to connect the board(siamilar to beaglebone black).
Now, I am wire a gps to uart2. but I think somehow the openwrt is not enable it by default.
I checked the device tree, am335x-bone.dts(I am using bone for my board, cause my board is not BBB). I not too much setting in it. most of config is from am33xx.dtst and am335x-bone-common.dtsi.
I check the am33xx dtsi, there are some code like this under the ocp{}
uart0: serial#44e09000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart1";
clock-frequency = <48000000>;
reg = <0x44e09000 0x2000>;
interrupts = <72>;
status = "disabled";
};
uart1: serial#48022000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart2";
clock-frequency = <48000000>;
reg = <0x48022000 0x2000>;
interrupts = <73>;
status = "disabled";
};
uart2: serial#48024000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart3";
clock-frequency = <48000000>;
reg = <0x48024000 0x2000>;
interrupts = <74>;
status = "disabled";
};
uart3: serial#481a6000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart4";
clock-frequency = <48000000>;
reg = <0x481a6000 0x2000>;
interrupts = <44>;
status = "disabled";
};
uart4: serial#481a8000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart5";
clock-frequency = <48000000>;
reg = <0x481a8000 0x2000>;
interrupts = <45>;
status = "disabled";
};
uart5: serial#481aa000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart6";
clock-frequency = <48000000>;
reg = <0x481aa000 0x2000>;
interrupts = <46>;
status = "disabled";
};
I did change uart2 from disabled status to "okay" and also change code in am335x-bone-common.dtsi undert &am33xx_pinmux{}
uart0_pins: pinmux_uart0_pins {
pinctrl-single,pins = <
0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
0x150 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
0x154 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
uart0 part is default there, I add code for uart2 part below it.
and in am335x-bone.dts, I add this code to enable uart2
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins>;
status = "okay";
};
after compile this, I can see the /dev/ttyO2 shows up in openwrt. but when I use script write to this port and then read from it. nothing shows up.
this is my script I use lua since it's build-in
local clock = os.clock
function wait(n) -- seconds
local t0 = clock()
while clock() - t0 <= n do end
end
while true do
print("Writing")
wuar0 = io.open("/dev/ttyO0","w")
wuar1 = io.open("/dev/ttyO1","w")
wuar2 = io.open("/dev/ttyO2","w")
wuar0:write("This is uart0 \n")
wuar1:write("This is uart1 \n")
wuar2:write("This is uart2 \n")
wuar0:flush()
wuar1:flush()
wuar2:flush()
wuar0 = io.close()
wuar1 = io.close()
wuar2 = io.close()
wait(2)
print("Reading")
ruar0 = io.open("/dev/ttyO0","r")
ruar1 = io.open("/dev/ttyO1","r")
ruar2 = io.open("/dev/ttyO2","r")
print(ruar0:read())
print(ruar1:read())
print(ruar2:read())
ruar0:flush()
ruar1:flush()
ruar2:flush()
ruar0 = io.close()
ruar1 = io.close()
ruar2 = io.close()
wait(2)
end
Did I do it right? if not, what I need to do to enable the uart2.
I did a lot research, but most of them are out of update. not work in my case.
or if anyone could tell me what is the step to enable this or how I can check if it is enable or not.
any information would help a lot. Thanks.
When I am trying to make a call using following code.
-(int)make_callWithURI:(char *) destURI{
/* Make call! : */
pj_str_t tmp;
pj_status_t status;
int regid = app_config.account_id;
int callNo = -1;
tmp = pj_str(destURI);
status = pjsua_call_make_call( regid, &tmp, 0, NULL, NULL, &callNo);
if (status != PJ_SUCCESS){
error_exit("Error making call", status);
return -1;
}
return callNo;
}
but getting signal SIGABRT at pjsua_call_make_call() line
Error log ::
16:18:04.376 pjsua_call.c !Making call with acc #0 to sip:mobile_number#sip_ip:port
16:18:04.376 pjsua_aud.c .Set sound device: capture=-1, playback=-2
16:18:04.376 pjsua_aud.c ..Opening sound device (speaker + mic) PCM#16000/1/20ms
16:18:04.376 coreaudio_dev. ...Using VoiceProcessingIO audio unit
16:18:04.378 tsx0x14e0cc8a8 !Timeout timer event
16:18:04.379 tsx0x14e0cc8a8 .State changed from Completed to Terminated, event=TIMER
16:18:04.379 tsx0x14e0cd0a8 Timeout timer event
16:18:04.379 tsx0x14e0cd0a8 .State changed from Completed to Terminated, event=TIMER
16:18:04.858 coreaudio_dev. !...core audio stream started
16:18:04.862 dlg0x14d8000a8 .UAC dialog created
16:18:04.862 dlg0x14d8000a8 ..Session count inc to 2 by mod-pjsua
List item
**16:18:04.862 pjsua_call.c .Error initializing media channel: Object is busy (PJ_EBUSY) [status=70011]
16:18:04.862 dlg0x14d8000a8 ..Session count dec to 1 by mod-pjsua
16:18:04.862 dlg0x14d8000a8 .Dialog destroyed
16:18:04.863 pjsua_media.c .Call 0: deinitializing media..
Assertion failed: (entry->cb != ((void*)0)), function schedule_w_grp_lock, file ../src/pj/timer.c, line 501.**
Please tell me why this issue is coming. I have initialise media with default configuration:
//initialize media config with default configuration
pjsua_media_config_default(&cfg->pjsua_media_cfg);
**> Please check this registration scenarios**
pj_status_t sip_startup(app_config_t *app_config)
{
pj_status_t status;
long val;
char tmp[80];
pjsua_transport_id transport_id = -1;
const char *srv;
const char *ip_addr;
NSArray * array;
NSString *dns;
SiphonApplication *app = (SiphonApplication *)[SiphonApplication sharedApplication];
/* Create pjsua first! */
status = pjsua_create();
if (status != PJ_SUCCESS)
return status;
/* Create pool for application */
app_config->pool = pjsua_pool_create("pjsua", 1000, 1000);
/* Initialize default config */
pjsua_config_default(&(app_config->cfg));
pj_ansi_snprintf(tmp, 80, "Siphon PjSip v%s/%s", pj_get_version(), PJ_OS_NAME);
pj_strdup2_with_null(app_config->pool, &(app_config->cfg.user_agent), tmp);
pjsua_logging_config_default(&(app_config->log_cfg));
val = [[NSUserDefaults standardUserDefaults] integerForKey:
#"logLevel"];
#ifdef RELEASE_VERSION
app_config->log_cfg.msg_logging = PJ_FALSE;
app_config->log_cfg.console_level = 0;
app_config->log_cfg.level = 0;
#else
app_config->log_cfg.msg_logging = (val!=0 ? PJ_TRUE : PJ_FALSE);
app_config->log_cfg.console_level = val;
app_config->log_cfg.level = val;
if (val != 0)
{
#if defined(CYDIA) && (CYDIA == 1)
NSArray *filePaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *path = [NSString stringWithFormat:#"%#/Siphon", [filePaths objectAtIndex:0]];
#else
NSArray *filePaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *path = [filePaths objectAtIndex: 0];
#endif
//NSString *path = NSTemporaryDirectory();
path = [path stringByAppendingString: #"/log.txt"];
app_config->log_cfg.log_filename = pj_strdup3(app_config->pool,
[path UTF8String]);
}
#endif
pjsua_media_config_default(&(app_config->media_cfg));
// TODO select clock rate with enabled codec (8000 if nb codec only, or 16000 and more if wb codec)
//app_config->media_cfg.clock_rate = 8000;
//app_config->media_cfg.snd_clock_rate = 8000;
app_config->media_cfg.clock_rate = 16000;
app_config->media_cfg.snd_clock_rate = 16000;
//app_config->media_cfg.ec_options = 0;//0=default,1=speex, 2=suppressor
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"enableEC"])
app_config->media_cfg.ec_tail_len = 0;
// Enable/Disable VAD/silence detector
app_config->media_cfg.no_vad = [[NSUserDefaults standardUserDefaults]
boolForKey:#"disableVad"];
app_config->media_cfg.snd_auto_close_time = 0;
//app_config->media_cfg.quality = 2;
//app_config->media_cfg.channel_count = 2;
app_config->media_cfg.enable_ice = [[NSUserDefaults standardUserDefaults]
boolForKey:#"enableICE"];
pjsua_transport_config_default(&(app_config->udp_cfg));
val = [[NSUserDefaults standardUserDefaults] integerForKey: #"localPort"];
if (val < 0 || val > 65535)
{
PJ_LOG(1,(THIS_FILE,
"Error: local-port argument value (expecting 0-65535"));
[app displayParameterError:
#"Invalid value for Local Port (expecting 1-65535)."];
status = PJ_EINVAL;
goto error;
}
app_config->udp_cfg.port = val;
pjsua_transport_config_default(&(app_config->rtp_cfg));
app_config->rtp_cfg.port = [[NSUserDefaults standardUserDefaults]
integerForKey: #"rtpPort"];
if (app_config->rtp_cfg.port == 0)
{
enum { START_PORT=4000 };
unsigned range;
range = (65535-START_PORT-PJSUA_MAX_CALLS*4);
app_config->rtp_cfg.port = START_PORT +
((pj_rand() % range) & 0xFFFE);
}
if (app_config->rtp_cfg.port < 1 || app_config->rtp_cfg.port > 65535)
{
PJ_LOG(1,(THIS_FILE,
"Error: rtp-port argument value (expecting 1-65535)"));
[app displayParameterError:
#"Invalid value for RTP port (expecting 1-65535)."];
status = PJ_EINVAL;
goto error;
}
#if 1 // TEST pour le vpn
ip_addr = [[[NSUserDefaults standardUserDefaults] stringForKey:
#"boundAddr"] UTF8String];
if (ip_addr && strlen(ip_addr))
{
pj_strdup2_with_null(app_config->pool,
&(app_config->udp_cfg.bound_addr),
ip_addr);
pj_strdup2_with_null(app_config->pool,
&(app_config->rtp_cfg.bound_addr),
ip_addr);
}
ip_addr = [[[NSUserDefaults standardUserDefaults] stringForKey:
#"publicAddr"] UTF8String];
if (ip_addr && strlen(ip_addr))
{
pj_strdup2_with_null(app_config->pool,
&(app_config->udp_cfg.public_addr),
ip_addr);
pj_strdup2_with_null(app_config->pool,
&(app_config->rtp_cfg.public_addr),
ip_addr);
}
#endif
/* Initialize application callbacks */
app_config->cfg.cb.on_call_state = &on_call_state;
app_config->cfg.cb.on_call_media_state = &on_call_media_state;
app_config->cfg.cb.on_incoming_call = &on_incoming_call;
app_config->cfg.cb.on_reg_state = &on_reg_state;
#if defined(MWI) && MWI==1
app_config->cfg.cb.on_mwi_info = &on_mwi_info;
app_config->cfg.enable_unsolicited_mwi = PJ_TRUE;
#endif
srv = [[[NSUserDefaults standardUserDefaults] stringForKey:
#"stunServer"] UTF8String];
if (srv && strlen(srv))
{
if (app_config->cfg.stun_srv_cnt==PJ_ARRAY_SIZE(app_config->cfg.stun_srv))
{
PJ_LOG(1,(THIS_FILE, "Error: too many STUN servers"));
return PJ_ETOOMANY;
}
pj_strdup2_with_null(app_config->pool,
&(app_config->cfg.stun_srv[app_config->cfg.stun_srv_cnt++]),
srv);
}
// app_config->cfg.outbound_proxy[0] = pj_str(outbound_proxy);
// app_config->cfg.outbound_proxy_cnt = 1;
dns = [[NSUserDefaults standardUserDefaults] stringForKey: #"dnsServer"];
array = [dns componentsSeparatedByString:#","];
NSEnumerator *enumerator = [array objectEnumerator];
NSString *anObject;
while (anObject = [enumerator nextObject])
{
NSMutableString *mutableStr = [anObject mutableCopy];
CFStringTrimWhitespace((CFMutableStringRef)mutableStr);
srv = [mutableStr UTF8String];
if (srv && strlen(srv))
{
if (app_config->cfg.nameserver_count==PJ_ARRAY_SIZE(app_config->cfg.nameserver))
{
PJ_LOG(1,(THIS_FILE, "Error: too many DNS servers"));
[mutableStr release];
break;
}
pj_strdup2_with_null(app_config->pool,
&(app_config->cfg.nameserver[app_config->cfg.nameserver_count++]),
srv);
}
[mutableStr release];
}
//[enumerator release];
//[array release];
/* Initialize pjsua */
status = pjsua_init(&app_config->cfg, &app_config->log_cfg,
&app_config->media_cfg);
if (status != PJ_SUCCESS)
goto error;
/* Initialize Ring and Ringback */
sip_ring_init(app_config);
/* Add UDP transport. */
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP,
&app_config->udp_cfg, &transport_id);
if (status != PJ_SUCCESS)
goto error;
/* Add RTP transports */
// status = pjsua_media_transports_create(&app_config->rtp_cfg);
// if (status != PJ_SUCCESS)
// goto error;
#if LOCAL_ACCOUNT
{
if (status == PJ_SUCCESS && transport_id != -1)
{
/* Add local account */
pjsua_acc_add_local(transport_id, PJ_TRUE, &aid);
}
}
#endif
/* */
sip_manage_codec();
/* Initialization is done, now start pjsua */
status = pjsua_start();
if (status != PJ_SUCCESS)
goto error;
return status;
error:
sip_cleanup(app_config);
return status;
}
/* */
pj_status_t sip_cleanup(app_config_t *app_config)
{
pj_status_t status;
/* Cleanup Ring and Ringback */
sip_ring_deinit(app_config);
if (app_config->pool)
{
pj_pool_release(app_config->pool);
app_config->pool = NULL;
}
/* Destroy pjsua */
status = pjsua_destroy();
pj_bzero(app_config, sizeof(app_config_t));
return status;
}
/* */
pj_status_t sip_connect(pj_pool_t *pool, pjsua_acc_id *acc_id)
{
pj_status_t status;
pjsua_acc_config acc_cfg;
const char *uname;
const char *authname;
const char *contactname;
const char *passwd;
const char *server;
SiphonApplication *app = (SiphonApplication *)[SiphonApplication sharedApplication];
// TODO Verify if wifi is connected, if not verify if user wants edge connection
uname = [[[NSUserDefaults standardUserDefaults] stringForKey:
#"username"] UTF8String];
authname = [[[NSUserDefaults standardUserDefaults] stringForKey:
#"authname"] UTF8String];
contactname = [[[NSUserDefaults standardUserDefaults] stringForKey:
#"contact"] UTF8String];
passwd = [[[NSUserDefaults standardUserDefaults] stringForKey:
#"password"] UTF8String];
server = [[[NSUserDefaults standardUserDefaults] stringForKey:
#"server"] UTF8String];
pjsua_acc_config_default(&acc_cfg);
// ID
acc_cfg.id.ptr = (char*) pj_pool_alloc(/*app_config.*/pool, PJSIP_MAX_URL_SIZE);
if (contactname && strlen(contactname))
acc_cfg.id.slen = pj_ansi_snprintf(acc_cfg.id.ptr, PJSIP_MAX_URL_SIZE,
"\"%s\"<sip:%s#%s>", contactname, uname, server);
else
acc_cfg.id.slen = pj_ansi_snprintf(acc_cfg.id.ptr, PJSIP_MAX_URL_SIZE,
"sip:%s#%s", uname, server);
if ((status = pjsua_verify_sip_url(acc_cfg.id.ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%s' in local id argument",
acc_cfg.id));
[app displayParameterError: #"Invalid value for username or server."];
return status;
}
// Registrar
acc_cfg.reg_uri.ptr = (char*) pj_pool_alloc(/*app_config.*/pool,
PJSIP_MAX_URL_SIZE);
acc_cfg.reg_uri.slen = pj_ansi_snprintf(acc_cfg.reg_uri.ptr,
PJSIP_MAX_URL_SIZE, "sip:%s", server);
if ((status = pjsua_verify_sip_url(acc_cfg.reg_uri.ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%s' in registrar argument",
acc_cfg.reg_uri));
[app displayParameterError: #"Invalid value for server parameter."];
return status;
}
//acc_cfg.id = pj_str(id);
//acc_cfg.reg_uri = pj_str(registrar);
acc_cfg.cred_count = 1;
acc_cfg.cred_info[0].scheme = pj_str("Digest");
acc_cfg.cred_info[0].realm = pj_str("*");//pj_str(realm);
if (authname && strlen(authname))
acc_cfg.cred_info[0].username = pj_str((char *)authname);
else
acc_cfg.cred_info[0].username = pj_str((char *)uname);
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"enableMJ"])
acc_cfg.cred_info[0].data_type = PJSIP_CRED_DATA_DIGEST;
else
acc_cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
acc_cfg.cred_info[0].data = pj_str((char *)passwd);
acc_cfg.publish_enabled = PJ_TRUE;
#if defined(MWI) && MWI==1
acc_cfg.mwi_enabled = PJ_TRUE;
#endif
acc_cfg.allow_contact_rewrite = [[NSUserDefaults standardUserDefaults]
boolForKey:#"enableNat"];
// FIXME: gestion du message 423 dans pjsip
acc_cfg.reg_timeout = [[NSUserDefaults standardUserDefaults] integerForKey:
#"regTimeout"];
if (acc_cfg.reg_timeout < 1 || acc_cfg.reg_timeout > 3600)
{
PJ_LOG(1,(THIS_FILE,
"Error: invalid value for timeout (expecting 1-3600)"));
[app displayParameterError:
#"Invalid value for timeout (expecting 1-3600)."];
return PJ_EINVAL;
}
// Keep alive interval
acc_cfg.ka_interval = [[NSUserDefaults standardUserDefaults] integerForKey:
#"kaInterval"];
// proxies server
NSString *proxies = [[NSUserDefaults standardUserDefaults] stringForKey: #"proxyServer"];
NSArray *array = [proxies componentsSeparatedByString:#","];
NSEnumerator *enumerator = [array objectEnumerator];
NSString *anObject;
while (anObject = [enumerator nextObject])
{
NSMutableString *mutableStr = [anObject mutableCopy];
CFStringTrimWhitespace((CFMutableStringRef)mutableStr);
const char *proxy = [mutableStr UTF8String];
if (proxy && strlen(proxy))
{
if (acc_cfg.proxy_cnt==PJ_ARRAY_SIZE(acc_cfg.proxy))
{
PJ_LOG(1,(THIS_FILE, "Error: too many proxy servers"));
[mutableStr release];
break;
}
pj_str_t pj_proxy;
pj_proxy.slen = strlen(proxy) + 8;
pj_proxy.ptr = (char*) pj_pool_alloc(pool, pj_proxy.slen);
pj_proxy.slen = pj_ansi_snprintf(pj_proxy.ptr, pj_proxy.slen, "sip:%s;lr", proxy);
if ((status = pjsua_verify_sip_url(pj_proxy.ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%*.s' in proxy argument (%d)",
pj_proxy.slen, pj_proxy.ptr, status));
[mutableStr release];
[app displayParameterError: #"Invalid value for proxy parameter."];
continue;
}
acc_cfg.proxy[acc_cfg.proxy_cnt++] = pj_proxy;
}
[mutableStr release];
}
#if LOCAL_ACCOUNT
*acc_id = aid;
#else
status = pjsua_acc_add(&acc_cfg, PJ_TRUE, acc_id);
if (status != PJ_SUCCESS)
{
pjsua_perror(THIS_FILE, "Error adding new account", status);
[app displayParameterError: #"Error adding new account."];
}
#endif
return status;
}
/* */
pj_status_t sip_disconnect(pjsua_acc_id *acc_id)
{
pj_status_t status = PJ_SUCCESS;
if (pjsua_acc_is_valid(*acc_id))
{
status = pjsua_acc_del(*acc_id);
if (status == PJ_SUCCESS)
*acc_id = PJSUA_INVALID_ID;
}
return status;
}
/* */
pj_status_t sip_dial_with_uri(pjsua_acc_id acc_id, const char *uri,
pjsua_call_id *call_id)
{
// FIXME: récupérer le domain à partir du compte (acc_id);
// TODO be careful app already mustn't be in communication!
// TODO if not SIP connected, use GSM ? NSURL with 'tel' protocol
pj_status_t status = PJ_SUCCESS;
pj_str_t pj_uri;
// pjsua_msg_data msg_data;
// pjsip_generic_string_hdr subject;
// pj_str_t hvalue, hname;
PJ_LOG(5,(THIS_FILE, "Calling URI \"%s\".", uri));
status = pjsua_verify_sip_url(uri);
if (status != PJ_SUCCESS)
{
PJ_LOG(1,(THIS_FILE, "Invalid URL \"%s\".", uri));
pjsua_perror(THIS_FILE, "Invalid URL", status);
return status;
}
pj_uri = pj_str((char *)uri);
//status = pjsua_set_null_snd_dev();
status = pjsua_snd_is_active();
// hname = pj_str("Subject");
// hvalue = pj_str("phone call");
//
// pjsua_msg_data_init(&msg_data);
// pjsip_generic_string_hdr_init2(&subject, &hname, &hvalue);
// pj_list_push_back(&msg_data.hdr_list, &subject);
//
// status = pjsua_call_make_call(acc_id, &pj_uri, 0, NULL, &msg_data, call_id);
status = pjsua_call_make_call(acc_id, &pj_uri, 0, NULL, NULL, call_id);
if (status != PJ_SUCCESS)
{
pjsua_perror(THIS_FILE, "Error making call", status);
}
return status;
}
pj_status_t sip_dial(pjsua_acc_id acc_id, const char *number,
pjsua_call_id *call_id)
{
// FIXME: récupérer le domain à partir du compte (acc_id);f
// TODO be careful app already mustn't be in communication!
// TODO if not SIP connected, use GSM ? NSURL with 'tel' protocol
char uri[256];
const char *sip_domain;
sip_domain = [[[NSUserDefaults standardUserDefaults] stringForKey:
#"server"] UTF8String];
pj_ansi_snprintf(uri, 256, "sip:%s#%s", number, sip_domain);
return sip_dial_with_uri(acc_id, uri, call_id);
}
/* */
pj_status_t sip_answer(pjsua_call_id *call_id)
{
pj_status_t status;
status = pjsua_set_null_snd_dev();
status = pjsua_call_answer(*call_id, 200, NULL, NULL);
if (status != PJ_SUCCESS)
{
*call_id = PJSUA_INVALID_ID;
}
return status;
}
/* */
pj_status_t sip_hangup(pjsua_call_id *call_id)
{
pj_status_t status = PJ_SUCCESS;
//pjsua_call_hangup_all();
/* TODO Hangup current calls */
if (*call_id != PJSUA_INVALID_ID)
status = pjsua_call_hangup(*call_id, 0, NULL, NULL);
*call_id = PJSUA_INVALID_ID;
return status;
}
#if SETTINGS
/* */
pj_status_t sip_add_account(NSDictionary *account, pjsua_acc_id *acc_id)
{
pj_status_t status;
pjsua_acc_config acc_cfg;
const char *uname;
const char *passwd;
const char *server;
const char *proxy;
SiphonApplication *app = (SiphonApplication *)[SiphonApplication sharedApplication];
app_config_t *app_config = [app pjsipConfig];
// TODO Verify if wifi is connected, if not verify if user wants edge connection
uname = [[account objectForKey: #"username"] UTF8String];
passwd = [[account objectForKey: #"password"] UTF8String];
server = [[account objectForKey: #"server"] UTF8String];
proxy = [[account objectForKey: #"proxyServer"] UTF8String];
pjsua_acc_config_default(&acc_cfg);
// ID
acc_cfg.id.ptr = (char*) pj_pool_alloc(app_config->pool, PJSIP_MAX_URL_SIZE);
acc_cfg.id.slen = pj_ansi_snprintf(acc_cfg.id.ptr, PJSIP_MAX_URL_SIZE,
"sip:%s#%s", uname, server);
// FIXME : verify in settings view
if ((status = pjsua_verify_sip_url(acc_cfg.id.ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%s' in local id argument",
acc_cfg.id));
[app displayParameterError: #"Invalid value for username or server."];
return status;
}
// Registrar
acc_cfg.reg_uri.ptr = (char*) pj_pool_alloc(app_config->pool,
PJSIP_MAX_URL_SIZE);
acc_cfg.reg_uri.slen = pj_ansi_snprintf(acc_cfg.reg_uri.ptr,
PJSIP_MAX_URL_SIZE, "sip:%s", server);
// FIXME : verify in settings view
if ((status = pjsua_verify_sip_url(acc_cfg.reg_uri.ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%s' in registrar argument",
acc_cfg.reg_uri));
[app displayParameterError: #"Invalid value for server parameter."];
return status;
}
//acc_cfg.id = pj_str(id);
//acc_cfg.reg_uri = pj_str(registrar);
acc_cfg.cred_count = 1;
acc_cfg.cred_info[0].scheme = pj_str("Digest");
acc_cfg.cred_info[0].realm = pj_str("*");//pj_str(realm);
acc_cfg.cred_info[0].username = pj_str((char *)uname);
acc_cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
acc_cfg.cred_info[0].data = pj_str((char *)passwd);
acc_cfg.publish_enabled = PJ_TRUE;
acc_cfg.allow_contact_rewrite = [[account objectForKey:#"enableNat"] boolValue];
// FIXME: gestion du message 423 dans pjsip
acc_cfg.reg_timeout = [[account objectForKey: #"regTimeout"] intValue];
// FIXME : verify in settings view
if (acc_cfg.reg_timeout < 1 || acc_cfg.reg_timeout > 3600)
{
PJ_LOG(1,(THIS_FILE,
"Error: invalid value for timeout (expecting 1-3600)"));
[app displayParameterError:
#"Invalid value for timeout (expecting 1-3600)."];
return PJ_EINVAL;
}
pj_str_t pj_proxy = pj_str((char *)proxy);
if (pj_strlen(&pj_proxy) > 0)
{
acc_cfg.proxy[0].ptr = (char*) pj_pool_alloc(app_config->pool,
PJSIP_MAX_URL_SIZE);
acc_cfg.proxy[0].slen = pj_ansi_snprintf(acc_cfg.proxy[0].ptr,
PJSIP_MAX_URL_SIZE, "sip:%s;lr", proxy);
// FIXME verify in settings view
if ((status = pjsua_verify_sip_url(acc_cfg.proxy[0].ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%s' in proxy argument",
acc_cfg.reg_uri));
[app displayParameterError: #"Invalid value for proxy parameter."];
return status;
}
acc_cfg.proxy_cnt = 1;
}
status = pjsua_acc_add(&acc_cfg, PJ_TRUE, acc_id);
if (status != PJ_SUCCESS)
{
pjsua_perror(THIS_FILE, "Error adding new account", status);
[app displayParameterError: #"Error adding new account."];
}
return status;
}
#endif
We have a little problem with creating a device tree for our configuration of a Marvell DSA switch and a Xilinx Zynq processor. They are connected like this:
|——————————————| |——————————————————————————————|
| e000b000—|———— SGMII ————|—port6 (0x16) port3 —— PHY3
| Zynq | | mv88e6321 |
| e000c000—|—x x—|—port5 port4 —— PHY4
|——————————————| |——————————————————————————————|
|___________ MDIO _______________|
And we have a device tree for the Linux kernel, which looks like this:
ps7_ethernet_0: ps7-ethernet#e000b000 {
#address-cells = <1>;
#size-cells = <0>;
clock-names = "ref_clk", "aper_clk";
clocks = <&clkc 13>, <&clkc 30>;
compatible = "xlnx,ps7-ethernet-1.00.a";
interrupt-parent = <&ps7_scugic_0>;
interrupts = <0 22 4>;
local-mac-address = [00 0a 35 00 00 00];
phy-handle = <&phy0>;
phy-mode = "gmii";
reg = <0xe000b000 0x1000>;
xlnx,ptp-enet-clock = <0x69f6bcb>;
xlnx,enet-reset = "";
xlnx,eth-mode = <0x0>;
xlnx,has-mdio = <0x1>;
mdio_0: mdio {
#address-cells = <1>;
#size-cells = <0>;
phy0: phy#16 {
compatiable = "marvell,dsa";
reg = <0x16>;
} ;
} ;
} ;
dsa#0 {
compatible = "marvell,dsa";
#address-cells = <2>;
#size-cells = <0>;
interrupts = <10>;
dsa,ethernet = <&ps7_ethernet_0>;
dsa,mii-bus = <&mdio_0>;
switch#0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0 0>;
port#3 {
reg = <3>;
label = "lan0";
};
port#4 {
reg = <4>;
label = "lan1";
};
port#5 {
reg = <5>;
label = "lan2";
};
port#6 {
reg = <6>;
label = "cpu";
};
};
};
} ;
The problem is, as you can see from the picture, there is no PHY attached to the port 6, i.e. the connection between the Zynq and the switch is PHY-less, but I had to specify <phy0> in the device tree to make the dsa driver to see the switch. But then it tries to talk to a non-existent PHY and fails, obviously.
So the question is: how to create a proper device tree for a dsa switch connected to a processor like this?
Thank you for any help!
(There is a somewhat similar question P1010 MAC to Switch port direct connection without PHY but I cannot comment on it and there is no answer, unfortunately)
Instead of specifying &phy0 when there is none, you can write it as fixed-link
fixed-link = <0 1 1000 0 0>;
Where 0 is emulated PHY ID, 1-> full-duplex and speed is 1000 Mb/s.
You would also want to disable autonegotiation for the processor port to which switch port 6 is connected.
ps7_ethernet_0: ps7-ethernet#e000b000 {
#address-cells = <1>;
#size-cells = <0>;
clock-names = "ref_clk", "aper_clk";
clocks = <&clkc 13>, <&clkc 30>;
compatible = "xlnx,ps7-ethernet-1.00.a";
interrupt-parent = <&ps7_scugic_0>;
interrupts = <0 22 4>;
local-mac-address = [00 0a 35 00 00 00];
fixed-link = <0 1 1000 0 0>;
phy-mode = "gmii";
reg = <0xe000b000 0x1000>;
xlnx,ptp-enet-clock = <0x69f6bcb>;
xlnx,enet-reset = "";
xlnx,eth-mode = <0x0>;
xlnx,has-mdio = <0x1>;
mdio_0: mdio {
#address-cells = <1>;
#size-cells = <0>;
} ;
} ;
dsa#0 {
compatible = "marvell,dsa";
#address-cells = <2>;
#size-cells = <0>;
interrupts = <10>;
dsa,ethernet = <&ps7_ethernet_0>;
dsa,mii-bus = <&mdio_0>;
switch#0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <22 0>;
port#3 {
reg = <3>;
label = "lan0";
};
port#4 {
reg = <4>;
label = "lan1";
};
port#5 {
reg = <5>;
label = "lan2";
};
port#6 {
reg = <6>;
label = "cpu";
};
};
};
} ;
I'm assuming switch chip SMI address is 0x16; if not make reg = <22,0> to <0,0> as before under switch#0.
Also you may need to add mdio driver reg address and compatible property , which are not specified in your device tree.
I have created a multichannel audio system in OpenSL ES on the Android NDK utilizing PCM buffer queues. I cannot seem to get the OS to support SL_IID_RATEPITCH and SL_IID_VOLUME despite the Android docs saying that these two interfaces are supported. Below is my initialization code. Am I doing something wrong?
static SLresult InitChannel(int i)
{
SLresult lRes;
OpenSLChannel *channel = &sndc[i];
// Initialize stuff for playing PCM channels
// Set-up sound audio source.
SLDataLocator_AndroidSimpleBufferQueue lDataLocatorIn;
lDataLocatorIn.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
// At most one buffer in the queue.
lDataLocatorIn.numBuffers = 1;
SLDataFormat_PCM lDataFormat;
lDataFormat.formatType = SL_DATAFORMAT_PCM;
lDataFormat.numChannels = 1; // Mono sound.
lDataFormat.samplesPerSec = SL_SAMPLINGRATE_22_05; // BASE_FREQUENCY
lDataFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
lDataFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
lDataFormat.channelMask = SL_SPEAKER_FRONT_CENTER;
lDataFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
SLDataSource lDataSource;
lDataSource.pLocator = &lDataLocatorIn;
lDataSource.pFormat = &lDataFormat;
SLDataLocator_OutputMix lDataLocatorOut;
lDataLocatorOut.locatorType = SL_DATALOCATOR_OUTPUTMIX;
lDataLocatorOut.outputMix = mOutputMixObj;
SLDataSink lDataSink;
lDataSink.pLocator = &lDataLocatorOut;
lDataSink.pFormat = NULL;
// Create and realize the sound player.
// We are going to need its SL_IID_PLAY and also SL_IID_BUFFERQUEUE interface
// now available thanks to the data locator configured in the previous step.
const SLuint32 lSoundPlayerIIDCount = 4;
const SLInterfaceID lSoundPlayerIIDs[] = { SL_IID_PLAY, SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_RATEPITCH };
const SLboolean lSoundPlayerReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE };
lRes = (*mEngine)->CreateAudioPlayer(mEngine, &channel->mPlayerObj, &lDataSource, &lDataSink, lSoundPlayerIIDCount, lSoundPlayerIIDs, lSoundPlayerReqs);
if (lRes != SL_RESULT_SUCCESS)
return lRes;
lRes = (*channel->mPlayerObj)->Realize(channel->mPlayerObj, SL_BOOLEAN_FALSE);
if (lRes != SL_RESULT_SUCCESS)
return lRes;
lRes = (*channel->mPlayerObj)->GetInterface(channel->mPlayerObj, SL_IID_PLAY, &channel->mPlayer);
if (lRes != SL_RESULT_SUCCESS)
return lRes;
lRes = (*channel->mPlayerObj)->GetInterface(channel->mPlayerObj, SL_IID_BUFFERQUEUE, &channel->mPlayerQueue);
if (lRes != SL_RESULT_SUCCESS)
return lRes;
// Get Volume Interface
lRes = (*channel->mPlayerObj)->GetInterface(channel->mPlayerObj, SL_IID_VOLUME, &channel->mVolume);
if (lRes != SL_RESULT_SUCCESS)
{
Err_Printf("Volume interface not supported.\n");
// return lRes;
}
lRes = (*channel->mPlayerObj)->GetInterface(channel->mPlayerObj, SL_IID_RATEPITCH, &channel->mRatePitch);
if (lRes != SL_RESULT_SUCCESS)
{
Err_Printf("RatePitch interface not supported.\n");
// return lRes;
}
lRes = (*channel->mPlayerQueue)->RegisterCallback(channel->mPlayerQueue, SoundFinished, channel);
// slCheckErrorWithStatus(lRes, "Problem registering player callback (Error %d).", lRes);
lRes = (*channel->mPlayer)->SetCallbackEventsMask(channel->mPlayer, SL_PLAYEVENT_HEADATEND);
// slCheckErrorWithStatus(lRes, "Problem registering player callback mask (Error %d).", lRes);
}
//
// SystemInit
//
// Initialization for
// the sound subsystem.
//
void SystemInit(void)
{
mEngineObj = NULL;
mEngine = NULL;
mOutputMixObj = NULL;
Err_Printf("Starting OpenSL ES...\n");
SLresult lRes;
const SLuint32 lEngineMixIIDCount = 1;
const SLInterfaceID lEngineMixIIDs[] = { SL_IID_ENGINE };
const SLboolean lEngineMixReqs[] = { SL_BOOLEAN_TRUE };
const SLuint32 lOutputMixIIDCount = 2;
const SLInterfaceID lOutputMixIIDs[] = { SL_IID_VOLUME, SL_IID_RATEPITCH };
const SLboolean lOutputMixReqs[] = { SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE };
lRes = slCreateEngine(&mEngineObj, 0, NULL, lEngineMixIIDCount, lEngineMixIIDs, lEngineMixReqs);
if (lRes != SL_RESULT_SUCCESS)
goto ERROR; // lolwut?
lRes = (*mEngineObj)->Realize(mEngineObj, SL_BOOLEAN_FALSE);
if (lRes != SL_RESULT_SUCCESS)
goto ERROR;
lRes = (*mEngineObj)->GetInterface(mEngineObj, SL_IID_ENGINE, &mEngine);
if (lRes != SL_RESULT_SUCCESS)
goto ERROR;
lRes = (*mEngine)->CreateOutputMix(mEngine, &mOutputMixObj, lOutputMixIIDCount, lOutputMixIIDs, lOutputMixReqs);
lRes = (*mOutputMixObj)->Realize(mOutputMixObj, SL_BOOLEAN_FALSE);
int i;
for (i = 0; i < NUMCHANNELS; i++)
{
lRes = InitChannel(i);
if (lRes != SL_RESULT_SUCCESS)
goto ERROR;
}
return;
ERROR:
Err_Printf("Error while starting OpenSL ES.");
SystemShutdown();
}
SL_IID_VOLUME is supported, however it only allows attenuation (max gain is 0). A good approximation of OpenAL's 0.0-1.0 is:
float attenuation = 1.0f / 1024.0f + gain * 1023.0f / 1024.0f;
float db = 3 * log10(attenuation) / log10(2);
SLmillibel setGain = (SLmillibel)(db * 1000);
SL_IID_RATEPITCH is not supported, but SL_IID_PLAYBACKRATE is. Unfortunately, it only allows setting the speed from 0.5 to 2.0 at this time.