2019-11-05 18:39:45 +00:00
/**
* @ file HPMA115S0 . cpp
* @ author Felix Galindo
* @ date June 2017
* @ brief Arduino Library for Honeywell ' s Particle Sensor ( HPMA115S0 - XXX )
* @ license MIT
*/
# include "Arduino.h"
# include "hpma115S0.h"
extern " C " {
# include <string.h>
# include <stdlib.h>
# include <stdio.h>
}
/**
* @ brief Constructor for HPMA115S0 class
* @ param a Stream ( { Software / Hardware } Serial ) object .
* @ note The serial stream should be already initialized
* @ return void
*/
HPMA115S0 : : HPMA115S0 ( Stream & serial ) :
_serial ( serial )
{
_serial . setTimeout ( 100 ) ;
}
/**
* @ brief Function that initializes sensor
* @ return a String containing sensor response
*/
void HPMA115S0 : : Init ( ) {
//Serial.println("PS- Initializing...");
delay ( 100 ) ;
StartParticleMeasurement ( ) ;
delay ( 100 ) ;
DisableAutoSend ( ) ;
}
/**
* @ brief Function that sends serial command to sensor
* @ param a unsigned char * containing the command
* @ param size of buffer
* @ return void
*/
2019-11-16 10:36:19 +00:00
void HPMA115S0 : : SendCmd ( const char * cmdBuf , unsigned int cmdSize ) {
2019-11-05 18:39:45 +00:00
//Clear RX
while ( _serial . available ( ) )
_serial . read ( ) ;
//Send command
//Serial.print("PS- Sending cmd: ");
unsigned int index = 0 ;
for ( index = 0 ; index < cmdSize ; index + + ) {
//Serial.print(cmdBuf[index], HEX);
//Serial.print(" ");
_serial . write ( cmdBuf [ index ] ) ;
}
//Serial.println("");
return ;
}
/**
* @ brief Function that reads command response from sensor
* @ param Buffer to store data in
* @ param Buffer size
* @ param Expected command type
* @ return returns number of bytes read from sensor
*/
int HPMA115S0 : : ReadCmdResp ( unsigned char * dataBuf , unsigned int dataBufSize , unsigned int cmdType ) {
static unsigned char respBuf [ HPM_MAX_RESP_SIZE ] ;
static unsigned int respIdx = 0 ;
static unsigned int calChecksum = 0 ;
//Read response
respIdx = 0 ;
calChecksum = 0 ;
memset ( respBuf , 0 , sizeof ( respBuf ) ) ;
_serial . setTimeout ( 100 ) ;
//Serial.println("PS- Waiting for cmd resp...");
if ( _serial . readStringUntil ( HPM_CMD_RESP_HEAD ) ) {
delay ( 1 ) ; //wait for the rest of the bytes to arrive
respBuf [ HPM_HEAD_IDX ] = HPM_CMD_RESP_HEAD ;
respBuf [ HPM_LEN_IDX ] = _serial . read ( ) ; //Read the command length
//Ensure buffers are big enough
if ( respBuf [ HPM_LEN_IDX ] & & ( ( respBuf [ HPM_LEN_IDX ] + 1 ) < = sizeof ( respBuf ) - 2 ) & & ( respBuf [ HPM_LEN_IDX ] - 1 ) < = dataBufSize ) {
if ( _serial . readBytes ( & respBuf [ HPM_CMD_IDX ] , respBuf [ HPM_LEN_IDX ] + 1 ) = = ( respBuf [ HPM_LEN_IDX ] + 1 ) ) { //read respBuf[HPM_LEN_IDX] num of bytes + calChecksum byte
if ( respBuf [ HPM_CMD_IDX ] = = cmdType ) { //check if CMD type matches
//Calculate and validate checksum
for ( respIdx = 0 ; respIdx < ( 2 + respBuf [ HPM_LEN_IDX ] ) ; respIdx + + ) {
calChecksum + = respBuf [ respIdx ] ;
}
calChecksum = ( 65536 - calChecksum ) % 256 ;
if ( calChecksum = = respBuf [ 2 + respBuf [ HPM_LEN_IDX ] ] ) {
//Serial.println("PS- Received valid data!!!");
memset ( dataBuf , 0 , dataBufSize ) ;
memcpy ( dataBuf , & respBuf [ HPM_DATA_START_IDX ] , respBuf [ HPM_LEN_IDX ] - 1 ) ;
return ( respBuf [ HPM_LEN_IDX ] - 1 ) ;
}
}
}
}
}
return false ;
}
/**
* @ brief Function that sends a read command to sensor
* @ return returns true if valid measurements were read from sensor
*/
boolean HPMA115S0 : : ReadParticleMeasurement ( unsigned int * pm2_5 , unsigned int * pm10 ) {
2019-11-16 10:36:19 +00:00
const char cmdBuf [ ] = { 0x68 , 0x01 , 0x04 , 0x93 } ;
static unsigned char dataBuf [ HPM_READ_PARTICLE_MEASURMENT_LEN_C - 1 ] ;
int len ;
2019-11-05 18:39:45 +00:00
2019-11-16 10:36:19 +00:00
// Serial.println("PS- Reading Particle Measurements..." );
2019-11-05 18:39:45 +00:00
//Send command
SendCmd ( cmdBuf , 4 ) ;
//Read response
2019-11-16 10:36:19 +00:00
len = ReadCmdResp ( dataBuf , sizeof ( dataBuf ) , READ_PARTICLE_MEASURMENT ) ;
if ( ( len = = ( HPM_READ_PARTICLE_MEASURMENT_LEN - 1 ) ) | | ( len = = ( HPM_READ_PARTICLE_MEASURMENT_LEN_C - 1 ) ) ) {
if ( len = = ( HPM_READ_PARTICLE_MEASURMENT_LEN - 1 ) ) {
// HPMA115S0 Standard devices
_pm2_5 = dataBuf [ 0 ] * 256 + dataBuf [ 1 ] ;
_pm10 = dataBuf [ 2 ] * 256 + dataBuf [ 3 ] ;
} else {
// HPMA115C0 Compact devices
_pm2_5 = dataBuf [ 2 ] * 256 + dataBuf [ 3 ] ;
_pm10 = dataBuf [ 6 ] * 256 + dataBuf [ 7 ] ;
}
2019-11-05 18:39:45 +00:00
* pm2_5 = _pm2_5 ;
* pm10 = _pm10 ;
// Serial.println("PS- PM 2.5: " + String(_pm2_5) + " ug/m3" );
// Serial.println("PS- PM 10: " + String(_pm10) + " ug/m3" );
return true ;
}
return false ;
}
/**
* @ brief Function that starts sensor measurement
* @ return void
*/
void HPMA115S0 : : StartParticleMeasurement ( ) {
2019-11-16 10:36:19 +00:00
const char cmd [ ] = { 0x68 , 0x01 , 0x01 , 0x96 } ;
2019-11-05 18:39:45 +00:00
SendCmd ( cmd , 4 ) ;
}
/**
* @ brief Function that stops sensor measurement
* @ return void
*/
void HPMA115S0 : : StopParticleMeasurement ( ) {
2019-11-16 10:36:19 +00:00
const char cmd [ ] = { 0x68 , 0x01 , 0x02 , 0x95 } ;
2019-11-05 18:39:45 +00:00
SendCmd ( cmd , 4 ) ;
}
/**
* @ brief Function that enables auto send
* @ return void
*/
void HPMA115S0 : : EnableAutoSend ( ) {
2019-11-16 10:36:19 +00:00
const char cmd [ ] = { 0x68 , 0x01 , 0x40 , 0x57 } ;
2019-11-05 18:39:45 +00:00
SendCmd ( cmd , 4 ) ;
}
/**
* @ brief Function that stops auto send
* @ return void
*/
void HPMA115S0 : : DisableAutoSend ( ) {
2019-11-16 10:36:19 +00:00
const char cmd [ ] = { 0x68 , 0x01 , 0x20 , 0x77 } ;
2019-11-05 18:39:45 +00:00
SendCmd ( cmd , 4 ) ;
}
/**
* @ brief Function that returns the latest PM 2.5 reading
* @ note Sensor reports new reading ~ every 1 sec .
* @ return PM 2.5 reading ( unsigned int )
*/
unsigned int HPMA115S0 : : GetPM2_5 ( ) {
return _pm2_5 ;
}
/**
* @ brief Function that returns the latest PM 10 reading
* @ note Sensor reports new reading ~ every 1 sec .
* @ return PM 10 reading ( unsigned int )
*/
unsigned int HPMA115S0 : : GetPM10 ( ) {
return _pm10 ;
}