how to get RAW Data when i use AudioQueue to Record voice? - audioqueue

when i use AudioQueue to Record voice to file, this is ok.
i try at MyInputBufferHandler function use
AudioQueueBufferRef->mAudioData
can get raw data, but in this MyInputBufferHandler function
can't call other object , like oStream .
i want get AudioQueue Buffer's raw data , and send this raw data to internet ,how to do ?

You need to set the format the way you want to receive data to AudioQueue, refer following function,
http://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/CoreAudioDataTypesRef/Reference/reference.html
One example,
FillOutASBDForLPCM (sRecordFormat,
16000,
1,
8,
8,
false,
false
);

See the answer to this question, which gives you raw data. You can then bundle it as NSData or whatever, zip and upload.

You need to modify some codes in myInputBufferHandler, I had created a obj-c object to adopt the cpp code from Apple SpeakHere sample.
Please feel free to use it:
MIP_StreamAudioRecorder.h
//
// MIP_StreamAudioRecorder.h
//
// Created by Dennies Chang on 12/10/3.
// Copyright (c) 2012年 Dennies Chang. All rights reserved.
//
#import <Foundation/Foundation.h>
#include <AudioToolbox/AudioToolbox.h>
#include <Foundation/Foundation.h>
#include <libkern/OSAtomic.h>
#include "CAStreamBasicDescription.h"
#include "CAXException.h"
#define kNumberRecordBuffers 3
#protocol MIP_StreamAudioRecorderDelegate;
#interface MIP_StreamAudioRecorder : NSObject {
CAStreamBasicDescription mRecordFormat;
AudioQueueRef mQueue;
AudioQueueBufferRef mBuffers[kNumberRecordBuffers];
BOOL mIsRunning;
id <MIP_StreamAudioRecorderDelegate> delegate;
}
#property (nonatomic, assign) id <MIP_StreamAudioRecorderDelegate> delegate;
#property (nonatomic, readonly) BOOL mIsRunning;
- (void)SetupAudioFormat:(UInt32) inFormatID;
- (void)startRecord;
- (void)stopRecord;
- (int)computeRecordBufferSize:(AudioStreamBasicDescription *)format duration:(float)second;
#end
#protocol MIP_StreamAudioRecorderDelegate <NSObject>
#optional
- (void)gotAudioData:(NSData *)audioData;
#end
And .mm file : MIP_StreamAudioRecorder.mm
//
// MIP_StreamAudioRecorder.mm
//
// Created by Dennies Chang on 12/10/3.
// Copyright (c) 2012年 Dennies Chang. All rights reserved.
//
#import "MIP_StreamAudioRecorder.h"
#implementation MIP_StreamAudioRecorder
#synthesize delegate;
#synthesize mIsRunning;
- (id)init {
self = [super init];
return self;
}
- (void)dealloc {
[super dealloc];
}
- (void)SetupAudioFormat:(UInt32) inFormatID {
memset(&mRecordFormat, 0, sizeof(mRecordFormat));
UInt32 size = sizeof(mRecordFormat.mSampleRate);
XThrowIfError(AudioSessionGetProperty( kAudioSessionProperty_CurrentHardwareSampleRate,
&size,
&mRecordFormat.mSampleRate), "couldn't get hardware sample rate");
size = sizeof(mRecordFormat.mChannelsPerFrame);
XThrowIfError(AudioSessionGetProperty( kAudioSessionProperty_CurrentHardwareInputNumberChannels,
&size,
&mRecordFormat.mChannelsPerFrame), "couldn't get input channel count");
mRecordFormat.mFormatID = inFormatID;
if (inFormatID == kAudioFormatLinearPCM)
{
// if we want pcm, default to signed 16-bit little-endian
mRecordFormat.mChannelsPerFrame = 1;
mRecordFormat.mSampleRate = 8000;
mRecordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
mRecordFormat.mBitsPerChannel = 16;
mRecordFormat.mBytesPerPacket = mRecordFormat.mBytesPerFrame = (mRecordFormat.mBitsPerChannel / 8) * mRecordFormat.mChannelsPerFrame;
mRecordFormat.mFramesPerPacket = 1;
}
}
- (int)computeRecordBufferSize:(AudioStreamBasicDescription *)format duration:(float)second {
int packets, frames, bytes = 0;
try {
frames = (int)ceil(second * format->mSampleRate);
if (format->mBytesPerFrame > 0)
bytes = frames * format->mBytesPerFrame;
else {
UInt32 maxPacketSize;
if (format->mBytesPerPacket > 0)
maxPacketSize = format->mBytesPerPacket; // constant packet size
else {
UInt32 propertySize = sizeof(maxPacketSize);
XThrowIfError(AudioQueueGetProperty(mQueue, kAudioQueueProperty_MaximumOutputPacketSize, &maxPacketSize,
&propertySize), "couldn't get queue's maximum output packet size");
}
if (format->mFramesPerPacket > 0)
packets = frames / format->mFramesPerPacket;
else
packets = frames; // worst-case scenario: 1 frame in a packet
if (packets == 0) // sanity check
packets = 1;
bytes = packets * maxPacketSize;
}
} catch (CAXException e) {
char buf[256];
fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
return 0;
}
return bytes;
}
/*
- (void)myInputBufferHandler:(id)inUserData AudioQueue:(AudioQueueRef) inAQ BufferRef:(AudioQueueBufferRef)inBuffer withAudioTS:(AudioTimeStamp *)inStartTime andNumPackets:(UInt32)inNumPackets andDescription:(AudioStreamPacketDescription *)inPacketDesc {
*/
void MyInputBufferHandler( void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp * inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription* inPacketDesc)
{
MIP_StreamAudioRecorder *THIS = (MIP_StreamAudioRecorder *)inUserData;
try {
if (inNumPackets > 0) {
//use delegate to handle;
if (THIS.delegate) {
NSMutableData *data = [[NSMutableData alloc] init];
if ([THIS.delegate respondsToSelector:#selector(gotAudioData:)]) {
[data appendBytes:inBuffer->mAudioData length:inBuffer->mAudioDataByteSize];
[THIS.delegate gotAudioData:data];
}
[data release];
}
/*
// write packets to file
XThrowIfError(AudioFileWritePackets(aqr->mRecordFile, FALSE, inBuffer->mAudioDataByteSize,
inPacketDesc, aqr->mRecordPacket, &inNumPackets, inBuffer->mAudioData),
"AudioFileWritePackets failed");
aqr->mRecordPacket += inNumPackets;
*/
}
// if we're not stopping, re-enqueue the buffe so that it gets filled again
if (THIS->mIsRunning)
XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL), "AudioQueueEnqueueBuffer failed");
} catch (CAXException e) {
char buf[256];
fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
}
- (void)startRecord {
int i, bufferByteSize;
try {
[self SetupAudioFormat:kAudioFormatLinearPCM];
// create the queue
XThrowIfError(AudioQueueNewInput(
&mRecordFormat,
MyInputBufferHandler,
self /* userData */,
NULL /* run loop */, NULL /* run loop mode */,
0 /* flags */, &mQueue), "AudioQueueNewInput failed");
// get the record format back from the queue's audio converter --
// the file may require a more specific stream description than was necessary to create the encoder.
UInt32 size = sizeof(mRecordFormat);
XThrowIfError(AudioQueueGetProperty(mQueue, kAudioQueueProperty_StreamDescription,
&mRecordFormat, &size), "couldn't get queue's format");
// allocate and enqueue buffers
bufferByteSize = [self computeRecordBufferSize:&mRecordFormat duration:kBufferDurationSeconds]; // enough bytes for half a second
for (i = 0; i < kNumberRecordBuffers; ++i) {
XThrowIfError(AudioQueueAllocateBuffer(mQueue, bufferByteSize, &mBuffers[i]),
"AudioQueueAllocateBuffer failed");
XThrowIfError(AudioQueueEnqueueBuffer(mQueue, mBuffers[i], 0, NULL),
"AudioQueueEnqueueBuffer failed");
}
// start the queue
mIsRunning = true;
XThrowIfError(AudioQueueStart(mQueue, NULL), "AudioQueueStart failed");
}
catch (CAXException &e) {
char buf[256];
fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
catch (...) {
fprintf(stderr, "An unknown error occurred\n");
}
}
- (void)stopRecord {
XThrowIfError(AudioQueueStop(mQueue, true), "AudioQueueStop failed");
AudioQueueDispose(mQueue, true);
}
#end
Please get informed, you should change the sampleRate and relative condition,
I set it as mono (1 channel), 16 bit, 8Khz to record.
And you can get the raw data in the obj-c code which implement MIP_StreamAudioRecorderDelegate, you can send the raw data with internet channel,
or save it to file.
Best Regard,
Dennies.

Related

How to fix no matching function for call in Arduino IDE?

This is my first time using Arduino IDE, and after replacing the jsonBuffer with jsonDOcument, as jsonBuffer was an older version, instructed by the jsonarduino website, and i have received the error message, "no matching function for call to 'ArduinoJson6171_91::BasicJsonDocument<ArduinoJson6171_91::DefaultAllocator>::BasicJsonDocument()'"
What should I do?
This is my code:
#include <FS.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <RCSwitch.h>
#include <WiFiUdp.h>
#include <WiFiManager.h>
#include <ArduinoJson.h>
#include
#ifndef CALLBACKFUNCTION_H //this is the beginning of the callbackfunction script
#define CALLBACKFUNCTION_H
#include <Arduino.h>
typedef void (*CallbackFunction) ();
#endif //this is the end of the callbackfunction script
#ifndef SWITCH_H //this is the beginning of the switch script
#define SWITCH_H
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiUDP.h>
#include "CallbackFunction.h"
class Switch {
private:
ESP8266WebServer *server = NULL;
WiFiUDP UDP;
String serial;
String persistent_uuid;
String device_name;
unsigned int localPort;
CallbackFunction onCallback;
CallbackFunction offCallback;
void startWebServer();
void handleEventservice();
void handleUpnpControl();
void handleRoot();
void handleSetupXml();
public:
Switch();
Switch(String alexaInvokeName, unsigned int port, CallbackFunction onCallback, CallbackFunction offCallback);
~Switch();
String getAlexaInvokeName();
void serverLoop();
void respondToSearch(IPAddress& senderIP, unsigned int senderPort);
};
#endif //this is the end of the switch script
#include "switch.h"
#include "UpnpBroadcastResponder.h"
#include "CallbackFunction.h"
UpnpBroadcastResponder upnpBroadcastResponder;
Switch *alexa_switch1 = NULL;
Switch *alexa_switch2 = NULL;
Switch *alexa_switch3 = NULL;
Switch *alexa_switch4 = NULL;
Switch *alexa_switch5 = NULL;
// Callback prototypes
void alexa_switch1On();
void alexa_switch1Off();
void alexa_switch2On();
void alexa_switch2Off();
void alexa_switch3On();
void alexa_switch3Off();
void alexa_switch4On();
void alexa_switch4Off();
void alexa_switch5On();
void alexa_switch5Off();
// Set Relay Pins
int relayOne = 12;
int relayTwo = 13;
int relayThree = 14;
int relayFour = 16;
// Names each relay/outlet/device is known by -- these are set during config
char alexa_name1[100] = "1";
char alexa_name2[100] = "2";
char alexa_name3[100] = "3";
char alexa_name4[100] = "4";
char alexa_name5[100] = "5";
const char* AP_Name = "EchoBase1";
char saved_ssid[100] = "";
char saved_psk[100] = "";
// Flag for saving config data
bool shouldSaveConfig = false;
bool forceConfigPortal = false;
WiFiManager wifiManager;
// RF Tooling - https://codebender.cc/sketch:80290#RCSwitch%20-%20Transmit%20(Etekcity%20Power%20Outlets).ino
RCSwitch RFSwitch = RCSwitch();
int RF_PULSE_LENGTH = 179; // Pulse length to use for RF transmitter
int RF_TX_PIN = 0; // Digital pin connected to RF transmitter
int RF_BIT_LENGTH = 24;
// RF Signals (varies per remote controlled plugin set)
unsigned long rc_codes[5][2] = {
// ON //OFF
{5313843, 5313852}, /* Outlet 1 /
{5313987, 5313996}, / Outlet 2 /
{5314307, 5314316}, / Outlet 3 /
{335107, 335116}, / Outlet 4 /
{341251, 341260}, / Outlet 5 */
};
// Callback notifying us of the need to save config
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
void setup()
{
Serial.begin(115200);
// -- WifiManager handling
// 5-second delay in case you wish to observe boot-up
for(int i=0; i < 5; i++) {
Serial.print(".");
delay(1000);
}
Serial.println("Booting");
// Clean FS, for testing... consider enabling if jumper is in flash mode, etc.
// SPIFFS.format();
// Set the flash/boot pin for input so we can read if the jumper is present
pinMode(0, INPUT);
// If the jumper is in "flash" mode (i.e., pin 0 is grounded), we will be enabling the config portal
forceConfigPortal = (digitalRead(0) == 0);
if(forceConfigPortal) {
Serial.println("Jumper set for flash - will trigger config portal");
} else {
Serial.println("Jumper set for boot - will attempt autoconnect, else config portal");
}
// Read configuration from FS json
Serial.println("Mounting ESP8266 integrated filesystem...");
if (SPIFFS.begin()) {
Serial.println("Mounted file system");
if (SPIFFS.exists("/config.json")) {
Serial.println("Found existing config; reading file");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println("Opened config file for reading");
size_t size = configFile.size();
Serial.print("File size (bytes) = ");
Serial.println(size);
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonDocument jsonDocument;
JsonObject& json = jsonDocument.parseObject(buf.get());
Serial.println("Parsed JSON content:");
json.printTo(Serial);
Serial.println();
if (json.success()) {
strcpy(alexa_name1, json["alexa_name1"]);
strcpy(alexa_name2, json["alexa_name2"]);
strcpy(alexa_name3, json["alexa_name3"]);
strcpy(alexa_name4, json["alexa_name4"]);
strcpy(alexa_name5, json["alexa_name5"]);
Serial.println("Parsed Alexa relay name #1: " + String(alexa_name1));
Serial.println("Parsed Alexa relay name #2: " + String(alexa_name2));
Serial.println("Parsed Alexa relay name CharlesJGantt#3: " + String(alexa_name3));
Serial.println("Parsed Alexa relay name CharlesJGantt#4: " + String(alexa_name4));
Serial.println("Parsed Alexa relay name CharlesJGantt#5: " + String(alexa_name5));
} else {
Serial.println("** ERROR ** Failed to load/parse JSON config");
}
} else {
Serial.println("No JSON file found in filesystem");
}
}
} else {
Serial.println("** ERROR ** Failed to mount ESP8266's integrated filesyste,m");
}
// The extra parameters to be configured (can be either global or just in the setup)
// After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt default length
WiFiManagerParameter custom_alexa_name1("alexa_name1", "Device #1 name", alexa_name1, 100);
WiFiManagerParameter custom_alexa_name2("alexa_name2", "Device #2 name", alexa_name2, 100);
WiFiManagerParameter custom_alexa_name3("alexa_name3", "Device CharlesJGantt#3 name", alexa_name3, 100);
WiFiManagerParameter custom_alexa_name4("alexa_name4", "Device CharlesJGantt#4 name", alexa_name4, 100);
WiFiManagerParameter custom_alexa_name5("alexa_name5", "Device CharlesJGantt#5 name", alexa_name5, 100);
// Set the function that will be called to save the custom parameter after config
wifiManager.setSaveConfigCallback(saveConfigCallback);
// Hand the parameter defintions to the WifiManager for use during config
wifiManager.addParameter(&custom_alexa_name1);
wifiManager.addParameter(&custom_alexa_name2);
wifiManager.addParameter(&custom_alexa_name3);
wifiManager.addParameter(&custom_alexa_name4);
wifiManager.addParameter(&custom_alexa_name5);
//reset settings - for testing
//wifiManager.resetSettings();
//set minimu quality of signal so it ignores AP's under that quality
//defaults to 8%
//wifiManager.setMinimumSignalQuality();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
//wifiManager.setTimeout(120);
if(forceConfigPortal) {
wifiManager.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
// Force config portal while jumper is set for flashing
if (!wifiManager.startConfigPortal(AP_Name)) {
Serial.println("** ERROR ** Failed to connect with new config / possibly hit config portal timeout; Resetting in 3sec...");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
} else {
// Autoconnect if we can
// Fetches ssid and pass and tries to connect; if it does not connect it starts an access point with the specified name
// and goes into a blocking loop awaiting configuration
if (!wifiManager.autoConnect(AP_Name)) {
Serial.println("** ERROR ** Failed to connect with new config / possibly hit timeout; Resetting in 3sec...");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
}
// --- If you get here you have connected to the WiFi ---
Serial.println("Connected to wifi");
// Save the connect info in case we need to reconnect
WiFi.SSID().toCharArray(saved_ssid, 100);
WiFi.psk().toCharArray(saved_psk, 100);
// Read updated parameters
strcpy(alexa_name1, custom_alexa_name1.getValue());
strcpy(alexa_name2, custom_alexa_name2.getValue());
strcpy(alexa_name3, custom_alexa_name3.getValue());
strcpy(alexa_name4, custom_alexa_name4.getValue());
strcpy(alexa_name5, custom_alexa_name5.getValue());
Serial.println("Read configured Alexa relay name #1: " + String(alexa_name1));
Serial.println("Read configured Alexa relay name #2: " + String(alexa_name2));
Serial.println("Read configured Alexa relay name CharlesJGantt#3: " + String(alexa_name3));
Serial.println("Read configured Alexa relay name CharlesJGantt#4: " + String(alexa_name4));
Serial.println("Read configured Alexa relay name CharlesJGantt#5: " + String(alexa_name5));
// Save the custom parameters to the ESP8266 filesystem if changed
if (shouldSaveConfig) {
Serial.println("Saving config to ESP8266 filesystem");
DynamicJsonDocument jsonDocument;
JsonObject& json = jsonDocument.createObject();
json["alexa_name1"] = alexa_name1;
json["alexa_name2"] = alexa_name2;
json["alexa_name3"] = alexa_name3;
json["alexa_name4"] = alexa_name4;
json["alexa_name5"] = alexa_name5;
Serial.println("Attempting to open config JSON file for writing");
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("** ERROR ** Failed to open JSON config file for writing");
} else {
json.printTo(Serial);
Serial.println();
json.printTo(configFile);
configFile.close();
Serial.println("File write complete");
}
}
Serial.print("SSID: " );
Serial.println(WiFi.SSID());
Serial.print("Local IP: ");
Serial.println(WiFi.localIP());
// -- ALEXA setup/handling --
upnpBroadcastResponder.beginUdpMulticast();
// Define your switches here. Max 14
// Format: Alexa invocation name, local port no, on callback, off callback
alexa_switch1 = new Switch(alexa_name1, 80, alexa_switch1On, alexa_switch1Off);
alexa_switch2 = new Switch(alexa_name2, 81, alexa_switch2On, alexa_switch2Off);
alexa_switch3 = new Switch(alexa_name3, 82, alexa_switch3On, alexa_switch3Off);
alexa_switch4 = new Switch(alexa_name4, 83, alexa_switch4On, alexa_switch4Off);
alexa_switch5 = new Switch(alexa_name5, 85, alexa_switch5On, alexa_switch5Off);
Serial.println("Adding switches upnp broadcast responder");
upnpBroadcastResponder.addDevice(*alexa_switch1);
upnpBroadcastResponder.addDevice(*alexa_switch2);
upnpBroadcastResponder.addDevice(*alexa_switch3);
upnpBroadcastResponder.addDevice(*alexa_switch4);
upnpBroadcastResponder.addDevice(*alexa_switch5);
// Setup RF Transmitter
RFSwitch.enableTransmit(RF_TX_PIN);
RFSwitch.setPulseLength(RF_PULSE_LENGTH);
}
/* If disconnected from Wifi, enter a blocking loop that periodically attempts reconnection */
void reconnectIfNecessary() {
while(WiFi.status() != WL_CONNECTED) {
Serial.println("Disconnected; Attempting reconnect to " + String(saved_ssid) + "...");
WiFi.disconnect();
WiFi.mode(WIFI_AP_STA);
WiFi.begin(saved_ssid, saved_psk);
// Output reconnection status info every second over the next 10 sec
for( int i = 0; i < 10 ; i++ ) {
delay(1000);
Serial.print("WiFi status = ");
if( WiFi.status() == WL_CONNECTED ) {
Serial.println("Connected");
break;
} else {
Serial.println("Disconnected");
}
}
if(WiFi.status() != WL_CONNECTED) {
Serial.println("Failure to establish connection after 10 sec. Will reattempt connection in 2 sec");
delay(2000);
}
}
}
void loop()
{
// Ensure wifi is connected (won't return until it has connected)
reconnectIfNecessary();
// Respond to any Alexa/discovery requests
upnpBroadcastResponder.serverLoop();
// Respond to any UPnP control requests
alexa_switch1->serverLoop();
alexa_switch2->serverLoop();
alexa_switch3->serverLoop();
alexa_switch4->serverLoop();
alexa_switch5->serverLoop();
}
void alexa_switch1On() {
Serial.println("Switch 1 turn on ...");
enableOutlet(1, true);
}
void alexa_switch1Off() {
Serial.println("Switch 1 turn off ...");
enableOutlet(1, false);
}
void alexa_switch2On() {
Serial.println("Switch 2 turn on ...");
enableOutlet(2, true);
}
void alexa_switch2Off() {
Serial.println("Switch 2 turn off ...");
enableOutlet(2, false);
}
void alexa_switch3On() {
Serial.println("Switch 3 turn on ...");
enableOutlet(3, true);
}
void alexa_switch3Off() {
Serial.println("Switch 3 turn off ...");
enableOutlet(3, false);
}
void alexa_switch4On() {
Serial.println("Switch 4 turn on ...");
enableOutlet(4, true);
}
void alexa_switch4Off() {
Serial.println("Switch 4 turn off ...");
enableOutlet(4, false);
}
void alexa_switch5On() {
Serial.println("Switch 5 turn on ...");
enableOutlet(5, true);
}
void alexa_switch5Off() {
Serial.println("Switch 5 turn off ...");
enableOutlet(5, false);
}
void enableOutlet(int outletNumber, bool onOrOff)
{
if (outletNumber < 1 || outletNumber > 5) {
Serial.println("Invalid outlet number");
return;
}
unsigned long *onOffCodes = rc_codes[outletNumber - 1];
unsigned long codeToSend = onOffCodes[onOrOff ? 0 : 1];
RFSwitch.send(codeToSend, RF_BIT_LENGTH);
char outletNumberString[1];
int retVal = snprintf(outletNumberString, 1, "%d", outletNumber);
if (retVal < 0) {
Serial.println("Log encoding error");
return;
}
Serial.print("Switch " + String(outletNumber) + " turned ");
if (onOrOff) {
Serial.println("on");
} else {
Serial.println("off");
}
}

how do i publish the data on mqtt of the bme680 sensor using ESP32cam

I am using windows 10 and working on getting the gas readings from BME680 using esp32cam. I tried to add this:
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
//#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#include <Arduino_JSON.h>
//uint64_t mac;
//uint32_t high;
//uint32_t low;
// Replace the next variables with your SSID/Password combination
const char* ssid = "";
const char* password = "";
// Add your MQTT Broker IP address, example:
//const char* mqtt_server = "";
const char* mqtt_server = "";
const char* mqtt_port = "";
const char* mqtt_user = "";
const char* mqtt_password = "";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
//uncomment the following lines if you're using SPI
#include <SPI.h>
#define BME_SCK 14
#define BME_MISO 12
#define BME_MOSI 13
#define BME_CS 15
//Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI
float temperature = 0;
float humidity = 0;
float pressure = 0;
float gas = 0;
//Device ID
//uint64_t chip_id;
//chip_id=ESP.getEfuseMac();//The chip ID is essentially its MAC address(length: 6 bytes).
// LED Pin
const int ledPin = 4;
void setup() {
Serial.begin(115200);
// default settings
// (you can also pass in a Wire library object like &Wire2)
//status = bme.begin();
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
WiFi.begin();
}
setup_wifi();
client.setServer(mqtt_server,...);
client.setCallback(callback);
pinMode(ledPin, OUTPUT);
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
// Feel free to add more if statements to control more GPIOs with MQTT
// If a message is received on the topic esp32/output, you check if the message is either "on" or "off".
// Changes the output state according to the message
if (String(topic) == "esp32/output") {
Serial.print("Changing output to ");
if(messageTemp == "on"){
Serial.println("on");
digitalWrite(ledPin, HIGH);
}
else if(messageTemp == "off"){
Serial.println("off");
digitalWrite(ledPin, LOW);
}
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("ESP32Client", mqtt_user, mqtt_password)) {
Serial.println("connected");
// Subscribe
client.subscribe("esp32/output");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(20000);
}
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 5000) {
lastMsg = now;
// Temperature in Celsius
temperature = bme.readTemperature();
// Uncomment the next line to set temperature in Fahrenheit
// (and comment the previous temperature line)
//temperature = 1.8 * bme.readTemperature() + 32; // Temperature in Fahrenheit
// Convert the value to a char array
char tempString[8];
dtostrf(temperature, 1, 2, tempString);
//Serial.print("Temperature: ");
//Serial.println(tempString);
//client.publish("esp32/temperature", tempString);
humidity = bme.readHumidity();
// Convert the value to a char array
char humString[8];
dtostrf(humidity, 1, 2, humString);
//Serial.print("Humidity: ");
//Serial.println(humString);
//client.publish("esp32/humidity", humString);
pressure = bme.readPressure();
//Convert the value to a char array
char preString[16];
dtostrf(pressure, 1, 2, preString);
//Serial.print("Pressure: ");
//Serial.println(preString);
//client.publish("esp32/pressure", preString);
gas = bme.readGas();
//Serial.print(bme.gas_resistance / 1000.0);
char gasString[8];
dtostrf(gas, 1, 2, gasString);
//Serial.println(" KOhms");
char macValue[13]; // Don't forget one byte for the terminating NULL...
uint64_t mac = ESP.getEfuseMac();
sprintf(macValue, "%012x", mac);
//Serial.print("ChipID: ");
//Serial.println(chipId);
//client.publish("esp32/chipid", chipId);
JSONVar data;
data["temperature"] = temperature;
data["humidity"] = humidity;
data["pressure"] = pressure;
data["macValue"] = macValue;
data["gas"] = gas;
//Serial.print("data.keys() = ");
//Serial.println(data.keys());
//Serial.print("Data = ");
//Serial.println(data);
String jsonString = JSON.stringify(data);
//Serial.print("JSON.stringify(data) = ");
//Serial.println(jsonString);
client.publish("esp32/data", jsonString.c_str());
}
}
everything got compiled perfectly. But when i tried to upload the code, this error came up:
Arduino: 1.8.9 (Windows 10), Board: "ESP32 Wrover Module, Huge APP
(3MB No OTA), QIO, 80MHz, 115200, Verbose"
Sketch uses 789282 bytes (25%) of program storage space. Maximum
is 3145728 bytes.
Global variables use 40652 bytes (12%) of dynamic memory, leaving
287028 bytes for local variables. Maximum is 327680 bytes.
esptool.py v2.6
Serial port COM7
Connecting.....
Chip is .....(revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse,
Coding Scheme None
MAC: .....
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Warning: Could not auto-detect Flash size (FlashID=0xffffff,
SizeID=0xff), defaulting to 4MB
Compressed 8192 bytes to 47...
A fatal error occurred: Timed out waiting for packet content
A fatal error occurred: Timed out waiting for packet content
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
I don't know why is this thing coming up because previously everything was working fine when I tried to incorporate BME280 and publish the available data on MQTT. Now, I have switched to bme680.
EDIT:
I tried to disconnect BME from ESP32, then uploaded the code, then connected BME back. The error did not show up, but still, the data is not being shown this time, rather something like this, continually:
rst:0x10 (RTCWDT_RTC_RESET),boot:0x33 (SPI_FAST_FLASH_BOOT)
flash read err, 1000
ets_main.c 371
ets Jun 8 2016 00:22:57
It looks to me that ESP32-CAM is not in the bootloader mode when you try to upload the code.
Did you connect IO0 and GND pins and push the reset button?
You should see the message that ESP32 is ready for upload in the terminal window.
Sorry for the late reply ... :)

Understanding how to use CGI programming with C and HTML

I'm attempting to use a local server made in C with an HTML page run on this server that will be able to interact with a program i made to be able to run bash commands which works perfectly outside of the html page but needs to be able to receive input from the user via text box on the web page, display the command entered as well as the output on the html page. Right now when i click the submit button on the html page it goes to localhost:PORT/pexec.cgi but shows absolutely no display at all, just white space. What am i doing wrong and how can i get this to work so that it will correctly display output?
WCServer.c
#include <sys/socket.h> // socket definitions
#include <sys/types.h> // socket types
#include <arpa/inet.h> // inet (3) funtions
#include <unistd.h> // misc. UNIX functions
#include <signal.h> // signal handling
#include <stdlib.h> // standard library
#include <stdio.h> // input/output library
#include <string.h> // string library
#include <errno.h> // error number library
#include <fcntl.h> // for O_* constants
#include <sys/mman.h> // mmap library
#include <sys/types.h> // various type definitions
#include <sys/stat.h> // more constants
// global constants
#define PORT 3838 // port to connect on
#define LISTENQ 10 // number of connections
int list_s; // listening socket
// structure to hold the return code and the filepath to serve to client.
typedef struct {
int returncode;
char *filename;
} httpRequest;
// Structure to hold variables that will be placed in shared memory
typedef struct {
pthread_mutex_t mutexlock;
int totalbytes;
} sharedVariables;
// headers to send to clients
char *header200 = "HTTP/1.0 200 OK\nServer: CS241Serv v0.1\nContent-Type: text/html\n\n";
char *header400 = "HTTP/1.0 400 Bad Request\nServer: CS241Serv v0.1\nContent-Type: text/html\n\n";
char *header404 = "HTTP/1.0 404 Not Found\nServer: CS241Serv v0.1\nContent-Type: text/html\n\n";
// get a message from the socket until a blank line is recieved
char *getMessage(int fd) {
// A file stream
FILE *sstream;
// Try to open the socket to the file stream and handle any failures
if( (sstream = fdopen(fd, "r")) == NULL)
{
fprintf(stderr, "Error opening file descriptor in getMessage()\n");
exit(EXIT_FAILURE);
}
// Size variable for passing to getline
size_t size = 1;
char *block;
// Allocate some memory for block and check it went ok
if( (block = malloc(sizeof(char) * size)) == NULL )
{
fprintf(stderr, "Error allocating memory to block in getMessage\n");
exit(EXIT_FAILURE);
}
// Set block to null
*block = '\0';
// Allocate some memory for tmp and check it went ok
char *tmp;
if( (tmp = malloc(sizeof(char) * size)) == NULL )
{
fprintf(stderr, "Error allocating memory to tmp in getMessage\n");
exit(EXIT_FAILURE);
}
// Set tmp to null
*tmp = '\0';
// Int to keep track of what getline returns
int end;
// Int to help use resize block
int oldsize = 1;
// While getline is still getting data
while( (end = getline( &tmp, &size, sstream)) > 0)
{
// If the line its read is a caridge return and a new line were at the end of the header so break
if( strcmp(tmp, "\r\n") == 0)
{
break;
}
// Resize block
block = realloc(block, size+oldsize);
// Set the value of oldsize to the current size of block
oldsize += size;
// Append the latest line we got to block
strcat(block, tmp);
}
// Free tmp a we no longer need it
free(tmp);
// Return the header
return block;
}
// send a message to a socket file descripter
int sendMessage(int fd, char *msg) {
return write(fd, msg, strlen(msg));
}
// Extracts the filename needed from a GET request and adds public_html to the front of it
char * getFileName(char* msg)
{
// Variable to store the filename in
char * file;
// Allocate some memory for the filename and check it went OK
if( (file = malloc(sizeof(char) * strlen(msg))) == NULL)
{
fprintf(stderr, "Error allocating memory to file in getFileName()\n");
exit(EXIT_FAILURE);
}
// Get the filename from the header
sscanf(msg, "GET %s HTTP/1.1", file);
// Allocate some memory not in read only space to store "public_html"
char *base;
if( (base = malloc(sizeof(char) * (strlen(file) + 18))) == NULL)
{
fprintf(stderr, "Error allocating memory to base in getFileName()\n");
exit(EXIT_FAILURE);
}
char* ph = "public_html";
// Copy public_html to the non read only memory
strcpy(base, ph);
// Append the filename after public_html
strcat(base, file);
// Free file as we now have the file name in base
free(file);
// Return public_html/filetheywant.html
return base;
}
// parse a HTTP request and return an object with return code and filename
httpRequest parseRequest(char *msg){
httpRequest ret;
// A variable to store the name of the file they want
char* filename;
// Allocate some memory to filename and check it goes OK
if( (filename = malloc(sizeof(char) * strlen(msg))) == NULL)
{
fprintf(stderr, "Error allocating memory to filename in parseRequest()\n");
exit(EXIT_FAILURE);
}
// Find out what page they want
filename = getFileName(msg);
// Check if its a directory traversal attack
char *badstring = "..";
char *test = strstr(filename, badstring);
// Check if they asked for / and give them input.html
int test2 = strcmp(filename, "public_html/");
// Check if the page they want exists
FILE *exists = fopen(filename, "r" );
// If the badstring is found in the filename
if( test != NULL )
{
// Return a 400 header and 400.html
ret.returncode = 400;
ret.filename = "400.html";
}
// If they asked for / return input.html
else if(test2 == 0)
{
ret.returncode = 200;
ret.filename = "public_html/input.html";
}
// If they asked for a specific page and it exists because we opened it sucessfully return it
else if( exists != NULL )
{
ret.returncode = 200;
ret.filename = filename;
// Close the file stream
fclose(exists);
}
// If we get here the file they want doesn't exist so return a 404
else
{
ret.returncode = 404;
ret.filename = "404.html";
}
// Return the structure containing the details
return ret;
}
// print a file out to a socket file descriptor
int printFile(int fd, char *filename) {
/* Open the file filename and echo the contents from it to the file descriptor fd */
// Attempt to open the file
FILE *read;
if( (read = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Error opening file in printFile()\n");
exit(EXIT_FAILURE);
}
// Get the size of this file for printing out later on
int totalsize;
struct stat st;
stat(filename, &st);
totalsize = st.st_size;
// Variable for getline to write the size of the line its currently printing to
size_t size = 1;
// Get some space to store each line of the file in temporarily
char *temp;
if( (temp = malloc(sizeof(char) * size)) == NULL )
{
fprintf(stderr, "Error allocating memory to temp in printFile()\n");
exit(EXIT_FAILURE);
}
// Int to keep track of what getline returns
int end;
// While getline is still getting data
while( (end = getline( &temp, &size, read)) > 0)
{
sendMessage(fd, temp);
}
// Final new line
sendMessage(fd, "\n");
// Free temp as we no longer need it
free(temp);
// Return how big the file we sent out was
return totalsize;
}
// clean up listening socket on ctrl-c
void cleanup(int sig) {
printf("Cleaning up connections and exiting.\n");
// try to close the listening socket
if (close(list_s) < 0) {
fprintf(stderr, "Error calling close()\n");
exit(EXIT_FAILURE);
}
// Close the shared memory we used
shm_unlink("/sharedmem");
// exit with success
exit(EXIT_SUCCESS);
}
int printHeader(int fd, int returncode)
{
// Print the header based on the return code
switch (returncode)
{
case 200:
sendMessage(fd, header200);
return strlen(header200);
break;
case 400:
sendMessage(fd, header400);
return strlen(header400);
break;
case 404:
sendMessage(fd, header404);
return strlen(header404);
break;
}
}
// Increment the global count of data sent out
int recordTotalBytes(int bytes_sent, sharedVariables *mempointer)
{
// Lock the mutex
pthread_mutex_lock(&(*mempointer).mutexlock);
// Increment bytes_sent
(*mempointer).totalbytes += bytes_sent;
// Unlock the mutex
pthread_mutex_unlock(&(*mempointer).mutexlock);
// Return the new byte count
return (*mempointer).totalbytes;
}
int main(int argc, char *argv[]) {
int conn_s; // connection socket
short int port = PORT; // port number
struct sockaddr_in servaddr; // socket address structure
// set up signal handler for ctrl-c
(void) signal(SIGINT, cleanup);
// create the listening socket
if ((list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
fprintf(stderr, "Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
// set all bytes in socket address structure to zero, and fill in the relevant data members
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
// bind to the socket address
if (bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
fprintf(stderr, "Error calling bind()\n");
exit(EXIT_FAILURE);
}
// Listen on socket list_s
if( (listen(list_s, 10)) == -1)
{
fprintf(stderr, "Error Listening\n");
exit(EXIT_FAILURE);
}
// Set up some shared memory to store our shared variables in
// Close the shared memory we use just to be safe
shm_unlink("/sharedmem");
int sharedmem;
// Open the memory
if( (sharedmem = shm_open("/sharedmem", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1)
{
fprintf(stderr, "Error opening sharedmem in main() errno is: %s ", strerror(errno));
exit(EXIT_FAILURE);
}
// Set the size of the shared memory to the size of my structure
ftruncate(sharedmem, sizeof(sharedVariables) );
// Map the shared memory into our address space
sharedVariables *mempointer;
// Set mempointer to point at the shared memory
mempointer = mmap(NULL, sizeof(sharedVariables), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
// Check the memory allocation went OK
if( mempointer == MAP_FAILED )
{
fprintf(stderr, "Error setting shared memory for sharedVariables in recordTotalBytes() error is %d \n ", errno);
exit(EXIT_FAILURE);
}
// Initalise the mutex
pthread_mutex_init(&(*mempointer).mutexlock, NULL);
// Set total bytes sent to 0
(*mempointer).totalbytes = 0;
// Size of the address
int addr_size = sizeof(servaddr);
// Sizes of data were sending out
int headersize;
int pagesize;
int totaldata;
// Number of child processes we have spawned
int children = 0;
// Variable to store the ID of the process we get when we spawn
pid_t pid;
// Loop infinitly serving requests
while(1)
{
// If we haven't already spawned 10 children fork
if( children <= 10)
{
pid = fork();
children++;
}
// If the pid is -1 the fork failed so handle that
if( pid == -1)
{
fprintf(stderr,"can't fork, error %d\n" , errno);
exit (1);
}
// Have the child process deal with the connection
if ( pid == 0)
{
// Have the child loop infinetly dealing with a connection then getting the next one in the queue
while(1)
{
// Accept a connection
conn_s = accept(list_s, (struct sockaddr *)&servaddr, &addr_size);
// If something went wrong with accepting the connection deal with it
if(conn_s == -1)
{
fprintf(stderr,"Error accepting connection \n");
exit (1);
}
// Get the message from the file descriptor
char * header = getMessage(conn_s);
// Parse the request
httpRequest details = parseRequest(header);
// Free header now were done with it
free(header);
// Print out the correct header
headersize = printHeader(conn_s, details.returncode);
// Print out the file they wanted
pagesize = printFile(conn_s, details.filename);
// Increment our count of total datasent by all processes and get back the new total
totaldata = recordTotalBytes(headersize+pagesize, mempointer);
// Print out which process handled the request and how much data was sent
printf("Process %d served a request of %d bytes. Total bytes sent %d \n", getpid(), headersize+pagesize, totaldata);
// Close the connection now were done
close(conn_s);
}
}
}
return EXIT_SUCCESS;
}
Pexec.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
static char* args[512];
pid_t pid;
int command_pipe[2];
#define READ 0
#define WRITE 1
static int command(int input, int first, int last)
{
int pipettes[2];
pipe( pipettes );
pid = fork();
if (pid == 0) {
if (first == 1 && last == 0 && input == 0) {
// First command
dup2( pipettes[WRITE], STDOUT_FILENO );
} else if (first == 0 && last == 0 && input != 0) {
// Middle command
dup2(input, STDIN_FILENO);
dup2(pipettes[WRITE], STDOUT_FILENO);
} else {
// Last command
dup2( input, STDIN_FILENO );
}
if (execvp( args[0], args) == -1)
_exit(EXIT_FAILURE);
}
if (input != 0)
close(input);
close(pipettes[WRITE]);
if (last == 1)
close(pipettes[READ]);
return pipettes[READ];
}
static void cleanup(int n)
{
int i;
for (i = 0; i < n; ++i)
wait(NULL);
}
static int run(char* cmd, int input, int first, int last);
static char line[1024];
static int n = 0; /* number of calls to 'command' */
int main(int argc, char *argv[])
{
while (1) {
// for(int i = 1; i < argc; i++){
// strcat(line, argv[i]);
// strcat(line, " ");
// }
/* Read a command line */
//if (!fgets(line, 1024, stdin))
//return 0;
int InputLength = atoi(getenv("INPUT_LENGTH"));
fread(line, InputLength, 1, stdin);
int input = 0;
int first = 1;
char* cmd = line;
char* next = strchr(cmd, '#'); /* Find first '|' */
while (next != NULL) {
/* 'next' points to '|' */
*next = '\0';
input = run(cmd, input, first, 0);
cmd = next + 1;
next = strchr(cmd, '#'); /* Find next '|' */
first = 0;
}
input = run(cmd, input, first, 1);
cleanup(n);
n = 0;
}
return 0;
}
static void split(char* cmd);
static int run(char* cmd, int input, int first, int last)
{
split(cmd);
if (args[0] != NULL) {
if (strcmp(args[0], "exit") == 0)
exit(0);
n += 1;
return command(input, first, last);
}
return 0;
}
static char* skipwhite(char* s)
{
while (isspace(*s)) ++s;
return s;
}
static void split(char* cmd)
{
cmd = skipwhite(cmd);
char* next = strchr(cmd, ' ');
int i = 0;
while(next != NULL) {
next[0] = '\0';
args[i] = cmd;
++i;
cmd = skipwhite(next + 1);
next = strchr(cmd, ' ');
}
if (cmd[0] != '\0') {
args[i] = cmd;
next = strchr(cmd, '\n');
next[0] = '\0';
++i;
}
args[i] = NULL;
}
input.html
<!DOCTYPE html>
<html>
<style>
input[type=text], select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
input[type=submit] {
width: 100%;
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}
input[type=submit]:hover {
background-color: #45a049;
}
div {
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
</style>
<body>
<h3><center>The Html Page Title </center></h3>
<div>
<form method="POST" action="pexec.cgi">
<label for="cmmd">Command</label>
<input type="text" id="cmmd" name="firstname" placeholder="Enter your Command here and then hit Run! Below">
<label for="lname">Entered Command </label>
<input type="text" id="lname" name="lastname" placeholder="This is what you entered...">
<label for="lname">Standard Output </label>
<input type="text" id="lname" name="lastname" placeholder="Standard Output will be shown here...">
<label for="lname">Standard Error </label>
<input type="text" id="lname" name="lastname" placeholder="standard error will be shown here...">
<input type="submit" value="Run!">
</form>
</div>
</body>
</html>

C:HTTP webserver - the image "http://localhost.... cannot be displayed because it contains errors

It's my first time dabbling with socket programming and I stumbled upon this amazing code from https://dzone.com/articles/web-server-c.
WHAT WE NEED TO DO: implement a simple HTTP web server that uses the web browser(input from the user) as a client
Here it is:
/*
* WebServer.c
*
* Created on: Nov 3, 2012
* Author: pavithra
*
* A web server in C language using only the standard libraries.
* The port number is passed as an argument.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#define EOL "\r\n"
#define EOL_SIZE 2
typedef struct {
char *ext;
char *mediatype;
} extn;
//Possible media types
extn extensions[] ={
{"gif", "image/gif" },
{"txt", "text/plain" },
{"jpg", "image/jpg" },
{"jpeg","image/jpeg"},
{"png", "image/png" },
{"ico", "image/ico" },
{"zip", "image/zip" },
{"gz", "image/gz" },
{"tar", "image/tar" },
{"htm", "text/html" },
{"html","text/html" },
{"php", "text/html" },
{"pdf","application/pdf"},
{"zip","application/octet-stream"},
{"rar","application/octet-stream"},
{0,0} };
//find webroot, add design
/*
A helper function
*/
void error(const char *msg) {
perror(msg);
exit(1);
}
/*
A helper function
*/
int get_file_size(int fd) {
struct stat stat_struct;
if (fstat(fd, &stat_struct) == -1)
return (1);
return (int) stat_struct.st_size;
}
/*
A helper function
*/
void send_new(int fd, char *msg) {
int len = strlen(msg);
if (send(fd, msg, len, 0) == -1) {
printf("Error in send\n");
}
}
/*
This function recieves the buffer
until an "End of line(EOL)" byte is recieved
*/
int recv_new(int fd, char *buffer) {
char *p = buffer; // Use of a pointer to the buffer rather than dealing with the buffer directly
int eol_matched = 0; // Use to check whether the recieved byte is matched with the buffer byte or not
while (recv(fd, p, 1, 0) != 0) // Start receiving 1 byte at a time
{
if (*p == EOL[eol_matched]) // if the byte matches with the first eol byte that is '\r'
{
++eol_matched;
if (eol_matched == EOL_SIZE) // if both the bytes matches with the EOL
{
*(p + 1 - EOL_SIZE) = '\0'; // End the string
return (strlen(buffer)); // Return the bytes recieved
}
} else {
eol_matched = 0;
}
p++; // Increment the pointer to receive next byte
}
return (0);
}
/*
A helper function: Returns the
web root location.
*/
char* webroot() {
// open the file "kill.txt" for reading
FILE *in = fopen("kill.txt", "rt");
// read the first line from the file
char buff[1000];
fgets(buff, 1000, in);
// close the stream
fclose(in);
char* nl_ptr = strrchr(buff, '\n');
if (nl_ptr != NULL)
*nl_ptr = '\0';
return strdup(buff);
}
/*
Handles php requests
*/
void php_cgi(char* script_path, int fd) {
send_new(fd, "HTTP/1.1 200 OK\n Server: Web Server in C\n Connection: close\n");
dup2(fd, STDOUT_FILENO);
char script[500];
strcpy(script, "SCRIPT_FILENAME=");
strcat(script, script_path);
putenv("GATEWAY_INTERFACE=CGI/1.1");
putenv(script);
putenv("QUERY_STRING=");
putenv("REQUEST_METHOD=GET");
putenv("REDIRECT_STATUS=true");
putenv("SERVER_PROTOCOL=HTTP/1.1");
putenv("REMOTE_HOST=127.0.0.1");
execl("/usr/bin/php-cgi", "php-cgi", NULL);
}
/*
This function parses the HTTP requests,
arrange resource locations,
check for supported media types,
serves files in a web root,
sends the HTTP error codes.
*/
int connection(int fd) {
char request[500], resource[500], *ptr;
int fd1, length;
if (recv_new(fd, request) == 0) {
printf("Receive Failed\n");
}
printf("%s\n", request);
// Check for a valid browser request
ptr = strstr(request, " HTTP/");
if (ptr == NULL) {
printf("NOT HTTP !\n");
} else {
*ptr = 0;
ptr = NULL;
if (strncmp(request, "GET ", 4) == 0) {
ptr = request + 4;
}
if (ptr == NULL) {
printf("Unknown Request ! \n");
} else {
if (ptr[strlen(ptr) - 1] == '/') {
strcat(ptr, "test.html");
}
strcpy(resource, webroot());
strcat(resource, ptr);
char* s = strchr(ptr, '.');
int i;
for (i = 0; extensions[i].ext != NULL; i++) {
if (strcmp(s + 1, extensions[i].ext) == 0) {
fd1 = open(resource, O_RDONLY, 0);
printf("Opening \"%s\"\n", resource);
if (fd1 == -1) {
printf("404 File not found Error\n");
send_new(fd, "HTTP/1.1 404 Not Found\r\n");
send_new(fd, "Server : Web Server in C\r\n\r\n");
send_new(fd, "<html><head><title>404 Not Found</head></title>");
send_new(fd, "<body><p>404 Not Found: The requested resource could not be found!</p></body></html>\r\n");
//Handling php requests
} else if (strcmp(extensions[i].ext, "php") == 0) {
php_cgi(resource, fd);
sleep(1);
close(fd);
exit(1);
} else {
printf("200 OK, Content-Type: %s\n\n",
extensions[i].mediatype);
send_new(fd, "HTTP/1.1 200 OK\r\n");
send_new(fd, "Server : Web Server in C\r\n\r\n");
if (ptr == request + 4) // if it is a GET request
{
if ((length = get_file_size(fd1)) == -1)
printf("Error in getting size !\n");
size_t total_bytes_sent = 0;
ssize_t bytes_sent;
while (total_bytes_sent < length) {
//Zero copy optimization
if ((bytes_sent = sendfile(fd, fd1, 0,
length - total_bytes_sent)) <= 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
perror("sendfile");
return -1;
}
total_bytes_sent += bytes_sent;
}
//why is it not appearing up to 11:30
}
}
break;
}
int size = sizeof(extensions) / sizeof(extensions[0]);
if (i == size - 2) {
printf("415 Unsupported Media Type\n");
send_new(fd, "HTTP/1.1 415 Unsupported Media Type\r\n");
send_new(fd, "Server : Web Server in C\r\n\r\n");
send_new(fd, "<html><head><title>415 Unsupported Media Type</head></title>");
send_new(fd, "<body><p>415 Unsupported Media Type!</p></body></html>");
}
}
close(fd);
}
}
shutdown(fd, SHUT_RDWR);
}
int main(int argc, char *argv[]) {
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr, "ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
/*
Server runs forever, forking off a separate
process for each connection.
*/
while (1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
pid = fork();
if (pid < 0)
error("ERROR on fork");
if (pid == 0) {
close(sockfd);
connection(newsockfd);
exit(0);
} else
close(newsockfd);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
NOTE: the kill.txt contains the directory of the server, the files(jpegs, gifs, etc.: /home/user/Desktop)
PROBLEM:
1. After I compile the program and execute it on my web browser as "localhost:port number/file" this is what appears on my web browser:
the image "http://localhost.... cannot be displayed because it contains errors.
And this is what appears on my terminal:
GET /sample5.gif HTTP/1.1
Opening "/home/user/Desktop/sample5.gif"
200 OK, Content-Type: image/gif
GET /favicon.ico HTTP/1.1
Opening "/home/user/Desktop/favicon.ico"
404 File not found Error
How do I fix this? Any help/comment would be greatly appreciated! Thanks.
Where is that favicon.ico bit coming from? /I looked this up and apparently having that favicon.ico bit is quite normal (can somebody please confirm this?)/
… I stumbled upon this amazing code from …
It is indeed amazing how bad it is.
At the end of the function int connection(int fd) there's:
close(fd);
}
}
shutdown(fd, SHUT_RDWR);
}
Browsers don't like the connection being reset by peer (due to close()) before it's tidily shut down. Move the close() after the shutdown().
The program neglects to reap child processes, thus a zombie process remains after each request. #include <signal.h> and add sigignore(SIGCHLD); at the start of main().
If the action for the SIGCHLD signal is set to SIG_IGN, child
processes of the calling processes will not be transformed into zombie
processes when they terminate.

arduino json parser failing to parse a uri

HI I am trying to use the Json Library by Benoit Blanchon 2014-2016 from this URL https://github.com/bblanchon/ArduinoJson
I struggled at first as I had the second generation ethernet shield. Got it going once I realised I needed the second ethernet library.
However I get the error message unable to parse json and I am unsure why, and how debug.
// Sample Arduino Json Web Client
// Downloads and parse http://api.sunrise-sunset.org/json?lat=53.440&lng=0.200&date=today
//
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include <ArduinoJson.h>
#include <SPI.h>
#include <Ethernet.h>
EthernetClient client;
const char* server = "api.sunrise-sunset.org"; // server's address
const char* resource = "/json?lat=53.440&lng=0.200&date=today"; // http resource
const unsigned long BAUD_RATE = 9600; // serial connection speed
const unsigned long HTTP_TIMEOUT = 10000; // max respone time from server
const size_t MAX_CONTENT_SIZE = 512; // max size of the HTTP response
// The type of data that we want to extract from the page
struct UserData {
char sunrise[32];
char sunset[32];
};
// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
// initSerial();
// initEthernet();
Serial.begin(9600);
Serial.println("Serial ready");
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
byte ip[] = { 192,168,0,202 };
Ethernet.begin(mac, ip);
Serial.println("Ethernet ready");
delay(1000);
}
// ARDUINO entry point #2: runs over and over again forever
void loop() {
if (connect(server)) {
if (sendRequest(server, resource) && skipResponseHeaders()) {
char response[MAX_CONTENT_SIZE];
readReponseContent(response, sizeof(response));
UserData userData;
if (parseUserData(response, &userData)) {
printUserData(&userData);
}
}
disconnect();
}
wait();
}
// Initialize Serial port
void initSerial() {
Serial.begin(BAUD_RATE);
while (!Serial) {
; // wait for serial port to initialize
}
Serial.println("Serial ready");
}
// Initialize Ethernet library
void initEthernet() {
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
if (!Ethernet.begin(mac)) {
Serial.println("Failed to configure Ethernet");
return;
}
Serial.println("Ethernet ready");
delay(1000);
}
// Open connection to the HTTP server
bool connect(const char* hostName) {
Serial.print("Connect to ");
Serial.println(hostName);
bool ok = client.connect(hostName, 80);
Serial.println(ok ? "Connected" : "Connection Failed!");
return ok;
}
// Send the HTTP GET request to the server
bool sendRequest(const char* host, const char* resource) {
Serial.print("GET ");
Serial.println(resource);
client.print("GET ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
return true;
}
// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders() {
// HTTP headers end with an empty line
char endOfHeaders[] = "\r\n\r\n";
client.setTimeout(HTTP_TIMEOUT);
bool ok = client.find(endOfHeaders);
if (!ok) {
Serial.println("No response or invalid response!");
}
return ok;
}
// Read the body of the response from the HTTP server
void readReponseContent(char* content, size_t maxSize) {
size_t length = client.readBytes(content, maxSize);
content[length] = 0;
Serial.println(content);
}
// Parse the JSON from the input string and extract the interesting values
// Here is the JSON we need to parse
//{
// "results":{
// "sunrise":"5:45:00 AM",
// "sunset":"5:58:51 PM",
// "solar_noon":"11:51:55 AM",
// "day_length":"12:13:51",
// "civil_twilight_begin":"5:10:15 AM",
// "civil_twilight_end":"6:33:36 PM",
// "nautical_twilight_begin":"4:28:54 AM",
// "nautical_twilight_end":"7:14:57 PM",
// "astronomical_twilight_begin":"3:45:29 AM",
// "astronomical_twilight_end":"7:58:22 PM"
// },
// "status":"OK"
//}
bool parseUserData(char* content, struct UserData* userData) {
// Compute optimal size of the JSON buffer according to what we need to parse.
// This is only required if you use StaticJsonBuffer.
const size_t BUFFER_SIZE =
JSON_OBJECT_SIZE(2) // the root object has 2 elements
+ JSON_OBJECT_SIZE(10); // the "result" object has 10 elements
// Allocate a temporary memory pool on the stack
StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
// If the memory pool is too big for the stack, use this instead:
// DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(content);
if (!root.success()) {
Serial.println("JSON parsing failed!");
return false;
}
// Here were copy the strings we're interested in
strcpy(userData->sunrise, root["results"]["sunrise"]);
strcpy(userData->sunset, root["results"]["sunset"]);
// It's not mandatory to make a copy, you could just use the pointers
// Since, they are pointing inside the "content" buffer, so you need to make
// sure it's still in memory when you read the string
return true;
}
// Print the data extracted from the JSON
void printUserData(const struct UserData* userData) {
Serial.print("Name = ");
Serial.println(userData->sunrise);
Serial.print("Company = ");
Serial.println(userData->sunset);
}
// Close the connection with the HTTP server
void disconnect() {
Serial.println("Disconnect");
client.stop();
}
// Pause for a 1 minute
void wait() {
Serial.println("Wait 60 seconds");
delay(60000);
}
There is a 161 before the JSON string because the server is using Chunked transfer encoding.
It is a feature of the HTTP 1.1 specification and the only way to disable it is to use HTTP 1.0 in the request.
See:
New JsonHttpClient.ino, which uses HTTP 1.0 and doesn't require the response buffer.
FAQ: Why parsing fails?