How to collect and analyze sensing data of IoT platform

This post shows how to connect IoT platform to Cloud service and how to display sensing data for graphical analysis.
* Scope of post
* Platform : WIZwiki-W7500
* cloud data loger : data.sparkfun.com (Phant.io)
* cloud chart : analog.io
* IDE; Web-Compiler(mbed.com)
* HTTP Query

data.sparkfun.com

  • What is Phant?
    • Phant is a open source cloud server platform by powered Sparkfun Electronics.
    • Sparkfun created data.spartfun.com ,which is a free cloud service running phant. –
    • To collect data from your device to cloud service, you just need to register a new stream.
    • After register, you get two keys for accessing the data; one is q private key is required to update that stream, other is a public key grants access to any other stream on the service.
    • All communication with Phant is carried out over HTTP. So, your device should be acted as HTTP Client.
    • http://data.sparkfun.com/input/%5BpublicKey%5D?private_key=%5BprivateKey%5D&%5Bfield1%5D=%5Bvalue%5D&%5Bfield2%5D=%5Bvalue%5D

  • Phant : Phant.io

    Phant is a modular node.js based data logging tool for collecting data from the Internet of Things. It is the open source software that powers data.sparkfun.com, and is actively maintained by SparkFun Electronics. Phant is short for elephant. Elephants are known for their remarkable recall ability, so it seemed appropriate to name a data logging project in honor of an animal that never forgets.

analog.io

  • 3rd party of data.sparkfun.com
  • Graphing front end
    >analog.io is a full stack IoT web service and hardware platforms where people can create connected devices and share them with the world. It is designed to solve all kinds of world problems from air pollution, improving farm output or studying the bee population. It is really only limited by the users imagination. (for more detail)
    2015-09-22_19-36-25//embedr.flickr.com/assets/client-code.js

Prepare materials

  • Hardware
    IMG_20150922_195307//embedr.flickr.com/assets/client-code.js

    • mbed platform : WIZwiki-W7500
      • ARM® Cortex™-M0 Core 48MHz
      • 128KB Flash memory
      • 16KB to 48 KB SRAM (Min 16KB available if 32KB socket buffer is used, Max 48KB available if no socket buffer is used)
      • Hardwired TCP/IP Core (8 Sockets, MII: Medium-Independent Interface)
      • 12-bit, 8ch ADC
      • 53 I/Os
      • 1ch Watchdog, 4ch Timers and 8ch PWM
      • 3ch UART
      • 2ch SPI
      • 2ch I2C
    • Sensors (ywrobot easy module shield v1): DHT11
      ywrobot//embedr.flickr.com/assets/client-code.js

  • Registrations

    • data.sparkfun.com
      To create a data stream, head over to data.sparkfun.com, and click “CREATE”.

Software

2015-09-22_20-28-32//embedr.flickr.com/assets/client-code.js
* Used Lib
* WIZnetInterface Lib. : for Ethernet connectivity of W7500
* DHT Lib. : for DHT11 sensor

Codes flow

/*
 *Input Pins, Misc
 * D4 - Temp. and Hum. Sensor
 * D3 - Push buttom
 */
DHT sensor(D4, DHT11);
DigitalIn  triggerPin(D3);
  • Configuration Phat Stuff
/*
 * Phant Stuffs
 * Insert your publicKey
 * Insert your privateKey
 * Generat Fileds; 'Files name shoud be same "field name" in Create Stream form'
 */
char publicKey[] = "insert_your_publicKey";
char privateKey[] = "insert_your_privateKey";
uint8_t NUM_FIELDS = 2;
char fieldNames1[] = "hum";
char fieldNames2[] = "temp";
  • Network Configuration : DHCP Client
   // Enter a MAC address for your controller below.
    uint8_t mac_addr[6] = {0x00, 0x08, 0xDC, 0x00, 0x01, 0x02};     

    printf("initializing Ethernetrn");
    // initializing MAC address
    eth.init(mac_addr);

    // Check Ethenret Link
    if(eth.link() == true)   printf("- Ethernet PHY Link-Done rn");
    else printf("- Ethernet PHY Link- Failrn");

    // Start Ethernet connecting: Trying to get an IP address using DHCP
    if (eth.connect()<0)    printf("Fail - Ethernet Connecing");

    // Print your local IP address:
    printf("IP=%snr",eth.getIPAddress());
    printf("MASK=%snr",eth.getNetworkMask());
    printf("GW=%snr",eth.getGateway());
  • HTTP Client
/*
 *  - If the trigger pin (3) goes low, send the data.
 *      - Get sensing datas by using analogread()
 *      - Call postData
 *          - Open socket as TCP Client
 *          - Try to connet TCP server (data.sparkfun.com); if needs, do DNS clinet for getting IP address of server
 *          - Make query string based on Phant frame
 *          - Send query
 *          - Check for a response from the server, and route it out the serial port.
 */

    while(1)
    {
        if(triggerPin ==0)
        {
            sensor.readData();
            c   = sensor.ReadTemperature(CELCIUS);
            h   = sensor.ReadHumidity();
           printf("Temperature in Celcius: %4.2f", c);
           printf("Humidity is %4.2fn", h, dp, dpf);

          sock.connect("data.sparkfun.com", 80);

          snprintf(http_cmd, http_cmd_sz,  "GET /input/%s?private_key=%s&%s=%2.2f&%s=%3.3f HTTP/1.1rnHost: data.sparkfun.comrnConection: closernrn", 
                                            publicKey, privateKey, fieldNames1, h, fieldNames2, c);
          sock.send_all(http_cmd, http_cmd_sz-1);

          while ( (returnCode = sock.receive(buffer, buffer_sz-1)) > 0)
          {
              buffer[returnCode] = '';
              printf("Received %d chars from server:nr%sn", returnCode, buffer);
          }

          sock.close();         
        }

        wait(2);
    } 

Demo

Serial Monitor

  1. DHCP Clinet message
  2. Press the button to send query to server.
  3. Confirm the response message on serial terminal and data.spark.com/your_stream
    initializing Ethernet
    - Ethernet PHY Link-Done
    IP=192.168.11.224
    MASK=255.255.255.0
    GW=192.168.11.1
    Temperature in Celcius: 27.00Humidity is 55.00
    Received 299 chars from server:
    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: GET,POST,DELETE
    Access-Control-Allow-Headers: X-Requested-With, Phant-Private-Key
    Content-Type: text/plain
    X-Rate-Limit-Limit: 300
    X-Rate-Limit-Remaining: 298
    X-Rate-Limit-Reset: 1441353380.898
    Date: Fri, 04 Sep 20
    Received 299 chars from server:
    15 07:46:03 GMT
    Transfer-Encoding: chunked
    Set-Cookie: SERVERID=phantworker2; path=/
    Cache-control: private
    

https://data.sparkfun.com/office_monitoring

2015-09-04_16-39-51//embedr.flickr.com/assets/client-code.js

analog.io: import stream from data.sparkfun.com/your_stream

Advertisements

WZTOE Coding Guide for WIZwiki-W7500

WIZwiki_W7500

wizwiki_W7500

  • WIZnet W7500
  • 32-bit ARM Cortex-M0
  • 128KB Flash / 48 SRAM
  • Hardware TCP/IP coe (WIZnet TCP/IP Engine)
  • 64TQFP( 7x7mm)

  • CMSIS-DAP

  • SWD Con.

  • WIZwiki-W7500 feature

  • Arduino Pin compatible

  • ISP / SD Slot / REG LED
  • Ethernet PHY

HW : MII Interface

MII Interface
* WZTOE Signals

W7500_WZTOE Ethernet PHY
PD_00 CRS
PD_01 RXDV
PD_02 RXD0
PD_03 RXD1
PD_04 RXD2
PD_06 RXD3
PB_04 TXEN
PB_05 COL
PB_07 RXCLK
PB_08 DUP
PB_09 TXCLK
PB_10 TXD0
PB_11 TXD1
PB_12 TXD2
PB_13 TXD3
  • MDIO via GPIO

    Management Data Input/Output (MDIO), also known as Serial Management Interface (SMI) or Media Independent Interface Management (MIIM), is a serial bus defined for the Ethernet family of IEEE 802.3 standards for the Media Independent Interface, or MII. The MII connects Media Access Control (MAC) devices with Ethernet physical layer (PHY) circuits.
    http://en.wikipedia.org/wiki/Management_Data_Input/Output

  • PB_14 — MDIO (@IC+101)

  • PB_15 — MDC (@IC+101

SW : (will update code location)

  • ioLibary :“Internet Offload Library” for WIZnet chip. It includes drivers and application protocols.
    $\W7500_FW\Projects\Peripheral_Examples\WZTOE\ioLibrary

  • MDIO via GPIO: It Includes the MDIO Read and Write functions.
    $\W7500_FW\Projects\Peripheral_Examples\WZTOE\ioLibrary\MDIO\W7500x_miim.h
    $\W7500_FW\Projects\Peripheral_Examples\WZTOE\ioLibrary\MDIO\W7500x_miim.c

  • W7500 WZTOE (WIZnet TCPIP Engine) Driver
    $\W7500_FW\Libraries\W7500x_stdPeriph_Driver\inc\W7500x_WZTOE.h
    $\W7500_FW\Libraries\W7500x_stdPeriph_Driver\src\W7500x_WZTOE.c

Coding Guides

  • To use accurate Ticker of 1usec, set WZ100US value according to main clock(HCLK)
/* Set WZ_100US Register */
setTIC100US((GetSystemClock()/10000));
//getTIC100US();
//printf(" GetSystemClock: %X, getTIC100US: %X, (%X) rn",
// GetSystemClock, getTIC100US(), *(uint32_t *)TIC100US);
  • To clear Interrupt register, use Interrupt Clear Register (ICR) , Socket Interrupt Clear Register(Sn_ICR).
setSn_IMR(socket_number, interrupt_mask_bits);
...
socket_interrupt_state = getSn_IR(socket_number);
...
socket_interrupt_state = setSn_ICR(socket_number, interrupt_clear_bit);
  • To use previous codes, setSn_ICR() is warped by setSn_IR().

  • How to access WZTOE
    Memory map of TOE memory

  • Registers

#define WZTOE_COMMON_REGISTER_BASEADDR (0x4100_0000)
#define WZTOE_SOCKET_REGISTER_BASEADDR(sock_num) (0x4101_0000 + (sock_num)<<18))

/* Write to wztoe common register with offset address of 3 */
offset_addr = 3;
*(volatile uint32_t *)(WZTOE_COMMON_REGISTER_BASEADDR + offset_addr) = 0x12;

/* Read to wztoe socket 3 register with offset address of 8 */
sock_num = 3;
offset_addr = 8;
val = *(volatile uint32_t *)(WZTOE_SOCKET_REGISTER_BASEADDR(sock_num) + offset_addr)
  • TX/RX Buffer
    Cortex-m0 is able to access by 32-bits address. However, Sn_TX_WR(Socket n TX Write Pointer Register) and Sn_RX_RD (Socket n RX Read Pointer Register) is only the lower 16 bits of the pointer. Hence, to calcurate the address boundary, offset address shoud be masked by 0xFFFF.
#define WZTOE_SOCKET_TXBUF_BASEADDR(sock_num) (0x4102_0000 + (sock_num)<<18))
#define WZTOE_SOCKET_RXBUF_BASEADDR(sock_num) (0x4103_0000 + (sock_num)<<18))

/* Write to wztoe TX buffer with offset address of 3 */
sock_num = 3;
offset_addr = 0x0001_0000;
*(volatile uint32_t *)(WZTOE_SOCKET_TXBUF_BASEADDR(sock_num) + (offset_addr&0xFFFF)) = 0x12;

/* Read to wztoe RX buffer with offset address of 8 */
sock_num = 2;
offset_addr = 8;
val = *(volatile uint32_t *)(WZTOE_SOCKET_RXBUF_BASEADDR(sock_num) + (offset_addr&0xFFFF)
  • API for TX/RX Buffer
void WIZCHIP_READ_BUF (uint32_t BaseAddr, uint32_t ptr, uint8_t* pBuf, uint16_t len)
{
uint16_t i = 0;
WIZCHIP_CRITICAL_ENTER();

for(i = 0; i < len; i++)
pBuf[i] = *(volatile uint8_t *)(BaseAddr +((ptr+i)&0xFFFF));

WIZCHIP_CRITICAL_EXIT();
}

void WIZCHIP_WRITE_BUF(uint32_t BaseAddr, uint32_t ptr, uint8_t* pBuf, uint16_t len)
{
uint16_t i = 0;
WIZCHIP_CRITICAL_ENTER();

for( i=0; i<len; i++)
*(volatile uint8_t *)(BaseAddr + ((ptr+i)&0xFFFF)) = pBuf[i];

WIZCHIP_CRITICAL_EXIT();
}

void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
{
uint32_t ptr = 0;
uint32_t sn_tx_base = 0;

if(len == 0) return;
ptr = getSn_TX_WR(sn);
sn_tx_base = (TXMEM_BASE) | ((sn&0x7)<<18);
WIZCHIP_WRITE_BUF(sn_tx_base, ptr, wizdata, len);
ptr += len;
setSn_TX_WR(sn,ptr);
}

void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
{
uint32_t ptr = 0;
uint32_t sn_rx_base = 0;

if(len == 0) return;
ptr = getSn_RX_RD(sn);
sn_rx_base = (RXMEM_BASE) | ((sn&0x7)<<18); WIZCHIP_READ_BUF(sn_rx_base, ptr, wizdata, len); ptr += len; setSn_RX_RD(sn,ptr); } ``` ### MDIO via GPIO * Port Init. ```cpp /* Set GPIOs for MDIO and MDC */ GPIO_InitTypeDef GPIO_InitDef; GPIO_InitDef.GPIO_Pin = GPIO_Pin_MDC | GPIO_Pin_MDIO; GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT; GPIO_Init(GPIOx, &GPIO_InitDef); PAD_AFConfig(PAD_PB, GPIO_Pin_MDIO, PAD_AF1); PAD_AFConfig(PAD_PB, GPIO_Pin_MDC, PAD_AF1); ``` * MDIO APIs ```cpp uint32_t link(void) { return ((mdio_read(GPIOB, PHYREG_STATUS)>>SVAL)&0x01);
}

void set_link(SetLink_Type mode)
{
uint32_t val=0;
assert_param(IS_SETLINK_TYPE(mode));

if( mode == CNTL_AUTONEGO)
{
val = CNTL_AUTONEGO;
}
else
{
val = (mode & (CNTL_SPEED|CNTL_DUPLEX));
}

mdio_write(GPIOB, PHYREG_CONTROL, val);

}
  • MDIO Read/Write Functions
void output_MDIO(GPIO_TypeDef* GPIOx, uint32_t val, uint32_t n)
{
for(val <<= (32-n); n; val<<=1, n--)
{
if(val & 0x80000000)
GPIO_SetBits(GPIOx, MDIO);
else
GPIO_ResetBits(GPIOx, MDIO);

delay(1);
GPIO_SetBits(GPIOx, MDC);
delay(1);
GPIO_ResetBits(GPIOx, MDC);
}
}

uint32_t input_MDIO( GPIO_TypeDef* GPIOx )
{
uint32_t i, val=0;
for(i=0; i<16; i++)
{
val <<=1;
GPIO_SetBits(GPIOx, MDC);
delay(1);
GPIO_ResetBits(GPIOx, MDC);
delay(1);
val |= GPIO_ReadInputDataBit(GPIOx, MDIO);
}
return (val);
}