Linked list – Library for Arduino

As I was struggling with my HC-05 Bluetooth module which might return an unspecified count of lines when responding to a command in AT (attention) mode, I have written a small library for a single chained list. It is just a dynamic data structure supporting chronological pushing while it allows iterating through all its elements.

/*
  List.h - Linked List (single chain)
  Created by B. Blechschmidt (Ovex), 16 August 2013
  Released into the public domain.
*/
#ifndef List_h
#define List_h

#include "Arduino.h"

template <class T> class ListElement
{
	public:
		ListElement(T Element)
		{
			Content = Element;
			NextElement = NULL;
		}
		~ListElement()
		{
			delete NextElement;
		}
		T Content;
		ListElement<T> *NextElement;
};

template <class T> class List
{
  public:
	~List()
	{
		Clear();
		delete FirstElement;
		delete LastElement;
		delete CurrentElement;
	}
	List()
	{
		FirstElement = NULL;
		CurrentElement = NULL;
		LastElement = NULL;
		Length = 0;
	}
	void Clear()
	{
		ToBegin();
		delete CurrentElement;
		FirstElement = NULL;
		CurrentElement = NULL;
		LastElement = NULL;
		Length = 0;
	}
	void Push(T Element)
	{
		if(LastElement)
		{
			LastElement->NextElement = new ListElement<T>(Element);
			LastElement = LastElement->NextElement;
		}
		else
		{
			FirstElement = new ListElement<T>(Element);
			LastElement = FirstElement;
			CurrentElement = FirstElement;
		}
		Length++;
	}
	bool IsEnd()
	{
		if(CurrentElement)
		{
			return false;
		}
		else
		{
			return true;
		}
	}

	bool IsEmpty()
	{
		return FirstElement == NULL;
	}

	unsigned long Count()
	{
		return Length;
	}
	void ToBegin()
	{
		CurrentElement = FirstElement;
	}
	void Next()
	{
		if(CurrentElement)
		{
			CurrentElement = CurrentElement->NextElement;
		}
	}
	T GetValue()
	{
		return CurrentElement->Content;
	}
  private:
	  unsigned long Length;
	  ListElement<T> *FirstElement;
	  ListElement<T> *LastElement;
	  ListElement<T> *CurrentElement;
};

#endif

Usage:

#include <List.h>

void setup()
{
	List<String> StringList;
	StringList.Push("a");
	StringList.Push("b");
	StringList.Push("c");

	//Iterate through list
	bool ListEmpty = StringList.IsEmpty(); //false
	Serial.println("Count: "+String(StringList.GetCount()));
	StringList.ToBegin();
	while(!StringList.IsEnd())
	{
		Serial.println(StringList.GetValue());
		StringList.Next();
	}
	/*Output:
		Count: 3
		a
		b
		c
	*/
	StringList.Clear();
	ListEmpty = StringList.IsEmpty(); //true
}

void loop()
{
}

HiTechnic Infrared Seeker library for Arduino

Today I have created a class allowing you to connect a HiTechnic IR Seeker V2, which is originally designed for use with a LEGO Mindstorms NXT robot, to an Arduino Due board with a 9V battery. I struggled a bit with the the different sensor pins but I could finally manage to connect the sensor correctly.

  1. white -> battery +9V (Vcc)
  2. black -> Arduino GND
  3. red -> battery – (GND)
  4. green -> Arduino +3.3V (Vcc)
  5. yellow -> Arduino SCL
  6. blue -> Arduino SDA

The following code is executed by the Arduino:

#include <Wire.h>

/*
  IRSeeker.ino - A library/class for the HiTechnic IRSeeker V2 infrared sensor.
  Created by B. Blechschmidt, August 1, 2013.
  Released into the public domain.
*/

struct InfraredResult
{
  byte Direction;
  byte Strength;
};

class InfraredSeeker
{
  public:
    static void Initialize();
    static boolean Test();
    static void ReadACRaw(byte* buffer);
    static void ReadDCRaw(byte* buffer);
    static InfraredResult ReadAC();
    static InfraredResult ReadDC();
    static int DirectionAngle(byte Direction);
  private:
    static InfraredResult PopulateValues(byte* buffer);
    static void ReadValues(byte OffsetAddress, byte* buffer);
    static const int Address = 0x10 / 2; //Divide by two as 8bit-I2C address is provided
};

void InfraredSeeker::Initialize()
{
  Wire.begin();
  Wire.beginTransmission(InfraredSeeker::Address);
  Wire.write(0x00);
  Wire.endTransmission();
  while(Wire.available() > 0)
    Wire.read();
}

boolean InfraredSeeker::Test()
{
  Wire.beginTransmission(InfraredSeeker::Address);
  Wire.write(0x08);
  Wire.endTransmission();
  Wire.requestFrom(InfraredSeeker::Address, 16);
  char Manufacturer_Model[16];
  while(Wire.available() < 16);
  for(byte i=0; i < 16; i++)
  {
    Manufacturer_Model[i] = Wire.read();
  }
  while(Wire.available() > 0)
    Wire.read();
  return strncmp(Manufacturer_Model, "HiTechncNewIRDir", 16)==0;
}

void InfraredSeeker::ReadValues(byte OffsetAddress, byte* buffer)
{
  Wire.beginTransmission(InfraredSeeker::Address);
  Wire.write(OffsetAddress);
  Wire.endTransmission();
  Wire.requestFrom(InfraredSeeker::Address, 6);
  while(Wire.available() < 6);
  for(byte i = 0; i < 6; i++)
  {
    buffer[i] = Wire.read();
  }
  while(Wire.available() > 0)
    Wire.read();
}

void InfraredSeeker::ReadACRaw(byte* buffer)
{
  ReadValues(0x49, buffer);
}

void InfraredSeeker::ReadDCRaw(byte* buffer)
{
  ReadValues(0x42, buffer);
}

InfraredResult InfraredSeeker::PopulateValues(byte* buffer)
{
  InfraredResult Data;
  Data.Direction = buffer[0];
  if(buffer[0] != 0)
  {
    if(buffer[0] % 2 == 0)
    {
      Data.Strength = (buffer[buffer[0] / 2] + buffer[buffer[0] / 2 + 1]) / 2;
    }
    else
    {
      Data.Strength = buffer[buffer[0] / 2 + 1];
    }
  }
  else
  {
    Data.Strength = 0;
  }
  return Data;
}

InfraredResult InfraredSeeker::ReadAC()
{
  byte buffer[6];
  ReadACRaw(buffer);
  return PopulateValues(buffer);
}

InfraredResult InfraredSeeker::ReadDC()
{
  byte buffer[6];
  ReadDCRaw(buffer);
  return PopulateValues(buffer);
}

int DirectionAngle(byte Direction)
{
  return Direction * 30 - 150;
}

void setup()
{
  Serial.begin(9600);
  Serial.println("HiTechnic IRSeeker V2");
  Serial.println();
  Serial.println();
  Serial.println("Dir\tAngle\tStrength");
  Serial.println();
  InfraredSeeker::Initialize();
}

void loop()
{   
  InfraredResult InfraredBall = InfraredSeeker::ReadAC();
  Serial.print(InfraredBall.Direction);
  Serial.print("\t");
  Serial.print(DirectionAngle(InfraredBall.Direction));
  Serial.print("\t");
  Serial.print(InfraredBall.Strength);
  Serial.println();
  delay(100); //optional
}

To download the compressed zip-archive of the library just go to https://blog.blechschmidt.saarland/wp-content/uploads/2013/08/HTInfraredSeeker.zip. This archive can be imported using the “Sketch” menu of your Arduino IDE. Just click “Import library” and choose “Add library…”. Then just #include <HTInfraredSeeker.h> and use it as shown above in the loop- and main function.