Sunday, September 1, 2013

Multithreaded IGMP Query

Example how to access raw socket in Python:


#!/usr/bin/python

from socket import *
from struct import *
from time import *
import sys
import IN
import threading
import signal


src = '192.168.2.2'
dst = '224.0.0.1'
dev = "eth1.100" + "\0"

if len(sys.argv) > 1:
    dev = sys.argv[1]
    print "device = %s" % dev

src = gethostbyname(gethostname())
                  
def ichecksum(data, sum=0):
    """ Compute the Internet Checksum of the supplied data.  The checksum is
    initialized to zero.  Place the return value in the checksum field of a
    packet.  When the packet is received, check the checksum, by passing
    in the checksum field of the packet and the data.  If the result is zero,
    then the checksum has not detected an error.
    """
    # make 16 bit words out of every two adjacent 8 bit words in the packet
    # and add them up
    for i in range(0,len(data),2):
        if i + 1 >= len(data):
            sum += ord(data[i]) & 0xFF
        else:
            w = ((ord(data[i]) <> 16) > 0)
        sum = (sum & 0xFFFF) + (sum >> 16)

    # one's complement the result
    sum = ~sum

    return sum & 0xFFFF


def dump( data ):
    i = 0
    for x in data:
        if i == 4:
            print ''
            i = 0
        i += 1
        sys.stdout.write( ' %0.2x' % ord(x) )
    print ''


# ip header generation

def create_ip_hdr(id, type):
    ip_ihl = 5
    ip_ver = 4
    ip_tos = 0
    ip_tot_len = 0  # kernel will fill the correct total length
    ip_frag_off = 0
    ip_ttl = 255
    ip_proto = type #IPPROTO_IGMP
    ip_check = 0    # kernel will fill the correct checksum
    isrc = inet_aton( src )
    idst = inet_aton( dst )
    ip_ihl_ver = (ip_ver << 4) + ip_ihl
    router_alert = int( '1001010000000100', 2 ) << 16

    # the ! in the pack format string means network order
    ip_hdr = pack('!BBHHHBBH4s4sI',
        ip_ihl_ver, ip_tos, ip_tot_len, id, ip_frag_off, ip_ttl, ip_proto,
        ip_check,
        isrc, idst,
        router_alert)

    crc = pack( '!H', ichecksum( ip_hdr ) )
    ip_hdr = ip_hdr[:10] + crc + ip_hdr[12:]
    return ip_hdr


# IGMP header:
# type (octet), max resp time (octet), checksum (octet), group (4-octets)
IGMP_QUERY = 0x11
IGMP_REPORT = 0x16
IGMP_LEAVE = 0x17
igmp_type = IGMP_QUERY
IGMP_RESP_TIME = 120


def create_igmp_packet(id, type, group_addr='224.0.0.1'):
    igmp = pack( '!BBH4s', type, IGMP_RESP_TIME, 0, inet_aton(group_addr))
    crc = pack( '!H', ichecksum( igmp ) )
    igmp = igmp[0:2] + crc + igmp[4:]
    packet = create_ip_hdr(id, IPPROTO_IGMP) + igmp
    print 'packet:'
    dump( packet )
    return packet

def create_non_igmp_packet(id, type, group_addr='224.0.0.1'):
    igmp = pack( '!BBH4s', type, IGMP_RESP_TIME, 0, inet_aton(group_addr))
    crc = pack( '!H', ichecksum( igmp ) )
    igmp = igmp[0:2] + crc + igmp[4:]
    packet = create_ip_hdr(id, IPPROTO_UDP) + igmp
    print 'packet:'
    dump( packet )
    return packet


group = '224.0.0.1'
id = 1

s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW )
s.setsockopt( IPPROTO_IP, IP_HDRINCL, 1 )
s.setsockopt( IPPROTO_IP, IP_MULTICAST_TTL, 2)
s.setsockopt( SOL_SOCKET, IN.SO_BINDTODEVICE, dev)

socksema = threading.Semaphore()
stop = False

def signal_handler(signal, frame):
    global stop
    print 'You pressed Ctrl+C!'
    stop = True
    #th1.join()
    #th2.join()
    #sys.exit(0)

class IgmpQueryThread(threading.Thread):
    def run(self):
        global stop,id
        while (not stop):
            socksema.acquire()
            print "Sending IGMP query"
            igmp_q = create_igmp_packet(id, IGMP_QUERY, group)
            print s.sendto( igmp_q, (dst, 0) )
            socksema.release()
            dump( igmp_q)
            id += 1
            sleep(1)


class IgmpReportThread(threading.Thread):       
    def run(self):
        global stop,id
        while (not stop):
            socksema.acquire()
            print "Sending IGMP report"
            igmp_r = create_igmp_packet(id, IGMP_REPORT, group)
            print s.sendto( igmp_r, (dst, 0) )
            id += 1
            socksema.release()
            sleep(1)


i = 0
th1 = IgmpQueryThread()
th2 = IgmpReportThread()

th1.start()
th2.start()

signal.signal(signal.SIGINT, signal_handler)
print 'Press Ctrl+C to quit'
#signal.pause()


while(not stop):
    if (i % 5 == 0):
        print "Sending NON-IGMP (%d)" % i
        false_igmp = create_non_igmp_packet(id, IGMP_QUERY, group)
        print s.sendto( false_igmp, (dst, 0) )
        #stop = True
        id += 1
    sleep( 1 )
    i += 1
   
th1.join()
th2.join()

s.close()




Sunday, July 7, 2013

Create Delay using Number of Cycles in PIC MCU

Most of the delay code available on the Internet for PIC is based on real time delay.  The problem with this approach is that it's hardcoded for certain clock frequency only.  When we use the code for different frequency clock, we have to change the code, sometimes drastically.

Another approach is just to make a routine to waste number of instruction cycles, regardless of the clock frequency.  The caller then later calculate how many cycles it needs to waste in order to get the wanted delay.  It's more maintainable this way than the former.  All PIC MCUs have each instruction executed in 4 clock frequency, or F_cy = F_clock/4, hence T_cy = 1/F_cy = 4/F_clock.

Here is the example of the code for PIC16F877A to waste 10 T_cy cycles.  If F_clock is 16 MHz, F_Cy = 4MHz and T_Cy = 0.25 uSec.  So 10*T_cy = 2.5 uSec delay.
I don't see any reason it won't be compiled and working on other pic16-based MCUs.  I compiled the code with gpasm and header file from sdcc.
 


    title "Delay 10 Tcy"

    include <p16f_common.inc>

    list n=0

    radix    dec
    global    _delay10tcy
    extern   _d1
 
; -----------------------------------------------------------------------
; Variables declaration
;DLY_VAR UDATA_SHR  0x190
;WREG         res 1
WREG        equ     _d1



code_delay10tcy code

_delay10tcy:
    ; polynomial for 10tcy delay is f(x) = 10 + 10 * (x-1)

    ; caller takes 2 TCy, return takes 2 Tcy, so we need 6 more Tcy here
      banksel   WREG            ; 2 Tcy
      decf      WREG,f          ; (x-1), 1 TCy.  TCy so far = 4 + 2 + 1 = 7

      movfw     WREG            ; 1, TCy so far = 8
      bz        @delay10_end    ; 2 Tcy if x=0, otherwise 1, TCy so far = 9 (if x>0)
      nop                       ; 1 TCy, TCy so far = 10

@delay10_loop:                  ; (x-1) * 10
      goto       $+1            ; 2 TCy, TCy so far = 2
      goto       $+1            ; 2 TCy, TCy so far = 4
      goto       $+1            ; 2 TCy, TCy so far = 6

      nop                       ; TCy so far 7
      decfsz    WREG, f         ; TCy so far 8 (if x>0), else 9
      goto       @delay10_loop  ; TCy so far 10
      nop                     

@delay10_end:

      return                    ; 2

      end



Save the code to a file name delay10tcy.S.

To compile it on Linux:

gpasm -c -M -m --mpasm-compatible -e ON -DSDCC -Dpic16f877a -p16f877a -I/usr/local/share/sdcc/include/pic14  delay10tcy.S

The variable "_d1" above has been defined elsewhere as 8-bit user data (so it's shareable among other delayxtcl routines), but if we want to make it local just declare is such as:

DELAY_VAR  udata_shr 0x190
d1  res 1

and remove underscore in all references to d1.

Wednesday, June 19, 2013

Parent-Child Relationship in OOP C++

The C++ source code below:


#include <cstdio>
#include <iostream>

using namespace std;

class CParent {
public:
 CParent() {
  ref++;
  cout <<  "class CParent: constructor ref=" << ref << endl;
  Function();
 };
 virtual ~CParent() {
  ref--;
  cout << "class CParent: destructor ref=" << ref << endl;
 }
 virtual int Function() {
  cout << "\tA::Function()" << endl;
  return ref;
 }
 static unsigned int ref;
};


class CChild : public CParent {
public:
 CChild() {
  ref++;
  cout << "\tclass CChild: constructor ref=" << ref << endl;
  m_a = new CParent();
 };
 virtual ~CChild() {
  ref--;
  cout << "\tclass CChild: destructor ref=" << ref << endl;
  delete m_a;
 }

 static unsigned int ref;
private:
 CParent *m_a;
};


unsigned int CParent::ref = 0;
unsigned int CChild::ref = 0;

int main()
{
 int i;
 int n = 2;

 CChild *c = new CChild[n];
 for(i=0; i(&c[i]);
  printf("p[%d].Function()=%d\n", i, p->Function());
 }
 cout << "CChild::Ref=" << CChild::ref << endl;
 delete [] c;
}

SPI on Arduino Nano v3.0

IC Package: 32 pin MLF



Arduino
Pin #
ATMEL 328P
 (MLF) pin#
ATMEL 328P
(PDIP) pin#
Label Function
D10 14 16 PB2 SS*
D11 15 17 PB3 MOSI
D12 16 18 PB4 MISO
D13 17 19 PB5 SCK


The problem is, according to Arduino Nano schematic, pin 13 is connected to LED through 330 ohm resistor in series.
To be able to use SPI correctly, we need to disconnect the LED.

Tuesday, June 18, 2013

Arduino Nano v3.0 with avr-dude



My order of two Arduino Nano-compatible v3.0 from eBay (shipped from China) just arrived. Also bought the USBASP USBISP AVR Programmer from eBay (about $3.0, from China too, see the picture on the left).


The good thing about this USBISP AVR programmer, besides the unbelievable price, I was told that it is  also compatible with avrdude, even Atmel AVR Studio (never tried it, thought)

But when I tried to program it with avr-dude, it always failed with various errors, such as:






avrdude: ser_recv(): programmer is not responding
avrdude: stk500v2_ReceiveMessage(): timeout

avrdude: stk500v2_getsync(): timeout communicating with programmer
or:
...
         Using Port                    : /dev/ttyUSB2
         Using Programmer              : avrisp
         Overriding Baud Rate          : 57600
avrdude: ser_recv(): programmer is not responding
avrdude: stk500_recv(): programmer is not responding
...



I tried "-c arduino" without setting the baud-rate, I also tried different programmer type (stk500v2, etc.), nothing worked.  Turned out, the parameters combination I used was wrong.
In this case, the programmer should be "arduino" but the baudrate must be set to something (in this case, 57600).

The following is the correct one:


bash-4.2$ avrdude -c arduino -b 57600 -P /dev/ttyUSB2 -p atmega328p -vv -U flash:w:blink.hex

avrdude: Version 5.11, compiled on Sep  9 2011 at 16:00:41
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "/usr/local/etc/avrdude.conf"
         User configuration file is "/home/mlutfi/.avrduderc"

         Using Port                    : /dev/ttyUSB2
         Using Programmer              : arduino
         Overriding Baud Rate          : 57600
         AVR Part                      : ATMEGA328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65     5     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : Arduino
         Description     : Arduino
         Hardware Version: 2
         Firmware Version: 1.16
         Vtarget         : 0.0 V
         Varef           : 0.0 V
         Oscillator      : Off
         SCK period      : 0.1 us

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f
avrdude: safemode: lfuse reads as 0
avrdude: safemode: hfuse reads as 0
avrdude: safemode: efuse reads as 0
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "blink.hex"
avrdude: input file blink.hex auto detected as Intel Hex
avrdude: writing flash (1468 bytes):

Writing | ################################################## | 100% 0.41s

avrdude: 1468 bytes of flash written
avrdude: verifying flash memory against blink.hex:
avrdude: load data flash data from input file blink.hex:
avrdude: input file blink.hex auto detected as Intel Hex
avrdude: input file blink.hex contains 1468 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.30s

avrdude: verifying ...
avrdude: 1468 bytes of flash verified

avrdude: safemode: lfuse reads as 0
avrdude: safemode: hfuse reads as 0
avrdude: safemode: efuse reads as 0
avrdude: safemode: Fuses OK

avrdude done.  Thank you.

Monday, May 27, 2013

MSP430 or PIC?

After sometime using LaunchPad, I was ready to buid my own board utilizing some msp430g2211 on breakout boards laying around on my workbench.  I was going to use the JTAG pins available to program them, but bumped with the overpriced USB-based JTAG programmers/debuggers available in the market.  Yes, I could use the LaunchPad to program these separate microcontrollers, but it's not a good and decent way.

I got a  msp430 BSL usb-to-serial programmer from eBay.  After reading the datasheet for msp430g2211, I realized these type of low-cost microcontrollers don't support BSL, either.  So the only way (other than wiring LauchPad to my protoboard) to in-circuit program the chips is to use a JTAG programmer.  That's a lame, as with PIC microcontrollers, I still could used my PicKit2 to program 44-pin 18Fxx chips.  Even AVR from Atmel could do the similar way using cheap programmer available on eBay or even BusPirate.

Well, sorry msp430, for now I am back to PIC as it has so many features I need (wide availability of PDIP footprints, wide I/O voltage (2 - 5 volt) and cheap programmer).  I am aware there are some open-source efforts to build this kind of programmer for msp430 (GoodFet is one of them, the pre-assembled board is sold at https://www.adafruit.com/products/1279#Technical%20Details)