I have a problem with my esp8266 project. My purpose is to use esp8266 to transmit beacon frames every one second so that my android device or my laptop can receive it and display in list of APs which i can connect to.
Here is my code I wrote:
#include <ESP8266WiFi.h>
extern "C" {
#include "user_interface.h"
}
void setup() {
delay(500);
sendBeacon("ESP8266");
ESP.deepSleep(10e5);
}
void loop() {
}
void sendBeacon(char* ssid) {
// Randomize channel //
byte channel = 1;
wifi_set_channel(channel);
uint8_t packet[128] = { 0x80, 0x00, //Frame Control
0x00, 0x00, //Duration
/*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //Destination address
/*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //Source address - overwritten later
/*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //BSSID - overwritten to the same as the source address
/*22*/ 0xc0, 0x6c, //Seq-ctl
//Frame body starts here
/*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, //timestamp - the number of microseconds the AP has been active
/*32*/ 0xFF, 0x00, //Beacon interval
/*34*/ 0x01, 0x04, //Capability info
/* SSID */
/*36*/ 0x00
};
int ssidLen = strlen(ssid);
packet[37] = ssidLen;
for(int i = 0; i < ssidLen; i++) {
packet[38+i] = ssid[i];
}
uint8_t postSSID[13] = {0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, //supported rate
0x03, 0x01, 0x04 /*DSSS (Current Channel)*/ };
for(int i = 0; i < 12; i++) {
packet[38 + ssidLen + i] = postSSID[i];
}
packet[50 + ssidLen] = channel;
// get SRC MAC
unsigned char mac[6];
WiFi.macAddress(mac);
packet[10] = packet[16] = mac[0];
packet[11] = packet[17] = mac[1];
packet[12] = packet[18] = mac[2];
packet[13] = packet[19] = mac[3];
packet[14] = packet[20] = mac[4];
packet[15] = packet[21] = mac[5];
int packetSize = 51 + ssidLen;
wifi_send_pkt_freedom(packet, packetSize, 0);
delay(1);
}
I used tcpdump to capture those frame and yes, they are there. But I still couldn't see it in list of AP on my laptop and my android device.
I can see it if I stop using deep sleep mode. For example:
#include <ESP8266WiFi.h>
extern "C" {
#include "user_interface.h"
}
void setup() {
delay(500);
// sendBeacon("ESP8266");
// ESP.deepSleep(10e5);
}
void loop() {
sendBeacon("ESP8266");
}
void sendBeacon(char* ssid) {
// Randomize channel //
byte channel = 1;
wifi_set_channel(channel);
uint8_t packet[128] = { 0x80, 0x00, //Frame Control
0x00, 0x00, //Duration
/*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //Destination address
/*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //Source address - overwritten later
/*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //BSSID - overwritten to the same as the source address
/*22*/ 0xc0, 0x6c, //Seq-ctl
//Frame body starts here
/*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, //timestamp - the number of microseconds the AP has been active
/*32*/ 0xFF, 0x00, //Beacon interval
/*34*/ 0x01, 0x04, //Capability info
/* SSID */
/*36*/ 0x00
};
int ssidLen = strlen(ssid);
packet[37] = ssidLen;
for(int i = 0; i < ssidLen; i++) {
packet[38+i] = ssid[i];
}
uint8_t postSSID[13] = {0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, //supported rate
0x03, 0x01, 0x04 /*DSSS (Current Channel)*/ };
for(int i = 0; i < 12; i++) {
packet[38 + ssidLen + i] = postSSID[i];
}
packet[50 + ssidLen] = channel;
// get SRC MAC
unsigned char mac[6];
WiFi.macAddress(mac);
packet[10] = packet[16] = mac[0];
packet[11] = packet[17] = mac[1];
packet[12] = packet[18] = mac[2];
packet[13] = packet[19] = mac[3];
packet[14] = packet[20] = mac[4];
packet[15] = packet[21] = mac[5];
int packetSize = 51 + ssidLen;
wifi_send_pkt_freedom(packet, packetSize, 0);
delay(1);
}
Does anyone know why? Please help me to get this, thanks!
First of all, ESP.deepSleep(10e5) makes the processor sleep for 100ms, not a second. The correct would be ESP.deepSleep(10e6). Secondly, you are trying to send just one packet every second or so, it's quite hard to make sure that the wifi reading from the device is gonna get that packet for sure and display it on the list of SSIDs. From my experiments, I had to send three packets every 200ms to make sure it was displayed on my android mobile and pc. You can try to play with the number of packets you send and the interval to see what fits you best...
Also, make sure to configure the ESP correctly at the setup function. When I tried my similar code I had to use two instructions: wifi_set_opmode(STATION_MODE) and wifi_promiscuous_enable(1)
UPDATE: I can't even get this calculator to reproduce the SMBus PECs illustrated in figures 8 and 9 of this datasheet!
So I'm interfacing an arduino with a Melexis temperature sensor, and it's going okay--aside from the fact that I can't seem to get the CRC check to work.
I've gotten read operations to complete successfully (although my software ignores the packet error code) but I have tried a lot of implementations of CRC8 to check the PEC byte to no avail. The code block I am using now came from OneWire:
uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *addr++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
I rewrote it to consider just the one byte:
int smbCRC(int message) {
uint8_t crc = 0;
uint8_t inbyte = message & 0xFF;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
return crc;
}
But its CRC does not match that of the MLX datasheet (Figure 8 from here for example). When I print an int with its CRC8 like so:
int message = 0x3aD2;
lcd.print(String(message,HEX) + " " + String(smbCRC(message),HEX));
I get back "3ad2 eb", though the datasheet says the correct PEC is 0x30. Where am I going wrong? It seems like this could be caused by a bad implementation of CRC or bad assumptions on my part about the CRC input, and I'm not sure where to start troubleshooting.
I haven't checked your CRC implementation but there is a mistake in the MLX datasheet or at least it's badly written. You have to include all the I2C frame's data for the PEC's calculation not just the replied data.
For a read word command you have to include [SA_W, Command, SA_R, LSB, MSB] and for a write word command [SA_W, Command, LSB, MSB].
So, for their first example the calculation must be made on [ 0xB4, 0x07, 0xB5, 0xD2, 0x3A ] and not just on [ 0xD2, 0x3A ] and this way you get the expected 0x30.
Here is a simple C implementation of the CRC with a lookup table (non Arduino but it must be quite simple to adapt):
static const uint8_t crc_table[] = {
0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31,
0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9,
0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1,
0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe,
0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16,
0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80,
0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8,
0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10,
0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f,
0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef,
0xfa, 0xfd, 0xf4, 0xf3
};
uint8_t
crc8(uint8_t *p, uint8_t len)
{
uint16_t i;
uint16_t crc = 0x0;
while (len--) {
i = (crc ^ *p++) & 0xFF;
crc = (crc_table[i] ^ (crc << 8)) & 0xFF;
}
return crc & 0xFF;
}
It is possible to get the compiler to figure out the lookup table for you, as follows:
#include <stdio.h>
#include <stdint.h>
/* * *
* Just change this define to whatever polynomial is in use
*/
#define CRC1B(b) ( (uint8_t)((b)<<1) ^ ((b)&0x80? 0x07 : 0) ) // MS first
/* * *
* 8+1 entry enum lookup table define
*/
#define CRC(b) CRC_##b // or CRC8B(b)
enum {
CRC(0x01) = CRC1B(0x80),
CRC(0x02) = CRC1B(CRC(0x01)),
CRC(0x04) = CRC1B(CRC(0x02)),
CRC(0x08) = CRC1B(CRC(0x04)),
CRC(0x10) = CRC1B(CRC(0x08)),
CRC(0x20) = CRC1B(CRC(0x10)),
CRC(0x40) = CRC1B(CRC(0x20)),
CRC(0x80) = CRC1B(CRC(0x40)),
// Add 0x03 to optimise in CRCTAB1
CRC(0x03) = CRC(0x02)^CRC(0x01)
};
/* * *
* Build a 256 byte CRC constant lookup table, built from from a reduced constant
* lookup table, namely CRC of each bit, 0x00 to 0x80. These will be defined as
* enumerations to take it easy on the compiler. This depends on the relation:
* CRC(a^b) = CRC(a)^CRC(b)
* In other words, we can build up each byte CRC as the xor of the CRC of each bit.
* So CRC(0x05) = CRC(0x04)^CRC(0x01). We include the CRC of 0x03 for a little more
* optimisation, since CRCTAB1 can use it instead of CRC(0x01)^CRC(0x02), again a
* little easier on the compiler.
*/
#define CRCTAB1(ex) CRC(0x01)ex, CRC(0x02)ex, CRC(0x03)ex,
#define CRCTAB2(ex) CRCTAB1(ex) CRC(0x04)ex, CRCTAB1(^CRC(0x04)ex)
#define CRCTAB3(ex) CRCTAB2(ex) CRC(0x08)ex, CRCTAB2(^CRC(0x08)ex)
#define CRCTAB4(ex) CRCTAB3(ex) CRC(0x10)ex, CRCTAB3(^CRC(0x10)ex)
#define CRCTAB5(ex) CRCTAB4(ex) CRC(0x20)ex, CRCTAB4(^CRC(0x20)ex)
#define CRCTAB6(ex) CRCTAB5(ex) CRC(0x40)ex, CRCTAB5(^CRC(0x40)ex)
/* * *
* This is the final lookup table. It is rough on the compiler, but generates the
* required lookup table automagically at compile time.
*/
static const uint8_t crc_table[256] = { 0, CRCTAB6() CRC(0x80), CRCTAB6(^CRC(0x80)) };
uint8_t crc8(uint8_t *p, uint8_t len)
{
uint8_t crc = 0x0;
while (len--) {
crc = crc_table[crc ^ *p++];
}
return crc;
}
void main( void )
{
int i, j;
printf("static const uint8_t crc_table[] = {");
for (i = 0; i < 0x10; i++)
{
printf("\n ");
for (j = 0; j < 0x10; j++)
{
printf( " 0x%02x,", crc_table[i*0x10+j] );
}
}
printf("\n};\n\n");
}
See reference on following links:
http://www.melexis.com/Asset/SMBus-communication-with-MLX90614-DownloadLink-5207.aspx
http://www.sbs-forum.org/marcom/dc2/20_crc-8_firmware_implementations.pdf
Function code for Arduino:
byte c8( byte x ){
for( byte i = 8; i--; ) {
x = ( x << 1 ) ^ ( x & 128 ? 7 : 0 );
}
return x;
}
void setup() {
Serial.begin( 9600 );
int msg = 0x3AD2;
Serial.print( '0x' );
Serial.print( c8( msg ), HEX );
// '0x30' is displayed on Serial Monitor
}
void loop() {}
Since argument x is strong-typed as byte (uint8_t), word-size data (such 0x3AD2) will be truncated to byte-size (which is 0xD2 in case of 0x3AD2).
Stripped code from linux kernel code, i am using it for smbus pec calculation..
#include<stdio.h>
#define POLY (0x1070U << 3)
#define DST_SLAVE_ADDRESS 0x1d //7-bit Slave Address
static unsigned char crc8(short int data)
{
int i;
for (i = 0; i < 8; i++) {
if (data & 0x8000)
data = data ^ POLY;
data = data << 1;
}
return (unsigned char)(data >> 8);
}
unsigned char i2c_smbus_pec(unsigned char crc, unsigned char *p, int count)
{
int i;
for (i = 0; i < count; i++)
crc = crc8((crc ^ p[i]) << 8);
return crc;
}
/* Assume a 7-bit address, which is reasonable for SMBus */
static unsigned char i2c_smbus_msg_pec(unsigned char slave_addr, char *msg, int len)
{
/* The address will be sent first */
unsigned char addr = slave_addr << 1;
int pec;
pec = i2c_smbus_pec(0, &addr, 1);
/* The data buffer follows */
return i2c_smbus_pec(pec, msg, len);
}
main()
{
//SMBUS PEC include everthing include dst slave address
//dst i2c address here is 0x1d (7bit) , 0x3a (8bit)
char msg[] = {0x0F,0x19,0x21,0x01,0x00,0x00,0xEB,0x84,0x08,0x00,0x00,0x01,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xAA,0xEF,0x81,0xB4};
//dst i2c address here is 0x10 (7bit) , 0x20 (8bit)
//char msg[] = { 0x0F,0x19,0x3B,0x01,0x00,0x00,0xD3,0x84,0x88,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x30,0xFF,0xEF,0x00,0x00,0x00,0x00,0x00,0x21,0xE5,0xD5,0xA8};
int len = sizeof(msg);
int calc_pec = i2c_smbus_msg_pec(DST_SLAVE_ADDRESS, msg , len);
printf("pec = 0x%x\n", calc_pec);
}
I am working on a project, and I am trying to get a grasp of it. Using the WiShield. I have been trying to complete the example program for a simple tweeter. However, I have had no luck yet. I have been trying to find the solutions, and everything I find never seems to work. How do I fix this problem?
My code is below as well as the errors I receive.
Code
#include <WiServer.h>
#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2
unsigned char local_ip[] = {192,168,2,2};
unsigned char gateway_ip[] = {192,168,2,1};
unsigned char subnet_mask[] = {255,255,255,0};
const prog_char ssid[] PROGMEM = {"myssid"};
unsigned char security_type = 3; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2
const prog_char security_passphrase[] PROGMEM = {"mywifipassword"};
prog_uchar wep_keys[] PROGMEM = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3
};
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
unsigned char ssid_len;
unsigned char security_passphrase_len;
// Authentication string for the Twitter account.
char* auth = "[user:pass]"; // Base64 encoded USERNAME:PASSWORD
// This function generates a message with the current system time.
void currentTime() {
WiServer.print("Arduino has been running for ");
WiServer.printTime(millis());
}
// A request that sends a tweet using the currentTime function.
TWEETrequest sentMyTweet(auth, currentTime);
void setup() {
// Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages).
WiServer.init(NULL);
// Enable Serial output and ask WiServer to generate log messages (optional).
Serial.begin(57600);
WiServer.enableVerboseMode(true);
}
// Time (in milliseconds) when the next tweet should be sent.
long tweetTime = 0;
void loop(){
// Check if it's time to sent a tweet
if (millis() >= tweetTime) {
sentMyTweet.submit();
// Send next tweet 5 minutes from now
tweetTime += 1000 * 60 * 5;
}
// Run WiServer
WiServer.server_task();
delay(10);
}
Errors
In file included from SimpleTweeter.cpp:5:
C:\Program Files (x86)\arduino-1.0\libraries\WiShield/WiServer.h:198: error: conflicting return type specified for 'virtual void Server::write(uint8_t)'
C:\Program Files (x86)\arduino-1.0\hardware\arduino\cores\arduino/Print.h:48: error: overriding 'virtual size_t Print::write(uint8_t)'
SimpleTweeter.pde:-1: error: 'TWEETrequest' does not name a type
SimpleTweeter.cpp: In function 'void loop()':
SimpleTweeter.pde:-1: error: 'sentMyTweet' was not declared in this scope
(I am new to Arduino.)
It looks like the WiServer library hasn't been upgraded to work with Arduino 1.0. In this version of the Arduino software, the return type of the write method in the Print class was changed from void to size_t.
There is a fork of WiShield on GitHub by Juan C. Muller which makes it compatible with Arduino 1.0.
The subsequent error about the type TWEETrequest is a knock-on effect of this previous error.