Electron Cellular Locate Test App

Any progress?

When sensor_used = 2, that's a value retrieved from the server. When it's 0, then the results are a cached value.

I can't say for sure, but the cached value is probably used when the server thinks you haven't moved enough to waste system resources recalculating the position.

This is one of the reasons I've released this test app first, before we create the official API. To get more real user data and see how this feature works and doesn't work for people in different areas.

I think we will have to experiment with ways to force the system to recalculate the position, as some users here have already been doing. The question then will be if those forced ways should become part of the official API, or just something that is required to refresh the data. A simple indicator for if the value is fresh or cached would be a good add-on to the API I think, instead of testing the sensor_used element explicitly.

1 Like

Hey everyone, so I’ve been working on this problem for about 3 weeks straight and here’s my findings. I want to see if anyone else has other info.

So from what I’ve seen +ULOC can return a URC containing cached, gnss, or CellLocate data. It can also return a combination of them <sensor_used=3>. However it never does return sensor = 3 even when +ULOC is configured for it. Sensor 3 = sensor 1 (gnss) + sensor 2 (CellLocate) creating assisted gps (agps).

According to the white paper on CellLocate this mode is what improves accuracy. Combining the sensors for agps is the ideal solution for minimized power consumption.

So after sensor kept defaulting to 2 and GPS was pulling accurate data seperately (using AssetTracker library, not AT commands) I found that there is an AT command to manually aid +ULOC called +ULOCAID. This seemed perfect, plug in the GPS coordinates and manually create an agps call.

This AT command however returns a +CME: Unknown. As it turns out the chip on the electron is a ublox SARA-U260-00S. This chip does NOT support +ULOCAID explicitly and I’m going to assume this means it doesn’t support agps via the sensor parameter in +ULOC and that’s why the sensor 3 is never used.

If you look at the chart below the ublox SARA-U260-03S chip does support this command, however the SARA-U260-00S does not.

Am I just going crazy or does this mean CellLocate is doomed to be inaccurate until a new version of the electron is released with a different chip?

EDIT: I just looked on the electron datasheet and I guess the electron can come with U-blox SARA-U260/U270 (3G) or G350 (2G) cellular modules. Those chips may have the same issue though as some versions do have +ULOCAID and some do not.

EDIT 2: Just emailed Particle asking for full model specs on the 270 and G350 chips and requested the 260-00S be swapped out for the 260-03S.

1 Like

Maybe I am wrong, but why not using another AT command (AT+CREG? or AT+CGED?) and send through an HTTP request to another Website to get your GPS. I found this website and it looks great www.unwiredlabs.com .

Let me know if you think it is a fix for your application.

2 Likes

Interesting! I’ll give it a try today and report results.

@BenoitD your suggestion sounds good, and I want to try getting some cell tower data from my Electron to feed into Unwired Labs, but from what I’ve read commands like AT+CGED aren’t working right now. See these threads:

It looks like @BDub was working on this a while back but I haven’t seen a recent update.

Has anyone tried running the CellLocate test app on a 3G Electron? I can get decent results from many 2G Electrons that I've tested at my location (NYC), but I tried two brand new 3G Electrons and get useless results, e.g.

1/1/2004,0:2:12,LAT:0.0000000,LONG:0.0000000,0,UNCERTAINTY:20000000,SPEED:0,0,0,
0,0,0,0,MATCHED_COUNT:17

I did try the "a" command to set AssistNow back to factory defaults, with no change in results.

@Pixelmatix What do you mean by “useless results”?

What do you mean by "useless results"?

A Latitude and Longitude of 0, with uncertainty of 20000000 meters.

I tested it when it first came out on a 3G and was really accurate, off by 622 feet. I just ran it again and it was off by 4700 feet with an uncertainty of 808 meters. Not great, not useless either.

1 Like

Oooo! This is an awesome thread! CellularLocate would be great! Until then all I want is the info of the cell tower the electron is connected to (I just need to know the general location of where the unit is, like what town or state). Am I better off modifying this code or is there already something in place that would be more direct for simply IDing the nearest cell tower?

I’m able to get a response containing cell tower data about 50% of the time when using the Electron Troubleshooting App as described here. The other 50% of the time the communication with the modem is lost and I have to reset the Electron to continue using the app. There’s a bug that needs to be tracked down and I plan to make a GitHub Issue for it as I haven’t seen one open already.

I can use the cell tower data to get my location (fairly accurately with limited testing) with Unwired Lab’s API.

2 Likes

Trying to use this to publish coordinates on timed schedule. Not sure if that eliminates the 6K handshake, or how to modify code so this could run and publish data over long periods of time without the resets?

Hi guys,

sorry to disturb your discussion with a complete different question rgd. the cellular location feature.
I tried to transform the example provided by @BDub to a own class.
Unfortunately my c++ knowledge is too far away to get usable results :frowning:

Anyway, I put the code into a git rep, currently it fails at the callback function. I’ve no idea how I can pass the object to it,…

CellLocate.cpp: In member function 'int CellLocate::cell_locate(uint32_t)':
CellLocate.cpp:72:75: error: cannot create pointer to reference member 'CellLocate::_self'
	   if (RESP_OK == Cellular.command(CellLocate::_cbLOCATE, &CellLocate::_self, timeout_ms, "AT+ULOC=2,2,1,%d,5000\r\n", timeout_ms/1000)) {
																		   ^
CellLocate.cpp:71:17: warning: unused variable '_self' [-Wunused-variable]
	 CellLocate *_self;
				 ^
CellLocate.cpp: In member function 'bool CellLocate::get_response()':
CellLocate.cpp:100:56: error: cannot create pointer to reference member 'CellLocate::_self'
   Cellular.command(CellLocate::_cbLOCATE, &CellLocate::_self, 1000, "");
														^
make[1]: *** [../build/target/user/platform-10CellLocate.o] Error 1
make: *** [user] Error 2

kind regards

What would be the difference between _self and the default pointer this?

right, this is the right solution… but I still get an error:

CellLocate.cpp: In member function 'int CellLocate::cell_locate(uint32_t)':
CellLocate.cpp:71:125: error: no matching function for call to 'spark::CellularClass::command(<unresolved overloaded function type>, CellLocate&, uint32_t&, const char [24], long unsigned int)'

With that error message you usually get one or more note messages that give you a clue what you could do instead of what’s not possible.
Comparing your provided parameter list to the ones possible might help you find a solution.

Or if you post these extra notes we might be able to.

But I don’t think there is an overload for CellularClass::command() that takes an object method as callback. @mdma, is there?
You could try make that function static tho’

Hi,
here the complete output of the warning,…

CellLocate.cpp: In member function 'int CellLocate::cell_locate(uint32_t)':
CellLocate.cpp:71:125: error: no matching function for call to 'spark::CellularClass::command(<unresolved overloaded function type>, CellLocate&, uint32_t&, const char [24], long unsigned int)'
	   if (RESP_OK == Cellular.command(CellLocate::_cbLOCATE, *this, timeout_ms, "AT+ULOC=2,2,1,%d,5000\r\n", timeout_ms/1000)) {
																															 ^
CellLocate.cpp:71:125: note: candidates are:
In file included from ../wiring/inc/spark_wiring.h:44:0,
				 from ./inc/application.h:36,
				 from CellLocate.cpp:1:
../wiring/inc/spark_wiring_cellular.h:95:16: note: template<class ... Targs> int spark::CellularClass::command(const char*, Targs ...)
	 inline int command(const char* format, Targs... Fargs)
				^
../wiring/inc/spark_wiring_cellular.h:95:16: note:   template argument deduction/substitution failed:
CellLocate.cpp:71:125: note:   cannot convert '((CellLocate*)this)->CellLocate::_cbLOCATE' (type '<unresolved overloaded function type>') to type 'const char*'
	   if (RESP_OK == Cellular.command(CellLocate::_cbLOCATE, *this, timeout_ms, "AT+ULOC=2,2,1,%d,5000\r\n", timeout_ms/1000)) {
																															 ^
In file included from ../wiring/inc/spark_wiring.h:44:0,
				 from ./inc/application.h:36,
				 from CellLocate.cpp:1:
../wiring/inc/spark_wiring_cellular.h:101:16: note: template<class ... Targs> int spark::CellularClass::command(system_tick_t, const char*, Targs ...)
	 inline int command(system_tick_t timeout_ms, const char* format, Targs... Fargs)
				^
../wiring/inc/spark_wiring_cellular.h:101:16: note:   template argument deduction/substitution failed:
CellLocate.cpp:71:125: note:   cannot convert '((CellLocate*)this)->CellLocate::_cbLOCATE' (type '<unresolved overloaded function type>') to type 'system_tick_t {aka long unsigned int}'
	   if (RESP_OK == Cellular.command(CellLocate::_cbLOCATE, *this, timeout_ms, "AT+ULOC=2,2,1,%d,5000\r\n", timeout_ms/1000)) {
																															 ^
In file included from ../wiring/inc/spark_wiring.h:44:0,
				 from ./inc/application.h:36,
				 from CellLocate.cpp:1:
../wiring/inc/spark_wiring_cellular.h:107:16: note: template<class T, class ... Targs> int spark::CellularClass::command(int (*)(int, const char*, int, T*), T*, const char*, Targs ...)
	 inline int command(int (*cb)(int type, const char* buf, int len, T* param),
				^
../wiring/inc/spark_wiring_cellular.h:107:16: note:   template argument deduction/substitution failed:
CellLocate.cpp:71:125: note:   mismatched types 'int (*)(int, const char*, int, T*)' and 'int (CellLocate::*)(int, const char*, int, CellLocate*)'
	   if (RESP_OK == Cellular.command(CellLocate::_cbLOCATE, *this, timeout_ms, "AT+ULOC=2,2,1,%d,5000\r\n", timeout_ms/1000)) {
																															 ^
CellLocate.cpp:71:125: note:   could not resolve address from overloaded function '((CellLocate*)this)->CellLocate::_cbLOCATE'
In file included from ../wiring/inc/spark_wiring.h:44:0,
				 from ./inc/application.h:36,
				 from CellLocate.cpp:1:
../wiring/inc/spark_wiring_cellular.h:114:16: note: template<class T, class ... Targs> int spark::CellularClass::command(int (*)(int, const char*, int, T*), T*, system_tick_t, const char*, Targs ...)
	 inline int command(int (*cb)(int type, const char* buf, int len, T* param),
				^
../wiring/inc/spark_wiring_cellular.h:114:16: note:   template argument deduction/substitution failed:
CellLocate.cpp:71:125: note:   mismatched types 'int (*)(int, const char*, int, T*)' and 'int (CellLocate::*)(int, const char*, int, CellLocate*)'
	   if (RESP_OK == Cellular.command(CellLocate::_cbLOCATE, *this, timeout_ms, "AT+ULOC=2,2,1,%d,5000\r\n", timeout_ms/1000)) {
																															 ^
CellLocate.cpp:71:125: note:   could not resolve address from overloaded function '((CellLocate*)this)->CellLocate::_cbLOCATE'
CellLocate.cpp: In member function 'bool CellLocate::get_response()':
CellLocate.cpp:99:58: error: no matching function for call to 'spark::CellularClass::command(<unresolved overloaded function type>, CellLocate&, int, const char [1])'
   Cellular.command(CellLocate::_cbLOCATE, *this, 1000, "");
														  ^
CellLocate.cpp:99:58: note: candidates are:
In file included from ../wiring/inc/spark_wiring.h:44:0,
				 from ./inc/application.h:36,
				 from CellLocate.cpp:1:
../wiring/inc/spark_wiring_cellular.h:95:16: note: template<class ... Targs> int spark::CellularClass::command(const char*, Targs ...)
	 inline int command(const char* format, Targs... Fargs)
				^
../wiring/inc/spark_wiring_cellular.h:95:16: note:   template argument deduction/substitution failed:
CellLocate.cpp:99:58: note:   cannot convert '((CellLocate*)this)->CellLocate::_cbLOCATE' (type '<unresolved overloaded function type>') to type 'const char*'
   Cellular.command(CellLocate::_cbLOCATE, *this, 1000, "");
														  ^
In file included from ../wiring/inc/spark_wiring.h:44:0,
				 from ./inc/application.h:36,
				 from CellLocate.cpp:1:
../wiring/inc/spark_wiring_cellular.h:101:16: note: template<class ... Targs> int spark::CellularClass::command(system_tick_t, const char*, Targs ...)
	 inline int command(system_tick_t timeout_ms, const char* format, Targs... Fargs)
				^
../wiring/inc/spark_wiring_cellular.h:101:16: note:   template argument deduction/substitution failed:
CellLocate.cpp:99:58: note:   cannot convert '((CellLocate*)this)->CellLocate::_cbLOCATE' (type '<unresolved overloaded function type>') to type 'system_tick_t {aka long unsigned int}'
   Cellular.command(CellLocate::_cbLOCATE, *this, 1000, "");
														  ^
In file included from ../wiring/inc/spark_wiring.h:44:0,
				 from ./inc/application.h:36,
				 from CellLocate.cpp:1:
../wiring/inc/spark_wiring_cellular.h:107:16: note: template<class T, class ... Targs> int spark::CellularClass::command(int (*)(int, const char*, int, T*), T*, const char*, Targs ...)
	 inline int command(int (*cb)(int type, const char* buf, int len, T* param),
				^
../wiring/inc/spark_wiring_cellular.h:107:16: note:   template argument deduction/substitution failed:
CellLocate.cpp:99:58: note:   mismatched types 'int (*)(int, const char*, int, T*)' and 'int (CellLocate::*)(int, const char*, int, CellLocate*)'
   Cellular.command(CellLocate::_cbLOCATE, *this, 1000, "");
														  ^
CellLocate.cpp:99:58: note:   could not resolve address from overloaded function '((CellLocate*)this)->CellLocate::_cbLOCATE'
In file included from ../wiring/inc/spark_wiring.h:44:0,
				 from ./inc/application.h:36,
				 from CellLocate.cpp:1:
../wiring/inc/spark_wiring_cellular.h:114:16: note: template<class T, class ... Targs> int spark::CellularClass::command(int (*)(int, const char*, int, T*), T*, system_tick_t, const char*, Targs ...)
	 inline int command(int (*cb)(int type, const char* buf, int len, T* param),
				^
../wiring/inc/spark_wiring_cellular.h:114:16: note:   template argument deduction/substitution failed:
CellLocate.cpp:99:58: note:   mismatched types 'int (*)(int, const char*, int, T*)' and 'int (CellLocate::*)(int, const char*, int, CellLocate*)'
   Cellular.command(CellLocate::_cbLOCATE, *this, 1000, "");
														  ^
CellLocate.cpp:99:58: note:   could not resolve address from overloaded function '((CellLocate*)this)->CellLocate::_cbLOCATE'
make[1]: *** [../build/target/user/platform-10CellLocate.o] Error 1
make: *** [user] Error 2

The sourcecode is on github so everyone can try to compile it using particle cli or particle dev.

thanks

Yup, I don’t need to compile that to find out that this can’t build for above reason :wink:
Have you tried making that method static?

sorry, I have no glue what method I should set static nor what it should fix?!