Accelerometer data over BLE are not sent in synch - node.js

I am sending temperature, humidity, pressure and accelerometer data over BLE, from Arduino (peripheral) to Raspberry Pi 4 (central). I created BLE characteristic per each acceleration dimension (accX, accY, accZ), and I am subscribing to these characteristics.
However, I put counter for each characteristic and realized that data are not sent in order:
18 Nov 12:27:35 - [info] [BLE Connect:bf9be48b4648f12e] x = 233
18 Nov 12:27:35 - [info] [BLE Connect:bf9be48b4648f12e] y = 230
18 Nov 12:27:35 - [info] [BLE Connect:bf9be48b4648f12e] z = 236
So x is read 233 times while y 230 times vice versa. In ideal scenario, they all should be same.
I am posting my full Arduino code minus comments, hence I believe it might be needed:
#include <ArduinoBLE.h>
#include <Arduino_HTS221.h>
#include <Arduino_LPS22HB.h>
#include <Arduino_LSM9DS1.h>
#define BLE_UUID_ENVIRONMENTAL_SENSING_SERVICE "181A"
#define BLE_UUID_TEMPERATURE "2A6E"
#define BLE_UUID_HUMIDITY "2A6F"
#define BLE_UUID_PRESSURE "2A6D"
#define BLE_UUID_ACCELEROMETER_SERVICE "1101"
#define BLE_UUID_ACCELEROMETER_X "2101"
#define BLE_UUID_ACCELEROMETER_Y "2102"
#define BLE_UUID_ACCELEROMETER_Z "2103"
#define BLE_DEVICE_NAME "Hako"
#define BLE_LOCAL_NAME "Hako"
BLEService environmentalSensingService(BLE_UUID_ENVIRONMENTAL_SENSING_SERVICE);
BLEService accelerometerService(BLE_UUID_ACCELEROMETER_SERVICE);
BLEShortCharacteristic temperatureCharacteristic(BLE_UUID_TEMPERATURE, BLERead | BLENotify);
BLEUnsignedShortCharacteristic humidityCharacteristic(BLE_UUID_HUMIDITY, BLERead | BLENotify);
BLEUnsignedLongCharacteristic pressureCharacteristic(BLE_UUID_PRESSURE, BLERead | BLENotify);
BLEShortCharacteristic accelerometerCharacteristic_X(BLE_UUID_ACCELEROMETER_X, BLERead | BLENotify);
BLEShortCharacteristic accelerometerCharacteristic_Y(BLE_UUID_ACCELEROMETER_Y, BLERead | BLENotify);
BLEShortCharacteristic accelerometerCharacteristic_Z(BLE_UUID_ACCELEROMETER_Z, BLERead | BLENotify);
#define ENV_SENSOR_UPDATE_INTERVAL (1000)
#define ACC_SENSOR_UPDATE_INTERVAL (1000)
typedef struct __attribute__((packed))
{
float temperature;
float humidity;
float pressure;
bool updated = false;
} env_sensor_data_t;
env_sensor_data_t envSensorData;
typedef struct __attribute__((packed))
{
float accX;
float accY;
float accZ;
bool updated = false;
} acc_sensor_data_t;
acc_sensor_data_t accSensorData;
#define BLE_LED_PIN LED_BUILTIN
void setup()
{
Serial.begin(9600);
while (!Serial);
Serial.println( "BLE Example - Environmental Sensing Service (ESS)" );
pinMode( BLE_LED_PIN, OUTPUT );
digitalWrite( BLE_LED_PIN, LOW );
// Without Serial when using USB power bank HTS sensor seems to needs some time for setup
delay(10);
if (!HTS.begin()) {
Serial.println("Failed to initialize humidity temperature sensor!");
while (1);
}
if (!BARO.begin()) {
Serial.println( "Failed to initialize pressure sensor!" );
while (1);
}
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}
if (!setupBleMode()) {
while (1);
}
else {
Serial.println( "BLE initialized. Waiting for clients to connect." );
}
}
void loop() {
bleTask();
if (envSensorTask()) {
envPrintTask();
}
if (accSensorTask()) {
accPrintTask();
}
}
bool envSensorTask() {
static long previousMillis = 0;
unsigned long currentMillis = millis();
if (currentMillis - previousMillis < ENV_SENSOR_UPDATE_INTERVAL) {
return false;
}
previousMillis = currentMillis;
envSensorData.temperature = HTS.readTemperature();
envSensorData.humidity = HTS.readHumidity();
envSensorData.pressure = BARO.readPressure() * 1000; // kPa -> Pa
envSensorData.updated = true;
return envSensorData.updated;
}
bool accSensorTask() {
static long previousMillis2 = 0;
unsigned long currentMillis2 = millis();
float x = 0.00, y = 0.00, z = 0.00;
if (currentMillis2 - previousMillis2 < ACC_SENSOR_UPDATE_INTERVAL) {
return false;
}
previousMillis2 = currentMillis2;
if(IMU.accelerationAvailable()){
IMU.readAcceleration(x, y, z);
accSensorData.accX = x;
accSensorData.accY = y;
accSensorData.accZ = z;
accSensorData.updated = true;
}
return accSensorData.updated;
}
bool setupBleMode() {
if (!BLE.begin()) {
return false;
}
BLE.setDeviceName(BLE_DEVICE_NAME);
BLE.setLocalName(BLE_LOCAL_NAME);
BLE.setAdvertisedService(environmentalSensingService);
BLE.setAdvertisedService(accelerometerService);
environmentalSensingService.addCharacteristic(temperatureCharacteristic);
environmentalSensingService.addCharacteristic(humidityCharacteristic);
environmentalSensingService.addCharacteristic(pressureCharacteristic);
accelerometerService.addCharacteristic(accelerometerCharacteristic_X);
accelerometerService.addCharacteristic(accelerometerCharacteristic_Y);
accelerometerService.addCharacteristic(accelerometerCharacteristic_Z);
BLE.addService(environmentalSensingService);
BLE.addService(accelerometerService);
temperatureCharacteristic.writeValue(0);
humidityCharacteristic.writeValue(0);
pressureCharacteristic.writeValue(0);
accelerometerCharacteristic_X.writeValue(0);
accelerometerCharacteristic_Y.writeValue(0);
accelerometerCharacteristic_Z.writeValue(0);
BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
BLE.advertise();
return true;
}
void bleTask()
{
const uint32_t BLE_UPDATE_INTERVAL = 10;
static uint32_t previousMillis = 0;
uint32_t currentMillis = millis();
if (currentMillis - previousMillis >= BLE_UPDATE_INTERVAL) {
previousMillis = currentMillis;
BLE.poll();
}
if (envSensorData.updated) {
// BLE defines Temperature UUID 2A6E Type sint16 ( see XML links )
// Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius
int16_t temperature = round(envSensorData.temperature * 100.0);
temperatureCharacteristic.writeValue(temperature);
// BLE defines Humidity UUID 2A6F Type uint16
// Unit is in percent with a resolution of 0.01 percent
uint16_t humidity = round(envSensorData.humidity * 100.0);
humidityCharacteristic.writeValue(humidity);
// BLE defines Pressure UUID 2A6D Type uint32
// Unit is in Pascal with a resolution of 0.1 Pa
uint32_t pressure = round(envSensorData.pressure * 10.0);
pressureCharacteristic.writeValue(pressure);
envSensorData.updated = false;
}
if (accSensorData.updated) {
// BLE does not define accelerometer UUID
// Alls units is in G
int16_t accelerometer_X = round(accSensorData.accX * 100.0);
accelerometerCharacteristic_X.writeValue(accelerometer_X);
int16_t accelerometer_Y = round(accSensorData.accY * 100.0);
accelerometerCharacteristic_Y.writeValue(accelerometer_Y);
int16_t accelerometer_Z = round(accSensorData.accZ * 100.0);
accelerometerCharacteristic_Z.writeValue(accelerometer_Z);
envSensorData.updated = false;
}
}
void envPrintTask() {
Serial.print( "Temperature = " );
Serial.print( envSensorData.temperature );
Serial.println( " °C" );
Serial.print( "Humidity = " );
Serial.print( envSensorData.humidity );
Serial.println( " %" );
Serial.print( "Pressure = " );
Serial.print( envSensorData.pressure );
Serial.println( " Pa" );
Serial.print(temperatureCharacteristic.subscribed());
Serial.print(humidityCharacteristic.subscribed());
Serial.println(pressureCharacteristic.subscribed());
}
void accPrintTask() {
Serial.print("AccX = ");
Serial.print(accSensorData.accX);
Serial.println(" G");
Serial.print("AccY = ");
Serial.print(accSensorData.accY);
Serial.println(" G");
Serial.print("AccZ = ");
Serial.print( accSensorData.accZ );
Serial.println(" G");
Serial.print(accelerometerCharacteristic_X.subscribed());
Serial.print(accelerometerCharacteristic_Y.subscribed());
Serial.println(accelerometerCharacteristic_Z.subscribed());
}
void blePeripheralConnectHandler(BLEDevice central) {
digitalWrite(BLE_LED_PIN, HIGH);
Serial.print(F( "Connected to central: " ));
Serial.println(central.address());
}
void blePeripheralDisconnectHandler( BLEDevice central ) {
digitalWrite(BLE_LED_PIN, LOW);
Serial.print(F("Disconnected from central: "));
Serial.println(central.address());
}
I am reading the data on Pi via in Node.js environment via #abandonware/noble library.
I will only post the related part, where I subscribe to characteristics first, then I read the data. You can see the counters at the end.
for (const [key, character] of Object.entries(ALL.characteristics)) {
// Check the notify bit, if not set, set it. //
if (character.properties.includes("notify")) {
const descriptors = await character.discoverDescriptorsAsync().catch(e => send(e));
for (const [key, descriptor] of Object.entries(descriptors)) {
node.log(descriptor);
let descriptorData = await descriptor.readValueAsync().catch(e => send(e));
if (descriptorData[0] === bufferChecker[0] || descriptorData[1] === bufferChecker [1]) {
node.log(`The ${character.name} ${character.uuid} notify bit is disabled.`);
node.log("Enabling notification bit...");
descriptor.writeValueAsync(notifySetter).catch(e => send(e));
node.log (`Notification for ${character.name} characteristic is enabled.`);
} else {
node.log(`The ${character.name} ${character.uuid} notify bit is already enabled.`);
return;
}
}
} else {
node.log(`Notification is not allowed for ${character.name} characteristic.`)
}
}
for (const [key, character] of Object.entries(ALL.characteristics)) {
character.on('data', (data) => {
if (character.uuid === '2a6d') {
data = data.readUInt32LE() * decimalSetter[1];
environmentalData.payload[character.name] = data.toFixed(2);
counterPres++;
} else if (character.uuid === '2a6e') {
data = data.readUInt16LE() * decimalSetter[0];
environmentalData.payload[character.name] = data.toFixed(2);
counterTemp++;
} else if (character.uuid === '2a6f') {
data = data.readUInt16LE() * decimalSetter[0];
environmentalData.payload[character.name] = data.toFixed(2);
counterHum++;
} else if (character.uuid === '2101') {
data = data.readInt16LE() * decimalSetter[0];
accData.payload[character.name] = data.toFixed(2);
counterAccX++;
} else if (character.uuid === '2102') {
data = data.readInt16LE() * decimalSetter[0];
accData.payload[character.name] = data.toFixed(2);
counterAccY++;
} else if (character.uuid === '2103') {
data = data.readInt16LE() * decimalSetter[0];
accData.payload[character.name] = data.toFixed(2);
counterAccZ++;
}
node.log("x = " + counterAccX);
node.log("y = " + counterAccY);
node.log("z = " + counterAccZ);
// Sends Temp., Hum., and Pres. data together.
if ( (counterHum + counterPres + counterTemp) % 3 == 0 && (counterHum + counterPres + counterTemp) !== 0){
send(environmentalData);
}
});
// Character data event listener END //
}
I asked the same question at Arduino forum as well.

The peripherals GATT server only sends data if the measured value has really changed. This behaviour saves energy and bandwidth. I think your observation is therefore perfectly normal.

Related

Using RegisterHotKey with number pad values not working?

I have some constants:
constexpr int MonitorDisplay1 = 100;
constexpr int MonitorDisplay2 = 200;
constexpr int MonitorDisplay3 = 400;
constexpr int MonitorDisplay4 = 500;
constexpr int MonitorDisplay1KeyPad = 101;
constexpr int MonitorDisplay2KeyPad = 201;
constexpr int MonitorDisplay3KeyPad = 401;
constexpr int MonitorDisplay4KeyPad = 501;
I have an OnCreate where I setup the hot keys:
int CCenterCursorOnScreenDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (__super::OnCreate(lpCreateStruct) == -1)
return -1;
auto RegisterAppHotkey = [hAppWnd = GetSafeHwnd()](const int nHotKeyID, UINT vk)->bool
{
if (!::RegisterHotKey(hAppWnd, nHotKeyID, MOD_CONTROL | MOD_SHIFT, vk))
{
auto const ec = ::GetLastError();
auto const err_msg = std::format(L"RegisterHotKey failed (error: {})\n",
ec);
AfxMessageBox(err_msg.c_str());
return false;
}
return true;
};
if (m_monitors.rcMonitors.size() > 0)
{
if (!RegisterAppHotkey(MonitorDisplay1, '1'))
{
return -1;
}
if (!RegisterAppHotkey(MonitorDisplay1KeyPad, VK_NUMPAD1))
{
return -1;
}
}
if (m_monitors.rcMonitors.size() > 1)
{
if (!RegisterAppHotkey(MonitorDisplay2, '2'))
{
return -1;
}
if (!RegisterAppHotkey(MonitorDisplay2KeyPad, VK_NUMPAD2))
{
return -1;
}
}
if (m_monitors.rcMonitors.size() > 2)
{
if (!RegisterAppHotkey(MonitorDisplay3, '3'))
{
return -1;
}
if (!RegisterAppHotkey(MonitorDisplay3KeyPad, VK_NUMPAD3))
{
return -1;
}
}
if (m_monitors.rcMonitors.size() > 3)
{
if (!RegisterAppHotkey(MonitorDisplay4, '4'))
{
return -1;
}
if (!RegisterAppHotkey(MonitorDisplay4KeyPad, VK_NUMPAD4))
{
return -1;
}
}
return 0;
}
Previously I just had the 4 hotkeys for 1 / 2 / 3 and 4. They still work. I tried to add new hotkeys for for the number pad on the keyboard, but they are not working.
My OnHotKey handler:
void CCenterCursorOnScreenDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
if (nHotKeyId == MonitorDisplay1 || nHotKeyId == MonitorDisplay1KeyPad)
{
CenterCursorOnMonitor(0);
}
else if (nHotKeyId == MonitorDisplay2 || nHotKeyId == MonitorDisplay2KeyPad)
{
CenterCursorOnMonitor(1);
}
else if (nHotKeyId == MonitorDisplay3 || nHotKeyId == MonitorDisplay3KeyPad)
{
CenterCursorOnMonitor(2);
}
else if (nHotKeyId == MonitorDisplay4 || nHotKeyId == MonitorDisplay4KeyPad)
{
CenterCursorOnMonitor(3);
}
__super::OnHotKey(nHotKeyId, nKey1, nKey2);
}
But the number pad versions are not working. Why?
I am unregistering all 8 hotkeys, and num-lock is on. I get no warnings when registering.
This article explains List of Keys (Keyboard, Mouse and Joystick):
Because I was using CTRL + SHIFT, then the meaning of the 4 numeric keys was changing:
End
Down
Page Down
Left
It made sense to change my hotkeys to CTRL + ALT instead to avoid this issue.

arduino uno if string cotains a word

I very new to Arduino Uno and need some advice....so here we go.
I want to use my Arduino to:
1. read my serial data --received as plain text
2. look for a specific word within a line of data received
3. only transmit/print the complete string if it contains the specific "word"
I found this sketch and it works only if I'm looking for char
// Example 3 - Receive with start- and end-markers
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;
void setup() {
Serial.begin(9600);
Serial.println("<Arduino is ready>");
}
void loop() {
recvWithStartEndMarkers();
showNewData();
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.print("This just in ... ");
Serial.println(receivedChars);
newData = false;
}
}
I think it is better to use String class methods.
you can get the Data using Serial.readString()
then use the String methods for looking for a specific word.
Here are some useful links
https://www.arduino.cc/en/Serial/ReadString
https://www.arduino.cc/en/Reference/StringObject

Arduino Error with Casting from string to float

In following code, I'm Trying to cast String value to float, but i get Following error."class String has no named toFloat".Error in following line " yaw = s.substring(5,s.indexOf(",",i)).toFloat();".
#include <SoftwareSerial.h>
SoftwareSerial softSerial(2, 3);
String buff;
void setup() {
Serial.begin(115200);
softSerial.begin(19200);
}
void loop() {
if(softSerial.available()){
buff = "";
while(softSerial.available()){
char in = (char)softSerial.read();
buff += in;
}
Serial.println(buff);
parseData(buff);
}
if(Serial.available()){
while(Serial.available()){
softSerial.write(Serial.read());
}
}
}
void parseData(String s){
union byte2float{
byte bval[4];
float fval;
}
b2f;
float yaw;
float pitch;
float roll;
int i=0;
String temp;
//Check if ASCII or Binary (usually, binary output doesn't start with #)
if(s.substring(0,1)=="#"){
if(s.substring(1,4)=="YPR"){
Serial.println("Output is Text");
Serial.println(s.substring(5,s.indexOf(",",i)));
yaw = s.substring(5,s.indexOf(",",i)).toFloat();
i = 1 + s.indexOf(",",i) ;
Serial.println(s.substring(i,s.indexOf(",",i)));
pitch = s.substring(i,s.indexOf(",",i)).toFloat();
i = 1 + s.indexOf(",",i);
Serial.println(s.substring(i,s.indexOf(",",i)));
roll = s.substring(i,s.indexOf(",",i)).toFloat();
}
}
else{
// 1234 5678 9101112
Serial.println("Output is Binary: ");
byte b[13];
s.getBytes(b,13);
Serial.println("[#]\t[A]\t[B]\t[Ah]\t[Bh]");
for(int x=0;x<12;x++){
Serial.print("[");
Serial.print(x,DEC);
Serial.print("]\t");
Serial.print(s[x]);
Serial.print("\t");
Serial.print((char)b[x]);
Serial.print("\t");
Serial.print((byte)s[x],HEX);
Serial.print("\t");
Serial.println((byte)b[x],HEX);
}
b2f.bval[0] = b[0];
b2f.bval[1] = b[1];
b2f.bval[2] = b[2];
b2f.bval[3] = b[3];
yaw = b2f.fval;
b2f.bval[0] = b[4];
b2f.bval[1] = b[5];
b2f.bval[2] = b[6];
b2f.bval[3] = b[7];
pitch = b2f.fval;
b2f.bval[0] = b[8];
b2f.bval[1] = b[9];
b2f.bval[2] = b[10];
b2f.bval[3] = b[11];
roll = b2f.fval;
}
Serial.print("Yaw: ");
Serial.println(yaw);
Serial.print("Pitch: ");
Serial.println(pitch);
Serial.print("Roll: ");
Serial.println(roll);
}
Use for example
float(s.substring(5,s.indexOf(",",i)))
instead of
s.substring(5,s.indexOf(",",i)).toFloat()
The error message says, you were using the toFloat() method of a string, which does not exists. Instead, pass the string into the global function float(string).

Where to retrieve audio file? -- Arduino - Photon project

I have just started with electronics, and doing a project using the Spark Photon, which is based on Arduino. The project website is here: http://hackster.io/middleca/sending-sound-over-the-internet
I uploaded the following two files (.ino and .js) to the Photon, which should then capture and transmit sound (directly I assume). I expected a test.wav would be created. However, where should I find this file so I can check if everything worked?
main.ino file:
#define MICROPHONE_PIN A5
#define AUDIO_BUFFER_MAX 8192
int audioStartIdx = 0, audioEndIdx = 0;
uint16_t audioBuffer[AUDIO_BUFFER_MAX];
uint16_t txBuffer[AUDIO_BUFFER_MAX];
// version without timers
unsigned long lastRead = micros();
char myIpAddress[24];
TCPClient audioClient;
TCPClient checkClient;
TCPServer audioServer = TCPServer(3443);
void setup() {
Serial.begin(115200);
pinMode(MICROPHONE_PIN, INPUT);
// so we know where to connect, try:
// particle get MY_DEVICE_NAME ipAddress
Spark.variable("ipAddress", myIpAddress, STRING);
IPAddress myIp = WiFi.localIP();
sprintf(myIpAddress, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);
// 1/8000th of a second is 125 microseconds
audioServer.begin();
lastRead = micros();
}
void loop() {
checkClient = audioServer.available();
if (checkClient.connected()) {
audioClient = checkClient;
}
//listen for 100ms, taking a sample every 125us,
//and then send that chunk over the network.
listenAndSend(100);
}
void listenAndSend(int delay) {
unsigned long startedListening = millis();
while ((millis() - startedListening) < delay) {
unsigned long time = micros();
if (lastRead > time) {
// time wrapped?
//lets just skip a beat for now, whatever.
lastRead = time;
}
//125 microseconds is 1/8000th of a second
if ((time - lastRead) > 125) {
lastRead = time;
readMic();
}
}
sendAudio();
}
// Callback for Timer 1
void readMic(void) {
uint16_t value = analogRead(MICROPHONE_PIN);
if (audioEndIdx >= AUDIO_BUFFER_MAX) {
audioEndIdx = 0;
}
audioBuffer[audioEndIdx++] = value;
}
void copyAudio(uint16_t *bufferPtr) {
//if end is after start, read from start->end
//if end is before start, then we wrapped, read from start->max, 0->end
int endSnapshotIdx = audioEndIdx;
bool wrapped = endSnapshotIdx < audioStartIdx;
int endIdx = (wrapped) ? AUDIO_BUFFER_MAX : endSnapshotIdx;
int c = 0;
for(int i=audioStartIdx;i<endIdx;i++) {
// do a thing
bufferPtr[c++] = audioBuffer[i];
}
if (wrapped) {
//we have extra
for(int i=0;i<endSnapshotIdx;i++) {
// do more of a thing.
bufferPtr[c++] = audioBuffer[i];
}
}
//and we're done.
audioStartIdx = audioEndIdx;
if (c < AUDIO_BUFFER_MAX) {
bufferPtr[c] = -1;
}
}
// Callback for Timer 1
void sendAudio(void) {
copyAudio(txBuffer);
int i=0;
uint16_t val = 0;
if (audioClient.connected()) {
write_socket(audioClient, txBuffer);
}
else {
while( (val = txBuffer[i++]) < 65535 ) {
Serial.print(val);
Serial.print(',');
}
Serial.println("DONE");
}
}
// an audio sample is 16bit, we need to convert it to bytes for sending over the network
void write_socket(TCPClient socket, uint16_t *buffer) {
int i=0;
uint16_t val = 0;
int tcpIdx = 0;
uint8_t tcpBuffer[1024];
while( (val = buffer[i++]) < 65535 ) {
if ((tcpIdx+1) >= 1024) {
socket.write(tcpBuffer, tcpIdx);
tcpIdx = 0;
}
tcpBuffer[tcpIdx] = val & 0xff;
tcpBuffer[tcpIdx+1] = (val >> 8);
tcpIdx += 2;
}
// any leftovers?
if (tcpIdx > 0) {
socket.write(tcpBuffer, tcpIdx);
}
}
and the waveRecorder.js file:
// make sure you have Node.js Installed!
// Get the IP address of your photon, and put it here:
// CLI command to get your photon's IP address
//
// particle get MY_DEVICE_NAME ipAddress
// Put your IP here!
var settings = {
ip: "192.168.0.54",
port: 3443
};
/**
* Created by middleca on 7/18/15.
*/
//based on a sample from here
// http://stackoverflow.com/questions/19548755/nodejs-write-binary-data-into-writablestream-with-buffer
var fs = require("fs");
var samplesLength = 1000;
var sampleRate = 8000;
var outStream = fs.createWriteStream("test.wav");
var writeHeader = function() {
var b = new Buffer(1024);
b.write('RIFF', 0);
/* file length */
b.writeUInt32LE(32 + samplesLength * 2, 4);
//b.writeUint32LE(0, 4);
b.write('WAVE', 8);
/* format chunk identifier */
b.write('fmt ', 12);
/* format chunk length */
b.writeUInt32LE(16, 16);
/* sample format (raw) */
b.writeUInt16LE(1, 20);
/* channel count */
b.writeUInt16LE(1, 22);
/* sample rate */
b.writeUInt32LE(sampleRate, 24);
/* byte rate (sample rate * block align) */
b.writeUInt32LE(sampleRate * 2, 28);
/* block align (channel count * bytes per sample) */
b.writeUInt16LE(2, 32);
/* bits per sample */
b.writeUInt16LE(16, 34);
/* data chunk identifier */
b.write('data', 36);
/* data chunk length */
//b.writeUInt32LE(40, samplesLength * 2);
b.writeUInt32LE(0, 40);
outStream.write(b.slice(0, 50));
};
writeHeader(outStream);
var net = require('net');
console.log("connecting...");
client = net.connect(settings.port, settings.ip, function () {
client.setNoDelay(true);
client.on("data", function (data) {
try {
console.log("GOT DATA");
outStream.write(data);
//outStream.flush();
console.log("got chunk of " + data.toString('hex'));
}
catch (ex) {
console.error("Er!" + ex);
}
});
});
setTimeout(function() {
console.log('recorded for 10 seconds');
client.end();
outStream.end();
process.exit(0);
}, 10 * 1000);
Thieme! Such a beginner's question... SO unworthy!
Anyway, I will iron my heart and tell you the answer.
First of all, you misunderstood: the .ino file should go to the Photon and the waveRecorder.js file should be stored on your computer (or server) and called whenever you want to retrieve the audio. As you can read in the code, the .ino file makes sure that every millisecond it will check if something wants to connect, and if so, it will stream the sound to the wav.file stored in the same location as your waveRecorder.js file. "Something wants to connect" happens when you launch waveRecorder.js. Make sure you have node installed.
So, to sum it up:
Download the two files (main.ino and waveRecorder.js) to your computer in a folder ../xx/folderName
Then configure the IPAddress in both files using your photon's IPAddress
Upload main.ino to the photon (type 'particle flash abcdefgh123456578 "xx/../folderName/main.ino"' in the terminal)
Then run waveRecorder.js by typing 'node "xx/../folderName/waveRecorder.js"' in your terminal.
That should do it.. Even I got it working :)

Ardunio, decoding a string at postion N

I'm having this little problem with some easy code, basically what I'm doing is sending information via the serial port via a program I wrote in Java. The information is getting their for basic statements (IE, can turn on lights and stuff) but I'm having errors getting it to decode strings with number values send to it.
So for example, I'm sending strings that look like this
BS//:+000/+000/+000
and the decoding method I'm using looks like this.
After adding the string via this:
if (inputString.startsWith("BS//:")) //**fixed
{
inputInfoToBaseStepper(inputString);
baseStepperRunAction(baseStepperRotCount, baseStepperRotStepSize, baseStepperTime);
}
Sends it too...
void inputInfoToBaseStepper(String baseStepper)
{
baseStepperRotCount = baseStepper.substring(6,9).toInt();
baseStepperRotStepSize = baseStepper.substring(10,13).toInt();
baseStepperTime = baseStepper.substring(15,18).toInt();
}
Which should decode and run
void baseStepperRunAction (int rotations, int StepSize, int delayTime)
{
for (int rotations; rotations >=0; rotations--)
{
baseStepper.step(StepSize);
delay(delayTime);
}
}
Problem seems to be that it doesn't decode... ideas I'm sort of lost at this stage. :/
(total past of the code, I know the information is getting there, just not compiling like it should.)
#include <Stepper.h>
//#include <HardwareSerial.h>
// int intensity = 0; // led intensity this is needed just as example for this sketch
String inputString = ""; // a string to hold incoming data (this is general code you can reuse)
boolean stringComplete = false; // whether the string is complete (this is general code you can reuse)
int stepsPerRevolution = 64; //at 5.625 degrees a step
// initialize the stepper library on pins 8 through 11:
Stepper baseStepper(stepsPerRevolution, 2,3,4,5); // protocols start with //BS:
Stepper shoulderStepper(stepsPerRevolution, 6,7,8,9); // protocols start with //SS:
Stepper armStepper(stepsPerRevolution, 10,11,12,13); // protocols start with //AS:
//--------baseStepper--------//
int baseStepperRotCount = 0; //how many rotations in the for loop is needed
int baseStepperRotStepSize = 0; // how large should the steps be...
int baseStepperTime = 0; //delay time needed between each step (delay); so the stepper can do it's work.
//--------shoulderStepper--------//
int shoulderStepperRotCount =0;
void setup() {
// initialize serial: (this is general code you can reuse)
Serial.begin(115200);
}
void loop() {
// when a newline arrives:
if (stringComplete) {
//these are test if statements, they serve no purpose after the intial boot, but must be included to test the connectivity;
if (inputString.startsWith("alpha"))
{
boolean msgRecognized = true;
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
inputString = "";
stringComplete = false;
}
else if (inputString.startsWith("beta"))
{
boolean msgRecognized = true;
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
inputString = "";
stringComplete = false;
}
//---------------------///
//these statements set the engines and prepare for running of the program.
if (inputString.startsWith("//BS:")) // "BS//:+000/+000/+000"
{
inputInfoToBaseStepper(inputString);
baseStepperRunAction(baseStepperRotCount, baseStepperRotStepSize, baseStepperTime);
}
else if (inputString.startsWith("//SS:"))
{
//inputInfoToShoulderStepper();
//outputConfirmed();
}
else if (inputString.startsWith("//AS:"))
{
//inputInfoToArmStepper();
// outputConfirmed();
}
if(inputString.startsWith("alp://")) { // OK is a message I know (this is general code you can reuse)
boolean msgRecognized = true;
if(inputString.substring(6,10) == "kprs") { // KeyPressed }
msgRecognized = false; // this sketch doesn't know other messages in this case command is ko (not ok)
// Prepare reply message if caller supply a message id (this is general code you can reuse)
int idPosition = inputString.indexOf("?id=");
if(idPosition != -1) {
String id = inputString.substring(idPosition + 4);
// print the reply
Serial.print("alp://rply/");
if(msgRecognized) { // this sketch doesn't know other messages in this case command is ko (not ok)
Serial.print("ok?id=");
} else {
Serial.print("ko?id=");
}
Serial.print(id);
Serial.write(255); // End of Message
Serial.flush();
}
}
// clear the string:
inputString = "";
stringComplete = false;
}
}
}
/*
Send listen messages
int index = 0;
for (index = 0; index < digitalPinListeningNum; index++) {
if(digitalPinListening[index] == true) {
int value = digitalRead(index);
if(value != digitalPinListenedValue[index]) {
digitalPinListenedValue[index] = value;
Serial.print("alp://dred/");
Serial.print(index);
Serial.print("/");
Serial.print(value);
Serial.write(255);
Serial.flush();
}
}
}
for (index = 0; index < analogPinListeningNum; index++) {
if(analogPinListening[index] == true) {
int value = analogRead(index);
if(value != analogPinListenedValue[index]) {
analogPinListenedValue[index] = value;
Serial.print("alp://ared/");
Serial.print(index);
Serial.print("/");
Serial.print(value);
Serial.write(255); // End of Message
Serial.flush();
}
}
}
} */
//this method decodes and stores inputs
void inputInfoToBaseStepper(String baseStepper)
{
baseStepperRotCount = baseStepper.substring(6,9).toInt(); // B S / / : + 0 0 0 / + 0 0 0 / + 0 0 0
baseStepperRotStepSize = baseStepper.substring(10,13).toInt();// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
baseStepperTime = baseStepper.substring(15,18).toInt();
}
//this method runs the base stepper off the decoded actions.
void baseStepperRunAction (int rotations, int StepSize, int delayTime)
{
for (int rotations; rotations >=0; rotations--)
{
baseStepper.step(StepSize);
delay(delayTime);
}
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
This is general code you can reuse.
*/
void serialEvent() {
while (Serial.available() && !stringComplete) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}

Resources