@@ -18,6 +18,8 @@ class DustSensorStateProvider extends ChangeNotifier {
1818 double _currentPM25 = 0.0 ;
1919 double _currentPM10 = 0.0 ;
2020
21+ final List <int > _uartBuffer = [];
22+
2123 Timer ? _timeTimer;
2224 Timer ? _dustTimer;
2325
@@ -97,54 +99,131 @@ class DustSensorStateProvider extends ChangeNotifier {
9799 });
98100 }
99101
102+ Future <void > testSingleUARTRead () async {
103+ ScienceLab scienceLab = getIt.get <ScienceLab >();
104+
105+ logger.i ("--- STARTING SINGLE UART TEST ---" );
106+
107+ if (! scienceLab.isConnected ()) {
108+ logger.e ("TEST: ScienceLab is not connected!" );
109+ return ;
110+ }
111+
112+ try {
113+ // 1. Wait 2 seconds. The SDS011 sends data once every 1 second.
114+ // This guarantees that at least one packet should be waiting in the PSLab buffer.
115+ logger.i ("TEST: Waiting 2 seconds to let SDS011 send data..." );
116+ await Future .delayed (const Duration (seconds: 2 ));
117+
118+ // 2. Check available bytes
119+ logger.i ("TEST: Requesting available byte count..." );
120+ int available = await scienceLab.getUART2BytesAvailable ();
121+ logger.i ("TEST: PSLab reports $available bytes available." );
122+
123+ // 3. Read if available
124+ if (available > 0 ) {
125+ List <int > rxBytes = await scienceLab.readUARTBytes (available);
126+ logger.i ("TEST: Successfully read $available bytes." );
127+
128+ // Convert to HEX string for easy reading in the console
129+ String hexString = rxBytes.map ((b) => b.toRadixString (16 ).padLeft (2 , '0' ).toUpperCase ()).join (' ' );
130+ logger.i ("TEST: RAW DATA (HEX): $hexString " );
131+
132+ if (rxBytes.contains (0xAA )) {
133+ logger.i ("TEST: SUCCESS! Found SDS011 Start Byte (0xAA) in the stream." );
134+ } else {
135+ logger.w ("TEST: Data received, but no 0xAA start byte. Is baud rate correct? Are RX/TX swapped?" );
136+ }
137+ } else {
138+ logger.w ("TEST: No data available. The sensor might be asleep, or TX/RX are disconnected." );
139+ }
140+ } catch (e) {
141+ logger.e ("TEST: Exception during single read: $e " );
142+ }
143+
144+ logger.i ("--- END SINGLE UART TEST ---" );
145+ }
146+
147+
148+
100149 void initializeSensors ({Function (String )? onError}) async {
101150 onSensorError = onError;
102151
103152 try {
104153 ScienceLab scienceLab = getIt.get <ScienceLab >();
105154
155+ // 1. Configure the UART port on the PSLab to 9600 baud
106156 await scienceLab.configureUART (baudRate: 9600 );
107157 await Future .delayed (const Duration (milliseconds: 500 ));
108158
159+ // Give the sensor a second to spin up the fan and stabilize [cite: 314]
160+ await Future .delayed (const Duration (seconds: 1 ));
161+ // ---------------------------------------------------------
162+
109163 _startTime = DateTime .now ().millisecondsSinceEpoch / 1000.0 ;
110164
165+ // 2. Start Time Tracking Timer
111166 _timeTimer = Timer .periodic (const Duration (seconds: 1 ), (timer) {
112- _currentTime =
113- (DateTime .now ().millisecondsSinceEpoch / 1000.0 ) - _startTime;
114- _updateData ();
115- notifyListeners ();
167+ if (! _isPlayingBack) {
168+ _currentTime =
169+ (DateTime .now ().millisecondsSinceEpoch / 1000.0 ) - _startTime;
170+ _updateData ();
171+ notifyListeners ();
172+ }
116173 });
117174
118- _dustTimer = Timer .periodic (const Duration (seconds: 2 ), (timer) async {
175+ // 3. Start UART Polling Timer (Runs every 1 second)
176+ _dustTimer = Timer .periodic (const Duration (seconds: 1 ), (timer) async {
177+ if (! scienceLab.isConnected ()) return ;
178+
119179 int available = await scienceLab.getUART2BytesAvailable ();
120- if (available < 10 ) {
121- logger.d ("SDS011: only $available bytes available, skipping" );
122- return ;
180+
181+ if (available > 0 ) {
182+ List <int > rxBytes = await scienceLab.readUARTBytes (available);
183+ String hexData = rxBytes.map ((b) => b.toRadixString (16 ).padLeft (2 , '0' ).toUpperCase ()).join (' ' );
184+ logger.i ("📥 RECEIVED DATA: $hexData " );
185+ _uartBuffer.addAll (rxBytes);
123186 }
124187
125- List <int > rxBytes = await scienceLab.readUARTBytes (20 );
188+ // 4. Process the continuous buffer
189+ while (_uartBuffer.length >= 10 ) {
190+ int headerIdx = _uartBuffer.indexOf (0xAA );
126191
127- int startIdx = - 1 ;
128- for (int i = 0 ; i <= rxBytes.length - 10 ; i++ ) {
129- if (rxBytes[i] == 0xAA && rxBytes[i + 9 ] == 0xAB ) {
130- startIdx = i;
192+ if (headerIdx == - 1 ) {
193+ _uartBuffer.clear ();
131194 break ;
132195 }
133- }
134- if (startIdx == - 1 ) return ;
135196
136- final frame = rxBytes.sublist (startIdx, startIdx + 10 );
137- int checksum = 0 ;
138- for (int i = 2 ; i <= 7 ; i++ ) {
139- checksum += frame[i];
140- }
197+ if (headerIdx > 0 ) {
198+ _uartBuffer.removeRange (0 , headerIdx);
199+ }
141200
142- if ((checksum & 0xFF ) == frame[8 ]) {
143- _currentPM25 = ((frame[3 ] * 256 ) + frame[2 ]) / 10.0 ;
144- _currentPM10 = ((frame[5 ] * 256 ) + frame[4 ]) / 10.0 ;
145- notifyListeners ();
146- } else {
147- logger.w ("SDS011: Checksum error" );
201+ if (_uartBuffer.length >= 10 ) {
202+ if (_uartBuffer[9 ] != 0xAB ) {
203+ _uartBuffer.removeAt (0 );
204+ continue ;
205+ }
206+
207+ final frame = _uartBuffer.sublist (0 , 10 );
208+ _uartBuffer.removeRange (0 , 10 );
209+
210+ if (frame[1 ] != 0xC0 ) continue ;
211+
212+ int checksum = 0 ;
213+ for (int i = 2 ; i <= 7 ; i++ ) {
214+ checksum += frame[i];
215+ }
216+
217+ if ((checksum & 0xFF ) == frame[8 ]) {
218+ _currentPM25 = ((frame[3 ] * 256 ) + frame[2 ]) / 10.0 ;
219+ _currentPM10 = ((frame[5 ] * 256 ) + frame[4 ]) / 10.0 ;
220+
221+ logger.d ("SDS011 Valid Reading -> PM2.5: $_currentPM25 , PM10: $_currentPM10 " );
222+ notifyListeners ();
223+ } else {
224+ logger.w ("SDS011: Checksum error on received frame." );
225+ }
226+ }
148227 }
149228 });
150229 } catch (e) {
0 commit comments