@@ -105,8 +105,8 @@ JTIME NoteTime()
105
105
//**************************************************************************/
106
106
/*!
107
107
@brief Set the number of minutes between refreshes of the time
108
- from the Notecard, to help minimize clock drift on this host.
109
- Set this to 0 for no auto-refresh; it defaults to daily.
108
+ from the Notecard, to help minimize clock drift on this host.
109
+ Set this to 0 for no auto-refresh; it defaults to daily.
110
110
@returns Nothing
111
111
*/
112
112
/**************************************************************************/
@@ -1043,29 +1043,78 @@ bool NoteGetStatusST(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *r
1043
1043
return success ;
1044
1044
}
1045
1045
1046
+ //**************************************************************************/
1047
+ /*!
1048
+ @brief Save the current state and use `card.attn` to set a host
1049
+ sleep interval.
1050
+ @param payload An optional binary payload to keep in memory while the host sleeps.
1051
+ @param seconds The duration to sleep.
1052
+ @param modes Optional list of additional `card.attn` modes.
1053
+ @returns boolean. `true` if request was successful.
1054
+ */
1055
+ /**************************************************************************/
1056
+ bool NotePayloadSaveAndSleep (NotePayloadDesc * desc , uint32_t seconds , const char * modes )
1057
+ {
1058
+ char * stateB64 = NULL ;
1059
+
1060
+ // If specified, encode
1061
+ if (desc -> data != NULL && desc -> length != 0 ) {
1062
+
1063
+ // Get length that it will be when converted to base64
1064
+ unsigned b64Len = JB64EncodeLen (desc -> length );
1065
+
1066
+ // Convert the state to base64
1067
+ stateB64 = _Malloc (b64Len );
1068
+ if (stateB64 == NULL ) {
1069
+ return false;
1070
+ }
1071
+
1072
+ // Encode the state buffer into a string
1073
+ JB64Encode (stateB64 , (const char * ) desc -> data , desc -> length );
1074
+
1075
+ }
1076
+
1077
+ // Sleep
1078
+ bool success = NoteSleep (stateB64 , seconds , modes );
1079
+
1080
+ // Free the temp buffer
1081
+ if (stateB64 != NULL ) {
1082
+ _Free (stateB64 );
1083
+ }
1084
+
1085
+ // Done
1086
+ return success ;
1087
+
1088
+ }
1089
+
1046
1090
//**************************************************************************/
1047
1091
/*!
1048
1092
@brief Save the current state and use `card.attn` to set a host
1049
1093
sleep interval.
1050
1094
@param stateb64 A base64 payload to keep in memory while the host sleeps.
1051
1095
@param seconds The duration to sleep.
1052
- @param modes A list of `card.attn` modes.
1096
+ @param modes Optional list of additional `card.attn` modes.
1053
1097
@returns boolean. `true` if request was successful.
1054
1098
*/
1055
1099
/**************************************************************************/
1056
1100
bool NoteSleep (char * stateb64 , uint32_t seconds , const char * modes )
1057
1101
{
1058
1102
bool success = false;
1059
1103
1104
+ // Trace
1105
+ _Debug ("ABOUT TO SLEEP\n" );
1106
+
1060
1107
// Use a Command rather than a Request so that the Notecard doesn't try to send
1061
1108
// a response back to us, which would cause a communications error on that end.
1062
1109
_Debug ("requesting sleep\n" );
1063
1110
J * req = NoteNewCommand ("card.attn" );
1064
1111
if (req != NULL ) {
1065
1112
// Add the base64 item in a wonderful way that doesn't strdup the huge string
1066
- J * stringReferenceItem = JCreateStringReference (stateb64 );
1067
- if (stringReferenceItem != NULL ) {
1068
- JAddItemToObject (req , "payload" , stringReferenceItem );
1113
+ if (stateb64 != NULL ) {
1114
+ J * stringReferenceItem = JCreateStringReference (stateb64 );
1115
+ if (stringReferenceItem != NULL ) {
1116
+ JAddItemToObject (req , "payload" , stringReferenceItem );
1117
+ }
1069
1118
}
1070
1119
char modestr [64 ];
1071
1120
strlcpy (modestr , "sleep" , sizeof (modestr ));
@@ -1078,6 +1127,9 @@ bool NoteSleep(char *stateb64, uint32_t seconds, const char *modes)
1078
1127
success = NoteRequest (req );
1079
1128
}
1080
1129
1130
+ // Trace
1131
+ _Debug ("DIDN'T SLEEP\n" );
1132
+
1081
1133
// Done
1082
1134
return success ;
1083
1135
}
@@ -1094,13 +1146,42 @@ bool NoteSleep(char *stateb64, uint32_t seconds, const char *modes)
1094
1146
/**************************************************************************/
1095
1147
bool NoteWake (int stateLen , void * state )
1096
1148
{
1149
+ NotePayloadDesc desc ;
1150
+ bool success = NotePayloadRetrieveAfterSleep (& desc );
1151
+ if (!success ) {
1152
+ return false;
1153
+ }
1154
+ if (desc .length != (uint32_t )stateLen ) {
1155
+ NotePayloadFree (& desc );
1156
+ return false;
1157
+ }
1158
+ memcpy (state , desc .data , stateLen );
1159
+ NotePayloadFree (& desc );
1160
+ return true;
1161
+ }
1097
1162
1163
+ //**************************************************************************/
1164
+ /*!
1165
+ @brief Wake the module by restoring state into a state buffer, returning
1166
+ its length, and fail if it isn't available.
1167
+ @param payloadLen (out) Optional place to receive the length of the returned buffer
1168
+ @param payload (out) The place to store address of returned in-memory payload
1169
+ @returns boolean. `true` if request was successful.
1170
+ */
1171
+ /**************************************************************************/
1172
+ bool NotePayloadRetrieveAfterSleep (NotePayloadDesc * desc )
1173
+ {
1174
+
1175
+ // Initialize payload descriptor
1176
+ if (desc != NULL ) {
1177
+ memset (desc , 0 , sizeof (NotePayloadDesc ));
1178
+ }
1179
+
1180
+ // Send the Notecard a request to retrieve the saved state
1098
1181
J * req = NoteNewRequest ("card.attn" );
1099
1182
if (req == NULL ) {
1100
1183
return false;
1101
1184
}
1102
-
1103
- // Send it a command to request the saved state
1104
1185
JAddBoolToObject (req , "start" , true);
1105
1186
J * rsp = NoteRequestResponse (req );
1106
1187
if (rsp == NULL ) {
@@ -1117,39 +1198,36 @@ bool NoteWake(int stateLen, void *state)
1117
1198
setTime (seconds );
1118
1199
}
1119
1200
1120
- // Exit if no payload
1121
- char * payload = JGetString (rsp , "payload" );
1122
- if (payload [0 ] == '\0' ) {
1201
+ // If we didn't expect any state to be restored, we're done
1202
+ if (desc == NULL ) {
1123
1203
NoteDeleteResponse (rsp );
1124
- return false ;
1204
+ return true ;
1125
1205
}
1126
1206
1127
- // Exit if the purpose of the call was to intentionally discard saved state
1128
- if (state == NULL ) {
1207
+ // Exit if no payload, knowing that we expected one
1208
+ char * payload = JGetString (rsp , "payload" );
1209
+ if (payload [0 ] == '\0' ) {
1129
1210
NoteDeleteResponse (rsp );
1130
- return true ;
1211
+ return false ;
1131
1212
}
1132
1213
1133
1214
// Allocate a buffer for the payload. (We can't decode in-place because we can't
1134
1215
// risk overwriting memory if the actual payload is even slightly different.)
1135
- char * p = (char * ) _Malloc (JB64DecodeLen (payload ));
1216
+ uint32_t allocLen = JB64DecodeLen (payload );
1217
+ uint8_t * p = (uint8_t * ) _Malloc (allocLen );
1136
1218
if (p == NULL ) {
1137
1219
NoteDeleteResponse (rsp );
1138
1220
return false;
1139
1221
}
1140
- int actualLen = JB64Decode (p , payload );
1141
- if (actualLen != stateLen ) {
1142
- _Free (p );
1143
- _Debug ("*** discarding saved state\n" );
1144
- NoteDeleteResponse (rsp );
1145
- return false;
1146
- }
1147
- memcpy (state , p , stateLen );
1148
- _Free (p );
1222
+ uint32_t actualLen = (uint32_t ) JB64Decode ((char * )p , payload );
1149
1223
1150
- // State restored
1151
- _Debug ("STATE RESTORED\n" );
1224
+ // Fill out the payload descriptor
1225
+ desc -> data = p ;
1226
+ desc -> alloc = allocLen ;
1227
+ desc -> length = actualLen ;
1152
1228
1229
+ // State restored
1230
+ _Debug ("AWAKENED SUCCESSFULLY\n" );
1153
1231
NoteDeleteResponse (rsp );
1154
1232
return true;
1155
1233
}
@@ -1692,3 +1770,159 @@ uint32_t NoteMemAvailable()
1692
1770
return total ;
1693
1771
1694
1772
}
1773
+
1774
+ //**************************************************************************/
1775
+ /*!
1776
+ @brief Create a desc from a buffer, or initialize a new to-be-allocated desc
1777
+ if the buf is null
1778
+ @param desc Pointer to the payload descriptor
1779
+ @param buf Pointer to the buffer to initialize the desc with (or NULL)
1780
+ @param buflen Length of the buffer to initialize the desc with (or 0)
1781
+ */
1782
+ /**************************************************************************/
1783
+ void NotePayloadSet (NotePayloadDesc * desc , uint8_t * buf , uint32_t buflen )
1784
+ {
1785
+ desc -> data = buf ;
1786
+ desc -> alloc = buflen ;
1787
+ desc -> length = buflen ;
1788
+ }
1789
+
1790
+ //**************************************************************************/
1791
+ /*!
1792
+ @brief Free the payload pointed to by the descriptor
1793
+ @param desc Pointer to the payload descriptor
1794
+ */
1795
+ /**************************************************************************/
1796
+ void NotePayloadFree (NotePayloadDesc * desc )
1797
+ {
1798
+ if (desc -> data != NULL ) {
1799
+ _Free (desc -> data );
1800
+ }
1801
+ desc -> data = NULL ;
1802
+ desc -> alloc = 0 ;
1803
+ desc -> length = 0 ;
1804
+ }
1805
+
1806
+ //**************************************************************************/
1807
+ /*!
1808
+ @brief Add a segment to the specified binary with 4-character type code
1809
+ @param desc Pointer to the payload descriptor
1810
+ @param segtype Pointer to the 4-character payload identifier
1811
+ @param data Pointer to the data segment to be appended
1812
+ @param len Length of data segment
1813
+ @returns boolean. `true` if named segment is appended successfully
1814
+ */
1815
+ /**************************************************************************/
1816
+ bool NotePayloadAddSegment (NotePayloadDesc * desc , const char segtype [NP_SEGTYPE_LEN ], void * data , uint32_t len )
1817
+ {
1818
+ uint32_t alloc = 512 ;
1819
+ uint32_t hlen = len + NP_SEGHDR_LEN ;
1820
+ if (hlen > alloc ) {
1821
+ alloc += hlen ;
1822
+ }
1823
+ if (desc -> data == NULL ) {
1824
+ uint8_t * base = _Malloc (alloc );
1825
+ if (base == NULL ) {
1826
+ return false;
1827
+ }
1828
+ uint8_t * p = base ;
1829
+ memcpy (p , segtype , NP_SEGTYPE_LEN );
1830
+ p += NP_SEGTYPE_LEN ;
1831
+ memcpy (p , & len , NP_SEGLEN_LEN );
1832
+ p += NP_SEGLEN_LEN ;
1833
+ memcpy (p , data , len );
1834
+ desc -> data = base ;
1835
+ desc -> alloc = alloc ;
1836
+ desc -> length = hlen ;
1837
+ } else if ((desc -> alloc - desc -> length ) < hlen ) {
1838
+ uint8_t * base = _Malloc (desc -> alloc + alloc );
1839
+ if (base == NULL ) {
1840
+ return false;
1841
+ }
1842
+ uint8_t * p = base ;
1843
+ memcpy (p , desc -> data , desc -> length );
1844
+ p += desc -> length ;
1845
+ memcpy (p , segtype , NP_SEGTYPE_LEN );
1846
+ p += NP_SEGTYPE_LEN ;
1847
+ memcpy (p , & len , NP_SEGLEN_LEN );
1848
+ p += NP_SEGLEN_LEN ;
1849
+ memcpy (p , data , len );
1850
+ _Free (desc -> data );
1851
+ desc -> data = base ;
1852
+ desc -> alloc = desc -> alloc + alloc ;
1853
+ desc -> length += hlen ;
1854
+ } else {
1855
+ uint8_t * p = desc -> data + desc -> length ;
1856
+ memcpy (p , segtype , NP_SEGTYPE_LEN );
1857
+ p += NP_SEGTYPE_LEN ;
1858
+ memcpy (p , & len , NP_SEGLEN_LEN );
1859
+ p += NP_SEGLEN_LEN ;
1860
+ memcpy (p , data , len );
1861
+ desc -> length += hlen ;
1862
+ }
1863
+ return true;
1864
+ }
1865
+
1866
+ //**************************************************************************/
1867
+ /*!
1868
+ @brief Find and copy a named segment from a segmented payload
1869
+ @param desc Pointer to the payload descriptor
1870
+ @param segtype Pointer to the 4-character payload identifier
1871
+ @param pdata Pointer to the found segment if return is true
1872
+ @param len The expected length of the returned segment
1873
+ @returns boolean. `true` if named segment is restored successfully
1874
+ */
1875
+ /**************************************************************************/
1876
+ bool NotePayloadGetSegment (NotePayloadDesc * desc , const char segtype [NP_SEGTYPE_LEN ], void * pdata , uint32_t len )
1877
+ {
1878
+ uint8_t * data ;
1879
+ uint32_t datalen ;
1880
+ bool success = NotePayloadFindSegment (desc , segtype , & data , & datalen );
1881
+ if (success && datalen == len ) {
1882
+ memcpy (pdata , data , len );
1883
+ return true;
1884
+ }
1885
+ return false;
1886
+ }
1887
+
1888
+ //**************************************************************************/
1889
+ /*!
1890
+ @brief Find a named segment within a segmented payload
1891
+ @param desc Pointer to the payload descriptor
1892
+ @param segtype Pointer to the 4-character payload identifier
1893
+ @param pdata Pointer to the found segment if return is true
1894
+ @param plen Pointer to the returned segment length if return is true
1895
+ @returns boolean. `true` if named segment is found
1896
+ */
1897
+ /**************************************************************************/
1898
+ bool NotePayloadFindSegment (NotePayloadDesc * desc , const char segtype [NP_SEGTYPE_LEN ], void * pdata , uint32_t * plen )
1899
+ {
1900
+
1901
+ // Preset returns
1902
+ * (uint8_t * * ) pdata = NULL ;
1903
+ * plen = 0 ;
1904
+
1905
+ // Locate the segment
1906
+ uint8_t * p = desc -> data ;
1907
+ uint32_t left = desc -> length ;
1908
+ if (p == NULL ) {
1909
+ return false;
1910
+ }
1911
+ while (left >= NP_SEGHDR_LEN ) {
1912
+ uint32_t len ;
1913
+ memcpy (& len , p + NP_SEGTYPE_LEN , sizeof (len ));
1914
+ if (memcmp (p , segtype , NP_SEGTYPE_LEN ) == 0 ) {
1915
+ * plen = len ;
1916
+ * (uint8_t * * ) pdata = p + NP_SEGHDR_LEN ;
1917
+ return true;
1918
+ }
1919
+ len += NP_SEGHDR_LEN ;
1920
+ p += len ;
1921
+ if (len > left ) {
1922
+ left = 0 ;
1923
+ } else {
1924
+ left -= len ;
1925
+ }
1926
+ }
1927
+ return false;
1928
+ }
0 commit comments