Other Parts Discussed in Thread: CODECOMPOSER, UNIFLASH
Hi,
Up until a few hours ago, I've had no problem programming and connecting to my DK-TM4C129X board. However, shortly after trying to program a modified qs_weather onto the board, I can no longer talk to the board. That is, the board's QVGA is turned on, and the ICDI power, 5 V and 3.3 V LEDs are both on, but nothing else is. Pressing the Reset button has no apparent effect. None of the ICs on the board are heating up.
When I try to program the board through CodeComposer, I get the error: "Error connecting to the target", and then "Unable to connect to the target", before CCS crashes with the output:
# # An unexpected error has been detected by Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x0822ebad, pid=2815, tid=2181499712 # # Java VM: Java HotSpot(TM) Client VM (11.3-b02 mixed mode linux-x86) # Problematic frame: # C 0x0822ebad # # An error report file with more information is saved as: # /opt/ti3/uniflashv3/eclipse/hs_err_pid2815.log # # If you would like to submit a bug report, please visit: # http://java.sun.com/webapps/bugreport/crash.jsp #
I tried downloading UniFlash to try and do a Debug Port Unlock, but I get the error message:
Flash operation NCO_DebugPortUnlock failed on core Stellaris In-Circuit Debug Interface/CORTEX_M4_0 .
I also tried programming the board using lm4flash (not LMFlash - I'm on Linux), and I get the output:
badvariant@sinking-raft /opt/ti3/uniflashv3/eclipse $ ~/bin/lm4flash ~/workspace/tivaware/examples/boards/dk-tm4c129x/blinky/gcc/blinky.bin Found ICDI device with serial: ICDI version: 9270
The program never finishes executing.
Ideas? Is the board damaged beyond repair, for whatever reason? Thanks.
The code that I think was last run on the board (debug session) is a modified version of qs_weather. The two slightly modified files are attached. 7416.qs_weather.c
//*****************************************************************************
//
// eth_client.c - This file handles all of the Ethernet connections using lwIP.
//
// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 2.1.0.12573 of the DK-TM4C129X Firmware Package.
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/flash.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "utils/lwiplib.h"
#include "lwip/dns.h"
#include "driverlib/systick.h"
#include "lwip/dns.h"
#include "eth_client.h"
#include "json.h"
//*****************************************************************************
//
// Flag indexes for g_sEnet.ui32Flags
//
//*****************************************************************************
#define FLAG_TIMER_DHCP_EN 0
#define FLAG_TIMER_DNS_EN 1
#define FLAG_TIMER_TCP_EN 2
#define FLAG_DHCP_STARTED 3
#define FLAG_DNS_ADDRFOUND 4
//*****************************************************************************
//
// g_sEnet.ulRequest Values
//
//*****************************************************************************
#define WEATHER_NONE 0
#define WEATHER_CURRENT 1
#define WEATHER_FORECAST 2
//*****************************************************************************
//
// The current state of the Ethernet connection.
//
//*****************************************************************************
struct
{
volatile uint32_t ui32Flags;
//
// Array to hold the MAC addresses.
//
uint8_t pui8MACAddr[8];
//
// Global define of the TCP structure used.
//
struct tcp_pcb *psTCP;
//
// Global IP structure to hold a copy of the IP address.
//
struct ip_addr sLocalIP;
//
// Global IP structure to hold a copy of the DNS resolved address.
//
struct ip_addr sServerIP;
//
// The saved proxy name as a text string.
//
const char *pcProxyName;
volatile enum
{
iEthNoConnection,
iEthDHCPWait,
iEthDHCPComplete,
iEthDNSWait,
iEthTCPConnectWait,
iEthTCPConnectComplete,
iEthQueryWait,
iEthTCPOpen,
iEthIdle
} eState;
unsigned long ulRequest;
tEventFunction pfnEvent;
}
g_sEnet;
//*****************************************************************************
//
// Maximum size of an weather request.
//
//*****************************************************************************
#define MAX_REQUEST 256
extern uint32_t g_ui32SysClock;
//*****************************************************************************
//
// Various strings used to access weather information on the web.
//
//*****************************************************************************
static const char g_cWeatherRequest[] =
"GET http://api.openweathermap.org/data/2.5/weather?q=";
static const char g_cWeatherRequestForecast[] =
"GET http://api.openweathermap.org/data/2.5/forecast/daily?q=";
static const char g_cMode[] = "&mode=json&units=metric";
static char g_cAPPIDOpenWeather[] =
"&APIID=afc5370fef1dfec1666a5676346b163b";
static char g_cHTTP11[] = " HTTP/1.0\r\n\r\n";
//*****************************************************************************
//
// CUSTOM: Defines and function declarations
//
//*****************************************************************************
static const char g_BatteryStatusUpdateRequest[] =
"GET /reqdump.php?var1=test HTTP/1.1\r\nHost: aquasol-solutions.no-ip.biz\r\nConnection: close\r\n\r\n";
/*"GET /~badvani/index.html HTTP/1.1\r\nHost: www.sfu.ca\r\nConnection: close\r\n\r\n";*/
/*"GET www.sfu.ca/~badvani/index.html";*/
/*"GET 24.87.64.193:10000/~emartin/LOL/";*/
static const char g_jsonTest[] = "GET http://ip.jsontest.com";
static char g_cHTTP_append[] = " HTTP/1.0\r\nHost:\r\n\r\n";
int32_t
BatteryUpdateRequestForecast(tWeatherSource eWeatherSource, const char *pcQuery,
tWeatherReport *psWeatherReport, tEventFunction pfnEvent);
int32_t
BatteryUpdateRequestCurrent(tWeatherSource eWeatherSource, const char *pcQuery,
tWeatherReport *psWeatherReport, tEventFunction pfnEvent);
//*****************************************************************************
//
// This structure holds the state and control values for the weather requests.
//
//*****************************************************************************
struct
{
//
// The current weather source.
//
tWeatherSource eWeatherSource;
//
// The format expected from the weather source.
//
enum
{
iFormatJSON
}
eFormat;
//
// The application provided callback function.
//
tEventFunction pfnEvent;
//
// The application provided weather information structure.
//
tWeatherReport *psWeatherReport;
//
// The local buffer used to store the current weather request.
//
char pcRequest[MAX_REQUEST];
//
// The number of valid bytes in the request.
//
uint32_t ui32RequestSize;
}
g_sWeather;
//*****************************************************************************
//
// Close an active connection.
//
//*****************************************************************************
void
EthClientReset(void)
{
//
// No longer have a link.
//
g_sEnet.eState = iEthNoConnection;
//
// Reset the flags to just enable the lwIP timer.
//
g_sEnet.ui32Flags = (1 << FLAG_TIMER_DHCP_EN);
//
// Reset the addresses.
//
g_sEnet.sLocalIP.addr = 0;
g_sEnet.sServerIP.addr = 0;
//
// Deallocate the TCP structure if it was already allocated.
//
if(g_sEnet.psTCP)
{
//
// Clear out all of the TCP callbacks.
//
tcp_sent(g_sEnet.psTCP, NULL);
tcp_recv(g_sEnet.psTCP, NULL);
tcp_err(g_sEnet.psTCP, NULL);
//
// Close the TCP connection.
//
tcp_close(g_sEnet.psTCP);
g_sEnet.psTCP = 0;
}
}
//*****************************************************************************
//
// Handles lwIP TCP/IP errors.
//
// \param vPArg is the state data for this connection.
// \param iErr is the error that was detected.
//
// This function is called when the lwIP TCP/IP stack has detected an error.
// The connection is no longer valid.
//
// \return None.
//
//*****************************************************************************
static void
TCPError(void *vPArg, err_t iErr)
{
}
//*****************************************************************************
//
// Finalizes the TCP connection in client mode.
//
// \param pvArg is the state data for this connection.
// \param psPcb is the pointer to the TCP control structure.
// \param psBuf is the buffer structure that holds the data for this receive
// event.
// \param iErr is not used in this implementation.
//
// This function is called when the lwIP TCP/IP stack has completed a TCP
// connection.
//
// \return This function will return an lwIP defined error code.
//
//*****************************************************************************
static err_t
TCPReceive(void *pvArg, struct tcp_pcb *psPcb, struct pbuf *psBuf, err_t iErr)
{
struct pbuf *psBufCur;
int32_t i32Items;
if(psBuf == 0)
{
//
// Tell the application that the connection was closed.
//
if(g_sWeather.pfnEvent)
{
g_sWeather.pfnEvent(ETH_EVENT_CLOSE, 0, 0);
g_sWeather.pfnEvent = 0;
}
//
// Close out the port.
//
tcp_close(psPcb);
if(psPcb == g_sEnet.psTCP)
{
g_sEnet.psTCP = 0;
}
g_sEnet.eState = iEthIdle;
return(ERR_OK);
}
if(g_sEnet.eState == iEthQueryWait)
{
if(g_sEnet.ulRequest == WEATHER_CURRENT)
{
//
// Read items from the buffer.
//
i32Items = JSONParseCurrent(0, g_sWeather.psWeatherReport, psBuf);
//
// Make sure some items were found.
//
if(i32Items > 0)
{
if(g_sWeather.pfnEvent)
{
g_sWeather.pfnEvent(ETH_EVENT_RECEIVE,
(void *)g_sWeather.psWeatherReport, 0);
//
// Clear the event function and return to the idle state.
//
g_sEnet.eState = iEthIdle;
}
}
else if(i32Items < 0)
{
if(g_sWeather.pfnEvent)
{
//
// This was not a valid request.
//
g_sWeather.pfnEvent(ETH_EVENT_INVALID_REQ, 0, 0);
//
// Clear the event function and return to the idle state.
//
g_sEnet.eState = iEthIdle;
}
}
}
else if(g_sEnet.ulRequest == WEATHER_FORECAST)
{
//
// Read items from the buffer.
//
i32Items = JSONParseForecast(0, g_sWeather.psWeatherReport, psBuf);
if(i32Items > 0)
{
if(g_sWeather.pfnEvent)
{
g_sWeather.pfnEvent(ETH_EVENT_RECEIVE,
(void *)g_sWeather.psWeatherReport, 0);
//
// Clear the event function and return to the idle state.
//
g_sEnet.eState = iEthIdle;
}
}
else if(i32Items < 0)
{
if(g_sWeather.pfnEvent)
{
//
// This was not a valid request.
//
g_sWeather.pfnEvent(ETH_EVENT_INVALID_REQ, 0, 0);
//
// Clear the event function and return to the idle state.
//
g_sEnet.eState = iEthIdle;
}
}
}
}
else
{
//
// Go to idle state.
//
g_sEnet.eState = iEthIdle;
}
//
// Initialize the linked list pointer to parse.
//
psBufCur = psBuf;
//
// Free the buffers used since they have been processed.
//
while(psBufCur->len != 0)
{
//
// Indicate that you have received and processed this set of TCP data.
//
tcp_recved(psPcb, psBufCur->len);
//
// Go to the next buffer.
//
psBufCur = psBufCur->next;
//
// Terminate if there are no more buffers.
//
if(psBufCur == 0)
{
break;
}
}
//
// Free the memory space allocated for this receive.
//
pbuf_free(psBuf);
//
// Return.
//
return(ERR_OK);
}
//*****************************************************************************
//
// Handles acknowledgment of data transmitted via Ethernet.
//
// \param pvArg is the state data for this connection.
// \param psPcb is the pointer to the TCP control structure.
// \param ui16Len is the length of the data transmitted.
//
// This function is called when the lwIP TCP/IP stack has received an
// acknowledgment for data that has been transmitted.
//
// \return This function will return an lwIP defined error code.
//
//*****************************************************************************
static err_t
TCPSent(void *pvArg, struct tcp_pcb *psPcb, u16_t ui16Len)
{
//
// Return OK.
//
return (ERR_OK);
}
//*****************************************************************************
//
// Finalizes the TCP connection in client mode.
//
// \param pvArg is the state data for this connection.
// \param psPcb is the pointer to the TCP control structure.
// \param iErr is not used in this implementation.
//
// This function is called when the lwIP TCP/IP stack has completed a TCP
// connection.
//
// \return This function will return an lwIP defined error code.
//
//*****************************************************************************
static err_t
TCPConnected(void *pvArg, struct tcp_pcb *psPcb, err_t iErr)
{
//
// Check if there was a TCP error.
//
if(iErr != ERR_OK)
{
//
// Clear out all of the TCP callbacks.
//
tcp_sent(psPcb, NULL);
tcp_recv(psPcb, NULL);
tcp_err(psPcb, NULL);
//
// Close the TCP connection.
//
tcp_close(psPcb);
if(psPcb == g_sEnet.psTCP)
{
g_sEnet.psTCP = 0;
}
//
// And return.
//
return (ERR_OK);
}
//
// Setup the TCP receive function.
//
tcp_recv(psPcb, TCPReceive);
//
// Setup the TCP error function.
//
tcp_err(psPcb, TCPError);
//
// Setup the TCP sent callback function.
//
tcp_sent(psPcb, TCPSent);
//
// Connection is complete.
//
g_sEnet.eState = iEthTCPConnectComplete;
//
// Return a success code.
//
return(ERR_OK);
}
//*****************************************************************************
//
// TCP connect
//
// This function attempts to connect to a TCP endpoint.
//
// \return None.
//
//*****************************************************************************
err_t
EthClientTCPConnect(uint32_t ui32Port)
{
err_t eTCPReturnCode;
//
// Enable the TCP timer function calls.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_TCP_EN) = 1;
if(g_sEnet.psTCP)
{
//
// Initially clear out all of the TCP callbacks.
//
tcp_sent(g_sEnet.psTCP, NULL);
tcp_recv(g_sEnet.psTCP, NULL);
tcp_err(g_sEnet.psTCP, NULL);
//
// Make sure there is no lingering TCP connection.
//
tcp_close(g_sEnet.psTCP);
}
//
// Create a new TCP socket.
//
g_sEnet.psTCP = tcp_new();
//
// Check if you need to go through a proxy.
//
if(g_sEnet.pcProxyName != 0)
{
//
// Attempt to connect through the proxy server.
//
eTCPReturnCode = tcp_connect(g_sEnet.psTCP, &g_sEnet.sServerIP,
ui32Port, TCPConnected);
}
else
{
//
// Attempt to connect to the server directly.
//
eTCPReturnCode = tcp_connect(g_sEnet.psTCP, &g_sEnet.sServerIP,
ui32Port, TCPConnected);
}
return(eTCPReturnCode);
}
//*****************************************************************************
//
// TCP connect
//
// This function attempts to connect to a TCP endpoint.
//
// \return None.
//
//*****************************************************************************
void
EthClientTCPDisconnect(void)
{
//
// No longer have a link.
//
g_sEnet.eState = iEthNoConnection;
//
// Deallocate the TCP structure if it was already allocated.
//
if(g_sEnet.psTCP)
{
//
// Close the TCP connection.
//
tcp_close(g_sEnet.psTCP);
g_sEnet.psTCP = 0;
}
}
//*****************************************************************************
//
// Handler function when the DNS server gets a response or times out.
//
// \param pcName is DNS server name.
// \param psIPAddr is the DNS server's IP address.
// \param vpArg is the configurable argument.
//
// This function is called when the DNS server resolves an IP or times out.
// If the DNS server returns an IP structure that is not NULL, add the IP to
// to the g_sEnet.sServerIP IP structure.
//
// \return None.
//
//*****************************************************************************
static void
DNSServerFound(const char *pcName, struct ip_addr *psIPAddr, void *vpArg)
{
//
// Check if a valid DNS server address was found.
//
if(psIPAddr != NULL)
{
//
// Copy the returned IP address into a global IP address.
//
g_sEnet.sServerIP = *psIPAddr;
//
// Tell the main program that a DNS address was found.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_DNS_ADDRFOUND) = 1;
}
else
{
//
// Disable the DNS timer.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 0;
}
}
//*****************************************************************************
//
// Required by lwIP library to support any host-related timer functions.
//
//*****************************************************************************
void
lwIPHostTimerHandler(void)
{
}
//*****************************************************************************
//
// Send a request to the server
//
// \param pcRequest request to be sent
// \param ui32Size length of the request to be sent. this is usually the size
// of the request minus the termination character
//
// This function will send the request to the connected server
//
// \return the lwIP error code.
//
//*****************************************************************************
err_t
EthClientSend(char *pcRequest, uint32_t ui32Size)
{
err_t eError;
eError = tcp_write(g_sEnet.psTCP, pcRequest, ui32Size,
TCP_WRITE_FLAG_COPY);
//
// Write data for sending (but does not send it immediately).
//
if(eError == ERR_OK)
{
//
// Find out what we can send and send it
//
tcp_output(g_sEnet.psTCP);
}
return(eError);
}
//*****************************************************************************
//
// DHCP connect
//
// This function obtains the MAC address from the User registers, starts the
// DHCP timer and blocks until an IP address is obtained.
//
// \return None.
//
//*****************************************************************************
err_t
EthClientDHCPConnect(void)
{
//
// Check if the DHCP has already been started.
//
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_DHCP_STARTED) == 0)
{
//
// Set the DCHP started flag.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_DHCP_STARTED) = 1;
}
else
{
//
// If DHCP has already been started, we need to clear the IPs and
// switch to static. This forces the LWIP to get new IP address
// and retry the DHCP connection.
//
lwIPNetworkConfigChange(0, 0, 0, IPADDR_USE_STATIC);
//
// Restart the DHCP connection.
//
lwIPNetworkConfigChange(0, 0, 0, IPADDR_USE_DHCP);
}
return ERR_OK;
}
//*****************************************************************************
//
// Handler function when the DNS server gets a response or times out.
//
// \param pcName is DNS server name.
//
// This function is called when the DNS server resolves an IP or times out.
// If the DNS server returns an IP structure that is not NULL, add the IP to
// to the g_sEnet.sServerIP IP structure.
//
// \return None.
//
//*****************************************************************************
int32_t
EthClientDNSResolve(const char *pcName)
{
err_t iRet;
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN))
{
return(ERR_INPROGRESS);
}
//
// Set DNS config timer to true.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 1;
//
// Initialize the host name IP address found flag to false.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_DNS_ADDRFOUND) = 0;
//
// Resolve host name.
//
iRet = dns_gethostbyname(pcName, &g_sEnet.sServerIP, DNSServerFound, 0);
/*IP4_ADDR(&g_sEnet.sServerIP, 24, 87, 64, 193);*/
//
// If ERR_OK is returned, the local DNS table resolved the host name. If
// ERR_INPROGRESS is returned, the DNS request has been queued and will be
// sent to the DNS server.
//
if(iRet == ERR_OK)
{
//
// Stop calling the DNS timer function.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 0;
}
//
// Return host name not found.
//
return(iRet);
}
//*****************************************************************************
//
// Returns the IP address for this interface.
//
// This function will read and return the currently assigned IP address for
// the Tiva Ethernet interface.
//
// \return Returns the assigned IP address for this interface.
//
//*****************************************************************************
uint32_t
EthClientAddrGet(void)
{
//
// Return IP.
//
return(lwIPLocalIPAddrGet());
}
//*****************************************************************************
//
// Returns the weather server IP address for this interface.
//
// This function will read and return the weather server IP address that is
// currently in use. This could be the proxy server if the Internet proxy
// is enabled.
//
// \return Returns the weather server IP address for this interface.
//
//*****************************************************************************
uint32_t
EthClientServerAddrGet(void)
{
//
// Return IP.
//
return((uint32_t)g_sEnet.sServerIP.addr);
}
//*****************************************************************************
//
// Returns the MAC address for the Tiva Ethernet controller.
//
// \param pui8MACAddr is the 6 byte MAC address assigned to the Ethernet
// controller.
//
// This function will read and return the MAC address for the Ethernet
// controller.
//
// \return Returns the weather server IP address for this interface.
//
//*****************************************************************************
void
EthClientMACAddrGet(uint8_t *pui8MACAddr)
{
int32_t iIdx;
for(iIdx = 0; iIdx < 6; iIdx++)
{
pui8MACAddr[iIdx] = g_sEnet.pui8MACAddr[iIdx];
}
}
//*****************************************************************************
//
// Set the proxy string for the Ethernet connection.
//
// \param pcProxyName is the string used as the proxy server name.
//
// This function sets the current proxy used by the Ethernet connection. The
// \e pcProxyName value can be 0 to indicate that no proxy is in use or it can
// be a pointer to a string that holds the name of the proxy server to use.
// The content of the pointer passed to \e pcProxyName should not be changed
// after this call as this function only stores the pointer and does not copy
// the data from this pointer.
//
// \return None.
//
//*****************************************************************************
void
EthClientProxySet(const char *pcProxyName)
{
//
// Save the new proxy string.
//
g_sEnet.pcProxyName = pcProxyName;
//
// Reset the connection on any change to the proxy.
//
EthClientReset();
}
//*****************************************************************************
//
// Initialize the Ethernet client
//
// This function initializes all the Ethernet components to not configured.
// This tells the SysTick interrupt which timer modules to call.
//
// \return None.
//
//*****************************************************************************
void
EthClientInit(tEventFunction pfnEvent)
{
uint32_t ui32User0, ui32User1;
//
// Initialize all the Ethernet components to not configured. This tells
// the SysTick interrupt which timer modules to call.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DHCP_EN) = 0;
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 0;
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_TCP_EN) = 0;
g_sEnet.eState = iEthNoConnection;
g_sEnet.pfnEvent = pfnEvent;
//
// Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC
// address needed to program the hardware registers, then program the MAC
// address into the Ethernet Controller registers.
//
FlashUserGet(&ui32User0, &ui32User1);
g_sEnet.pui8MACAddr[0] = ((ui32User0 >> 0) & 0xff);
g_sEnet.pui8MACAddr[1] = ((ui32User0 >> 8) & 0xff);
g_sEnet.pui8MACAddr[2] = ((ui32User0 >> 16) & 0xff);
g_sEnet.pui8MACAddr[3] = ((ui32User1 >> 0) & 0xff);
g_sEnet.pui8MACAddr[4] = ((ui32User1 >> 8) & 0xff);
g_sEnet.pui8MACAddr[5] = ((ui32User1 >> 16) & 0xff);
lwIPInit(g_ui32SysClock, g_sEnet.pui8MACAddr, 0, 0, 0, IPADDR_USE_DHCP);
//
// Start lwIP tick interrupt.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DHCP_EN) = 1;
}
//*****************************************************************************
//
// Periodic Tick for the Ethernet client
//
// This function is the needed periodic tick for the Ethernet client. It needs
// to be called periodically through the use of a timer or systick.
//
// \return None.
//
//*****************************************************************************
void
EthClientTick(uint32_t ui32TickMS)
{
uint32_t ui32IPAddr;
int32_t i32Ret;
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DHCP_EN))
{
lwIPTimer(ui32TickMS);
}
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN))
{
dns_tmr();
}
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_TCP_EN))
{
tcp_tmr();
}
//
// Check for loss of link.
//
if((g_sEnet.eState != iEthNoConnection) &&
(lwIPLocalIPAddrGet() == 0xffffffff))
{
//
// Reset the connection due to a loss of link.
//
EthClientReset();
//
// Signal a disconnect event.
//
g_sEnet.pfnEvent(ETH_EVENT_DISCONNECT, 0, 0);
}
else if(g_sEnet.eState == iEthNoConnection)
{
//
// Once link is detected start DHCP.
//
if(lwIPLocalIPAddrGet() != 0xffffffff)
{
EthClientDHCPConnect();
g_sEnet.eState = iEthDHCPWait;
}
}
else if(g_sEnet.eState == iEthDHCPWait)
{
//
// Get IP address.
//
ui32IPAddr = lwIPLocalIPAddrGet();
//
// If IP Address has not yet been assigned, update the display
// accordingly.
//
if((ui32IPAddr != 0xffffffff) && (ui32IPAddr != 0))
{
//
// Update the DHCP IP address.
//
g_sEnet.sLocalIP.addr = ui32IPAddr;
g_sEnet.eState = iEthDHCPComplete;
//
// Stop DHCP timer since an address has been provided.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_DHCP_STARTED) = 0;
}
}
else if(g_sEnet.eState == iEthDHCPComplete)
{
if(g_sEnet.pcProxyName == 0)
{
//
// Resolve the host by name.
//
/*i32Ret = EthClientDNSResolve("api.openweathermap.org");*/
i32Ret = EthClientDNSResolve("aquasol-solutions.no-ip.biz");
/*i32Ret = EthClientDNSResolve("ip.jsontest.com");*/
/*i32Ret = EthClientDNSResolve("www.sfu.ca");*/
}
else
{
//
// Resolve the proxy by name.
//
i32Ret = EthClientDNSResolve(g_sEnet.pcProxyName);
}
if(i32Ret == ERR_OK)
{
//
// If the address was already returned then go to idle.
//
g_sEnet.eState = iEthIdle;
//
// Notify the main routine of the new Ethernet connection.
//
g_sEnet.pfnEvent(ETH_EVENT_CONNECT, &g_sEnet.sLocalIP.addr, 4);
}
else if(i32Ret == ERR_INPROGRESS)
{
//
// If the request is pending the go to the iEthDNSWait state.
//
g_sEnet.eState = iEthDNSWait;
}
}
else if(g_sEnet.eState == iEthDNSWait)
{
//
// Check if the host name was resolved.
//
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_DNS_ADDRFOUND))
{
//
// Stop calling the DNS timer function.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 0;
g_sEnet.eState = iEthIdle;
//
// Notify the main routine of the new Ethernet connection.
//
g_sEnet.pfnEvent(ETH_EVENT_CONNECT, &g_sEnet.sLocalIP.addr, 4);
}
}
else if(g_sEnet.eState == iEthTCPConnectWait)
{
}
else if(g_sEnet.eState == iEthTCPConnectComplete)
{
err_t eError;
g_sEnet.eState = iEthTCPOpen;
eError = EthClientSend(g_sWeather.pcRequest,
g_sWeather.ui32RequestSize);
if(eError == ERR_OK)
{
//
// Waiting on a query response.
//
g_sEnet.eState = iEthQueryWait;
}
else
{
g_sEnet.eState = iEthIdle;
}
}
}
//*****************************************************************************
//
// Set the current weather source.
//
//*****************************************************************************
void
WeatherSourceSet(tWeatherSource eWeatherSource)
{
//
// Save the source.
//
g_sWeather.eWeatherSource = eWeatherSource;
g_sWeather.eFormat = iFormatJSON;
}
//*****************************************************************************
//
// Merges strings into the current request at a given pointer and offset.
//
//*****************************************************************************
static int32_t
MergeRequest(int32_t i32Offset, const char *pcSrc, int32_t i32Size,
bool bReplaceSpace)
{
int32_t i32Idx;
//
// Copy the base request to the buffer.
//
for(i32Idx = 0; i32Idx < i32Size; i32Idx++)
{
if((pcSrc[i32Idx] == ' ') && (bReplaceSpace))
{
if((i32Offset + 3) >= sizeof(g_sWeather.pcRequest))
{
break;
}
g_sWeather.pcRequest[i32Offset++] = '%';
g_sWeather.pcRequest[i32Offset++] = '2';
g_sWeather.pcRequest[i32Offset] = '0';
}
else
{
g_sWeather.pcRequest[i32Offset] = pcSrc[i32Idx];
}
if((i32Offset >= sizeof(g_sWeather.pcRequest)) ||
(pcSrc[i32Idx] == 0))
{
break;
}
i32Offset++;
}
return(i32Offset);
}
//*****************************************************************************
//
// Custom Battery Request
//
//*****************************************************************************
int32_t
BatteryUpdateRequestForecast(tWeatherSource eWeatherSource, const char *pcQuery,
tWeatherReport *psWeatherReport, tEventFunction pfnEvent)
{
int32_t i32Idx;
const char pcCount[] = "&cnt=1";
//
// If the requested source is not valid or there is no call back then
// just fail.
//
if((eWeatherSource != iWSrcOpenWeatherMap) || (g_sWeather.pfnEvent))
{
return (-1);
}
g_sWeather.pfnEvent = pfnEvent;
g_sWeather.psWeatherReport = psWeatherReport;
//
// Connect or reconnect to port 80.
//
g_sEnet.eState = iEthTCPConnectWait;
//
// Copy the base forecast request to the buffer.
//
i32Idx = MergeRequest(0, g_BatteryStatusUpdateRequest,
sizeof(g_BatteryStatusUpdateRequest), false);
/*i32Idx = MergeRequest(0, g_jsonTest,*/
/*sizeof(g_jsonTest), false);*/
//
// Append the request.
//
/*i32Idx = MergeRequest(i32Idx, pcQuery, sizeof(g_sWeather.pcRequest),*/
/*true);*/
//
// Append the request mode.
//
/*i32Idx = MergeRequest(i32Idx, g_cMode, sizeof(g_cMode), false);*/
//
// Append the count.
//
/*i32Idx = MergeRequest(i32Idx, pcCount, sizeof(pcCount), false);*/
//
// Append the App ID.
//
/*i32Idx = MergeRequest(i32Idx, g_cAPPIDOpenWeather,*/
/*sizeof(g_cAPPIDOpenWeather), false);*/
//
// Append the "HTTP:/1.1" string.
//
/*i32Idx = MergeRequest(i32Idx, g_cHTTP_append, sizeof(g_cHTTP_append), false);*/
//
// Forcast weather report request.
//
g_sEnet.ulRequest = WEATHER_FORECAST;
if(EthClientTCPConnect(80) != ERR_OK)
/*if(EthClientTCPConnect(10000) != ERR_OK)*/
{
return(-1);
}
//
// Save the size of the request.
//
g_sWeather.ui32RequestSize = i32Idx;
return(0);
}
int32_t
BatteryUpdateRequestCurrent(tWeatherSource eWeatherSource, const char *pcQuery,
tWeatherReport *psWeatherReport, tEventFunction pfnEvent)
{
int32_t i32Idx;
//
// If the requested source is not valid or there is no call back then
// just fail.
//
if((eWeatherSource != iWSrcOpenWeatherMap) || (g_sWeather.pfnEvent))
{
return (-1);
}
g_sWeather.pfnEvent = pfnEvent;
g_sWeather.psWeatherReport = psWeatherReport;
//
// Copy the base current request to the buffer.
//
/*i32Idx = MergeRequest(0, g_jsonTest,*/
/*sizeof(g_jsonTest), false);*/
i32Idx = MergeRequest(0, g_BatteryStatusUpdateRequest,
sizeof(g_BatteryStatusUpdateRequest), false);
//
// Append the request.
//
/*i32Idx = MergeRequest(i32Idx, pcQuery, sizeof(g_sWeather.pcRequest), true);*/
//
// Append the request mode.
//
/*i32Idx = MergeRequest(i32Idx, g_cMode, sizeof(g_cMode), false);*/
//
// Append the App ID.
//
/*i32Idx = MergeRequest(i32Idx, g_cAPPIDOpenWeather,*/
/*sizeof(g_cAPPIDOpenWeather), false);*/
//
// Append the "HTTP:/1.1" string.
//
/*i32Idx = MergeRequest(i32Idx, g_cHTTP11, sizeof(g_cHTTP11), false);*/
//
// Save the size of this request.
//
g_sWeather.ui32RequestSize = i32Idx;
//
// Connect or reconnect to port 80.
//
g_sEnet.eState = iEthTCPConnectWait;
//
// Current weather report request.
//
g_sEnet.ulRequest = WEATHER_CURRENT;
//
// Connect to server
//
if(EthClientTCPConnect(80) != ERR_OK)
{
return(-1);
}
return(0);
}
//*****************************************************************************
//
// Gets the daily forecast for a given city.
//
//*****************************************************************************
int32_t
WeatherForecast(tWeatherSource eWeatherSource, const char *pcQuery,
tWeatherReport *psWeatherReport, tEventFunction pfnEvent)
{
int32_t i32Idx;
const char pcCount[] = "&cnt=1";
//
// If the requested source is not valid or there is no call back then
// just fail.
//
if((eWeatherSource != iWSrcOpenWeatherMap) || (g_sWeather.pfnEvent))
{
return (-1);
}
g_sWeather.pfnEvent = pfnEvent;
g_sWeather.psWeatherReport = psWeatherReport;
//
// Connect or reconnect to port 80.
//
g_sEnet.eState = iEthTCPConnectWait;
//
// Copy the base forecast request to the buffer.
//
i32Idx = MergeRequest(0, g_cWeatherRequestForecast,
sizeof(g_cWeatherRequestForecast), false);
//
// Append the request.
//
i32Idx = MergeRequest(i32Idx, pcQuery, sizeof(g_sWeather.pcRequest),
true);
//
// Append the request mode.
//
i32Idx = MergeRequest(i32Idx, g_cMode, sizeof(g_cMode), false);
//
// Append the count.
//
i32Idx = MergeRequest(i32Idx, pcCount, sizeof(pcCount), false);
//
// Append the App ID.
//
i32Idx = MergeRequest(i32Idx, g_cAPPIDOpenWeather,
sizeof(g_cAPPIDOpenWeather), false);
//
// Append the "HTTP:/1.1" string.
//
i32Idx = MergeRequest(i32Idx, g_cHTTP11, sizeof(g_cHTTP11), false);
//
// Forcast weather report request.
//
g_sEnet.ulRequest = WEATHER_FORECAST;
if(EthClientTCPConnect(80) != ERR_OK)
{
return(-1);
}
//
// Save the size of the request.
//
g_sWeather.ui32RequestSize = i32Idx;
return(0);
}
//*****************************************************************************
//
// Gets the current weather information for a given city.
//
//*****************************************************************************
int32_t
WeatherCurrent(tWeatherSource eWeatherSource, const char *pcQuery,
tWeatherReport *psWeatherReport, tEventFunction pfnEvent)
{
int32_t i32Idx;
//
// If the requested source is not valid or there is no call back then
// just fail.
//
if((eWeatherSource != iWSrcOpenWeatherMap) || (g_sWeather.pfnEvent))
{
return (-1);
}
g_sWeather.pfnEvent = pfnEvent;
g_sWeather.psWeatherReport = psWeatherReport;
//
// Copy the base current request to the buffer.
//
i32Idx = MergeRequest(0, g_cWeatherRequest, sizeof(g_cWeatherRequest),
false);
//
// Append the request.
//
i32Idx = MergeRequest(i32Idx, pcQuery, sizeof(g_sWeather.pcRequest), true);
//
// Append the request mode.
//
i32Idx = MergeRequest(i32Idx, g_cMode, sizeof(g_cMode), false);
//
// Append the App ID.
//
i32Idx = MergeRequest(i32Idx, g_cAPPIDOpenWeather,
sizeof(g_cAPPIDOpenWeather), false);
//
// Append the "HTTP:/1.1" string.
//
i32Idx = MergeRequest(i32Idx, g_cHTTP11, sizeof(g_cHTTP11), false);
//
// Save the size of this request.
//
g_sWeather.ui32RequestSize = i32Idx;
//
// Connect or reconnect to port 80.
//
g_sEnet.eState = iEthTCPConnectWait;
//
// Current weather report request.
//
g_sEnet.ulRequest = WEATHER_CURRENT;
//
// Connect to server
//
if(EthClientTCPConnect(80) != ERR_OK)
{
return(-1);
}
return(0);
}
Edit: the LEDs that are on are D9 (5V ON), D10 (3.3V ON), D1 (ICDI POWER) and D2 (STATUS).