Fun with interrupts on MSP-EXP430FR5739 FRAM Experimenter Board

Print Friendly

Just a small program coded for learning interrupts. Code is commented and self explanatory.

Hardware :TI MSP-EXP430FR5739 FRAM Experimenter Board

Target Board

Software : Code Composer Studio Version: 4.2.3.00004

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/* Blink LEDs using button S1 and S2 and interrupts.
 * In MSP-EXP430FR5739 FRAM board there are 8 user programmable LEDs
 * four of them are connected to PORTJ pins 0..3 and
 * another four are to PORT3 4..7 pins.
 * LEDs are connected to GND via current limiting resistors.
 * Button S1 and S2 are connected to GND via PORT4 0&1 respectively
 * --coded by Ishan Karve (ishan.karve@gmail.com), Feb 12 as part of his self learning process
 */


#include <msp430fr5739.h>

//defines for MSP-430FR5739 EXP Board
#define S1  BIT0 //P4.0
#define S2  BIT1 //P4.1
#define LED0    BIT0 //PJ.0
#define LED1    BIT1 //PJ.1
#define LED2    BIT2 //PJ.2
#define LED3    BIT3 //PJ.3
#define LED4    BIT4 //P3.4
#define LED5    BIT5 //P3.5
#define LED6    BIT6 //P3.6
#define LED7    BIT7 //P3.7

void main(){
    //stop watchdog
    WDTCTL = WDTPW + WDTHOLD;
    //Select pins 4,5,6,7 of Port 3 and 0 to 3 of Port J for output
    PJDIR|=(LED0+LED1+LED2+LED3);
    P3DIR|=(PWR+LED4+LED5+LED6+LED7);
    //turn off leds on both P3 and PJ
    PJOUT&amp;=~(LED0+LED1+LED2+LED3);
    P3OUT&amp;=~(LED4+LED5+LED6+LED7);
    //setup interrupts for buttons S1 and S2
    P4DIR=0x00; //all ports as inputs
    P4IE|=(S1+S2);  //enable interrupts for S1 button
    //Button S1 and S2 are in active-low configuration
    P4REN=(S1+S2);//enable pullups on resoective ports
    //Since S1,S2 are in an active low config,
    //the other end of the resistor has to be pulled high
    P4OUT=(S1+S2);
    P4IFG&amp;=~(S1+S2); //clear interrupt flag
    _enable_interrupt();
    for (;;)
    {
        //do nothing.interrupt routine will take charge
    }
}

// Port 4 interrupt service routine
#pragma vector=PORT4_VECTOR
__interrupt void Port_4(void)
{
    if(P4IFG&amp;S1) { //check if S1 was pressed
        P4IFG &amp;= ~S1;    // clear the interrupt flag
        PJOUT^=(LED0+LED1+LED2+LED3);//toggle leds on Port J
    }

    if(P4IFG&amp;S2) { //check if S2 was pressed
        P4IFG &amp;= ~S2;    // clear the interrupt flag
        P3OUT^=(LED4+LED5+LED6+LED7);//toggle leds on Port 3
    }

 }
Posted in Electronics, MSP-GCC, MSP430 | Tagged , , , , , , | Leave a comment

APC UPS Shutdown Manager

Print Friendly

I work in an office where working late in the night is the norm including weekends.. This post is not about my office or about the work we do late into the night but about a problem statement posed to me by my subordinates. It goes like this..

The office or rather the building rules demand that we shut down (hard off) all electrical equipment once the office is finally shut for the day. This means that our office servers also requires to be shut down along with the UPS (APC SMART 2200). Now this has nothing to do with our office trying to be green but more to do about obviating any fire risks.

So, whats the problem. The problem is that, once we (management) leave the office, the duty staff has to shut down all the equipment including the servers. The issue is that our two servers running WindoZe 2008 R2 and WindoZe 2003 take about 15 minutes to shut down cleanly. And the UPS then needs to be shutdown afterwards. 15 minutes may seem a small time interval for an office which works routinely for 15+ hours in a day in a single shifts 7 days a week. But at night 2330 when its time to go home every minute looks like an hour to the subordinate staff.  So the problem was narrated to me over a short tea break. Since I believe in working Smarter and not Harder, I decided to save 15 man minutes every day.

Thus (coming to the point), this post describes a circuit / contraption I have devised which shuts down the  UPS once it detects that both the computers dependent upon it have secured for the day.

Detection of the state of the servers is done by pinging the servers at a predetermined time interval.  However generally since persistent ICMP pings are blocked by firewalls, I have decided to do an ARP request to find the state of servers. So in a nutshell if a server responds to ARP request it is deemed to be alive.

The Arduino board communicates with the UPS over a serial port. The serial communication is done at 2400 8N1, No handshake. The communication protocol used is well discussed and elaborated here. Once the micro-controller detects that the servers are down for a defined time interval, it is assumed that the servers are off and a shutdown command is then  issued to the UPS via Serial Port.

However, during the day time there is a possibility that the network (read physical media) might itself be under maintenance or the network switch might be down due to a power outage, so there emerges a possibility that the server may not respond to any ARP requests, leading to a shutdown of the UPS and thereby causing an unclean server shutdown.

To circumnavigate this issue, it becomes  essential that the microcontroller  knows the time of the day and shutdowns the servers only after 2000 hrs . The solution to this problem is a simple RTC clock. Now how does the RTC update its own time.. NTP. One of my server functions as an NTP server and I decided to use the same to update my RTC clock one when its booted up.  Once this was done, the code was modfied accordingly.

RTC Module

Knowing time of the day was also essential since I had to switch on the UPS and then the servers. UPS is switched on via a serial command and the servers are switched on via a Wake on Lan (WOL) magic packet. Not implemented since I have configured the Server’s Bios to WakeUp on restoration of power on.

I have also thrown in a DS18B20 temperature sensor to measure the ambient room temperature.

The system state including UPS statistics are available on a webpage… The Arduino  board also behaves like a webserver.

Connection Matrix

 

 

 

Code (Sans NTP +RTC Part)

#include <OneWire.h>
#include "EtherShield.h"
#include <Wire.h>
#include <RTClib.h>

//---------------defines for EtherShield----------------------
#define MYWWWPORT 80               //www server port
#define BUFFER_SIZE 1200
static uint8_t buf[BUFFER_SIZE+1]; //data buffer
static uint8_t mymac[6] = {0x54,0x55,0x58,0x12,0x34,0x56 };
static uint8_t myip[4] = {159,12,23,148};
static uint8_t Server1ip[4] = {159,12,23,160};
static uint8_t Server2ip[4] = {159,12,23,150};
static uint8_t ntpServer[4] = {159,12,23,150};
long server_poll_interval=30000; //query/ping server status every n seconds
uint16_t print_webpage(uint8_t *buf); //function prototype
EtherShield es=EtherShield(); //instantiate class

//---------------defines for UPS Manager----------------------
long serialtimeout=500; //time in milliseconds to timeout serial port response
long serial_poll_interval=60000; //query ups every minute
int shutdown_grace=5; //time in minutes after which shutdown command will be issued to ups
int ups_shut_flag=2;//1-> UPS OFF 0->UPS ON 2-> dont know
long shutdown_interval=0;
int server1=0; //server1 flag
int server2=0; //server2 flag
boolean ups_state=false; //ups flag
char line_voltage[6];
char line_freq[6];
char batt_voltage[6];
char load_voltage[6];
char load_factor[6];
char batt_level[6];
char estimated_runtime[6];
char status_flag[6];
char ups_flag[6];
char response[5];
char internal_temp[6];
char external_temp[6];
char time_string[50];

//---------------defines for RTC , NTP & DS18S20 Temperature Module--------------------
OneWire  ds(6); //Sensor connecd to pin 6
#define SECONDS_FROM_1900_TO_1970 2208988800  
RTC_DS1307 RTC;
//---------------function----------------------------------------------------------------
uint16_t http200ok(void)
{
  return(es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n")));
}

// prepare the webpage by writing the data to the tcp send buffer
uint16_t print_webpage(uint8_t *buf)
{
 // get_RTC_time(time_string);
  uint16_t plen;
  plen=http200ok();
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<center><p><h1>Welcome to Ishan-s UPS Shutdown Manager V0.1 </h1></p> "));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<hr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<table border=1 align=center>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>Server 1 Status</th><th>Server2 Status</th><th>UPS Status</th></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><td align=center><strong>"));
  if(server1==1)
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("ON"));
  else
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("OFF"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</strong></td><td align=center><strong>"));
  if(server2==1)
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("ON"));
  else
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("OFF"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</strong></td><td align=center><strong>"));
  if(ups_state)
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("ON"));
  else
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("OFF"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</strong></td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</table>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<h2 align=center>UPS Status</h2>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<table align=center border=1>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>Line Voltage (Volts)</th><td>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,line_voltage,6);
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>Line Frequency (Hz)</th><td>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,line_freq,6);
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>Battery Voltage (Volts)</th><td>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,batt_voltage,6);
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>Output Voltage (Volts)</th><td>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,load_voltage,6);
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>UPS Load (%)</th><td>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,load_factor,6);
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>Battery Level (%)</th><td>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,batt_level,6);
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>Internal Temp(deg C)</th><td>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,internal_temp,6);
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>External Ambient Temp(deg C)</th><td>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,external_temp,6);
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<tr><th>Estimated Runtime (Minutes)</th><td>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,estimated_runtime,6);
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</td></tr>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</table>"));
  plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<hr>"));
  plen=es.ES_fill_tcp_data_len(buf,plen,time_string,50);

  if (plen >= BUFFER_SIZE)
  {
    plen=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<center><p><h1>Welcome to Ishan-s UPS Shutdown Manager V0.1 </h1></p> "));
    plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<p><h1>Error: buffer is too small...</h1></p> "));
  }

  return(plen);
}

void setup(){
  pinMode(16,OUTPUT);
  pinMode(17,OUTPUT);
  digitalWrite(16,LOW);
  digitalWrite(17,HIGH);
  pinMode(5,OUTPUT);
  pinMode(7,OUTPUT);
  digitalWrite(5,HIGH);
  digitalWrite(7,LOW);
  Serial.begin(2400);
  Wire.begin();
  RTC.begin();
  // Initialise SPI interface
  es.ES_enc28j60SpiInit();
  // initialize enc28j60
  es.ES_enc28j60Init(mymac);
  // init the ethernet/ip layer:
  es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
  //calculate shutdown interval
  shutdown_interval=(shutdown_grace*60000)/server_poll_interval;
  //init serial port
  get_ntp_time();

}

void loop(){
	unsigned long starttime,servertime;
	int shutcount=0;
	uint16_t plen, dat_p;
	while(1) {
		while ((millis() - starttime > serial_poll_interval) && (ups_shut_flag!=1)){

			ups_state=false;
			query_ups('Y',response);
			if (response[0]=='S' && response[1]=='M'){
				query_ups('L',line_voltage);
				query_ups('F',line_freq);
				query_ups('B',batt_voltage);
				query_ups('O',load_voltage);query_ups('P',load_factor);
				query_ups('f',batt_level);
				query_ups('j',estimated_runtime);
				query_ups('Q',status_flag);
				query_ups('C',internal_temp);
				query_ups('R',response);
				ups_state=true;
                        }
                        //read TIME & temperature
			dtostrf(get_temp(),6,2,external_temp);
                        starttime=millis();

		}
		Serial.flush();
		while (millis() - servertime > server_poll_interval) {

			server1=arp_ping(Server1ip); //ping server1
			server2=arp_ping(Server2ip); //ping server2
                        if (server1==1 || server2==1){
				shutcount=0;
				ups_shut_flag=0;
			} 
			//do not switchoff if any of the server is alive
			if (server1==0 && server2==0){
				shutcount++;
			}
			if ((shutcount>shutdown_interval) && ups_shut_flag!=1){
				shutdown_ups();//issue powerdown command to ups
			}
			servertime=millis();
		}
		// read packet, handle ping and wait for a tcp packet:
		dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
		/* dat_p will be unequal to zero if there is a valid http get */
		if(dat_p==0){
			// no http request
			continue;
		}
		// tcp port 80 begin
		if (strncmp("GET ",(char *)&(buf[dat_p]),4)!=0){
			// head, post and other methods:
			dat_p=http200ok();
			dat_p=es.ES_fill_tcp_data_p(buf,dat_p,PSTR("<h1>200 OK</h1>"));
			sendtcp(dat_p);
		}
		// just one web page in the "root directory" of the web server
		if (strncmp("/ ",(char *)&(buf[dat_p+4]),2)==0){
			dat_p=print_webpage(buf);
			sendtcp(dat_p);
		}
	}//end of while loop
}//end of main loop

void sendtcp(uint16_t dat_p){
	es.ES_www_server_reply(buf,dat_p);
}

char *query_ups(char cmd,char *temp){
	int i=0;
	long Stime;
	//flush serial port
	Serial.flush();
	//senda command on serial port
	Serial.print(cmd);//wakeup UPS from dumb mode
	Stime=millis();
	delay(50);
	//wait for reply till timeout
        while(millis()-Stime<serialtimeout){
          //read serial input
	  if(Serial.available()>0){
	    while(Serial.available()>0){
	      char inChar=Serial.read();
	      //add it to the inputString:
	      *(temp+i)=inChar;
	      i++;
	      }
	    }
	  }
	*(temp+i)='\0'; //null terminate the buffer
	return temp;
}

int arp_ping(uint8_t *remIP){
	int state=0;
	uint32_t endtime,dat_p;
	uint16_t timeout=5000;//time out ping after 500 milliseconds
	endtime=millis();
	//send an arp request to get the mac address of the remote IP
	es.ES_client_set_gwip(remIP);
	while(1){
		if(millis()-endtime>=timeout){
			state=0;
			return 0;
		}//time out ping
		int plen=es.ES_enc28j60PacketReceive(BUFFER_SIZE,buf);
		dat_p=es.ES_packetloop_icmp_tcp(buf,plen);
		if(dat_p==0){
			//we idle here
			if(es.ES_client_waiting_gw()){
				continue;
			}
		}
		if(!es.ES_client_waiting_gw()){ //got arp reply
			state=1;
			return 1;
		}
	}
}

void shutdown_ups(){
        //get time from rtc clock
        DateTime now = RTC.now();
        int hour=now.hour();
        int minute=now.minute();
        //execute shutdown only after 1700
        if (hour>=15)
          if (minute>=30){
      	  query_ups('Y',response);
    	  delay(500);
    	  query_ups('Z',response);
    	  delay(1600);
    	  query_ups('Z',response);
    	  query_ups('R',response);
    	  ups_shut_flag=1;
          pinMode(2,OUTPUT);
          pinMode(8,OUTPUT);
          digitalWrite(2,HIGH);
          digitalWrite(8,LOW);
      }
}

float get_temp(){
	byte i;
	byte present = 0;
	byte type_s;
	byte data[12];
	byte addr[8]={0x10, 0x28, 0xC, 0xBB, 0x0, 0x8, 0x0, 0xBE};
	float celsius;
	type_s=2; //ds18s20
	ds.reset();
	ds.select(addr);
	ds.write(0x44,1); // start conversion
	delay(1000);
	present = ds.reset();
	ds.select(addr);
	ds.write(0xBE); // Read Scratchpad
	for ( i = 0; i < 9; i++) {data[i] = ds.read();}
	// convert the data to actual temperature
	unsigned int raw = (data[1] << 8) | data[0];
        raw = raw << 3; // 9 bit resolution default
	if (data[7] == 0x10) {
		// count remain gives full 12 bit resolution
		raw = (raw & 0xFFF0) + 12 - data[6];
	}
	celsius = (float)raw / 16.0;
	return celsius;
}

boolean get_ntp_time(){
   uint32_t endtime,d;
   boolean stat=false;
  uint16_t timeout=3000; //timeout ping after 2 seconds
  endtime=millis();
  uint16_t dat_p;
  uint16_t clientPort = 123;
  char dstr[4];
  int sec = 0;
  int plen = 0;

  // Get IP Address details

  // Main processing loop now we have our addresses
  while(1) {
    if(millis()-endtime>=timeout){return false;}
    // handle ping and wait for a tcp packet
    dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
    // Has unprocessed packet response
    if (dat_p > 0)
    {
     uint32_t time = 0L;
      if (es.ES_client_ntp_process_answer(buf,&time,clientPort)) {

          if (time) {
          time -= SECONDS_FROM_1900_TO_1970; //calculate no of seconds after 2000
          time +=19800; //add offset of +5hr 30 min for IST (Indian Standard Time)
          DateTime now(time);
          DateTime RTC_now = RTC.now();
          //sync RTC to NTP
          RTC.adjust(DateTime(now.year(),now.month(),now.day(),now.hour(),now.minute(),now.second()));
          return true;
        }
      }
    }

      if (stat==false){

      if (set_mac(ntpServer))
      {

      es.ES_client_ntp_request(buf,ntpServer,123);}//reset timeout counter
      stat=true;
      }
    }

  }

boolean set_mac(uint8_t *remIP){
  uint32_t endtime,dat_p;
  uint16_t timeout=3000; //timeout ping after 500 milli seconds
  endtime=millis();
  es.ES_client_set_gwip(remIP);
    while(1){
      if(millis()-endtime>=timeout){return false;}//timeout ping
       int plen=es.ES_enc28j60PacketReceive(BUFFER_SIZE,buf);
       dat_p=es.ES_packetloop_icmp_tcp(buf,plen);
       if(dat_p==0) {
          // we are idle here
          if (es.ES_client_waiting_gw() ){
          continue;
          }

        }
        if (!es.ES_client_waiting_gw() ){return true;}

}

}
Posted in Default | Tagged , , , , , , , , , , , , , , , , , , | 15 Comments

Arduino NTP Client using EtherShield library

Print Friendly

This code is snippet of a larger project I am working on. The project requires time synchronization so I decided to use NTP to retrieve time from server as the project hardware (Arduino ATMega328 board + ENC28J60 based shield) already had the the QR to execute the requirement.

The NTP server is a Windoze 2008 R2 server and my sketch is based on one published on github. However some tweaks have been done to make it compatible with my arduino board.

The sketch is for a simple network and does not cater for routers, firwall gateways and works..

Here are some of the salient changes.

  1. Static IP being used.
  2. Timestamp offset corrected to 1970 instead of 2000.
  3. set_mac() function added to set correct mac address of the destination ntp server.. Without this the packets are sent with destination mac address as 00:00:00:00:00:00
  4. A positive offset of 19800 seconds has been added to get Indian Standard Time.
#include <Wire.h>
#include <RTClib.h>
#include <EtherShield.h>

// Jan 1 
#define SECONDS_FROM_1900_TO_1970 2208988800

static uint8_t mymac[6] = {
  0x54,0x55,0x58,0x10,0x00,0x25};

// IP and netmask allocated by DHCP
static uint8_t myip[4] = { 159,12,23,149 };
static uint8_t mynetmask[4] = { 255,255,255,0 };
static uint8_t gwip[4] = {159,12,23,150};
// From http://support.ntp.org/bin/view/Servers/StratumTwoTimeServers
byte ntpServer[4] = {159,12,23,150};
// Packet buffer, must be big enough to packet and payload
#define BUFFER_SIZE 550
static uint8_t buf[BUFFER_SIZE+1];

EtherShield es=EtherShield();
uint32_t lastUpdate = 0;
uint32_t time;
static const char day_abbrev[] PROGMEM = "SunMonTueWedThuFriSat";

void setup(){
  Serial.begin(19200);
  Serial.println("EtherShield NTP Client");

  // Initialise SPI interface
  es.ES_enc28j60SpiInit();
  // initialize enc28j60
  es.ES_enc28j60Init(mymac);
  es.ES_init_ip_arp_udp_tcp(mymac,myip,80);
  Serial.print( "ENC28J60 version " );
  Serial.println( es.ES_enc28j60Revision(), HEX);
  if( es.ES_enc28j60Revision() <= 0 ) {
    Serial.println( "Failed to access ENC28J60");
    while(1);    // Just loop here
  }

  // init the ethernet/ip layer
//  es.ES_init_ip_arp_udp_tcp(mymac,myip, 80);
//  es.ES_client_set_gwip(gwip);  // e.g internal IP of dsl router
  lastUpdate = millis();
}

// Output a ip address from buffer from startByte
void printIP( uint8_t *buf ) {
  for( int i = 0; i < 4; i++ ) {
    Serial.print( buf[i], DEC );
    if( i<3 )
      Serial.print( "." );
  }
}

void loop(){
  uint16_t dat_p;
  uint16_t clientPort = 123;
  char dstr[4];
  int sec = 0;
  int plen = 0;

  // Get IP Address details

  // Main processing loop now we have our addresses
  while(1) {
    // handle ping and wait for a tcp packet
    dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
    // Has unprocessed packet response
    if (dat_p > 0)
    {
     time = 0L;
      if (es.ES_client_ntp_process_answer(buf,&time,clientPort)) {
        Serial.print("Time:");
        Serial.println(time); // secs since year 1900

        if (time) {
          time -= SECONDS_FROM_1900_TO_1970; //calculate no of seconds after 2000
          time +=19800; //add offset of +5hr 30 min for IST (Indian Standard Time)

          DateTime now(time);

          Serial.print(now.year(), DEC);
          Serial.print('/');
          Serial.print(now.month(), DEC);
          Serial.print('/');
          Serial.print(now.day(), DEC);
          Serial.print(' ');
          int i=0;
          while (i<3){
            dstr[i]= pgm_read_byte(&(day_abbrev[(now.dayOfWeek()-1) * 3 + i])); 
            i++;
          }
          dstr[3]='\0';

          Serial.print( dstr );
          Serial.print(' ');
          Serial.print(now.hour(), DEC);
          Serial.print(':');
          Serial.print(now.minute(), DEC);
          Serial.print(':');
          Serial.print(now.second(), DEC);
          Serial.println();
        }
      }
    }
    // Request an update every 5s
    if( lastUpdate + 5000L < millis() ) {
      // time to send request
      lastUpdate = millis();
      Serial.print("Send NTP request ");
      if (set_mac(ntpServer))
      es.ES_client_ntp_request(buf,ntpServer,clientPort);

    }

  }
}

boolean set_mac(uint8_t *remIP){
  uint32_t endtime,dat_p;
  uint16_t timeout=2000; //timeout ping after 500 milli seconds
  endtime=millis();
  Serial.print("Senidng ARP Request to ");printIP(remIP);Serial.println();
  es.ES_client_set_gwip(remIP);
    while(1){
      if(millis()-endtime>=timeout){Serial.print("Timeout Waitin for Ping Reply ");Serial.print(endtime);Serial.println();return false;}//timeout ping
       int plen=es.ES_enc28j60PacketReceive(BUFFER_SIZE,buf);
       dat_p=es.ES_packetloop_icmp_tcp(buf,plen);
       if(dat_p==0) {
          // we are idle here
          if (es.ES_client_waiting_gw() ){
          continue;
          }

        }
        if (!es.ES_client_waiting_gw() ){Serial.println("Got ARP Reply");return true;}

}

}
Posted in Arduino, Arduino, Projects | Tagged , , , , , , | Leave a comment

Sketch to ping remote computer using Arduino (Using EtherShield Library and an ENC28J60 Shield)

Print Friendly

Well over the past weekend I had been scouring the net trying to get a cue as to how to ping a remote computer using an Arduino Duemilanove and an ENC28J60 based shield (I am using SureElectronics Ethernet Communication Module USB SPI – ENC28J60 Remote Control).

SureElectronics Ethernet Shield

After hours of Wiresharking my code and scouring the Ethershield library for possible cues I was finally able to ping a remote computer

Without much ado here is a dump of the sketch. I have used Andy’s EtherShield library.
Caution: -To make this sketch work following changes are required in ip_arp_udp_tcp.c file in the Ethershield library.

Replace
buf[IP_TOTLEN_L_P]=0x82;//gives error when viewed in wireshark
By
buf[IP_TOTLEN_L_P]=0x54;
Replace
buf[IP_PROTO_P]=IP_PROTO_UDP_V;;//sends packet as UDP instead of ICMP
By
buf[IP_PROTO_P]=IP_PROTO_ICMP_V;

The stuff works, but it stops sending packets after 3rd iteration. I have not resolved the problem.(Solved. Problem was in variable type definition of  endtime. Had defined it as uint16_t instead of uint32_t.)

 

#include 
#define PING_client
static uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x25};
static uint8_t myip[4] = { 172,16,100,25 };
static uint8_t pcip[4] = { 172,16,100,2 };
static uint8_t gwip[4] = { 172,16,100,1 };
static uint8_t fooip[4] = { 172,16,100,100 }; //unavailable pc. simulating a offline pc

#define BUFFER_SIZE 700
static uint32_t timer,count;
static uint8_t buf[BUFFER_SIZE+1];
int state=0;
EtherShield es=EtherShield();
void setup(){
  Serial.begin(19200);
    // Initialise SPI interface
  es.ES_enc28j60SpiInit();

  // initialize enc28j60
  es.ES_enc28j60Init(mymac);

  // init the ethernet/ip layer:
  es.ES_init_ip_arp_udp_tcp(mymac,myip,80);
  Serial.println("Starting"); delay(3000);
}

// Output a ip address from buffer from startByte
void printIP( uint8_t *buf ) {
  for( int i = 0; i < 4; i++ ) {
    Serial.print( buf[i], DEC );
    if( i<3 )
      Serial.print( "." );
  }
}

void printHex( uint8_t hexval ) {
  if( hexval < 16 ) {
    Serial.print("0");
  }
  Serial.print( hexval, HEX );
  Serial.print( " " );
  timer = -9999999; // start timing out right away
}

void loop(){
  pinMode(14, OUTPUT);      // sets the digital pin as output
  pinMode(15, OUTPUT);      // sets the digital pin as output
  digitalWrite(14,HIGH);
  digitalWrite(15,LOW);

  ping(pcip);

  ping(gwip);

  ping(fooip);

}

void ping(uint8_t *remIP){

   uint32_t endtime,dat_p;
  uint16_t timeout=5000; //timeout ping after 2seconds
  endtime=millis();

  //send an arp request to get the mac address of teh remoteIP
//  Serial.print("Senidng ARP Request to ");printIP(remIP);Serial.println();
   es.ES_client_set_gwip(remIP);
    while(1){
      if(millis()-endtime>=timeout){Serial.print("Timeout Waitin for Ping Reply ");Serial.print(endtime);Serial.println();state=0;break;}//timeout ping
       int plen=es.ES_enc28j60PacketReceive(BUFFER_SIZE,buf);
       dat_p=es.ES_packetloop_icmp_tcp(buf,plen);
       if(dat_p==0) {
          // we are idle here
          if (es.ES_client_waiting_gw() ){
          continue;
          }

        }
      //  if (!es.ES_client_waiting_gw() ){Serial.println("Got ARP Reply");state=1;break;}

       // report whenever a reply to our outgoing ping comes back
       if (plen > 0 && es.ES_packetloop_icmp_checkreply(buf,remIP)) {
       Serial.print("  ");
       Serial.print((micros() - timer) * 0.001, 3);
       Serial.println(" ms");
       state=1;break;
        }
      if (micros() - timer >= 1000000) { //ping every 1 second
       Serial.print(count);
        Serial.print(". Pinging: ");
        printIP(remIP);
        Serial.print("-->");
        timer = micros();
        es.ES_client_icmp_request(buf,remIP);
        count++;
      } 

   }

}

 

 

 

Posted in Programming | Tagged , , , , , , | Leave a comment

Simple Python Script To Mimic APC UPS

Print Friendly

Just written this script to simulate a APC SMART UPS for one of my ongoing projects.

#! /usr/bin/env python
"""\
The purpose of this program is to simulate an APC UPS
It will respond to only 'basic' UPS commands
Presently only following commands are supported
YBFLOPR
"""
import datetime
import serial
import glob
import sys
name="/dev/ttyUSB0" # change to suit your needs
ser = serial.Serial(name, 2400, timeout=1)
print "Trying to open" + name
if (ser.isOpen()) :
	print "Sucessfully opened port " + name
	print "Waiting for command on serial port"
	#loop start
	while 1	:
		timenow= datetime.datetime.now().strftime("%I:%M:%S")
		cmd=ser.read() #read a single byte
		if len(cmd) != 0 :

			print timenow +  "--> Received command-> " + cmd
			#change output based on received command
			if cmd == 'Y':
				print timenow +  "--> Sending Reply SM"
				ser.write("SM\r\n")
			elif cmd == 'B':
				print timenow +  "--> Sending Reply 27.87"
				ser.write("27.87\r\n")
			elif cmd == 'F':
				print timenow +  "--> Sending Reply 50.00"
				ser.write("50.00\r\n")
			elif cmd == 'L':
				print timenow +  "--> Sending Reply 118.3"
				ser.write("118.3\r\n")
			elif cmd == 'O':
				print timenow +  "--> Sending Reply 118.3"
				ser.write("118.3\r\n")
			elif cmd == 'P':
				print timenow +  "--> Sending Reply 023.5"
				ser.write("023.5\r\n")
			elif cmd == 'f':
				print timenow +  "--> Sending Reply 099.0"
				ser.write("099.0\r\n")
			elif cmd == 'j':
				print timenow +  "--> Sending Reply 00327:"
				ser.write("0327:")
			elif cmd == 'R':
				print timenow +  "--> Sending Reply BYE"
				ser.write("BYE\r\n")
			print "-----------------------------------------------------"

	ser.close()
Posted in DIY, Electronics, PIC, Projects, Python | Tagged , , , , , , | Leave a comment

IR Remote Controlled 4 Channel Relay

Print Friendly

Code to read IR Signal from a Sony Remote and trigger a relay.

Code adapted from

Compiler : CCS C Compiler
Target MCU: Microchip PIC 16F628A

#include
#fuses INTRC_IO, NOWDT, BROWNOUT,  NOLVP
#use delay(internal=4MHz)
#define LED  PIN_B4
#define IR  PIN_B3
#define RELAY1  PIN_A2
#define RELAY2  PIN_A3
#define RELAY3  PIN_B1
#define RELAY4  PIN_B2

/* TIMER0 configuration */
#define TIMER0_CONFIG   RTCC_INTERNAL | RTCC_DIV_1 

/* Interrupt rate:                     */
/* 4/4000000*65536*1 = 0.256 ms       */
/*                                     */
/*     Start: 3.0 ms (ignored)         */
/*     "1":   1.8 ms (225)           */
/*     "0":   1.2 ms  (150)           */
/*

*/
#define ONE_MIN  190
#define ONE_MAX  400
#define ZERO_MIN 10
#define ZERO_MAX 185 

short rly1,rly2,rly3,rly4,state;

/* irframes[0] (start) will be garbage, ignore it...  */
int16 irframes[13];
int8 ircount = 0;
int1 irdone = FALSE; 

#int_ccp1
void ext_ccp1() {
  if (irdone) return;
  irframes[ircount++] = get_timer0();
  if (ircount >= 13)
    irdone = TRUE;
  set_timer0(0);
  enable_interrupts(INT_TIMER0);
//#output_bit(LED,1);delay_ms(1);output_bit(LED,0);delay_ms(1);
} 

#int_timer0
void timer0_isr() {
  disable_interrupts(INT_TIMER0);
} 

#separate
int1 decode_ir(int8 &addr, int8 &cmd) {
  int8 i;
  int8 mask;
  int8 bits[13]; 

  addr = 0;
  cmd = 0; 

  for (i=1; i
Posted in CCS C, Electronics, PIC | Tagged , , , , , , , , | Leave a comment

Download YouTube Playlist

Print Friendly

This script downloads all videos in your YouTube playlist . The script is extremely basic in nature and doesnot offer any choices.
Change the url in the below to reflect playlist of your choice.

Pseudo-algorithm as follows

  1. Download YouTube playlist page
  2. Parse the page for video names and their ids
  3. Store them in an array
  4. Iterate the array to download single video at a time
  5. Loop Start
  6. Download video page and grab session cookie
  7. Grab the download parameters
  8. Formulate download url
  9. Download the url and submit the session cookie
  10. Loop End
#!/bin/bash
clear
url="http://www.youtube.com/playlist?list=PLFAD51820C17E3A21"
#download the url page
debug=`wget -O /tmp/utube $url 2>&1`
#extract titles from the downloaded page
temp1=$(sed -n -e 's/.*\(.*\)<\/span>.*/\1/p' /tmp/utube | sed -e 's/ /_/g' )
title=($(echo $temp1 | tr " " "\n"))
#extract unique video id from the playlists
temp2=$(cat /tmp/utube | grep -i "/watch?v" | grep -i "a href" | sed 's/.*&1`
	  sleep 2
	  # get host details from testfile
	  host_url=$(sed -n -e 's/.*img.src = "\(.*\)generate.*/\1/p' $ty_dir/testout.txt | sed -e's/%\([0-9A-F][0-9A-F]\)/\\\\\x\1/g' | xargs echo -e)
      dl_param=$(sed -n -e 's/.*\/generate_204\(.*\)";.*/\1/p' $ty_dir/testout.txt | sed 's/\\u0026/\&/g' | sed -e's/%\([0-9A-F][0-9A-F]\)/\\\\\x\1/g' | xargs echo -e)
	  #devise download url
      dl_url=$host_url"videoplayback"$dl_param
      #attempt download.. return the cookies with regards
      debug=`wget -c --cookies=on --load-cookies=$ty_dir/cookie.txt --keep-session-cookies --save-cookies=$ty_dir/cookie.txt -O $O_FILE $dl_url 2>&1`
	  rm $ty_dir/cookie.txt
	  rm $ty_dir/testout.txt
	  arch_size=$(stat -c %s  $O_FILE)
	  #delete file if file too small
	  if [[ $arch_size -lt "1024" ]]
		then
		echo "....Failed.. FileSize too Small $arch_size bytes"
		rm $O_FILE
	  fi
	  #on successful download
	  if [[ $arch_size -gt "1024" ]]
		then
		echo "....Downloaded.. FileSize $arch_size bytes"
		fi
    done
Posted in BASH, Programming | Tagged , , , , , , | Leave a comment

Simple Script to Download epaper from The Hindustan

Print Friendly
#!/bin/bash
#ishan dot karve at gmail dot com
#
#Script to download epaper from The Hindustan
#Written on request for Jitendra
#No more subscription .. pls donate the money to Prime Ministers Welfare Fund
#As always /// Its free to use...
#Get user to select edition.
##############################################################################
START=$(date +%s)

#############################################################################################################
#date mod so that script gets the most current edition
#irrespective where it runs (india or server in orlando)
#script assumes that all digital edition are published on or after 6AM each day
#############################################################################################################

#by default export Indian Time Zone
export TZ=Asia/Calcutta
IST_hour=`date +%H`
IST_day=`date +%d`

#check current hour in india
if [ $((10#$IST_hour)) -lt 6 ]  # if script is executed before 6AM IST then export America/New_York Time Zone
	then
	export TZ=America/New_York
	echo "Using New York Time Zone"

elif [ $((10#$IST_hour)) -ge 6 ] #   if script is executed after 6AM IST do nothing as we have already exported IST
	then
	echo "Using Indian Time Zone"
fi

day=`date +%d`  #date compensated for IST.. server is 9 hours behind
nz_day=`date +%-d`
month=`date +%m`
year=`date +%Y`
nz_month=`date +%-m`
hour=`date +%H`
min=`date +%M`
sec=`date +%S`
datetime() { echo `date "+%Y-%m-%d %H:%M:%S"` ;}
##############################################################################

publication_name="The_Hindustan"
echo "$(datetime) $publication_name Script Started"
#delete previous incomplete /complete downloads
echo "$(datetime) Cleaning up previous downloads"
files=$(ls $HOME/public_html/news_archive/"$publication_name"_*.tar.gz 2> /dev/null | wc -l)
if [ "$files" != "0" ]
then
rm $HOME/public_html/news_archive/"$publication_name"_*.tar.gz
fi
echo "$(datetime) Downloading Index Page"
#extract page numbers from avl paper
url="http://epaper.livehindustan.com/PUBLICATIONS/HT/HT/$year/$month/$day/index.shtml"
#echo $url
curl -s $url > /tmp/Hindustan
echo "$(datetime) Parsing Avl Page Nos"
pagenos=$(sed -n -e 's/.*PageImgNames=\(.*\);.*/\1/p' /tmp/Hindustan | sed "s/'//g")
#echo $pagenos
#Load page no in an array pgrecord
IFS=',' pgrecord=(${pagenos})

ty_dir="$HOME/public_html/news_scripts/ty_dld/The_Hindustan_`date --date= +%d`_`date --date= +%m`_`date --date= +%Y`"
#ty_dir="$HOME/Desktop/The_Hindustan_"$day"_"$month"_$year"
#echo $ty_dir
#mkdir to store individual pages
if [ ! -d "$ty_dir" ]; then mkdir $ty_dir;fi

#spider the selected edition using wget to estimate number of pages
#define max incremental page limit
#echo "$(datetime) Please be patient..Bandwidth intensive operation starts..;-)"
echo "$(datetime) Downloading The Hindustan Paper .. total $npages pages"
pages_downloaded=0

pg_array_size=${#pgrecord[@]}
for ((  i =  0;  i < $pg_array_size;  i++  ))     do                  #echo -n "$(datetime) Downloading Page $pageno"       O_FILE="$ty_dir/${pgrecord[i]}.pdf"       I_FILE="http://epaper.livehindustan.com/PUBLICATIONS/HT/HT/$year/$month/$day/PagePrint/"$day"_"$month"_"$year"_${pgrecord[i]}.pdf"	       #echo $I_FILE       #echo $O_FILE       #curl  $I_FILE -o "$O_FILE"       debug=`wget -c -O $O_FILE $I_FILE 2>&1`
      echo $debug
      #echo "....Completed Download:-)"
     ((pages_downloaded=pages_downloaded+1))
    done

echo "$(datetime) Downloaded $pages_downloaded pages"
if [ $pages_downloaded -ne 0 ]
then
echo "$(datetime) Combining all pages into a single tar.gz archive"
#combine multiple pdf files
archive_name="$publication_name"_"$day"_"$month"_"$year".tar.gz
#cd to document source diectory
cd $ty_dir
#tar documents
tar -zcf $HOME/public_html/news_archive/$archive_name *.pdf
#empty directory
rm $ty_dir/*.pdf
# get archive file size
arch_size=$(stat -c %s  $HOME/public_html/news_archive/$archive_name)
	if [[ $arch_size -gt "1024" ]]
	then
	END=$(date +%s)
	DIFF=$(( $END - $START ))
	echo "$(datetime) Script Execution Completed in $DIFF seconds"
	echo "$(datetime) File Location $HOME/public_html/news_archive/$archive_name ($arch_size bytes)"
	fi
	if [[ $arch_size -lt "1024" ]]
	then
	END=$(date +%s)
	DIFF=$(( $END - $START ))
	echo "$(datetime) Script Execution Completed in $DIFF seconds"
	echo "$(datetime) Script Execution Failed.. FileSize too Small $arch_size bytes"
	rm $HOME/public_html/news_archive/$archive_name
	if [ -d "$ty_dir" ]; then rmdir $ty_dir;fi

	fi
fi

if [ $pages_downloaded -eq 0 ]
then
echo "$(datetime) Script Execution Failed"
echo "$(datetime) Last Debug .. $debug"
echo "$(datetime) Last Debug .. $I_FILE"
#remove directory
if [ -d "$ty_dir" ]; then rmdir $ty_dir;fi

fi

How to get it running

Copy the script to your Linux desktop
go to command prompt using terminal
type following commands

cd ~/Desktop
chmod +x thehindustan.sh
./thehindustan.sh

Posted in BASH, Programming | Leave a comment

Php Function To Find Distance Between Two Coordinates

Print Friendly

Simple PHP function to find distance between 02 coordinates.


Posted in PHP, Programming | Tagged , , , , , , , , | Leave a comment

PHP Script To Analyse GPS Tracks for Vehicle Movement

Print Friendly

See the script in action

 park_speed
$parking_flag=0; //Set when vehicle is parked
$motion_flag=0; //set when vehicle is in motion

echo "
\n";
echo "
\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n
	 

\n";

$display_flag=0;
while ($row = @mysql_fetch_assoc($result)){

$row_count++;
$speed=$row['gps_speed'];
$id=$row['id'];
$lat=degree2decimal($row['lat']);//convert to decimal degrees
$lon=degree2decimal($row['lon']);
$gps_time=$row['gps_time'];
$tstamp=strtotime("$date $gps_time"); //gen unix time stamp
$color="#FFFFFF";
$remarks="";
//determine parking boundary line condition
	if ($speed <= $park_speed ){
		$color="#00FF00"; //Default Color
		$display_flag=0;//Default display state		

		/* vehicle is considered to be parked if its speed if it is
		 * below $park_speed for more than $parking_timeout
		 * As soon as a fist parking event is generated save its
		 * time stamp and set the parking flag
		 */
		 if ($stop_flag==0){$move_flag=0;$start_time=$tstamp;$stop_flag=1;}
		 $tdiff=$tstamp-$start_time; //calculate time elapsed since flag raised
		 // Only show parking events whose $tdiff>$parking_timeout

		 if ($stop_flag==1 && $tdiff>=$parking_timeout && $parking_flag==0){
			$display_flag=1;
			$remarks="Vehicle Parked";
			$parking_flag=1;
			$motion_flag=0;
			$move_flag=0;
			}

	}

//determine vehicle motion boundary line condition
	if ($speed>$park_speed){
		$color="#FF0000"; //Default Color
		$display_flag=0;//Default display state
		/*Due to gps drift there can be spikes in gps_speed which
		 * may trigger false movement alarm. Hence vehicle is deemed
		 * to be in motion only when it travels a
		 * distance >=$dist_trigger
		 * As soon as movement is detected raise save its coordinates
		*/
		if ($move_flag==0){$slat=$lat;$slon=$lon;$move_flag=1;$stop_flag=0;}
		//calculate distance travelled
		$dist=get_distance($slat,$slon,$lat,$lon);

		if ($dist>=$dist_trigger && $motion_flag==0){
			$display_flag=1;
			$stop_flag=0;
			$remarks="Vehicle in Motion";
			$motion_flag=1;
			$parking_flag=0;

		}

		}

	if ($display_flag==1){
		echo "
\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n


\n
		

\n";
		}

}
echo "
Sl NoTimeStart TimeTimestampTimeDiffStart LatStart LonLatitudeLongitudeSpeedS_FlagM_FlagDistRemarks
$row_count$gps_time$start_time$tstamp$tdiff$slat$slon$lat$lon$speed$stop_flag$move_flag$dist$remarks
\n"; function degree2decimal($deg_coord) { //reference http://www.directionsmag.com/site/latlong-converter //GPS/NMEA fixes are in Degree Minutes.m format //for google maps we need to convert them to decimal degress //sample format of gps 4533.35 is 45 degrees and 33.35 minutes //formula is as follows //Degrees=Degrees //.d = M.m/60 //Decimal Degrees=Degrees+.d //first we need to split the input value into Degrees and Minutes.m $dot_pos=strpos($deg_coord,'.'); $degree=(int)($deg_coord/100); //simple way $minutes= $deg_coord-($degree*100); $dotdegree=$minutes/60; $decimal=$degree+$dotdegree; $direction=substr($deg_coord,-1); //South latitudes and West longitudes need to return a negative result if (($direction=="S") or ($direction=="W")) { $decimal=$decimal*(-1);} $decimal=number_format($decimal,4,'.',''); //truncate decimal to 4 places return $decimal; } //haversine calculation to find distance between 2 latlon coordinates //Ref: http://stackoverflow.com/questions/27928/how-do-i-calculate-distance-between-two-latitude-longitude-points function get_distance($s_lat,$slon,$e_lat,$e_lon){ $e_radius=6371000; //radius of earth in meters $latdiff=deg2rad(($s_lat-$e_lat)); $londiff=deg2rad(($s_lon-$e_lon)); $a=sin($latdiff/2) * sin($latdiff/2)+ cos(deg2rad($e_lat)) * cos(deg2rad($s_lat)) * sin($londiff/2) * sin($lodiff/2); $c=2 * atan2(sqrt($a),sqrt(1-$a)); $d= $e_radius* $c; return $d; } ?>
Posted in BASH, Programming | Tagged , , , , , , , | 1 Comment