makeImageRequest from stream

I can download PNG using makeImageRequest("https://serverl/png.png"...) but I'd like to not save any file on server.

I can generate PNG in server's memory, but how to return it? I've tried many things but always got 404.

  • It depends on how big your app is, and if you are doing this in a background service, how big that is.  And when you get the image on the device, it's been converted to the format used on Garmin devices so might be larger than the original file

  • As usual try/catch doesn't work as advertised. Based on what I see and don't see the out of memory error is in the function that has the makeImageRequest call, but the error is coming from Garmin, not my catch. Thus, the only executable statement IS makeImageRequest. So, why would the request get an out of memory condition before the call back function is started? I've tried smaller and smaller images, now at 40x23 png. Whatever the problem is, it seems like something is triggering a "feature" causing the callback handler to crash.

    Memory from getSystemStats()

    used 51752
    free 75160
    total 126912

    And in the background from getSystemStats()

    Background: used 12104
    Background: free 49272
    Background: total 61376

    Error: Out Of Memory Error
    Details: failed inside handle_image_callback
    Stack:

  • Apparently it isn't my code or my server. When I tried it on the simulated CIQ 3 Captain Marvel it worked a few times, meaning 200 and the returned image displayed on the watch face. But sometimes I get a 404 and sometimes it crashes, so obviously something else is going on. It sure would be nice to get meaningful error messages, but that's asking a lot.

  • With more experimentation I've learned a lot more:

    makeWebRequest works every time on the first try. The server log shows a request from my gateway IP address, and PHP says it took 4 ms to find the nearest tide station to my location and return the harmonic constituents for it. For the RESTful URL fields, the zeroth is the API, first is the PHP script, and second is the device unique identifier + System.gettimer() + retry counter. For now this field is just for debugging. You can see that the retry counter is zero. For this type of request the third and fourth fields are my latitude and longitude in radians. The agent says it is Mozilla/5.0 (important later):

    Tide station request from makeWebRequest:
    66.72.221.161   -       2024-01-19T12:49:15+00:00       3135    1       GET /g1/hc/ffa0f28f1a9e91d2133a05fc4ff987c817fb2ab4_34240937_0/+0.533639306/-1.521642584 HTTP/1.1       .       200     1961    -       Mozilla/5.0 0.004

    makeImageRequest works almost never. I increased the retry count to 100, but it rarely even makes it to 20. For every call to makeImageRequest that returns a 404, the server log shows nothing. Eventually, something will show up in the server log. I have encoded the retry number in to the request URL. I'm not using that REST field, it's for debugging:

    Tide station request from makeWebRequest:
    66.72.221.161   -       2024-01-19T12:49:15+00:00       3135    1       GET /g1/hc/ffa0f28f1a9e91d2133a05fc4ff987c817fb2ab4_34240937_0/+0.533639306/-1.521642584 HTTP/1.1       .       200     1961    -       Mozilla/5.0 0.004
    
    Image file request from makeImageRequest:
    198.233.176.132 -       2024-01-19T15:24:18+00:00       3300    1       GET /g1/ci/ffa0f28f1a9e91d2133a05fc4ff987c817fb2ab4_43543718_10/test.png HTTP/1.1       .       200     5491    -       Java/11.0.20    0.001
    198.233.176.132 -       2024-01-19T15:24:18+00:00       3300    2       GET /g1/ci/ffa0f28f1a9e91d2133a05fc4ff987c817fb2ab4_43543718_10/test.png HTTP/1.1       .       200     5497    -       Java/11.0.20    0.001

    In this sample the retry counter was at 10. The client IP for makeImageRequest is registered to CenturyLink, that's all whois knows. The request URL was received twice in a row, from agent Java/11.0.20. After this I get an uncatachable error:

    Error: Out Of Memory Error
    Details: failed inside handle_image_callback
    Stack: 

    I have seen it work twice, so I know the monkey C I have in the simulator and the PHP on the server are not the issue.

    At this point I tried wireshark on the PC, and what I learned is that a request from the simulator is going to 104.16.73.50 and it identifies itself as services.garmin.com EVERY time makeImageRequest is called, but it's being dropped for some reason, and when it does forward the request it's most likely to cause a crash:

    No.	Time	Source	Destination	Protocol	Length	Info
    (previous tries omitted)
    
    My server didn't see this (retry 16)
    12092	814.985750	192.168.3.144	104.16.173.50	TCP	66	49943 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM
    12094	815.022995	192.168.3.144	104.16.173.50	TCP	54	49943 → 443 [ACK] Seq=1 Ack=1 Win=263168 Len=0
    12095	815.024861	192.168.3.144	104.16.173.50	TLSv1.2	235	Client Hello (SNI=services.garmin.com)
    12099	815.070499	192.168.3.144	104.16.173.50	TCP	54	49943 → 443 [ACK] Seq=182 Ack=2528 Win=263168 Len=0
    12100	815.073234	192.168.3.144	104.16.173.50	TLSv1.2	147	Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
    12102	815.112765	192.168.3.144	104.16.173.50	TLSv1.2	367	Application Data
    12107	815.263626	192.168.3.144	104.16.173.50	TCP	54	49943 → 443 [ACK] Seq=588 Ack=4607 Win=263168 Len=0
    12108	815.264601	192.168.3.144	104.16.173.50	TLSv1.2	85	Encrypted Alert
    12109	815.265033	192.168.3.144	104.16.173.50	TCP	54	49943 → 443 [FIN, ACK] Seq=619 Ack=4607 Win=263168 Len=0
    12110	815.276657	192.168.3.144	104.16.9.45	TLSv1.2	576	Application Data
    12113	815.301001	192.168.3.144	104.16.173.50	TCP	54	49943 → 443 [ACK] Seq=620 Ack=4608 Win=263168 Len=0
    12118	815.508469	192.168.3.144	104.16.9.45	TCP	54	49927 → 443 [ACK] Seq=9060 Ack=25633 Win=263168 Len=0
    
    My server didn't see this (retry 17)
    12119	815.615881	192.168.3.144	104.16.173.50	TCP	66	49944 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM
    12121	815.649402	192.168.3.144	104.16.173.50	TCP	54	49944 → 443 [ACK] Seq=1 Ack=1 Win=263168 Len=0
    12122	815.650475	192.168.3.144	104.16.173.50	TLSv1.2	235	Client Hello (SNI=services.garmin.com)
    12126	815.693650	192.168.3.144	104.16.173.50	TCP	54	49944 → 443 [ACK] Seq=182 Ack=2528 Win=263168 Len=0
    12127	815.699507	192.168.3.144	104.16.173.50	TLSv1.2	147	Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
    12129	815.743076	192.168.3.144	104.16.173.50	TLSv1.2	367	Application Data
    12134	815.882957	192.168.3.144	104.16.173.50	TCP	54	49944 → 443 [ACK] Seq=588 Ack=4615 Win=263168 Len=0
    12135	815.883922	192.168.3.144	104.16.173.50	TLSv1.2	85	Encrypted Alert
    12136	815.884220	192.168.3.144	104.16.173.50	TCP	54	49944 → 443 [FIN, ACK] Seq=619 Ack=4615 Win=263168 Len=0
    12137	815.891028	192.168.3.144	104.16.9.45	TLSv1.2	576	Application Data
    12140	815.921807	192.168.3.144	104.16.173.50	TCP	54	49944 → 443 [ACK] Seq=620 Ack=4616 Win=263168 Len=0
    12156	816.109998	192.168.3.144	104.16.9.45	TCP	54	49927 → 443 [ACK] Seq=9582 Ack=26946 Win=261632 Len=0
    
    My server received this (retry 18), then the app crashed:
    12157	816.233784	192.168.3.144	104.16.173.50	TCP	66	49945 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM
    12159	816.273257	192.168.3.144	104.16.173.50	TCP	54	49945 → 443 [ACK] Seq=1 Ack=1 Win=263168 Len=0
    12160	816.274521	192.168.3.144	104.16.173.50	TLSv1.2	235	Client Hello (SNI=services.garmin.com)
    12164	816.319658	192.168.3.144	104.16.173.50	TCP	54	49945 → 443 [ACK] Seq=182 Ack=2530 Win=263168 Len=0
    12165	816.322198	192.168.3.144	104.16.173.50	TLSv1.2	147	Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
    12171	816.361248	192.168.3.144	104.16.173.50	TLSv1.2	367	Application Data
    12177	816.509596	192.168.3.144	104.16.173.50	TCP	54	49945 → 443 [ACK] Seq=588 Ack=4615 Win=263168 Len=0
    12178	816.510732	192.168.3.144	104.16.173.50	TLSv1.2	85	Encrypted Alert
    12179	816.511325	192.168.3.144	104.16.173.50	TCP	54	49945 → 443 [FIN, ACK] Seq=619 Ack=4615 Win=263168 Len=0
    12180	816.519235	192.168.3.144	104.16.9.45	TLSv1.2	576	Application Data
    12183	816.550910	192.168.3.144	104.16.173.50	TCP	54	49945 → 443 [ACK] Seq=620 Ack=4616 Win=263168 Len=0
    12192	817.034691	192.168.3.144	104.16.9.45	TCP	54	49927 → 443 [ACK] Seq=10104 Ack=29742 Win=263168 Len=0
    12195	817.035042	192.168.3.144	104.16.9.45	TCP	54	49927 → 443 [ACK] Seq=10104 Ack=32538 Win=263168 Len=0
    12198	817.089590	192.168.3.144	104.16.9.45	TCP	54	49927 → 443 [ACK] Seq=10104 Ack=33408 Win=262144 Len=0
    12863	918.879825	192.168.3.144	104.18.71.229	TCP	54	49924 → 80 [ACK] Seq=947 Ack=1092 Win=261888 Len=0
    12868	919.214467	192.168.3.144	104.18.71.229	TCP	54	49925 → 443 [ACK] Seq=1246 Ack=4402 Win=263168 Len=0
    14929	1217.036987	192.168.3.144	104.16.9.45	TCP	54	49927 → 443 [ACK] Seq=10104 Ack=33440 Win=262144 Len=0
    

    What I've learned is that we're relying on some server, presumably Garmin's, to do some image processing and fulfill the request. That is to say, this is an unsolvable problem, and attempts to debug code and our servers are in vain.

  • Now with SDK 7 I see that the image request hits my server on the first try, and the result code in the nginx server log is 200. However, I now get this error in the debug console:

    Error: Exception occurred
    Details: failed inside handle_image_callback
    Exception: Class usage is not allowed for the current app type.

    The web request in the same background class still works fine, so it doesn't seem like it's the background part it doesn't like. I get this println in the output:

            System.println("requestCenterImage getURL " + v_getURL);
            Communications.makeImageRequest(v_getURL, null, _cPic, method(:onReceiveCenterImage));

    But not the println that is the first line of the receive method:

        public function onReceiveCenterImage(response as Number, data as imgData) as Void {
            System.println("onReceiveCenterImage response " + response + ", getTimer " + System.getTimer());

    So the problem seems to be in makeImageRequest itself.

  • what is your app type, and device?

  • Fenix 7X watch face with CIQ 5.0.0 goodness in the watch and the simulator. With SDK 6.4.2 I mostly I get this, but I did see it work one or twice so at least it is or was theoretically possible.

    Error: Out Of Memory Error
    Details: failed inside handle_image_callback
    Stack:

    The image size according to nginx is 2317 bytes, and the request is asking for it to be sized to 20x20 so it shouldn't be an actual bytes issue.

  • Well, it works when I try it with the Captain Marvel simulator, so apparently the nginx server config and monkey c code are all OK. It's the Fenix 7X sim.

  • Some CIQ 3 devices work, like Venu Sq. Music Edition and vivoactive 4, some don't. I get this on the Fenix 5S sim:

    Error: Symbol Not Found Error
    Details: Could not find symbol 'BitmapReference'
    Stack:
      - setBitmap() at D:\grmn\prj\di\connectiq\toolchain\mbsimulator\submodules\technology\monkeybrains\virtual-machine\api\WatchUi.mb:4440 0x30003bca
      - initialize() at D:\grmn\prj\di\connectiq\toolchain\mbsimulator\submodules\technology\monkeybrains\virtual-machine\api\WatchUi.mb:4373 0x300039ac
      - loadPic() at C:\Users\Andy\Desktop\Garmin-GIT\Annulus\source\AnnulusFace.mc:772 0x10002e3d
      - onBackgroundData() at C:\Users\Andy\Desktop\Garmin-GIT\Annulus\source\AnnulusApp.mc:107 0x100009a8

    Executing this statement:

        public function loadPic(bMap) {
                bMap = new WatchUi.Bitmap((bMap instanceof ResourceId) ? {:rezId=>bMap} : {:bitmap=>bMap}); // SDK 7+

    Why is a CIQ 3 device looking for BitmapReference? The docs say it doesn't exist until CIQ 4, hence the error.

    I have yet to find one CIQ 4 or 5 device that it doesn't throw an error on; Some have this:

    Error: Symbol Not Found Error
    Details: Failed invoking <symbol>
    Stack:

    Some do this:

    Error: Exception occurred
    Details: failed inside handle_image_callback
    Exception: Class usage is not allowed for the current app type.

    So close, yet so far...

  • Are your devices files up to date and are you using the 7.1.1 SDK?

    Sound like you are also dealing with the devices with the graphics pool and those that don't