change an if / else if statement to a switch case in Arduino - server

I am making a web server with an ESP32D, I am programming it from the Arduino IDE and I have a function with spaghetti code which I want to refactor with switch case,
this is my function, which i am calling in the void loop()
void control(){
if (header.indexOf("GET /2/on") >= 0) {
Serial.println("GPIO 2 on");
output2State = "on";
digitalWrite(output2, HIGH);
} else if (header.indexOf("GET /2/off") >= 0) {
Serial.println("GPIO 2 off");
output2State = "off";
digitalWrite(output2, LOW);
} else if (header.indexOf("GET /15/on") >= 0) {
Serial.println("GPIO 15 on");
output15State = "on";
digitalWrite(output15, HIGH);
} else if (header.indexOf("GET /15/off") >= 0) {
Serial.println("GPIO 15 off");
output15State = "off";
digitalWrite(output15, LOW);
}
}
void function_loop(){
WiFiClient client = server.available(); // Listen for incoming client
// Serial.println(typeOf(client));
if (client) { // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
control();
}
How could I do to be able to pass it to switch case? I have no idea how to pass the variable to modify (in this case the header.indexOf)

It isn't clear from your example what type your header is, but I'm guessing it is a String.
Send header to control() like this
control(header);
and declare control() like this
void control(String& header) {

Related

65535 cnt value on TTN network

I'm trying to run Lmic library build for arduino (https://github.com/matthijskooijman/arduino-lmic) to work with my Renesas Synergy SK-S7G2 board using e2 studio.
I have altered the hal.cpp file and now the code runs perfectly and I can see the up-link message on the TTN network, The problem that I am facing is that my frame is somehow changing between aes encryption (my guess) because I have checked it before encryption and it shows the LMIC.frame[6] and
LMIC.frame[7] values to be 0x00 but for some reason what I am receiving on the TTN network is 0xFF. and because of this the cnt on TTN shows 65535 as the first count.
The library has 2 aes methods which can be used and I have tried both but they give me the same result.
The reasons I have come up with so far is:
32 bit arm m4 processor may be the cause, as the library was intended for 8 bit arduino (but library also has a 32bit processor version for aes and I have tried that as well but got same result)
My hal_ticks() function is still not doing what it is supposed to do.
I would love an input from anyone, below you can see the console output on e2 studio and the physical payload received on the TTN network. I am also attaching the hal.c file that I have made.
Thank you in advance
physical payload received on TTN
406511012680 FFFF 0171F9EF1810C3B61F4D4EDE940844A945CE
console messages while running on e2 studio
Starting..
Time: 0
RXMODE_RSSI
5824: engineUpdate, opmode=0x808
7349: TXMODE, freq=868100000, len=26, SF=7, BW=125, CR=4/5, IH=0
Packet queued
42111: RXMODE_SINGLE, freq=868100000, SF=7, BW=125, CR=4/5, IH=0
73505: RXMODE_SINGLE, freq=869525000, SF=9, BW=125, CR=4/5, IH=0
75435Event
EV_TXCOMPLETE (includes waiting for RX windows)
79028: engineUpdate, opmode=0x900
hal.c file
/*
* hal.c
*
* Created on: Jul 4, 2019
* Author: areeb
*/
/*******************************************************************************
* Copyright (c) 2015 Matthijs Kooijman
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This the HAL to run LMIC on top of the Arduino environment.
*******************************************************************************/
#include <hal/hal.h>
#include "hal_data.h"
#include <stdio.h>
#include "../lmic/lmic.h"
ssp_err_t err;
u4_t t ;
unsigned int ticks=0, fg=0;
u2_t cnt=0 ;
uint32_t scaled = 0, ch=0;
static volatile bool spi_done = false;
static bool dio_states[3] = {0};
void spi_callback(spi_callback_args_t *p_args)
{
SSP_PARAMETER_NOT_USED(p_args);
spi_done= true;
}
void timer0_callback(timer_callback_args_t *p_args)
{
SSP_PARAMETER_NOT_USED(p_args);
ticks++;
}
void irq_callback(external_irq_callback_args_t *p_args)
{
if(p_args->channel == 1)
{
dio_states[0]=1;
radio_irq_handler(0);
dio_states[0]=0;
}
else if(p_args->channel == 2)
{
dio_states[1]=1;
radio_irq_handler(1);
dio_states[0]=0;
}
else if(p_args->channel == 14)
{
dio_states[2]=1;
radio_irq_handler(2);
}
else
{
;
}
// if(p_args->channel == 14)
// {
// radio_irq_handler(2);
// }
}
// -----------------------------------------------------------------------------
// I/O
//#define nss (IOPORT_PORT_04_PIN_13)
//
//#define rst (IOPORT_PORT_05_PIN_11)
u1_t transmit[1]={0},ccc=0;
u1_t recv[1]={0};
static void hal_io_init () {
// g_ioport.p_api->pinDirectionSet(lmic_pins.nss, IOPORT_DIRECTION_OUTPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[0], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[0], IOPORT_DIRECTION_INPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[1], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[1], IOPORT_DIRECTION_INPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[2], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[2], IOPORT_DIRECTION_INPUT);
}
// val == 1 => tx 1
void hal_pin_rxtx (u1_t val) {
}
// set radio RST pin to given value (or keep floating!)
void hal_pin_rst (u1_t val) {
g_ioport.p_api->init(g_ioport.p_cfg);
if(val == 0 || val == 1)
{
g_ioport.p_api->pinCfg(lmic_pins.rst, IOPORT_DIRECTION_OUTPUT);
g_ioport.p_api->pinDirectionSet(lmic_pins.rst, IOPORT_DIRECTION_OUTPUT);
if(val == 0)
g_ioport.p_api->pinWrite(lmic_pins.rst,IOPORT_LEVEL_LOW);
else if (val == 1)
g_ioport.p_api->pinWrite(lmic_pins.rst,IOPORT_LEVEL_HIGH);
}
else
{
g_ioport.p_api->pinCfg(lmic_pins.rst, IOPORT_DIRECTION_INPUT);
g_ioport.p_api->pinDirectionSet(lmic_pins.rst, IOPORT_DIRECTION_INPUT);
}
}
ioport_level_t readpin;
u1_t rd=0;
//static void hal_io_check() {
//
// uint8_t i;
// for (i = 0; i < NUM_DIO; ++i) {
// if (lmic_pins.dio[i] == 0xff)
// continue;
// g_ioport.p_api->pinRead(lmic_pins.dio[i], &readpin);
// if(readpin == IOPORT_LEVEL_HIGH)
// rd = 1;
// else
// rd = 0;
//
// if (dio_states[i] != readpin) {
// dio_states[i] = !dio_states[i];
// if (dio_states[i])
// radio_irq_handler(i);
// }
// }
//
//
//}
void hal_io_check() {
uint8_t i;
// for (i = 0; i < 3; ++i) {
// if (lmic_pins.dio[i] == 0xff)
// continue;
//
// if (dio_states[i] != 0) {
// dio_states[i] = !dio_states[i];
// if (dio_states[i])
// radio_irq_handler(i);
// }
// }
// radio_irq_handler(0);
}
// -----------------------------------------------------------------------------
// SPI
//static const SPISettings settings(10E6, MSBFIRST, SPI_MODE0);
static void hal_spi_init () {
err = g_spi0.p_api->open(g_spi0.p_ctrl,g_spi0.p_cfg);
err = g_timer0.p_api->open(g_timer0.p_ctrl,g_timer0.p_cfg);
err = g_timer0.p_api->start(g_timer0.p_ctrl);
g_external_irq0.p_api->open(g_external_irq0.p_ctrl,g_external_irq0.p_cfg);
g_external_irq0.p_api->enable(g_external_irq0.p_ctrl);
g_external_irq0.p_api->triggerSet(g_external_irq0.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
g_external_irq1.p_api->open(g_external_irq1.p_ctrl,g_external_irq1.p_cfg);
g_external_irq1.p_api->enable(g_external_irq1.p_ctrl);
g_external_irq1.p_api->triggerSet(g_external_irq1.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
g_external_irq2.p_api->open(g_external_irq2.p_ctrl,g_external_irq2.p_cfg);
g_external_irq2.p_api->enable(g_external_irq2.p_ctrl);
g_external_irq2.p_api->triggerSet(g_external_irq2.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
}
void hal_pin_nss (u1_t val) {
g_ioport.p_api->pinDirectionSet(lmic_pins.nss, IOPORT_DIRECTION_OUTPUT);
if(val == 0)
g_ioport.p_api->pinWrite(lmic_pins.nss,IOPORT_LEVEL_LOW);
else if(val == 1)
g_ioport.p_api->pinWrite(lmic_pins.nss,IOPORT_LEVEL_HIGH);
}
// perform SPI transaction with radio
u1_t hal_spi (u1_t out) {
if((out & 0x80) == 0x80)
{
uint8_t temp[1] = {out};
g_spi0.p_api->write(g_spi0.p_ctrl, (const void*)temp,1,SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
return 0;
}
else if((out > 0x00) && (out & 0x80) != 0x80)
{
ccc = out;
uint8_t temp[1] = {out};
g_spi0.p_api->write(g_spi0.p_ctrl, (const void*)temp,1,SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
}
else if(out == 0x00)
{
g_spi0.p_api->read(g_spi0.p_ctrl, recv, sizeof(recv), SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
return recv[0];
}
return recv[0];
}
// -----------------------------------------------------------------------------
// TIME
static void hal_time_init () {
// Nothing to do
}
u4_t hal_ticks () {
// Because micros() is scaled down in this function, micros() will
// overflow before the tick timer should, causing the tick timer to
// miss a significant part of its values if not corrected. To fix
// this, the "overflow" serves as an overflow area for the micros()
// counter. It consists of three parts:
// - The US_PER_OSTICK upper bits are effectively an extension for
// the micros() counter and are added to the result of this
// function.
// - The next bit overlaps with the most significant bit of
// micros(). This is used to detect micros() overflows.
// - The remaining bits are always zero.
//
// By comparing the overlapping bit with the corresponding bit in
// the micros() return value, overflows can be detected and the
// upper bits are incremented. This is done using some clever
// bitwise operations, to remove the need for comparisons and a
// jumps, which should result in efficient code. By avoiding shifts
// other than by multiples of 8 as much as possible, this is also
// efficient on AVR (which only has 1-bit shifts).
// g_timer0.p_api->stop(g_timer0.p_ctrl);
// static uint8_t overflow = 0;
// Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0,
// the others will be the lower bits of our return value.
// u4_t t = ticks;
// g_timer0.p_api->counterGet(g_timer0.p_ctrl, &cnt);
// cnt = 65535-cnt;
// if( (cnt > 65000) && (cnt < 65535 ) )
// {
// g_timer0.p_api->reset(g_timer0.p_ctrl);
// cnt=0;
// t++;
// }
// scaled = ticks >> US_PER_OSTICK_EXPONENT; // 625
// Most significant byte of scaled
// uint8_t msb = scaled >> 24;
// Mask pointing to the overlapping bit in msb and overflow.
// const uint8_t mask = (1 << (7 - US_PER_OSTICK_EXPONENT));
// Update overflow. If the overlapping bit is different
// between overflow and msb, it is added to the stored value,
// so the overlapping bit becomes equal again and, if it changed
// from 1 to 0, the upper bits are incremented.
// overflow += (msb ^ overflow) & mask;
// Return the scaled value with the upper bits of stored added. The
// overlapping bit will be equal and the lower bits will be 0, so
// bitwise or is a no-op for them.
// g_timer0.p_api->start(g_timer0.p_ctrl);
// return scaled | ((uint32_t)overflow << 24);
// 0 leads to correct, but overly complex code (it could just return
// micros() unmodified), 8 leaves no room for the overlapping bit.
// static_assert(US_PER_OSTICK_EXPONENT > 0 && US_PER_OSTICK_EXPONENT < 8, "Invalid US_PER_OSTICK_EXPONENT value");
t = ticks;
//
//// hal_disableIRQs();
///
g_timer0.p_api->counterGet(g_timer0.p_ctrl, &cnt);
if(cnt != 0 )
cnt = 65535 - cnt;
// if( (cnt < 500) )
// {
// g_timer0.p_api->reset(g_timer0.p_ctrl);
// cnt=0;
// t++;
// }
// hal_enableIRQs();
return ((t<<16)|cnt);
}
// Returns the number of ticks until time. Negative values indicate that
// time has already passed.
static s4_t delta_time(u4_t time) {
u4_t t = hal_ticks();
s4_t d = time - t;
if( d<=0 ) return 0; // in the past
if( (d>>16)!=0 ) return 0xFFFF; // far ahead
return (u2_t)d;
}
void hal_waitUntil (u4_t time) {
while( delta_time(time) != 0 );
}
// s4_t delta = delta_time(time);
// // From delayMicroseconds docs: Currently, the largest value that
// // will produce an accurate delay is 16383.
// while (delta > (16000 / US_PER_OSTICK)) {
// R_BSP_SoftwareDelay(16, BSP_DELAY_UNITS_MILLISECONDS);
// delta -= (16000 / US_PER_OSTICK);
// }
// if (delta > 0)
// R_BSP_SoftwareDelay((delta * US_PER_OSTICK), BSP_DELAY_UNITS_MICROSECONDS);
//// delayMicroseconds(delta * US_PER_OSTICK);
//}
// check and rewind for target time
u1_t hal_checkTimer (u4_t time) {
// No need to schedule wakeup, since we're not sleeping
return delta_time(time) <= 0;
}
static uint8_t irqlevel = 0;
void hal_disableIRQs () {
// __disable_irq();
// g_timer0.p_api->close(g_timer0.p_ctrl);
// g_external_irq1.p_api->disable(g_external_irq1.p_ctrl);
// g_external_irq2.p_api->disable(g_external_irq2.p_ctrl);
irqlevel++;
}
void hal_enableIRQs () {
if(--irqlevel == 0) {
// __enable_irq();
// g_timer0.p_api->open(g_timer0.p_ctrl,g_timer0.p_cfg);
// g_external_irq1.p_api->enable(g_external_irq1.p_ctrl);
// g_external_irq2.p_api->enable(g_external_irq2.p_ctrl);
// Instead of using proper interrupts (which are a bit tricky
// and/or not available on all pins on AVR), just poll the pin
// values. Since os_runloop disables and re-enables interrupts,
// putting this here makes sure we check at least once every
// loop.
//
// As an additional bonus, this prevents the can of worms that
// we would otherwise get for running SPI transfers inside ISRs
hal_io_check();
}
hal_io_check();
}
void hal_sleep () {
// Not implemented
}
// -----------------------------------------------------------------------------
#if defined(LMIC_PRINTF_TO)
static int uart_putchar (char c, FILE *)
{
LMIC_PRINTF_TO.write(c) ;
return 0 ;
}
void hal_printf_init() {
// create a FILE structure to reference our UART output function
static FILE uartout;
memset(&uartout, 0, sizeof(uartout));
// fill in the UART file descriptor with pointer to writer.
fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
// The uart is the standard output device STDOUT.
stdout = &uartout ;
}
#endif // defined(LMIC_PRINTF_TO)
void hal_init () {
// configure radio I/O and interrupt handler
hal_io_init();
// configure radio SPI
hal_spi_init();
// configure timer and interrupt handler
hal_time_init();
#if defined(LMIC_PRINTF_TO)
// printf support
hal_printf_init();
#endif
}
void hal_failed (const char *file, u2_t line) {
}

"No Socket Available" - Wifi Shield on Arduino

I have an LDR/Photocell which sends a value 1 or 0 (depending on the value) to a text file on my web address. The code works for a few seconds then prints out No Socket available.
Any help will be appreciated; code below.
#include <SPI.h>
#include <WiFi.h>
int LDR = A0;
int LED = 11;
char ssid[] = "SSID";
char password[] = "password";
int status = WL_IDLE_STATUS;
char server[] = "www.example.com";
int value;
void setup() {
Serial.begin(9600);
pinMode(LDR, INPUT);
pinMode(LED, OUTPUT);
connectWifi();
printWifiStatus();
// postData();
}
void loop() {
value = analogRead(LDR);
postData();
delay(10000);
}
void connectWifi() {
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to ");
Serial.println(ssid);
status = WiFi.begin(ssid, password);
delay(500);
}
}
void printWifiStatus() {
// Print the SSID of the network you're attached to
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// Print your WiFi shield's IP address
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// Print the received signal strength
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
void postData() {
WiFiClient client;
if (client.connect(server, 80)) {
Serial.println("Connecting...");
if (value > 350) {
Serial.println("0");
digitalWrite(LED, LOW);
String data = "value=0";
client.print("GET /example/client.php?");
client.print(data);
client.println(" HTTP/1.1");
client.println("Host: www.example.com");
client.println("Connection: close");
client.println(); client.println();
//client.stop();
} else {
Serial.println("1");
digitalWrite(LED, HIGH);
String data = "value=1";
client.print("GET /example/client.php?");
client.print(data);
client.println(" HTTP/1.1");
client.println("Host: www.example.com");
client.println("Connection: close");
client.println(); client.println();
//client.stop();
}
} else {
Serial.println("Connection failed");
client.stop();
}
}
Output:
Attempting to connect to SSID
SSID: SSID
IP Address: 255.255.255.255
signal strength (RSSI):-47 dBm
Connecting...
1
Connecting...
0
Connecting...
0
Connecting...
0
No Socket available
Connection failed
No Socket available
Connection failed
No Socket available
Connection failed
No Socket available
Actual web address omitted.
first of all, try not use "delay()" and your are calling this function "postData()" every 0,5 seconds. Try use the millis() function to do the timer thing, like this:
unsigned long timerBefore = 0;
const int timer = 1000; //1 second
now inside your loop()
unsigned long timerNow=millis();
if((unsigned long)(timerNow-timerBefore)>=timer){
postData();
timerBefore=millis();
}
that code i'll not "pause" your microcontroller and will call that function every one second.

Get Xbee response from Serial and send to a browser

I am trying to do some experiments with Arduino, Ethernet Shield and Xbee Shield.
I demonstrate my set up board like this:
Group 1: Arduino Uno + Xbee shield : broadcast the signal
Group 2: Arduino Uno + Xbee shield + Ethernet shield: receive the signal from
group 1, get the signal strength from AT command and print it into the browser.
The problem here is I can't get the result after sending to the Serial my ATDB command, actually, I am not sure it did worked as I expected.
Here is the code that I used to retrieve the signal strength.
int data;
void setup()
{
Serial.begin(9600);
}
void receiver_checker(){
delay(1200);
Serial.print("+++");
delay(1200);
bool bOK = false;
while (Serial.available() > 0) {
Serial.write(Serial.read());
bOK = true;
}
if(bOK)
{
Serial.println();
Serial.println("ATDB");
delay(100);
while (Serial.available() > 0) {
Serial.write(Serial.read());
}
Serial.println();
}
Serial.println();
}
void loop()
{
while(Serial.available() > 0){
data = Serial.read();
if(data == '1'){
// Broadcaster 1
//Serial.println("1------------------");
receiver_checker();
}
}
}
This part worked as I expected, it printed out in hex number the signal strength of the last package that it received.
Here is the code I combined the previous one and the server part from Web Server tutorial:
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xCA, 0xFE, 0x00, 0x00, 0x00, 0x02
};
IPAddress ip(1, 1, 1, 2);
int data;
int count = 0;
char result;
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
// Serial.print("server is at ");
// Serial.println(Ethernet.localIP());
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
// Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
// Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
if (Serial.available() > 0) {
// read the oldest byte in the serial buffer:
data = Serial.read();
// if it's a capital H (ASCII 72), turn on the LED:
if (data == '1') {
count += 1;
client.print("The number of times:");
client.print(count);
result = receiver_checker();
client.print("========================");
client.print(result);
client.print("========================");
}
}
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
char receiver_checker(){
char signal;
delay(1200);
Serial.print("+++");
delay(1200);
bool bOK = false;
while (Serial.available() > 0) {
Serial.write(Serial.read());
bOK = true;
}
if(bOK)
{
Serial.println();
Serial.println("ATDB");
delay(100);
while (Serial.available() > 0) {
signal = Serial.read();
}
Serial.println();
}
Serial.println();
return signal;
}
If there is another way to interact with the Xbee shield not go through Serial like I ask and get response directly, please let me know!
Your receiver_checker() function is reading characters back from the XBee module, and just returning the last character received, which is likely a carriage return or line feed.
Update the function to return an int, and replace your while (Serial.available() > 0) with the following:
signal = (int) strtoul(Serial.readString().c_str(), 0, 16);
That's for when the XBee returns a hexadecimal value. If it's returning a decimal value, change the 16 parameter to a 10.

select socket call send and recv synchronization

I am using the select call and accepting the connection from "X" no of clients.
I made duplex connection i.e. server to client and client to server.
When connection is established between 2 entities ,I am going to send
data in chunks from one entity to other.
During send I read one file in chunks and send the data in chunks.
while(file_size !=0)
{
read_bytes = read(fd, buff, sizeof(buff));
cnt_ = send(_sock_fd,buff,actually_read,0);
file_size = file_size - cnt_;
printf("total sent remaining %d : %d\n",size,actually_read);
}
while at receiver side
//First I send the header which contain size it got accepted fine but during the following send call I used "get_readable_bytes" (Using ioctl) which returns me the no of bytes arrived at socket
`while(size != 0)
{
int test_ = 0;
while(((cnt_= get_readable_bytes(_sock_fd))== 0) )//&& test_ == 0
{
cnt_= get_n_readable_bytes(_sock_fd);
printf("Total bytes recved %d\n",cnt_);
//test_ = test_ + 1;
}
while(cnt_ != 0)
{
actually_read = recv(_sock_fd, buff, sizeof(buff),0);
int _cnt = get_n_readable_bytes(_sock_fd);
printf("Total bytes recved %d\n",cnt_-_cnt);
write(_fd,buff,actually_read);
cnt_ = cnt_ - actually_read;
test_ = 0;
}
`Now the problem is
1.During this execution of receive function control automatically go to the select function and it tries to execute whole receive function again so is there any way to synchronize the sender and receivers such that when the sender complete then start receiver or as soon as sender start receiver ?
2.And how do I maintain the count of bytes sent and received.
and this is my select call
`is_read_availble = select(maxfd + 1,&read_set,NULL,NULL,&timeout)`
with timeout 10sec.
Sketch of the kind of buffer code you need. (To allow partial reads/writes, the buffers need to be persistent between calls) BTW: you really need to handle the -1 return from read() and write() because they would seriously disturb your buffer-bookkeeping. EINTR + EAGAIN/EWOULDBLOCK is very common.
struct buff {
unsigned size;
unsigned bot;
unsigned top;
char *buff;
};
struct buff bf = {0,0,0,NULL};
initialisation:
bf.buff = malloc(SOME_SIZE);
/* ... error checking omitted */
bp.size = SOME_SIZE;
bp.bot = bp.top =0;
reading:
unsigned todo;
int rc;
/* (maybe) shift the buffer down to make place */
todo = bf.top - bf.bot;
if (todo) {
memmove (bf.buff, bf.buff + bf.bot, todo);
bf.top = todo; bf.bot = 0;
}
todo = bf.size - bf.top;
if (!todo) { /* maybe throttle? ... */ return; }
rc = read (fd, bf.buff+bp.top, todo);
/* ... error checking omitted */
if (rc == -1) switch (errno) {...}
else if (rc == 0) {...}
else {
total_read += rc;
bp.top += rc;
}
writing:
unsigned todo;
int rc;
todo = bf.top - bf.bot;
if (!todo) { /* maybe juggle fd_set ... */ return; }
rc = write (fd, bf.buff+bp.bot, todo);
/* ... error checking omitted */
if (rc == -1) switch (errno) {...}
else if (rc ==0) { ...}
else {
bp.bot += rc;
total_written += rc;
if (bp.bot == bp.top) bp.bot = bp.top =0;
}
/* ... this is the place to juggle the fd_set for writing */

Bad file descriptor with BSD socket

I keep getting a "Bad file descriptor" error when I try to send data from my tcp server to my tcp client. What does this mean in terms of sockets? I have been at this for awhile now and I don't see what could be wrong with my code. Its basically the same code I was using two days ago and that code worked fine. I was hoping someone could tell me what are common causes of bad file descriptors when trying to send over a socket and how I can go about checking/fixing them. Any help is appreciated. I will post some code below in case it helps.
/*Waits to connect a client. Returns true if successful*/
bool TcpServer::launchServer() {
int status;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET; //ipv4
hints.ai_socktype = SOCK_STREAM; //tcp
//get server info, put into servinfo
if ((status = getaddrinfo("192.168.2.3", port, &hints, &servinfo)) != 0) {
printf("\ngetaddrinfo error: %m", errno);
return false;
}
//make socket
fd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (fd < 0) {
printf("\nserver socket failure %m", errno);
return false;
}
//allow reuse of port
int yes=1;
if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*) &yes,sizeof(int)) == -1) {
perror("setsockopt");
return false;
}
//bind
if(bind (fd, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
return false;
}
//free up space
freeaddrinfo(servinfo);
//listen
if(listen(fd, 5) < 0) {
printf("\nListen error %m", errno);
return false;
}
their_addr_size = sizeof(their_addr);
//accept
comm_fd = accept(fd, (struct sockaddr*)&their_addr, &their_addr_size);
if( comm_fd < 0) {
printf("\nAccept error %m", errno);
return false;
}
return true;
} //END LAUNCHSERVER
void TcpServer::communicate() {
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd = {10, 0}; // the max wait time for an event
int sel; // holds return value for select();
int numRead; //holds return value for read()
int numSent; //holds return value for send()
char in[255]; //in buffer
char out[255]; //out buffer
//clear buffersz
memset(&in, 0, 255);
memset(&out, 0, 255);
while(!done) {
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(comm_fd, &read_flags);
FD_SET(comm_fd, &write_flags);
FD_SET(STDIN_FILENO, &read_flags);
FD_SET(STDIN_FILENO, &write_flags);
//call select
sel = select(comm_fd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
//if an error with select
if(sel < 0)
continue;
//if socket ready for reading
if(FD_ISSET(comm_fd, &read_flags)) {
//clear set
FD_CLR(comm_fd, &read_flags);
memset(&in, 0, 255);
numRead = recv(comm_fd, in, 255, 0);
//if an error, exit
if(numRead < 0) {
printf("\nError reading %m", errno);
myAgent->getRobot()->pauseSensorStream();
done = true;
} //end if error
//if connection closed, exit
else if(numRead == 0) {
printf("\nClosing socket");
close(comm_fd);
done = true;
} //end if connection closed
//if message, call getsendback
else if(in[0] != '\0') {
//std::cout<<"\nClient: "<<in;
getSendBack(in);
} //end if message
} //end if ready for read
//if stdin is ready for reading
if(FD_ISSET(STDIN_FILENO, &read_flags))
fgets(out, 255, stdin);
//if socket ready for writing
if(FD_ISSET(comm_fd, &write_flags)) {
//printf("\nSocket ready for write");
FD_CLR(comm_fd, &write_flags);
//check validity by checking for a digit
if(isdigit(out[0])) {
//create message to send
std::stringstream tosend;
tosend<<"# "<<out;
//std::cout<<"\ntosend: "<<tosend.str();
//send
//********ERROR HAPPENS HERE PRINTS OUT MESSAGE BELOW******
numSent = send(comm_fd, tosend.str().c_str(), tosend.str().length(), 0);
} //end if valid message
//if error, exit
if(numSent < 0) {
printf("\nError sending %m", errno);
done = true;
} //end if error
//wait for message to get there, then clear
usleep(5000);
memset(&out, 0, 255);
} //end if
} //end while
} //END COMMUNICATE
Client code is basically the same.
Your program prints "Bad file descriptor" when errno is EBADF.
From man page of send:
EBADF = An invalid descriptor was specified.
I'm quite sure that the socket is closed before the send() call.
That can happen, because program can go to "ready for writing" branch after "connection closed," branch.
Try the following:
else if(numRead == 0) {
printf("\nClosing socket");
close(comm_fd);
break;
}
Instead of:
else if(numRead == 0) {
printf("\nClosing socket");
close(comm_fd);
done = true;
}
You answered your own question. Without explicitly initializing numSent and numRead, you get garbage, which may happen to be a negative number for numSent, which would cause it to error if there was no digit in the out[] array.