-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcocowx_json.asm
2139 lines (1949 loc) · 60.3 KB
/
cocowx_json.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
**************************************************************************************************
* CoCo WX 2.1 - Written By Todd Wallace
*
* So I am a bit of a weather geek. I even have my own outdoor wireless sensor that can measure
* wind speed, direction, rainfall, etc. Weather "apps" are available on almost every platform
* capable of connecting to the internet, so how cool would it be to do it on a CoCo too? Well I
* found this cool web-based poweruser-oriented online weather service called wttr.in. It's
* free to use and has a very simple implementation. I figured out how to do a simple HTTP
* request over a TCP connection made with DriveWire's virtual serial port drivers and voila!
*
* New In Versin 2.1
* - better handling of HTTP server error responses
* - better detection of locations that arent found in the search
* - proper support for spaces in the location name
*
* New in Version 2.0
*
* I have completely rewritten the networking parts of the code to request and parse weather data
* in JSON format from wttr.in as that medium contains a much wider range of data and units of
* measure. This now lets the user view their weather data in either metric or imperial measurements
* regardless of the region they are checking the conditions of.
*
* The biggest change you'll actually notice is the new default full-color graphical output mode
* with icons and everything!
**************************************************************************************************
; Definitions/equates
STDOUT EQU 1
STDIN EQU 0
H6309 set 1
cr_lf EQU $0D0A
network_signal EQU 32
keyboard_signal EQU 33
connect_timeout_signal EQU $88
wx_refresh_signal EQU $80
;graphics_display EQU 1
;wttr_down EQU 1
include os9.d
include rbf.d
include scf.d
pragma cescapes
; Module header setup info
MOD MODULE_SIZE,moduleName,$11,$80,START_EXEC,data_size
START_MODULE
**************************************************************************************
; -----------------------------------------------------
; Variables
org 0
uRegImage RMB 2
networkPath RMB 1
gfxWindowPath RMB 1
digitGfxPath RMB 1
nilPath RMB 1
iconFilePath RMB 1
gfxStatusPath RMB 1
networkDataReady RMB 1
pendingConnect RMB 1
abortFlag RMB 1
networkTimeoutFlag RMB 1
keyInputFlag RMB 1
contentLengthFlag RMB 1
copyContentFlag RMB 1
groupID RMB 1
outputMode RMB 1
fColorSequence RMB 3
windIconIndex RMB 1
metricOutputFlag RMB 1
refreshFlag RMB 1
wxRefreshFlag RMB 1
networkBufferEndPtr RMB 2
replyBufferCurPtr RMB 2
replyBufferEndPtr RMB 2
contentBodyPtr RMB 2
jsonCurCondPtr RMB 2
shellParamPtr RMB 2
searchEndPtr RMB 2
dwReadBytes RMB 2
tempPtr RMB 2
tempChar RMB 1
tempByte RMB 1
tempWord RMB 2
tempCounter RMB 1
charDegreesSymbol RMB 1
pixelCharWidth RMB 1
jsonTableCounter RMB 1
strHexWord RMB 10
u8Value RMB 1
debugFlag RMB 1
contentLength RMB 2
constContentLength RMB 2
hpaValue RMB 2
u32Value RMB 4
; inHg pressure conversion variables
v24h RMB 1
v24m RMB 1
v24l RMB 1
pressureInches RMB 6
pdBuffer RMB 32
networkBuffer RMB 256
networkBufferSz EQU .-networkBuffer
outputBuffer RMB 512
replyBuffer RMB 4096
; json variables
jsonFeelsLikeC RMB 5
jsonFeelsLikeF RMB 5
jsonHumidity RMB 4
jsonLocalTime RMB 21
jsonObsTime RMB 10
jsonPrecipInches RMB 5
jsonPrecipMM RMB 5
jsonPressure RMB 6
jsonTempC RMB 5
jsonTempF RMB 5
jsonWeatherCode RMB 5
jsonWindDir RMB 4
jsonWindSpeedKPH RMB 4
jsonWindSpeedMPH RMB 4
jsonWeatherDesc RMB 32
jsonAreaName RMB 20
jsonRegion RMB 20
stringBuffer RMB 64
gfxWindDir RMB 3
; End of Variables
; -----------------------------------------------------
; YOU MUST RESERVE SOME SPACE FOR STACK HERE
stackSpace RMB 128
data_size EQU .
; -----------------------------------------------------
; Constants
moduleName FCS "cocowx"
networkPathName FCS "/N"
winPathName FCC "/W\r"
nilPathName FCC "/NIL\r"
gfxIconsFilename FCC "/dd/sys/cocowx/wx_icons.bin\r"
gfxDigitsFilename FCC "/dd/sys/cocowx/wx_digits.bin\r"
gfxCompassFilename FCC "/dd/sys/cocowx/wx_compass.bin\r"
dwSelectSequence FCB $1B,$21
dwSetWindow FCB $1B,$20,8,0,0,40,25,2,0,0
FCB $1B,$35,0 ; disable scaling of coords
; setup palette colors
FCB $1B,$31,0,0
FCB $1B,$31,1,53 ; orange for sun edges
FCB $1B,$31,2,11 ; darker blue color for rain and dark clouds
FCB $1B,$31,3,25 ; light blue for regular clouds
FCB $1B,$31,4,7 ; dark gray for cloud edges
FCB $1B,$31,5,54 ; yellow sun color
FCB $1B,$31,6,56 ; light gray for light clouds
FCB $1B,$31,7,63 ; white text
FCB $1B,$31,8,27 ; cyan blue for snow flakes and sleet
FCB $1B,$31,9,36 ; red for wind compass indicator
FCB $1B,$31,10,16 ; green for text
FCB $1B,$31,11,29
FCB $1B,$31,12,31
; turn off the text cursor
FCB $05,$20
dwSetWindowSz EQU *-dwSetWindow
; (make sure to use NULL at end)
selectFontTitle FCB $1B,$3A,$C8,$42,0
selectFontInfo FCB $1B,$3A,$C8,$02,0 ; $02 = standard narrow font, $32 = Mac narrow font (no degrees)
selectFontAuthor FCB $1B,$3A,$C8,$09,0
infoColorSequence FCB $1B,$32,11,0 ; 0 at end is null terminator
labelColorSequence FCB $1B,$32,7,0 ; 0 at end is null terminator
screenUpdateSeq FDB $1B40,0,40 ; move draw pointer
FCB $1B,$32,0 ; select black color
FDB $1B4A,319,199 ; draw a solid bar rectangle to blank out most of the screen
screenUpdateSeqSz EQU *-screenUpdateSeq
strTitle FCN "CoCo WX v2.1 - Written by Todd Wallace\r\n\n"
strUsage FCC "Check live weather conditions for anywhere in the world using your CoCo! This\r\n"
FCC "tool works by leveraging DriveWire (required) and the online weather info and\r\n"
FCC "forecasting service wttr.in to request and retrieve live data.\r\n\n"
FCC "Usage: cocowx [-t [-d hex_value]] [-m] <location>\r\n\n"
FCC " - New in version 2.0 is a fully graphical output mode, complete with full-color"
FCC " icons! This mode is now the default, however the traditional text-only output"
FCC " can still be used by including the -t flag.\r\n"
FCC " - When using the text-only mode, you can also optionally add the -d flag to\r\n"
FCC " customize the degrees symbol character displayed. This is to accommodate\r\n"
FCC " other OS-9 fonts with a different character set. The value must be expressed\r\n"
FCC " as a 2-character hexadecimal ASCII code. (Example: cocowx -t -d F8)\r\n"
FCC " - To display values in Metric units instead of Imperial (which is the default)\r\n"
FCC " use the optional -m flag.\r\n"
FCC " - The location parameter can be in a wide range of formats like city and state,"
FCC " city by itself, zipcode, etc. See http://wttr.in/help for more details.\r\n"
FCC " - In graphics mode, the weather info will be auto-updated every 10 minutes,\r\n"
FCC " but you can request a manual refresh at any time by pressing the ENTER key.\r\n"
strUsageSz EQU *-strUsage
strConnecting FCN "Connecting... "
strConnectSuccess FCN "Success\r\nRequesting weather data... "
strDone FCN "Done\r\n"
strMsgLoadingGfx FCN "Loading graphics from disk... "
strGfxRetrieving FCN " Updating WX Data: Requesting..."
strGfxTimeout FCN " Error: Network Timeout"
strGfxConnecting FCN " Updating WX Data: Connecting..."
strConnect FCC "TCP CONNECT wttr.in 80\r"
strConnectSz EQU *-strConnect
strUserAborted FCN "\x03\rUser aborted.\r\n"
strGetPrefix FCN "GET /"
strGetSuffix FCN " HTTP/1.1\r\n"
strHostInfo FCN "Host: wttr.in\r\n"
strUserAgent FCN "User-Agent: curl/7.68.0\r\n\r\n"
;strWeatherFormatTxt FCN "?format=TANDY%l\\n%C\\n%x\\n%t\\n%f\\n%h\\n%P\\n%w\\n%p\\n%m\\n%S\\n%s\\n"
strWeatherFormatTxt FCN "?format=j2"
;strWeatherFormatTxt FCN "?T2n"
;strGetConnection FCN "Connection: keep-alive\r\n"
strConnectFailed FCN "\x03\rCould not connect to server ("
strKEYWORDok FCN "OK "
strKEYWORDfail FCN "FAIL "
strKEYWORDcontent FCN "CONTENT-LENGTH: "
strKEYWORDtong FCN "TONG"
strKEYWORDhttp1.1 FCN "HTTP/1.1"
strKEYWORDdoubleCRLF FCB $0D,$0A,$0D,$0A,0
; json keywords and variable pointers
jsonKeywordCurCond FCN "current_condition"
strJSONfeelsLikeC FCN "FeelsLikeC"
strJSONfeelsLikeF FCN "FeelsLikeF"
strJSONhumidity FCN "humidity"
strJSONlocalTime FCN "localObsDateTime"
strJSONobsTime FCN "observation_time"
strJSONprecpInches FCN "precipInches"
strJSONprecipMM FCN "precipMM"
strJSONpressure FCN "pressure" ; in hPa
strJSONtemp_C FCN "temp_C"
strJSONtemp_F FCN "temp_F"
strJSONweatherCode FCN "weatherCode"
strJSONwindDir FCN "winddir16Point"
strJSONwindSpeedKPH FCN "windspeedKmph"
strJSONwindSpeedMPH FCN "windspeedMiles"
; these keywords are for use with sub-parameters
strJSONweatherDesc FCN "weatherDesc"
strJSONvalue FCN "value"
strJSONnearestArea FCN "nearest_area"
strJSONareaName FCN "areaName"
strJSONregion FCN "region"
jsonKeywordVarsTable FDB strJSONfeelsLikeC ; source keyword to find
FDB jsonFeelsLikeC ; destination for string to be copied to
FDB strJSONfeelsLikeF
FDB jsonFeelsLikeF
FDB strJSONhumidity
FDB jsonHumidity
FDB strJSONlocalTime
FDB jsonLocalTime
FDB strJSONobsTime
FDB jsonObsTime
FDB strJSONprecpInches
FDB jsonPrecipInches
FDB strJSONprecipMM
FDB jsonPrecipMM
FDB strJSONpressure
FDB jsonPressure
FDB strJSONtemp_C
FDB jsonTempC
FDB strJSONtemp_F
FDB jsonTempF
FDB strJSONweatherCode
FDB jsonWeatherCode
FDB strJSONwindDir
FDB jsonWindDir
FDB strJSONwindSpeedKPH
FDB jsonWindSpeedKPH
FDB strJSONwindSpeedMPH
FDB jsonWindSpeedMPH
json_keyword_vars_sz EQU (*-jsonKeywordVarsTable)/4 ; 2 bytes per ptr, 2 ptrs per entry = 4
IFDEF wttr_down
; DEBUG REASONS
XjsonTempF FCN "68"
XjsonFeelsLikeF FCN "65"
XjsonHumidity FCN "51"
XjsonLocalTime FCN "2022-04-24 01:15 PM"
XjsonPrecipInches FCN "0.0"
XjsonPressure FCN "1028"
XjsonWeatherCode FCN "116"
XjsonWindDir FCN "NE"
XjsonWindSpeedMPH FCN "19"
XjsonWeatherDesc FCN "Partly cloudy"
XjsonAreaName FCN "Providence"
XjsonRegion FCN "Rhode Island"
ENDC
strBlank FCN ""
testBufferSeq FCB $1B,$2D,3,2
FDB 0,0
bin32dec1M FQB 1000000 ; 1 million decimal
bin32dec100K FQB 100000 ; 100 thousand decimal
bin32dec10K FQB 10000
strCurrentWeather FCN "Current weather for "
strLocation FCN "WEST WARWICK, RI"
strTemperature FCN "\r\n\nTemperature: "
strFeelsLike FCN ", Feels Like: "
strHumidity FCN ", Humidity: "
strPressure FCN ", Pressure: "
strWind FCN "\r\nWind: "
strPrecipitation FCN ", Rainfall: "
strMoonPhase FCN ", Moon Phase: "
strSunrise FCN "\r\nSunrise: "
strSunset FCN ", Sunset: "
strTimeLocal FCN " (Times All Local)"
strDateTime FCN ", Observation Time: "
strWindMPH FCN " mph"
strWindKPH FCN " kph"
strPressureInHg FCN " inHg"
strPressurehPa FCN " hPa"
strForecast FCN "\r\n\n3-Day Forecast: "
strForecastHighLow FCN " "
strPartlyCloudy FCN "Partly Cloudy"
strLightSnowShowers FCN "Light Snow Showers"
strGfxCoCoWX FCN "CoCo WX v2.1"
strGfxAuthor FCN "Written by Todd Wallace"
strGfxFeelsLike FCN "Feels Like: "
strGfxHumidity FCN "Humidity: "
strGfxPressure FCN "Pressure: "
strGfxWind FCN "Wind"
strGfxObsTime FCN "Observation Time: "
strGfxRainfall FCN "Rainfall: "
; conditions weather code table (has to be 4 bytes per entry)
curCondCodeTable EQU *
symCloudy FCC "119" ; Cloudy
FCB 0
symFog1 FCC "143" ; Fog
FCB 1
symFog2 FCC "248" ; Fog (duplicate with different number)
FCB 1
symFog3 FCC "260" ; Fog (duplicate with different number)
FCB 1
symHeavyRain1 FCC "302" ; HeavyRain
FCB 2
symHeavyRain2 FCC "308" ; HeavyRain
FCB 2
symHeavyRain3 FCC "359" ; HeavyRain
FCB 2
symHeavyShowers1 FCC "299" ; HeavyShowers
FCB 6
symHeavyShowers2 FCC "305" ; HeavyShowers
FCB 6
symHeavyShowers3 FCC "356" ; HeavyShowers
FCB 6
symHeavySnow1 FCC "230" ; HeavySnow
FCB 4
symHeavySnow2 FCC "329" ; HeavySnow
FCB 4
symHeavySnow3 FCC "332" ; HeavySnow
FCB 4
symHeavySnow4 FCC "338" ; HeavySnow
FCB 4
symHeavySnowShowers1 FCC "335" ; HeavySnowShowers
FCB 5
symHeavySnowShowers2 FCC "371" ; HeavySnowShowers
FCB 5
symHeavySnowShowers3 FCC "395" ; HeavySnowShowers
FCB 5
symLightRain1 FCC "266" ; LightRain1
FCB 3
symLightRain2 FCC "293" ; LightRain2
FCB 3
symLightRain3 FCC "296" ; LightRain3
FCB 3
symLightShowers1 FCC "176" ; LightShowers1
FCB 6
symLightShowers2 FCC "263" ; LightShowers2
FCB 6
symLightShowers3 FCC "353" ; LightShowers3
FCB 6
symLightSleet1 FCC "182" ; LightSleet1
FCB 8
symLightSleet2 FCC "185" ; LightSleet2
FCB 8
symLightSleet3 FCC "281" ; LightSleet3
FCB 8
symLightSleet4 FCC "284" ; LightSleet4
FCB 8
symLightSleet5 FCC "311" ; LightSleet5
FCB 8
symLightSleet6 FCC "314" ; LightSleet6
FCB 8
symLightSleet7 FCC "317" ; LightSleet7
FCB 8
symLightSleet8 FCC "350" ; LightSleet8
FCB 8
symLightSleet9 FCC "377" ; LightSleet9
FCB 8
symLightSleetShwrs1 FCC "179" ; LightSleetShowers
FCB 8
symLightSleetShwrs2 FCC "362" ; LightSleetShowers
FCB 8
symLightSleetShwrs3 FCC "365" ; LightSleetShowers
FCB 8
symLightSleetShwrs4 FCC "374" ; LightSleetShowers
FCB 8
symLightSnow1 FCC "227" ; LightSnow
FCB 7
symLightSnow2 FCC "320" ; LightSnow
FCB 7
symLightSnowShowers1 FCC "323" ; LightSnowShowers
FCB 5
symLightSnowShowers2 FCC "326" ; LightSnowShowers
FCB 5
symLightSnowShowers3 FCC "368" ; LightSnowShowers
FCB 5
symPartlyCloudy FCC "116" ; PartlyCloudy
FCB 9
symSunny FCC "113" ; Sunny
FCB 10
symThunderHeavyRain FCC "389" ; ThunderyHeavyRain
FCB 13
symThunderShowers1 FCC "200" ; ThunderyShowers1
FCB 11
symThunderShowers2 FCC "386" ; ThunderyShowers2
FCB 11
symThunderSnowShwrs FCC "392" ; ThunderySnowShowers
FCB 5
symVeryCloudy FCC "122" ; VeryCloudy
FCB 12
curCondCodeTableEnd EQU *
moonphaseTable FDB strMoonNew
FDB strMoonWaxCrescent
FDB strMoonFirstQuarter
FDB strMoonWaxGibbous
FDB strMoonFull
FDB strMoonWanGibbous
FDB strMoonLastQuarter
FDB strMoonWanCrescent
; moonphase string descriptions
strMoonNew FCN "New Moon"
strMoonWaxCrescent FCN "Waxing Crescent"
strMoonFirstQuarter FCN "First Quarter"
strMoonWaxGibbous FCN "Waxing Gibbous"
strMoonFull FCN "Full Moon"
strMoonWanGibbous FCN "Waning Gibbous"
strMoonLastQuarter FCN "Last Quarter"
strMoonWanCrescent FCN "Waning Crescent"
strErrorInvalidParam FCN "Invalid parameters or syntax. Type COCOWX by itself to see usage information.\r\n"
strErrorInvalidFlag FCN "Invalid flag. Type COCOWX by itself to see usage information.\r\n"
strErrorNoDrivewire FCN "Error opening path to DriveWire Virtual Serial Port module /N.\r\nIs DriveWire installed correctly?\r\n"
strErrorVRNmodule FCN "Error opening path to /NIL module which is needed for connection timeout timer\r\nto function. Otherwise you will have to manually exit by pressing ESC.\r\n"
strErrorTimeout FCN "\x03\rError communicating with the wttr.in weather service. Connection either timed\r\nout or didn't responded to the request as expected. Is your DriveWire server\r\nconnected to the internet? Try visiting https://wttr.in from it to make sure the service is working and not having an outage.\r\n"
strErrorGraphics FCN "Graphics files not found. Exiting...\r\n"
strErrorLocation FCN "Location not found ("
strErrorServerReply FCN "Unexpected server reply ("
asciiHexList FCC "0123456789ABCDEF"
; -----------------------------------------------------
START_EXEC
**************************************************************************************
* Program code area
* RULE #1 - USE U TO REFERENCE ANY CHANGEABLE VARIABLES IN THE DATA AREA.
* RULE #2 - USE PCR TO REFERENCE CONSTANTS SINCE THEY RESIDE WITH EXECUTABLE CODE.
* RULE #3 - NEVER USE JSR FOR CALLING SUBROUTINES. ALWAYS USE BSR OR LBSR INSTEAD.
**************************************************************************************
stu <uRegImage ; save copy of data area pointer in U
stx <shellParamPtr
ldd #$1B32
std fColorSequence,U
; lbra DEBUG_BYPASS
; init path variables
lda #$FF
sta <gfxWindowPath
sta <iconFilePath
sta <networkPath
sta <nilPath
sta <digitGfxPath
clra
sta <debugFlag
sta <metricOutputFlag ; imperial units is the default so set metric to 0
sta <keyInputFlag
sta <refreshFlag
sta <wxRefreshFlag
; display title/author info
leax strTitle,PCR
lda #STDOUT
lbsr PRINT_NULL_STRING
; set default char for degree symbol
lda #$BE ; value for GIME text-mode screen types
sta <charDegreesSymbol
clr <outputMode ; set default output mode to graphics (any non-zero means text-only)
ldx <shellParamPtr
lbsr FIND_NEXT_NONSPACE_CHAR
cmpa #C$CR
lbeq DISPLAY_INFO_USAGE
FLAGS_SEARCH_NEXT
; check if we have a flag
lda ,X+
cmpa #C$CR
lbeq ERROR_INVALID_PARAMS ; missing city/state/location which is required
cmpa #'-'
bne NO_MORE_FLAGS
lda ,X+
; check for degree symbol character flag
lbsr CONVERT_UPPERCASE
cmpa #'D'
bne FLAGS_CHECK_TEXT_ONLY
lbsr FIND_NEXT_NONSPACE_CHAR
cmpa #C$CR
lbeq ERROR_INVALID_PARAMS
lbsr CONVERT_HEX_STRING_TO_BYTE ; convert the 2 character hex into a binary byte value
sta <charDegreesSymbol
lbsr FIND_NEXT_NONSPACE_CHAR
bra FLAGS_SEARCH_NEXT
FLAGS_CHECK_TEXT_ONLY
cmpa #'T'
bne FLAGS_CHECK_METRIC
lda ,X+
cmpa #C$SPAC
lbne ERROR_INVALID_PARAMS
sta <outputMode ; any value non-zero will force text-only output
lbsr FIND_NEXT_NONSPACE_CHAR
bra FLAGS_SEARCH_NEXT
FLAGS_CHECK_METRIC
cmpa #'M'
lbne ERROR_UNKNOWN_FLAG
lda ,X+
cmpa #C$SPAC
lbne ERROR_INVALID_PARAMS
sta <metricOutputFlag ; any value non-zero will select metric units output
lbsr FIND_NEXT_NONSPACE_CHAR
bra FLAGS_SEARCH_NEXT
NO_MORE_FLAGS
leax -1,X ; undo auto-increment
stx <shellParamPtr
; FOR TESTING WHEN WTTR.IN IS DOWN
IFDEF wttr_down
leay jsonTempF,U
leax XjsonTempF,PCR
lbsr STRING_COPY_RAW
leay jsonFeelsLikeF,U
leax XjsonFeelsLikeF,PCR
lbsr STRING_COPY_RAW
leay jsonHumidity,U
leax XjsonHumidity,PCR
lbsr STRING_COPY_RAW
leay jsonPressure,U
leax XjsonPressure,PCR
lbsr STRING_COPY_RAW
leay jsonPrecipInches,U
leax XjsonPrecipInches,PCR
lbsr STRING_COPY_RAW
leay jsonWindDir,U
leax XjsonWindDir,PCR
lbsr STRING_COPY_RAW
leay jsonWindSpeedMPH,U
leax XjsonWindSpeedMPH,PCR
lbsr STRING_COPY_RAW
leay jsonLocalTime,U
leax XjsonLocalTime,PCR
lbsr STRING_COPY_RAW
leay jsonWeatherDesc,U
leax XjsonWeatherDesc,PCR
lbsr STRING_COPY_RAW
leay jsonWeatherCode,U
leax XjsonWeatherCode,PCR
lbsr STRING_COPY_RAW
leay jsonAreaName,U
leax XjsonAreaName,PCR
lbsr STRING_COPY_RAW
leay jsonRegion,U
leax XjsonRegion,PCR
lbsr STRING_COPY_RAW
lbra DEBUG_WTTR_DOWN
ENDC
lda <nilPath
bpl VRN_PATH_ALREADY_OPEN
; setup path to VRN driver for timer functionality for connection timeout
lda #UPDAT.
clrb
leax nilPathName,PCR
os9 I$Open
bcc GOT_VRN_PATH
; tell user vrn is needed for the timeout timer to work
leax strErrorVRNmodule,PCR
lda #STDOUT
lbsr PRINT_NULL_STRING
lda #$FF ; this makes sure bit 7 is set so we know there is no VRN
GOT_VRN_PATH
sta <nilPath
VRN_PATH_ALREADY_OPEN
SETUP_REFRESH_WEATHER_REQUEST
ldd #0
sta <networkDataReady
sta <pendingConnect
sta <abortFlag
sta <networkTimeoutFlag
leax replyBuffer,U
stx <replyBufferEndPtr
lda <refreshFlag
bne SKIP_SIGNAL_HANDLER_SETUP
; setup the intercept stuff if not already configured
leax SIGNAL_HANDLER,PCR
os9 F$Icpt
SKIP_SIGNAL_HANDLER_SETUP
lbsr DRIVEWIRE_SETUP
lbcs ERROR_NO_DRIVEWIRE
; send the connect command to drivewire to connect to wttr.in web server
lda <networkPath
leax strConnect,PCR
ldy #strConnectSz
os9 I$Write
inc <pendingConnect
; setup timeout timer where if it cant connect or HTTP GET request timesout, we can gracefully fail.
lda <nilPath
ldb #SS.FSet ; code $C7
ldx #900 ; 15 seconds
ldy #0
ldu #connect_timeout_signal
os9 I$SetStt
ldu <uRegImage
; tell the user we are trying to connect and sending the request to server if successful
lda <refreshFlag
bne MAINLOOP ; skip STDOUT message since we are in graphics mode
lda #STDOUT
leax strConnecting,PCR
lbsr PRINT_NULL_STRING
MAINLOOP
lda <networkDataReady
bne MAINLOOP_NEXT_READ
lda <keyInputFlag
bne MAINLOOP_NEW_KEYSTROKES
lda <wxRefreshFlag
lbne REFRESH_WEATHER_DATA ; the refresh timer elapsed and its time to refresh wx data/display it
lda <abortFlag
lbne USER_ABORT_EXIT
lda <networkTimeoutFlag
lbne ERROR_TIMEOUT_EXIT
; if here, nothing to do except wait for more incoming signals. reset network signal, and then sleep
clr <networkDataReady
; reset signal for network activity
lda <networkPath
ldb #SS.SSig
ldx #network_signal
os9 I$SetStt
; sleep
ldx #0
os9 F$Sleep
bra MAINLOOP
MAINLOOP_NEW_KEYSTROKES
; if here, there was keyboard input. handle it
lda <gfxWindowPath
ldb #SS.Ready
os9 I$GetStt
bcs MAINLOOP ; something weird happened so ignore and go through mainloop again
clra
tfr D,Y
lda <gfxWindowPath
leax stringBuffer,U
os9 I$Read
bcs MAINLOOP ; something weird happened so ignore and go through mainloop again
clr <keyInputFlag ; reset keyInputFlag since all pending keystrokes have now been read in and cleared
tfr Y,D
MAINLOOP_CHECK_NEXT_KEYSTROKE
lda ,X+
cmpa #C$CR
lbeq REFRESH_WEATHER_DATA_MANUALLY
decb
bne MAINLOOP_CHECK_NEXT_KEYSTROKE
; if here, no ENTER key was pressed for a manual refresh of weather data. reset signal and go back to mainloop
lda <gfxWindowPath
ldb #SS.SSig
ldx #keyboard_signal
os9 I$SetStt
bra MAINLOOP
MAINLOOP_NEXT_READ
lbsr DRIVEWIRE_GET_DATA
bcs MAINLOOP ; check and reset signals and then sleep until more data comes through
lda <pendingConnect
lbeq MAINLOOP_NEW_DATA ; we are already connected so read in data from server reply
; set our string matching search routine to stop looking within temp dw network buffer
ldx <networkBufferEndPtr
stx <searchEndPtr
leax networkBuffer,U
leay strKEYWORDok,PCR
lbsr STRING_SEARCH_BUFFER
bcc MAINLOOP_NOW_CONNECTED
leay strKEYWORDfail,PCR
lbsr STRING_SEARCH_BUFFER
bcs MAINLOOP_NEXT_READ ; ignore and look for further network data
; if here, connection to drivewire server failed. report reason
lbsr FIND_NEXT_SPACE_NULL_CR
leax 1,X
lbsr FIND_NEXT_SPACE_NULL_CR
leax 1,X
stx <tempPtr
; disable timeout timer if exists
lda <nilPath
bmi MAINLOOP_SKIP_VRN_TIMER
ldb #SS.FClr
ldx #0
ldy #0
os9 I$SetStt
MAINLOOP_SKIP_VRN_TIMER
leay outputBuffer,U
leax strConnectFailed,PCR
lbsr STRING_COPY_RAW
ldx <tempPtr
lbsr STRING_COPY_CR
lda #')'
sta ,Y+
ldd #cr_lf
std ,Y++
clr ,Y
leax outputBuffer,U
lda #STDOUT
lbsr PRINT_NULL_STRING
; close paths and exit
lbra CLOSE_EXIT
MAINLOOP_NOW_CONNECTED
lda <refreshFlag
beq MAINLOOP_NOW_CONNECTED_STDOUT
; if here, we are in graphics mode and need to update status text
leax strGfxRetrieving,PCR
lbsr PRINT_GFX_STATUS
bra MAINLOOP_SETUP_WX_REQUEST
MAINLOOP_NOW_CONNECTED_STDOUT
lda #STDOUT
leax strConnectSuccess,PCR
lbsr PRINT_NULL_STRING
MAINLOOP_SETUP_WX_REQUEST
clr <pendingConnect
clr <copyContentFlag
clr <contentLengthFlag
; send the weather HTTP request to the server
lbsr SEND_WEATHER_REQUEST
; check for any more data/response from the network
lbra MAINLOOP_NEXT_READ
MAINLOOP_NEW_DATA
; first copy new data into our main buffer from temporary one
leax networkBuffer,U
ldy <replyBufferEndPtr
sty <replyBufferCurPtr ; this now will become our new current ptr after copying
ldb <dwReadBytes+1
MAINLOOP_NEW_DATA_COPY_NEXT
lda ,X+
sta ,Y+
decb
bne MAINLOOP_NEW_DATA_COPY_NEXT
sty <replyBufferEndPtr ; save end position in reply buffer for future data to continue at
sty <searchEndPtr
lda <copyContentFlag
beq MAINLOOP_CHECK_HEADER_STUFF
; subtract new bytes we just copied in from total remaining of the main content and keep copying
ldd <contentLength
subd <dwReadBytes
std <contentLength
lbhi MAINLOOP_NEXT_READ ; if we have not reached 0 (or less) bytes reamining, keep copying
lbra PROCESS_WEATHER_DATA
MAINLOOP_CHECK_HEADER_STUFF
lda <contentLengthFlag
lbne MAINLOOP_NEW_DATA_FIND_BODY
; before going any further, retrieve the HTTP server reply code to see if we have a valid
; reply from the server, or some kind of error like "Bad Reqest" of "Not Found"
leay strKEYWORDhttp1.1,PCR
ldx <replyBufferCurPtr
lbsr STRING_SEARCH_BUFFER
lbcs MAINLOOP_NEXT_READ
; if here, we found the HTTP reply version. check the reply code and handle accordingly
lbsr FIND_NEXT_NONSPACE_CHAR
ldd #"40"
cmpd ,X
bne MAINLOOP_CHECK_HEADER_VALID_REQUEST
cmpa 2,X
lbeq ERROR_LOCATION_NOT_FOUND
lbra ERROR_UNKNOWN_SERVER_RESPONSE
MAINLOOP_CHECK_HEADER_VALID_REQUEST
ldd #"20"
cmpd ,X
lbne ERROR_UNKNOWN_SERVER_RESPONSE
cmpb 2,X
lbne ERROR_UNKNOWN_SERVER_RESPONSE
; if here, we have a valid HTTP response code 200
; now search for the content length information so we know how much weather data to read in
leay strKEYWORDcontent,PCR
ldx <replyBufferCurPtr
lbsr STRING_SEARCH_BUFFER
lbcs MAINLOOP_NEXT_READ
; if here, we found the content length number for HTTP reply
inc <contentLengthFlag ; set flag so next time through, we will search for content body
; parse and copy content length value and convert to it's actual value
ldb #5 ; limit value to 5 chars (4 for numbers + 1 CR)
MAINLOOP_CONTENT_LENGTH_FIND_CR
lda ,X+
cmpa #C$CR
beq MAINLOOP_CONTENT_LENGTH_FOUND_CR
decb
bne MAINLOOP_CONTENT_LENGTH_FIND_CR
MAINLOOP_CONTENT_LENGTH_FOUND_CR
; now convert the ascii numbers into our actual content length value
ldy #0
clra
leax -1,X ; undo auto-increment
ldb ,-X ; get singles place
subb #'0' ; convert to value
leay D,Y ; add value to our total
ldb ,-X
cmpb #C$SPAC ; see if we reached beginning of content-length (and end of our calc)
beq MAINLOOP_CONTENT_LENGTH_DONE
subb #'0'
lda #10 ; 10's
mul
leay D,Y
ldb ,-X
cmpb #C$SPAC ; see if we reached beginning of content-length (and end of our calc)
beq MAINLOOP_CONTENT_LENGTH_DONE
subb #'0'
lda #100 ; 100's
mul
leay D,Y
ldb ,-X
cmpb #C$SPAC ; see if we reached beginning of content-length (and end of our calc)
beq MAINLOOP_CONTENT_LENGTH_DONE
subb #'0'
; 1000's is a little trickier for multiplication
lda #10
mul
lda #100
mul
leay D,Y
; never going to be more than 9999 bytes so skip finding higher multiples of 10
MAINLOOP_CONTENT_LENGTH_DONE
sty <contentLength
sty <constContentLength
MAINLOOP_NEW_DATA_FIND_BODY
; now find end of header (and start of actual body/content of HTTP request)
leay strKEYWORDdoubleCRLF,PCR
ldx <replyBufferCurPtr
lbsr STRING_SEARCH_BUFFER
lbcs MAINLOOP_NEXT_READ
; if here, we found start of content body. now continously read the rest of the server reply from dw
; until we reach the number of bytes in contentLength
stx <contentBodyPtr
; subtract the number of valid content bytes left in remainder of buffer from total content length count
ldd <replyBufferEndPtr
subd <contentBodyPtr
std <tempWord
ldd <contentLength
subd <tempWord
std <contentLength
inc <copyContentFlag ; tell mainloop that from now on, just copy data until we run out
lbra MAINLOOP_NEXT_READ
PROCESS_WEATHER_DATA
; disable timeout timer since we got valid request and read all data
lda <nilPath
bmi PROCESS_WEATHER_DATA_SKIP_VRN
ldb #SS.FClr
ldx #0
ldy #0
os9 I$SetStt
PROCESS_WEATHER_DATA_SKIP_VRN
lbsr PARSE_JSON_WEATHER_DATA
; check if location wasn't found by searching for location name "Tong Not, Vietnam" because that is
; what shows up for some reason when it cant find the location
leax jsonAreaName,U
leay strKEYWORDtong,PCR
lbsr COMPARE_PARAM
bcs PROCESS_WEATHER_DATA_VALID_AREA_FOUND
lda jsonRegion,U
lbeq ERROR_LOCATION_NOT_FOUND
PROCESS_WEATHER_DATA_VALID_AREA_FOUND
lda <refreshFlag
bne PROCESS_WEATHER_DATA_SKIP_STDOUT
; tell user we successfully finished retreiving data and found valid result
lda #STDOUT
leax strDone,PCR
lbsr PRINT_NULL_STRING
PROCESS_WEATHER_DATA_SKIP_STDOUT
DEBUG_WTTR_DOWN
leax jsonPressure,U
lbsr CONVERT_HPA_TO_INHG
lda <outputMode
lbeq OUTPUT_GRAPHICS_MODE
; ok user wants text-only output. build our formatted output string from the data
leay outputBuffer,U
leax strCurrentWeather,PCR
lbsr STRING_COPY_RAW
leax jsonAreaName,U
lbsr STRING_COPY_RAW
ldd #", "
std ,Y++
leax jsonRegion,U
lbsr STRING_COPY_RAW
ldd #": "
std ,Y++
leax jsonWeatherDesc,U
lbsr STRING_COPY_RAW
leax strTemperature,PCR
lbsr STRING_COPY_RAW
lda <metricOutputFlag
bne TEXT_SHOW_METRIC_TEMP
leax jsonTempF,U
ldb #'F'
bra TEXT_TEMP_STORE
TEXT_SHOW_METRIC_TEMP
leax jsonTempC,U
ldb #'C'
TEXT_TEMP_STORE
lbsr STRING_COPY_RAW
lda <charDegreesSymbol
std ,Y++
leax strFeelsLike,PCR
lbsr STRING_COPY_RAW
lda <metricOutputFlag
bne TEXT_SHOW_METRIC_FEELS_LIKE
leax jsonFeelsLikeF,U
ldb #'F'
bra TEXT_FEELS_LIKE_STORE
TEXT_SHOW_METRIC_FEELS_LIKE
leax jsonFeelsLikeC,U
ldb #'C'
TEXT_FEELS_LIKE_STORE
lbsr STRING_COPY_RAW
lda <charDegreesSymbol
std ,Y++
leax strHumidity,PCR
lbsr STRING_COPY_RAW
leax jsonHumidity,U
lbsr STRING_COPY_RAW
lda #'%'
sta ,Y+
leax strPressure,PCR
lbsr STRING_COPY_RAW
;leax jsonPressure,U
lda <metricOutputFlag
bne TEXT_SHOW_METRIC_PRESSURE
leax pressureInches,U
lbsr STRING_COPY_RAW
leax strPressureInHg,PCR
bra TEXT_PRESSURE_STORE
TEXT_SHOW_METRIC_PRESSURE
leax jsonPressure,U