22// #ifndef WEAROS
33#include < jni.h>
44#include < atomic>
5+ #include < cctype>
56#include < ctime>
67#include < memory>
78#include < string>
@@ -38,11 +39,13 @@ jstring jnightuploadEntries3url=nullptr;
3839jstring jnightuploadTreatmentsurl=nullptr ;
3940jstring jnightuploadTreatments3url=nullptr ;
4041jstring jnightuploadsecret= nullptr ;
42+ jclass nightscoutcalibrationclass=nullptr ;
4143static int lastNightUploadCode = 0 ;
4244static std::atomic<int > lastNightUploadResponseCode{0 };
4345static std::atomic<long long > lastNightUploadAttemptTime{0 };
4446static std::atomic<long long > lastNightUploadSuccessTime{0 };
4547static std::atomic<int > lastNightUploadWaitMinutes{0 };
48+ static bool lastNightUploadConfigError = false ;
4649/*
4750void makeuploadurl(JNIEnv *env) {
4851 const int namelen=settings->data()->nightuploadnamelen;
@@ -57,10 +60,54 @@ void makeuploadurl(JNIEnv *env) {
5760 jnightuploadEntriesurl= (jstring)env->NewGlobalRef(local);
5861 env->DeleteLocalRef(local);
5962 } */
60- static void makeuploadurl (JNIEnv *env,std::string_view pathstr,jstring &url) {
63+ static bool hasScheme (std::string_view text) {
64+ return text.rfind (" http://" , 0 ) == 0 || text.rfind (" https://" , 0 ) == 0 ;
65+ }
66+
67+ static int normalizeNightscoutBaseUrl (char *dest, int destsize, const char *src, int srclen) {
68+ if (!dest || destsize <= 0 ) {
69+ return 0 ;
70+ }
71+ if (!src || srclen <= 0 ) {
72+ dest[0 ]=' \0 ' ;
73+ return 0 ;
74+ }
75+ const char *start=src;
76+ const char *end=src+srclen;
77+ while (start<end && isspace (static_cast <unsigned char >(*start)))
78+ ++start;
79+ while (end>start && isspace (static_cast <unsigned char >(end[-1 ])))
80+ --end;
81+ std::string normalized (start,end-start);
82+ if (normalized.empty ()) {
83+ dest[0 ]=' \0 ' ;
84+ return 0 ;
85+ }
86+ if (!hasScheme (normalized)) {
87+ normalized.insert (0 ," https://" );
88+ }
89+ while (!normalized.empty () && normalized.back ()==' /' )
90+ normalized.pop_back ();
91+ const auto entriespos=normalized.find (" /api/" );
92+ if (entriespos!=std::string_view::npos)
93+ normalized.resize (entriespos);
94+ int len=std::min<int >(normalized.size (),destsize-1 );
95+ memcpy (dest,normalized.data (),len);
96+ dest[len]=' \0 ' ;
97+ return len;
98+ }
99+
100+ static bool makeuploadurl (JNIEnv *env,std::string_view pathstr,jstring &url) {
61101
62102 const int namelen=settings->data ()->nightuploadnamelen ;
63103 const char *name=settings->data ()->nightuploadname ;
104+ if (namelen<=0 || !hasScheme (std::string_view (name,namelen))) {
105+ if (url) {
106+ env->DeleteGlobalRef (url);
107+ url=nullptr ;
108+ }
109+ return false ;
110+ }
64111 char fullname[namelen+pathstr.size ()+1 ];
65112 memcpy (fullname,name,namelen);
66113 memcpy (fullname+namelen,pathstr.data (),pathstr.size ()+1 );
@@ -70,12 +117,32 @@ static void makeuploadurl(JNIEnv *env,std::string_view pathstr,jstring &url) {
70117 env->DeleteGlobalRef (url);
71118 url= (jstring)env->NewGlobalRef (local);
72119 env->DeleteLocalRef (local);
120+ return true ;
121+ }
122+ static bool makeuploadurls (JNIEnv *env) {
123+ const bool entriesv1=makeuploadurl (env,R"( /api/v1/entries)" ,jnightuploadEntriesurl);
124+ const bool entriesv3=makeuploadurl (env,R"( /api/v3/entries)" ,jnightuploadEntries3url);
125+ const bool treatmentsv1=makeuploadurl (env,R"( /api/v1/treatments)" ,jnightuploadTreatmentsurl);
126+ const bool treatmentsv3=makeuploadurl (env,R"( /api/v3/treatments)" ,jnightuploadTreatments3url);
127+ return entriesv1&&entriesv3&&treatmentsv1&&treatmentsv3;
128+ }
129+
130+ static bool ensureNightscoutBaseUrl () {
131+ char normalized[sizeof (settings->data ()->nightuploadname )]{};
132+ const int len=normalizeNightscoutBaseUrl (
133+ normalized,
134+ sizeof (normalized),
135+ settings->data ()->nightuploadname ,
136+ settings->data ()->nightuploadnamelen
137+ );
138+ if (len<=0 )
139+ return false ;
140+ if (len!=settings->data ()->nightuploadnamelen || memcmp (normalized,settings->data ()->nightuploadname ,len)!=0 ) {
141+ memcpy (settings->data ()->nightuploadname ,normalized,len+1 );
142+ settings->data ()->nightuploadnamelen =len;
143+ settings->updated ();
73144 }
74- static void makeuploadurls (JNIEnv *env) {
75- makeuploadurl (env,R"( /api/v1/entries)" ,jnightuploadEntriesurl);
76- makeuploadurl (env,R"( /api/v3/entries)" ,jnightuploadEntries3url);
77- makeuploadurl (env,R"( /api/v1/treatments)" ,jnightuploadTreatmentsurl);
78- makeuploadurl (env,R"( /api/v3/treatments)" ,jnightuploadTreatments3url);
145+ return true ;
79146 }
80147
81148extern std::string sha1encode (const char *secret, int len);
@@ -97,6 +164,12 @@ static void makeuploadsecret(JNIEnv *env) {
97164bool inituploader (JNIEnv *env) {
98165 if (!settings->data ()->nightuploadon )
99166 return false ;
167+ if (!ensureNightscoutBaseUrl ()) {
168+ lastNightUploadCode = -2 ;
169+ lastNightUploadResponseCode = -2 ;
170+ lastNightUploadConfigError = true ;
171+ return false ;
172+ }
100173 if (nightpostclass==nullptr ) {
101174 constexpr const char nightpostclassstr[]=" tk/glucodata/NightPost" ;
102175 if (jclass cl=env->FindClass (nightpostclassstr)) {
@@ -109,14 +182,56 @@ bool inituploader(JNIEnv *env) {
109182 return false ;
110183 }
111184 }
185+ if (nightscoutcalibrationclass==nullptr ) {
186+ constexpr const char calibrationclassstr[]=" tk/glucodata/NightscoutCalibration" ;
187+ if (jclass cl=env->FindClass (calibrationclassstr)) {
188+ nightscoutcalibrationclass=(jclass)env->NewGlobalRef (cl);
189+ env->DeleteLocalRef (cl);
190+ }
191+ }
112192 makeuploadsecret (env);
113- makeuploadurls (env);
114- extern void startuploaderthread ();
193+ if (!makeuploadurls (env)) {
194+ lastNightUploadCode = -2 ;
195+ lastNightUploadResponseCode = -2 ;
196+ lastNightUploadConfigError = true ;
197+ LOGSTRING (" Nightscout uploader disabled until URL is valid\n " );
198+ return false ;
199+ }
200+ extern void startuploaderthread ();
115201 startuploaderthread ();
116202 LOGAR (" end inituploader" );
117203 return true ;
118204 }
119205
206+ static int getNightscoutCalibrationOverrideForItem (SensorGlucoseData *sens,const char *sensorname,int autoMgdl,int rawCurrent,long long timestampMillis) {
207+ if (nightscoutcalibrationclass==nullptr )
208+ return 0 ;
209+ auto env=getenv ();
210+ if (env==nullptr )
211+ return 0 ;
212+ const static jmethodID nightscoutCalibrationOverride = env->GetStaticMethodID (
213+ nightscoutcalibrationclass,
214+ " getNightscoutCalibrationOverride" ,
215+ " (Ljava/lang/String;IIIJ)I"
216+ );
217+ if (nightscoutCalibrationOverride==nullptr )
218+ return 0 ;
219+ auto jsensor=env->NewStringUTF (sensorname);
220+ const auto *info=sens->getinfo ();
221+ const int viewMode=info?info->viewMode :0 ;
222+ const int overrideValue=env->CallStaticIntMethod (
223+ nightscoutcalibrationclass,
224+ nightscoutCalibrationOverride,
225+ jsensor,
226+ viewMode,
227+ autoMgdl,
228+ rawCurrent,
229+ timestampMillis
230+ );
231+ env->DeleteLocalRef (jsensor);
232+ return overrideValue;
233+ }
234+
120235// static boolean upload(String httpurl,byte[] postdata,String secret) ;
121236extern vector<Numdata*> numdatas;
122237static void reset () {
@@ -132,6 +247,12 @@ static void reset() {
132247 numdata->setNightSend (0 );
133248 }
134249static int nightupload (jstring jnightuploadurl,const char *data,int len,bool put) {
250+ if (jnightuploadurl==nullptr ) {
251+ lastNightUploadCode = -2 ;
252+ lastNightUploadResponseCode = -2 ;
253+ lastNightUploadConfigError = true ;
254+ return -2 ;
255+ }
135256 const static jmethodID upload=getenv ()->GetStaticMethodID (nightpostclass," upload" ," (Ljava/lang/String;[BLjava/lang/String;Z)I" );
136257 auto env=getenv ();
137258 jbyteArray uit=env->NewByteArray (len);
@@ -140,8 +261,10 @@ static int nightupload(jstring jnightuploadurl,const char *data,int len,bool put
140261 int res=env->CallStaticIntMethod (nightpostclass,upload,jnightuploadurl,uit,jnightuploadsecret,put);
141262 lastNightUploadCode = res;
142263 lastNightUploadResponseCode = res;
264+ lastNightUploadConfigError = (res==-2 );
143265 if (res==HTTP_OK || res==201 ) {
144266 lastNightUploadSuccessTime = static_cast <long long >(time (nullptr ));
267+ lastNightUploadConfigError = false ;
145268 }
146269 LOGGER (" nightupload=%d\n " ,res);
147270 env->DeleteLocalRef (uit);
@@ -170,7 +293,12 @@ extern std::string_view getdeltaname(float change);
170293template <class T > int mkuploaditem (SensorGlucoseData *sens,char *buf,const char *sensorname,const T &item) {
171294 const time_t tim=item.gettime ();
172295 int mgdL;
173- if (double calibrated=calibrateONEtest (sens,item);!isnan (calibrated)) {
296+ const int rawCurrent=sens->getRawForPoll (&item);
297+ const int overrideValue=getNightscoutCalibrationOverrideForItem (sens,sensorname,item.getmgdL (),rawCurrent,tim*1000LL );
298+ if (overrideValue>0 ) {
299+ mgdL=overrideValue;
300+ }
301+ else if (double calibrated=calibrateONEtest (sens,item);!isnan (calibrated)) {
174302 mgdL=(int )round (calibrated);
175303 }
176304 else
@@ -239,7 +367,19 @@ static bool uploadCGM3() {
239367extern char * writev3entry (char *outin,const ScanData *val, const sensorname_t *sensorname,bool server=true );
240368
241369 const char *ptr;
242- if (double calibrated=calibrateONEtest (sens,*el);!isnan (calibrated)) {
370+ const int overrideValue=getNightscoutCalibrationOverrideForItem (
371+ sens,
372+ sensorname->data (),
373+ el->getmgdL (),
374+ sens->getRawForPoll (el),
375+ el->gettime ()*1000LL
376+ );
377+ if (overrideValue>0 ) {
378+ ScanData newel=*el;
379+ newel.g =overrideValue;
380+ ptr=writev3entry (buf,&newel, sensorname,false );
381+ }
382+ else if (double calibrated=calibrateONEtest (sens,*el);!isnan (calibrated)) {
243383 ScanData newel=*el;
244384 newel.g =(int32_t )round (calibrated);
245385 ptr=writev3entry (buf,&newel, sensorname,false );
@@ -419,7 +559,7 @@ static void uploaderthread() {
419559 uploaded = uploadCGM3 ();
420560 }
421561 if (!uploaded) {
422- waitmin=15 ;
562+ waitmin=lastNightUploadConfigError? 0 : 15 ;
423563 lastNightUploadWaitMinutes = waitmin;
424564 continue ;
425565 }
@@ -437,7 +577,7 @@ static void uploaderthread() {
437577 treatmentsOk = uploadtreatments (true );
438578 }
439579 if (!treatmentsOk) {
440- waitmin=15 ;
580+ waitmin=lastNightUploadConfigError? 0 : 15 ;
441581 lastNightUploadWaitMinutes = waitmin;
442582 continue ;
443583 }
@@ -450,7 +590,10 @@ static void uploaderthread() {
450590void startuploaderthread ();
451591void wakeuploader () {
452592 if (!uploaderrunning && settings->data ()->nightuploadon ) {
453- startuploaderthread ();
593+ auto env=getenv ();
594+ if (env && inituploader (env)) {
595+ lastNightUploadConfigError = false ;
596+ }
454597 }
455598 if (uploaderrunning) {
456599 lastNightUploadWaitMinutes = 0 ;
0 commit comments