text:
Q: Get generic type of class at runtime How can I achieve this?
public class GenericClass<T>
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}

Everything I have tried so far always returns type Object rather than the specific type used.

A: Use Guava.
import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;

public abstract class GenericClass<T> {
  private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { };
  private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T>

  public Type getType() {
    return type;
  }

  public static void main(String[] args) {
    GenericClass<String> example = new GenericClass<String>() { };
    System.out.println(example.getType()); // => class java.lang.String
  }
}

A while back, I posted some full-fledge examples including abstract classes and subclasses here.
Note: this requires that you instantiate a subclass of GenericClass so it can bind the type parameter correctly. Otherwise it'll just return the type as T.

A: Here's one way, which I've had to use once or twice:
public abstract class GenericClass<T>{
    public abstract Class<T> getMyType();
}

Along with
public class SpecificClass extends GenericClass<String>{

    @Override
    public Class<String> getMyType(){
        return String.class;
    }
}

A: This is my solution:
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

public class GenericClass<T extends String> {

  public static void main(String[] args) {
     for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) {
      System.out.println(typeParam.getName());
      for (Type bound : typeParam.getBounds()) {
         System.out.println(bound);
      }
    }
  }
}

A: Here is working solution!!!
@SuppressWarnings("unchecked")
    private Class<T> getGenericTypeClass() {
        try {
            String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
            Class<?> clazz = Class.forName(className);
            return (Class<T>) clazz;
        } catch (Exception e) {
            throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
        }
    }

NOTES:
Can be used only as superclass
1. Has to be extended with typed class  (Child extends Generic<Integer>)
OR
2. Has to be created as anonymous implementation (new Generic<Integer>() {};)

A: You can't.  If you add a member variable of type T to the class (you don't even have to initialise it), you could use that to recover the type.

A: One simple solution for this cab be like below
public class GenericDemo<T>{
    private T type;

    GenericDemo(T t)
    {
        this.type = t;
    }

    public String getType()
    {
        return this.type.getClass().getName();
    }

    public static void main(String[] args)
    {
        GenericDemo<Integer> obj = new  GenericDemo<Integer>(5);
        System.out.println("Type: "+ obj.getType());
    }
}

A: Java generics are mostly compile time, this means that the type information is lost at runtime.
class GenericCls<T>
{
    T t;
}

will be compiled to something like
class GenericCls
{
   Object o;
}

To get the type information at runtime you have to add it as an argument of the ctor.
class GenericCls<T>
{
     private Class<T> type;
     public GenericCls(Class<T> cls)
     {
        type= cls;
     }
     Class<T> getType(){return type;}
}

Example:
GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;

A: Sure, you can.
Java does not use the information at run time, for backwards compatibility reasons.  But the information is actually present as metadata and can be accessed via reflection (but it is still not used for type-checking).
From the official API:
http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29
However, for your scenario I would not use reflection.  I'm personally more inclined to use that for framework code.  In your case I would just add the type as a constructor param.

A: As others mentioned, it's only possible via reflection in certain circumstances.
If you really need the type, this is the usual (type-safe) workaround pattern:
public class GenericClass<T> {

     private final Class<T> type;

     public GenericClass(Class<T> type) {
          this.type = type;
     }

     public Class<T> getMyType() {
         return this.type;
     }
}

A: public abstract class AbstractDao<T>
{
    private final Class<T> persistentClass;

    public AbstractDao()
    {
        this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
    }
}

A: I have seen something like this
private Class<T> persistentClass;

public Constructor() {
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                            .getGenericSuperclass()).getActualTypeArguments()[0];
 }

in the hibernate GenericDataAccessObjects Example

A: Just in case you use store a variable using the generic type you can easily solve this problem adding a getClassType method as follows:
public class Constant<T> {
  private T value;

  @SuppressWarnings("unchecked")
  public Class<T> getClassType () {
    return ((Class<T>) value.getClass());
  }
}

I use the provided class object later to check if it is an instance of a given class, as follows:
Constant<?> constant = ...;
if (constant.getClassType().equals(Integer.class)) {
    Constant<Integer> integerConstant = (Constant<Integer>)constant;
    Integer value = integerConstant.getValue();
    // ...
}

A: To complete some of the answers here, I had to get the ParametrizedType of MyGenericClass, no matter how high is the hierarchy, with the help of recursion:
private Class<T> getGenericTypeClass() {
        return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0];
}

private static ParameterizedType getParametrizedType(Class clazz){
    if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy
        return (ParameterizedType) clazz.getGenericSuperclass();
    } else {
        return getParametrizedType(clazz.getSuperclass());
    }
}

A: Here is my solution
public class GenericClass<T>
{
    private Class<T> realType;

    public GenericClass() {
        findTypeArguments(getClass());
    }

    private void findTypeArguments(Type t) {
        if (t instanceof ParameterizedType) {
            Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments();
            realType = (Class<T>) typeArgs[0];
        } else {
            Class c = (Class) t;
            findTypeArguments(c.getGenericSuperclass());
        }
    }

    public Type getMyType()
    {
        // How do I return the type of T? (your question)
        return realType;
    }
}

No matter how many level does your class hierarchy has,
this solution still works, for example:
public class FirstLevelChild<T> extends GenericClass<T> {

}

public class SecondLevelChild extends FirstLevelChild<String> {

}

In this case, getMyType() = java.lang.String

A: I used follow approach:
public class A<T> {

    protected Class<T> clazz;

    public A() {
        this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public Class<T> getClazz() {
        return clazz;
    }
}

public class B extends A<C> {
   /* ... */
    public void anything() {
       // here I may use getClazz();
    }
}

A: Here is my trick:
public class Main {

    public static void main(String[] args) throws Exception {

        System.out.println(Main.<String> getClazz());

    }

    static <T> Class getClazz(T... param) {

        return param.getClass().getComponentType();
    }

}

A: Here is my solution. The examples should explain it. The only requirement is that a subclass must set the generic type, not an object.
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;

public class TypeUtils {

    /*** EXAMPLES ***/

    public static class Class1<A, B, C> {

        public A someA;
        public B someB;
        public C someC;

        public Class<?> getAType() {
            return getTypeParameterType(this.getClass(), Class1.class, 0);
        }

        public Class<?> getCType() {
            return getTypeParameterType(this.getClass(), Class1.class, 2);
        }
    }

    public static class Class2<D, A, B, E, C> extends Class1<A, B, C> {

        public B someB;
        public D someD;
        public E someE;
    }

    public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {

        public E someE;
    }

    public static class Class4 extends Class3<Boolean, Long> {

    }

    public static void test() throws NoSuchFieldException {

        Class4 class4 = new Class4();
        Class<?> typeA = class4.getAType(); // typeA = Integer
        Class<?> typeC = class4.getCType(); // typeC = Long

        Field fieldSomeA = class4.getClass().getField("someA");
        Class<?> typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer

        Field fieldSomeE = class4.getClass().getField("someE");
        Class<?> typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean

    }

    /*** UTILS ***/

    public static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
        Map<TypeVariable<?>, Type> subMap = new HashMap<>();
        Class<?> superClass;
        while ((superClass = subClass.getSuperclass()) != null) {

            Map<TypeVariable<?>, Type> superMap = new HashMap<>();
            Type superGeneric = subClass.getGenericSuperclass();
            if (superGeneric instanceof ParameterizedType) {

                TypeVariable<?>[] typeParams = superClass.getTypeParameters();
                Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();

                for (int i = 0; i < typeParams.length; i++) {
                    Type actualType = actualTypeArgs[i];
                    if (actualType instanceof TypeVariable) {
                        actualType = subMap.get(actualType);
                    }
                    if (typeVariable == typeParams[i]) return (Class<?>) actualType;
                    superMap.put(typeParams[i], actualType);
                }
            }
            subClass = superClass;
            subMap = superMap;
        }
        return null;
    }

    public static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
        return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
    }

    public static Class<?> getFieldType(Class<?> clazz, AccessibleObject element) {
        Class<?> type = null;
        Type genericType = null;

        if (element instanceof Field) {
            type = ((Field) element).getType();
            genericType = ((Field) element).getGenericType();
        } else if (element instanceof Method) {
            type = ((Method) element).getReturnType();
            genericType = ((Method) element).getGenericReturnType();
        }

        if (genericType instanceof TypeVariable) {
            Class<?> typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
            if (typeVariableType != null) {
                type = typeVariableType;
            }
        }

        return type;
    }

}

A: If you have a class like:
public class GenericClass<T> {
    private T data;
}

with T variable, then you can print T name:
System.out.println(data.getClass().getSimpleName()); // "String", "Integer", etc.

A: Use an abstract method that returns the class type then use it in that class and wherever you extend generic class you will have to implement that abstract method to return the required class type
public class AbsractService<T>{
  public abstract Class<T> getClassType ();
   .......
}

at runtime
class AnimalService extends AbstractService<Animal>{

@Override
public Class<Animal> getClassType (){
        return Animal.class;
 }

  .....
}

A: I dont think you can, Java uses type erasure when compiling so your code is compatible with applications and libraries that were created pre-generics.
From the Oracle Docs:

Type Erasure
Generics were introduced to the Java language to provide tighter type
  checks at compile time and to support generic programming. To
  implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or
  Object if the type parameters are unbounded. The produced bytecode,
  therefore, contains only ordinary classes, interfaces, and methods.
  Insert type casts if necessary to preserve type safety. Generate
  bridge methods to preserve polymorphism in extended generic types.
  Type erasure ensures that no new classes are created for parameterized
  types; consequently, generics incur no runtime overhead.

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

A: Technique described in this article by Ian Robertson works for me.
In short quick and dirty example:
 public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V>
 {
    /**
     * Method returns class implementing EntityInterface which was used in class
     * extending AbstractDAO
     *
     * @return Class<T extends EntityInterface>
     */
    public Class<T> returnedClass()
    {
        return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0);
    }

    /**
     * Get the underlying class for a type, or null if the type is a variable
     * type.
     *
     * @param type the type
     * @return the underlying class
     */
    public static Class<?> getClass(Type type)
    {
        if (type instanceof Class) {
            return (Class) type;
        } else if (type instanceof ParameterizedType) {
            return getClass(((ParameterizedType) type).getRawType());
        } else if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            Class<?> componentClass = getClass(componentType);
            if (componentClass != null) {
                return Array.newInstance(componentClass, 0).getClass();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * Get the actual type arguments a child class has used to extend a generic
     * base class.
     *
     * @param baseClass the base class
     * @param childClass the child class
     * @return a list of the raw classes for the actual type arguments.
     */
    public static <T> List<Class<?>> getTypeArguments(
            Class<T> baseClass, Class<? extends T> childClass)
    {
        Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
        Type type = childClass;
        // start walking up the inheritance hierarchy until we hit baseClass
        while (!getClass(type).equals(baseClass)) {
            if (type instanceof Class) {
                // there is no useful information for us in raw types, so just keep going.
                type = ((Class) type).getGenericSuperclass();
            } else {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                Class<?> rawType = (Class) parameterizedType.getRawType();

                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
                }

                if (!rawType.equals(baseClass)) {
                    type = rawType.getGenericSuperclass();
                }
            }
        }

        // finally, for each actual type argument provided to baseClass, determine (if possible)
        // the raw class for that type argument.
        Type[] actualTypeArguments;
        if (type instanceof Class) {
            actualTypeArguments = ((Class) type).getTypeParameters();
        } else {
            actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
        }
        List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
        // resolve types by chasing down type variables.
        for (Type baseType : actualTypeArguments) {
            while (resolvedTypes.containsKey(baseType)) {
                baseType = resolvedTypes.get(baseType);
            }
            typeArgumentsAsClasses.add(getClass(baseType));
        }
        return typeArgumentsAsClasses;
    }
  }

A: Generics are not reified at run-time. This means the information is not present at run-time.
Adding generics to Java while mantaining backward compatibility was a tour-de-force (you can see the seminal paper about it: Making the future safe for the past: adding genericity to the Java programming language).
There is a rich literature on the subject, and some people are dissatisfied with the current state, some says that actually it's a lure and there is no real need for it. You can read both links, I found them quite interesting.

A: I think there is another elegant solution.
What you want to do is (safely) "pass" the type of the generic type parameter up from the concerete class to the superclass.
If you allow yourself to think of the class type as "metadata" on the class, that suggests the Java method for encoding metadata in at runtime:  annotations.
First define a custom annotation along these lines:
import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EntityAnnotation {
    Class entityClass();
}

You can then have to add the annotation to your subclass.
@EntityAnnotation(entityClass =  PassedGenericType.class)
public class Subclass<PassedGenericType> {...}

Then you can use this code to get the class type in  your base class:
import org.springframework.core.annotation.AnnotationUtils;
.
.
.

private Class getGenericParameterType() {
    final Class aClass = this.getClass();
    EntityAnnotation ne =
         AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);

    return ne.entityClass();
}

Some limitations of this approach are:

*

*You specify the generic type (PassedGenericType) in TWO places rather than one which is non-DRY.

*This is only possible if you can modify the concrete subclasses.

A: public static final Class<?> getGenericArgument(final Class<?> clazz)
{
    return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}

A: If you are working with spring:
public static Class<?>[] resolveTypeArguments(Class<?> parentClass, Class<?> subClass) {
    if (subClass.isSynthetic()) {
        return null;
    }
    return GenericTypeResolver.resolveTypeArguments(subClass, parentClass);
}

By the way, GenericTypeResolver will still get null for the non-subclasses class like the question mentioned, because the generic info of such class was completely erased after compilation.
The only way to solve this question may be:
public class GenericClass<T>
{
    private final Class<T> clazz;
    public Foo(Class<T> clazz) {
        this.clazz= clazz;
    }

    public Type getMyType()
    {
        return clazz;
    }
}

A: If you cannot change the generic class and use one of the method already explained on this page, then simple approach would be to get the type class based on the runtime instance class name.
Class getType(GenericType runtimeClassMember){
if (ClassA.class.equals(runtimeClassMember.getClass()){
  return TypeForClassA.class;
} else if (ClassB.class.equals(runtimeClassMember.getClass()){
  return TypeForClassB.class;
}

//throw an expectation or do whatever you want for the cases not described in the if section.
}

A: I found this to be a simple understandable and easily explainable  solution
public class GenericClass<T> {

    private Class classForT(T...t) {
        return t.getClass().getComponentType();
    }

    public static void main(String[] args) {
        GenericClass<String> g = new GenericClass<String>();

        System.out.println(g.classForT());
        System.out.println(String.class);
    }
}

A: It might be useful to someone. You can Use  java.lang.ref.WeakReference;
this way:
class SomeClass<N>{
  WeakReference<N> variableToGetTypeFrom;

  N getType(){
    return variableToGetTypeFrom.get();
  }
}

A: I did the same as @Moesio Above but in Kotlin it could be done this way:
class A<T : SomeClass>() {

    var someClassType : T

    init(){
    this.someClassType = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
    }

}

A: This was inspired by Pablo's and CoolMind's answers.
Occasionally I have also used the technique from kayz1's answer (expressed in many other answers as well), and I believe it is a decent and reliable way to do what the OP asked.
I chose to define this as an interface (similar to PJWeisberg) first because I have existing types that would benefit from this functionality, particularly a heterogeneous generic union type:
public interface IGenericType<T>
{
    Class<T> getGenericTypeParameterType();
}

Where my simple implementation in a generic anonymous interface implementation looks like the following:
//Passed into the generic value generator function: toStore
//This value name is a field in the enclosing class.
//IUnionTypeValue<T> is a generic interface that extends IGenericType<T>
value = new IUnionTypeValue<T>() {
    ...
    private T storedValue = toStore;
    ...

    @SuppressWarnings("unchecked")
    @Override
    public Class<T> getGenericTypeParameterType()
    {
        return (Class<T>) storedValue.getClass();
    }
}

I imagine this could be also implemented by being built with a class definition object as the source, that's just a separate use-case.
I think the key is as many other answers have stated, in one way or another, you need to get the type information at runtime to have it available at runtime; the objects themselves maintain their type, but erasure (also as others have said, with appropriate references) causes any enclosing/container types to lose that type information.


text:
#ifndef _ARM_KEXEC_H
#define _ARM_KEXEC_H

#ifdef CONFIG_KEXEC

/* Maximum physical address we can use pages from */
#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
/* Maximum address we can reach in physical address mode */
#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
/* Maximum address we can use for the control code buffer */
#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)

#define KEXEC_CONTROL_PAGE_SIZE	4096

#define KEXEC_ARCH KEXEC_ARCH_ARM

#define KEXEC_ARM_ATAGS_OFFSET  0x1000
#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000

#ifndef __ASSEMBLY__

/**
 * crash_setup_regs() - save registers for the panic kernel
 * @newregs: registers are saved here
 * @oldregs: registers to be saved (may be %NULL)
 *
 * Function copies machine registers from @oldregs to @newregs. If @oldregs is
 * %NULL then current registers are stored there.
 */
static inline void crash_setup_regs(struct pt_regs *newregs,
				    struct pt_regs *oldregs)
{
	if (oldregs) {
		memcpy(newregs, oldregs, sizeof(*newregs));
	} else {
		__asm__ __volatile__ (
			"stmia	%[regs_base], {r0-r12}\n\t"
			"mov	%[_ARM_sp], sp\n\t"
			"str	lr, %[_ARM_lr]\n\t"
			"adr	%[_ARM_pc], 1f\n\t"
			"mrs	%[_ARM_cpsr], cpsr\n\t"
		"1:"
			: [_ARM_pc] "=r" (newregs->ARM_pc),
			  [_ARM_cpsr] "=r" (newregs->ARM_cpsr),
			  [_ARM_sp] "=r" (newregs->ARM_sp),
			  [_ARM_lr] "=o" (newregs->ARM_lr)
			: [regs_base] "r" (&newregs->ARM_r0)
			: "memory"
		);
	}
}

/* Function pointer to optional machine-specific reinitialization */
extern void (*kexec_reinit)(void);

#endif /* __ASSEMBLY__ */

#endif /* CONFIG_KEXEC */

#endif /* _ARM_KEXEC_H */

redpajama_set_name: RedPajamaGithub


Home Décor theme from fmeextensions.com is a perfect theme for interior decors, carpet and upholstery sites, furniture and furnishing stores etc, and comes with a fast loading and user- friendly design scheme that can be easily customized as per your requirements.
The homepage comes with extensive navigation and search options that allow you to easily display all of your featured product categories and allow users to easily navigate through them. A full-width homepage slider helps you easily create a slideshow of your featured products and banners. The rest of the layout comes in a 4 column grid along with an extension ready footer and sidebar. It also has an opt-in box for subscription management.
The Home Decor theme comes with the below navigation options.
A primary Megamenu allows you to include multiple columns of your product category links within a single menu item along with a provision to add a image, widget or a video clip.
A separate Top menu has quicklinks to account management and shopping cart options. A keyword search box is also located in the header enabling users to easily do a quick search.
The footer block allows you to insert quicklinks to your internal page in two different locations. It also has an advanced search facility where users can search with multiple attributes.
The sidebar also has accordion styled menus which can be used for your product categories.
Each of the individual product pages come with embedded Lightbox galleries which can support multiple images with magnification and scrolling features. Users can submit reviews, add product tags, email the page and can also add the product to a wishlist. They can also compare between multiple featured products.
Embedded social media links in the header allow users to easily share a specific product with major social networking sites.
The checkout page allows users to redeem discount coupons, and also has a embedded Shipping and Tax estimator extension which allows users to get a cost estimate based on the location details.
The Magento admin panel helps you easily manage all your design, layout and e-commerce options with a complete ease of administration. The theme also comes with built-in extensions such as a shipping and tax estimator which gives an estimate as per the submitted location details.
The Home Décor premium Magento theme is priced at $69.99.


text:
'The Art of Eating Well' by Jasmine and Melissa Hemsley has soared into the league of the UK's best-selling non-fiction hardback books.
Four cookbooks feature in non-fiction hardback chart
28th January 2015	News Comments Off on Four cookbooks feature in non-fiction hardback chart 589 Views
'The Art of Eating Well' by Jasmine and Melissa Hemsley has soared into the league of the UK's best-selling non-fiction hardback books.
At number three in the chart, the cookbook by London-based sisters features more than 150 recipes which are free from grain, gluten, high starch and refined sugar. Jasmine and Melissa's philosophy is simple: a healthy gut leads to a healthy body and mind. "We are a London based family business for people who want to live healthier and more energised lives," they said.
'Home Comforts' by James Martin is at number eight. A tie-in book to the celebrity chef's BBC series entitled 'James Martin: Home Comforts', this collection of recipes ranges from 'fancy dinners to comforting puds'. The chapters are divided into Lighter Comforts, Quick Comforts, Easy Comforts, Slow Comforts, Spicy Comforts, Sweet Comforts and Baked Comforts. The recipes featured are taken from the first and second series of 'James Martin: Home Comforts', aired on BBC1 and BBC2 respectively.
"Here are the recipes I love to cook at home; the ones I turn to when away from the restaurant and from TV studios," James said. "These are all the things I've learned over my career, coupled with some new recipes inspired by local producers and suppliers."
'Jamie's Comfort Food' by Jamie Oliver is in ninth position. The TV cook's new book brings together 100 'ultimate comfort food' recipes. It features versions of all-time favourites, and also introduces dishes from countries around the world. "This isn't everyday cooking – this is about weekends, holidays, celebrations and occasions. Whether you're home alone, or sharing the love with a big group of family or friends, there really is something for everyone," Jamie said. Recipes include moussaka, gyoza with crispy wings, ramen and katsu curry to eggs Benedict, sticky toffee pudding and tutti frutti pear tarte tatin.
In tenth place is 'Best Ever Dishes' by Tom Kerridge. Known for his big flavours and accessible food, the Michelin-starred chef aims to show 'how to cook the best ever versions of the food everyone loves to eat, turning ordinary dishes into extraordinary ones'. The book features more than 100 of his favourite recipes, starting with classics such as tomato soup, chicken Kiev and rice pudding, which he 'refines and elevates to the best version that he has ever tasted'.
"Every day I try to make each dish as good as it can be: my personal best ever. I like getting the balance of taste and texture just right, using familiar ingredients and creating big, intense flavours. Now, I hope you'll use my recipes to make some best ever dishes of your own," Tom said.
The bestsellers list is compiled by Nielsen Bookscan TCM, which collates real time sales from over 6,500 retailers representing over 90% of the UK book market. It appeared in the January 25 issue of 'The Mail on Sunday's' 'Event' Magazine.
Previous Police need your help: do you recognise this tool?
Next Katie Alice comes to Spring Fair courtesy of Creative Tops

redpajama_set_name: RedPajamaCommonCrawl


text:
El municipio de West Holman (en inglés: West Holman Township) es un municipio ubicado en el condado de Osceola en el estado estadounidense de Iowa. En el año 2010 tenía una población de 2106 habitantes y una densidad poblacional de 22,64 personas por km².

Geografía
El municipio de West Holman se encuentra ubicado en las coordenadas . Según la Oficina del Censo de los Estados Unidos, el municipio tiene una superficie total de 93.01 km², de la cual 93,01 km² corresponden a tierra firme y (0 %) 0 km² es agua.

Demografía
Según el censo de 2010, había 2106 personas residiendo en el municipio de West Holman. La densidad de población era de 22,64 hab./km². De los 2106 habitantes, el municipio de West Holman estaba compuesto por el 91,55 % blancos, el 0,28 % eran afroamericanos, el 0,24 % eran amerindios, el 0,52 % eran asiáticos, el 6,55 % eran de otras razas y el 0,85 % eran de una mezcla de razas. Del total de la población el 12,73 % eran hispanos o latinos de cualquier raza.

Referencias

Enlaces externos

Municipios de Iowa
Localidades del condado de Osceola (Iowa)

redpajama_set_name: RedPajamaWikipedia


text:
WHERE JOURNALISTS MEET ISRAEL
About JPC
JPC facilities
IAPC
JPC Events
Cartoon Competition
תחרות קריקטורות
مسابقة الكرتون
Concurso De Dibujos Animados
Concours De Dessin Animé
Students Programs
Professional Delegations
Press Freedom Conference
Press Freedom Conference 2019
JPC Media Delegation to the Commemoration of 75 years since liberation of Auschwitz
On January 27th 2020, JPC with the cooperation of the World Jewish Congress, sent a delegation of Israeli journalists to cover the commemoration of the 75th anniversary of the liberation of Auschwitz.
Film Critics Delegation 2019
In July 2019 The JPC hosted leading international Film Critics who came to cover the 36th Jerusalem Film Festival. On July 25, film critics from Poland, Portugal, Czech Republic, China, Lithuania, Russia and the USA arrived to join the celebration of cinema in Jerusalem. The journalists enjoyed a rich program which included watching local and international films, interviews with filmmakers and film industry figures, guided tours and social events.
Discovering Israel: Industry, Innovation and Culture delegation from Latin America
On September 1-7, 2018, The JPC hosted a group of 10 leading tech and economic journalists from Latin America. The journalists participated in a week-long program tailor made by the Jerusalem Press Club, in cooperation with Foreign Trade Administration at the Ministry of Economy. The program focused on Israeli innovation in different fields, including cyber, fintech, medical tech and more. The group toured the country to encounter cutting-edge technology in Jerusalem, Yokne'am, Haifa, Be'er Sheva and Tel Aviv. In addition, the group visited the DLD innovation festival which was held in Tel Aviv for the 9th time.
We would like to thank our partners at the Ministry of Economy for this successful project.
We are looking forward to hosting our next economic and tech delegations in 2019. Stay tuned for more details!
Discovering Israel: Industry, Innovation and culture delegation from India
Film Critics Delegation – 2018
On July 7-13, 2018, we were honored to host a group of 9 leading tech and economic journalists from India. The journalists participated in a week-long program tailor made by the Jerusalem Press Club, in cooperation with Foreign Trade Administration at the Ministry of Economy. The program focused on Israeli innovation in different fields, including cyber, fintech, medical tech and more. The group toured the country to meet cutting-edge technology in Jerusalem, Be'er Sheva, Tel Aviv, Herzliya and Haifa.
We are Looking forward to hosting our next group of international tech reporters, from Latin America. Stay tuned for more details!
In July 2018, The JPC hosted leading international film critics that came to cover the 35th Jerusalem Film Festival. On July 26, fourteen film critics from France, India, Poland, Portugal, Switzerland, Austria, Belgium, USA, UK and Russia, arrived to enjoy the celebration of cinema in Jerusalem. The journalists enjoyed a rich program which included film-watching of local and international films; interviews with filmmakers and film industry figures; guided tours and social events.
Film critic Delegation
Chamber Music Delegation
In July, JPC hosted international leading film critics were brought to cover the Jerusalem Film Festival. On July 13, eleven film critics from Angola, Australia, Croatia, China ,Cyprus, the Czech Republic, India, Latvia, Spain and USA, arrived to enjoy the celebration of cinema in Jerusalem, with a rich program that included film-watching, interviews with filmmakers and actors, guided tours and social events.
In August, JPC hosted international leading chamber music critics for the International Chamber music festival in Jerusalem. Journalists arrived to enjoy the chamber music concerts held every night of the festival, as well as interviews with musicians and experiencing the Old City of Jerusalem.
Literature critic delegation
In July, JPC hosted international leading film critics that were brought to cover the Jerusalem Film Festival. The international delegation arrived to enjoy the celebration of cinema in Jerusalem, with a rich program that included film-watching, interviews with filmmakers and actors, being exposed to different Israeli film schools, guided tours around the city and social events.
In May, the JPC brought international literature critics in order to experience Israeli and international authors as part of the Jerusalem Writers Festival. The festival brought unique discussion and dialogue between the different authors, and provided a special experience to the literature critics.
Discovering Israel: Industry, Innovation and culture delegation
In September, The Jerusalem Press Club, together with the Israeli Ministry of Economy and the Chinese Media Center joined together to bring to Israel 12 leading Chinese journalists to cover israel's industry, innovation and culture. During their 10 days in Israel, the journalists visited cutting-edge hi-tech companies like Medinol and Mobileye; visited Weizmann Institute and the Technion, where they were exposed to Israel's recent accomplishments in science; and were exposed to the wide variety of innovation Israel has to offer.
In August, JPC hosted international leading chamber music critics that were brought to cover the International Jerusalem chamber music festival. The international delegation arrived to enjoy the celebration of chamber music in Jerusalem, with a rich program that included concerts, interviews with musicians and guided tours around the city and social events.
Science journalists delegation
In July, JPC hosted international film critics from around the world joined the 32nd Jerusalem Film Festival. The participants enjoyed a special program that included a meeting with the directors of two leading film schools in Jerusalem (Sam Spiegel and Ma'aleh), a tour of the Old City, a private tour of Yad Vashem and of its one-of-a-kind Visual Center, being exposed to the unique Israeli film industry.
Due to the success of the first Science delegation, the JPC assisted the Israel Academy of Sciences and Humanities with their delegation of international Science correspondents. The delegation was exposed to the variety of Israel science, innovation, accomplishments and Israeli scientists.
Former Soviet Union journalist delegation
In July, JPC hosted 20 leading film critics from around the world who came to cover Jerusalem's 31st Film Festival. The journalists enjoyed the festival along side tours of the Old City, the Sam Spiegel Film & Television School, Yad Vashem and it's visual center and several other events and discussions about film and Israel.
In the words of one of the participants: "One of the most thought-provoking, stimulating, moving places I have ever had the chance to visit, within the excellent framework of the Festival, showcasing the talents of a bunch of hardworking, energetic filmmakers whose work I would never have come across otherwise. I felt very privileged to be there, particularly at such a time."
Nativ, Genesis and the Jerusalem Press Club joined together to bring a group of leading Jewish journalists from the former Soviet Union. The group included journalists from leading main-stream (not Jewish) media companies in Moscow, Saint Petersburg, Odessa, Kiev, Kharkiv, Chisinau, Minsk, Novosibrsk, Dnipropetrovsk and Tashkent.
The participents met with Ministers, Members of the Knesset, immigrants from the former Soviet Union and various speakers, took part in panels and discussions about different issues and visited Yad Vashem, Hebrew University, the Old City, southern Israel, and Sderot. They learned about Israel's media, culture and agriculture and about the challenges and success Israel faces every day.
In November, the first and one-of-a-kind program of senior science editors and journalists took place in partnership of the Jerusalem Press Club, the Program Department at Mishkenot Sha'ananim and the Israel Academy of Sciences and Humanities. The program exposed participants to Israeli science, achievements and personalities in a unique and packed 9-day program.
All JPC Events
JPC – Jerusalem Press Club
2 Sh.A Nachon st.
you can get in touch with us on https://xnxxme.com
[email protected] JERUSALEMPRESSCLUB.COM
Jerusalem Press Club	@jpressclub
A #JPCBriefing on Israel's #COVID policy - 'Tightened Restraint' & Vaccines with Prof. @RanBalicer, Chief... Read More
While we do our best to obtain permission to use copyrighted material and photos, this site might nevertheless contain material and photos the use of which has not always been specifically authorized by the copyright owners. We encourage owners of such material and photos to report to us immediately if they are not satisfied with this use. In accord with our non-profit mission, we are making such material and photos available without profit, in an educational effort to advance the understanding of Israel and the Middle East, among people who are interested in receiving this information for research and educational purposes. We believe that this constitutes a "fair use" of any such copyrighted material and photos.
If you wish to use copyrighted material and photos from this site for purposes of your own, that go beyond fair use, you must first obtain permission from the copyright owner(s).
All rights reserved to JPC
xnxx filme porno
Reichman new media
WEmanage – website management
& our top sponsor xnxx1.biz
First Name Last Name Title Email Organization Country --None-- Choose country Afghanistan Åland Islands Albania Algeria American Samoa Andorra Angola Anguilla Antarctica Antigua and Barbuda Argentina Armenia Aruba Australia Austria Azerbaijan Bahamas Bahrain Bangladesh Barbados Belarus Belgium Belize Benin Bermuda Bhutan Bolivia, Plurinational State of Bonaire, Sint Eustatius and Saba Bosnia and Herzegovina Botswana Bouvet Island Brazil British Indian Ocean Territory Brunei Darussalam Bulgaria Burkina Faso Burundi Cambodia Cameroon Canada Cape Verde Cayman Islands Central African Republic Chad Chile China Christmas Island Cocos (Keeling) Islands Colombia Comoros Congo Congo, the Democratic Republic of the Cook Islands Costa Rica Côte d'Ivoire Croatia Cuba Curaçao Cyprus Czech Republic Denmark Djibouti Dominica Dominican Republic Ecuador Egypt El Salvador Equatorial Guinea Eritrea Estonia Ethiopia Falkland Islands (Malvinas) Faroe Islands Fiji Finland France French Guiana French Polynesia French Southern Territories Gabon Gambia Georgia Germany Ghana Gibraltar Greece Greenland Grenada Guadeloupe Guam Guatemala Guernsey Guinea Guinea-Bissau Guyana Haiti Heard Island and McDonald Islands Holy See (Vatican City State) Honduras Hong Kong Hungary Iceland India Indonesia Iran, Islamic Republic of Iraq Ireland Isle of Man Israel Italy Jamaica Japan Jersey Jordan Kazakhstan Kenya Kiribati Korea, Democratic People's Republic of Korea, Republic of Kuwait Kyrgyzstan Lao People's Democratic Republic Latvia Lebanon Lesotho Liberia Libya Liechtenstein Lithuania Luxembourg Macao Macedonia, the former Yugoslav Republic of Madagascar Malawi Malaysia Maldives Mali Malta Marshall Islands Martinique Mauritania Mauritius Mayotte Mexico Micronesia, Federated States of Moldova, Republic of Monaco Mongolia Montenegro Montserrat Morocco Mozambique Myanmar Namibia Nauru Nepal Netherlands New Caledonia New Zealand Nicaragua Niger Nigeria Niue Norfolk Island Northern Mariana Islands Norway Oman Pakistan Palau Palestinian Territory, Occupied Panama Papua New Guinea Paraguay Peru Philippines Pitcairn Poland Portugal Puerto Rico Qatar Réunion Romania Russian Federation Rwanda Saint Barthélemy Saint Helena, Ascension and Tristan da Cunha Saint Kitts and Nevis Saint Lucia Saint Martin (French part) Saint Pierre and Miquelon Saint Vincent and the Grenadines Samoa San Marino Sao Tome and Principe Saudi Arabia Senegal Serbia Seychelles Sierra Leone Singapore Sint Maarten (Dutch part) Slovakia Slovenia Solomon Islands Somalia South Africa South Georgia and the South Sandwich Islands South Sudan Spain Sri Lanka Sudan Suriname Svalbard and Jan Mayen Swaziland Sweden Switzerland Syrian Arab Republic Taiwan, Province of China Tajikistan Tanzania, United Republic of Thailand Timor-Leste Togo Tokelau Tonga Trinidad and Tobago Tunisia Turkey Turkmenistan Turks and Caicos Islands Tuvalu Uganda Ukraine United Arab Emirates United Kingdom United States United States Minor Outlying Islands Uruguay Uzbekistan Vanuatu Venezuela, Bolivarian Republic of Viet Nam Virgin Islands, British Virgin Islands, U.S. Wallis and Futuna Western Sahara Yemen Zambia Zimbabwe Phone Membership Type: Choose membership Press Associate Corporate Lead Source Website


text:
// Copyright (c) Sandeep Mistry. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#if !defined(NRF51) && !defined(NRF52) &&!defined(__RFduino__)

// #define NRF_8001_DEBUG
// #define NRF_8001_ENABLE_DC_DC_CONVERTER

#include <SPI.h>

#include "BLECharacteristic.h"
#include "BLEDescriptor.h"
#include "BLERemoteService.h"
#include "BLERemoteCharacteristic.h"
#include "BLEService.h"
#include "BLEUtil.h"
#include "BLEUuid.h"

#include "nRF8001.h"

struct setupMsgData {
  unsigned char length;
  unsigned char cmd;
  unsigned char type;
  unsigned char offset;
  unsigned char data[28];
};

#define NB_BASE_SETUP_MESSAGES                  7
#define MAX_ATTRIBUTE_VALUE_PER_SETUP_MSG       28

#define DYNAMIC_DATA_MAX_CHUNK_SIZE             26
#define DYNAMIC_DATA_SIZE                       (DYNAMIC_DATA_MAX_CHUNK_SIZE * 6)

#if defined (__AVR__)
  /* Store the setup for the nRF8001 in the flash of the AVR to save on RAM */
  #if ARDUINO < 150
static /*const*/ hal_aci_data_t baseSetupMsgs[NB_BASE_SETUP_MESSAGES] PROGMEM =
  #else
static const hal_aci_data_t baseSetupMsgs[NB_BASE_SETUP_MESSAGES] PROGMEM =
  #endif
#else
/* Having PROGMEM here caused the setup messages to be zeroed out */
static const hal_aci_data_t baseSetupMsgs[NB_BASE_SETUP_MESSAGES] /*PROGMEM*/ =
#endif
{\
  {0x00,\
    {\
      0x07,0x06,0x00,0x00,0x03,0x02,0x41,0xfe,\
    },\
  },\
  {0x00,\
    {\
      0x1f,0x06,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x06,0x00,0x06,\
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
    },\
  },\
  {0x00,\
    {\
      0x1f,0x06,0x10,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
      0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x03,0x90,0x00,0xff,\
    },\
  },\
  {0x00,\
    {\
      0x1f,0x06,0x10,0x38,0xff,0xff,0x02,0x58,0x0a,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
      0x10,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x01,0x02,0x01,0x02,\
    },\
  },\
  {0x00,\
    {\
      0x05,0x06,0x10,0x54,0x00,0x02,\
    },\
  },\
  {0x00,\
    {\
      0x19,0x06,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
      0x00,0x00,0x00,0x00,0x00,0x00,\
    },\
  },\
  {0x00,\
    {\
      0x19,0x06,0x70,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
      0x00,0x00,0x00,0x00,0x00,0x00,\
    },\
  },\
};

/** crc function to re-calulate the CRC after making changes to the setup data.
*/
uint16_t crc_16_ccitt(uint16_t crc, uint8_t * data_in, uint16_t data_len) {

  uint16_t i;

  for(i = 0; i < data_len; i++)
  {
    crc  = (unsigned char)(crc >> 8) | (crc << 8);
    crc ^= data_in[i];
    crc ^= (unsigned char)(crc & 0xff) >> 4;
    crc ^= (crc << 8) << 4;
    crc ^= ((crc & 0xff) << 4) << 1;
  }

  return crc;
}

nRF8001::nRF8001(unsigned char req, unsigned char rdy, unsigned char rst) :
  BLEDevice(),

  _localPipeInfo(NULL),
  _numLocalPipeInfo(0),
  _broadcastPipe(0),

  _timingChanged(false),
  _closedPipesCleared(false),
  _remoteServicesDiscovered(false),
  _remotePipeInfo(NULL),
  _numRemotePipeInfo(0),

  _dynamicDataOffset(0),
  _dynamicDataSequenceNo(0),
  _storeDynamicData(false),

  _crcSeed(0xFFFF)
{
  this->_aciState.aci_pins.reqn_pin               = req;
  this->_aciState.aci_pins.rdyn_pin               = rdy;

#if !defined(SPI_HAS_TRANSACTION) || defined(__SAMD21G18A__)
#if defined(__SAM3X8E__)
  this->_aciState.aci_pins.spi_clock_divider      = 42;
#else
  this->_aciState.aci_pins.spi_clock_divider      = SPI_CLOCK_DIV8;
#endif
#endif

  this->_aciState.aci_pins.reset_pin              = rst;
  this->_aciState.aci_pins.active_pin             = UNUSED;
  this->_aciState.aci_pins.optional_chip_sel_pin  = UNUSED;
}

nRF8001::~nRF8001() {
  this->end();
}

void nRF8001::begin(unsigned char advertisementDataSize,
                      BLEEirData *advertisementData,
                      unsigned char scanDataSize,
                      BLEEirData *scanData,
                      BLELocalAttribute** localAttributes,
                      unsigned char numLocalAttributes,
                      BLERemoteAttribute** remoteAttributes,
                      unsigned char numRemoteAttributes)
{
  unsigned char numLocalPipedCharacteristics = 0;
  unsigned char numLocalPipes = 0;

  this->_crcSeed = 0xFFFF;

  for (int i = 0; i < numLocalAttributes; i++) {
    BLELocalAttribute* localAttribute = localAttributes[i];

    if (localAttribute->type() == BLETypeCharacteristic) {
      BLECharacteristic* characteristic = (BLECharacteristic *)localAttribute;
      unsigned char properties = characteristic->properties();

      if (properties) {
        numLocalPipedCharacteristics++;

        if (properties & BLEBroadcast) {
          numLocalPipes++;
        }

        if (properties & BLENotify) {
          numLocalPipes++;
        }

        if (properties & BLEIndicate) {
          numLocalPipes++;
        }

        if (properties & BLEWriteWithoutResponse) {
          numLocalPipes++;
        }

        if (properties & BLEWrite) {
          numLocalPipes++;
        }

        if (properties & BLERead) {
          numLocalPipes++;
        }
      }
    }
  }

  this->_localPipeInfo = (struct localPipeInfo*)malloc(sizeof(struct localPipeInfo) * numLocalPipedCharacteristics);

  unsigned char numRemoteServices = 0;
  unsigned char numRemotePipedCharacteristics = 0;
  unsigned char numRemotePipes = 0;
  unsigned char numCustomUuids = 0;

  for (int i = 0; i < numRemoteAttributes; i++) {
    BLERemoteAttribute* remoteAttribute = remoteAttributes[i];
    unsigned short remoteAttributeType = remoteAttribute->type();
    BLEUuid uuid = BLEUuid(remoteAttribute->uuid());

    if (uuid.length() > 2) {
      numCustomUuids++;
    }

    if (remoteAttributeType == BLETypeService) {
      numRemoteServices++;
    } else if (remoteAttributeType == BLETypeCharacteristic) {
      BLERemoteCharacteristic* characteristic = (BLERemoteCharacteristic *)remoteAttribute;
      unsigned char properties = characteristic->properties();

      if (properties) {
        numRemotePipedCharacteristics++;

        if (properties & BLENotify) {
          numRemotePipes++;
        }

        if (properties & BLEIndicate) {
          numRemotePipes++;
        }

        if (properties & BLEWriteWithoutResponse) {
          numRemotePipes++;
        }

        if (properties & BLEWrite) {
          numRemotePipes++;
        }

        if (properties & BLERead) {
          numRemotePipes++;
        }
      }
    }
  }

  this->_remotePipeInfo = (struct remotePipeInfo*)malloc(sizeof(struct remotePipeInfo) * numRemotePipedCharacteristics);

  lib_aci_init(&this->_aciState, false);

  if (this->_bondStore) {
    this->_aciState.bonded = ACI_BOND_STATUS_FAILED;

    this->_storeDynamicData = false;
  }

  this->waitForSetupMode();

  hal_aci_data_t setupMsg;
  struct setupMsgData* setupMsgData = (struct setupMsgData*)setupMsg.buffer;

  setupMsg.status_byte = 0;

  bool hasAdvertisementData = advertisementDataSize && advertisementData;
  bool hasScanData          = scanDataSize && scanData;

  for (int i = 0; i < NB_BASE_SETUP_MESSAGES; i++) {
    int setupMsgSize = pgm_read_byte_near(&baseSetupMsgs[i].buffer[0]) + 2;

    memcpy_P(&setupMsg, &baseSetupMsgs[i], setupMsgSize);

    if (i == 1) {
      setupMsgData->data[5] = numRemoteServices;
      setupMsgData->data[6] = numLocalPipedCharacteristics;
      setupMsgData->data[7] = numRemotePipedCharacteristics;
      setupMsgData->data[8] = (numLocalPipes + numRemotePipes);

      if (this->_bondStore) {
        setupMsgData->data[4] |= 0x02;
      }

#ifdef NRF_8001_ENABLE_DC_DC_CONVERTER
      setupMsgData->data[13] |= 0x01;
#endif
    } else if (i == 2 && hasAdvertisementData) {
      setupMsgData->data[18] |= 0x40;

      setupMsgData->data[22] |= 0x40;

      setupMsgData->data[26] = numCustomUuids;
    } else if (i == 3) {
      if (hasAdvertisementData) {
        setupMsgData->data[16] |= 0x40;
      }

      if (hasScanData) {
        setupMsgData->data[8] |= 0x40;

        setupMsgData->data[12] |= 0x40;

        setupMsgData->data[20] |= 0x40;
      }
    } else if (i == 4) {
      if (this->_bondStore) {
        setupMsgData->data[0] |= 0x01;
      }
    } else if (i == 5 && hasAdvertisementData) {
      setupMsgData->data[0] = advertisementData[0].type;
      setupMsgData->data[1] = advertisementData[0].length;
      memcpy(&setupMsgData->data[2], advertisementData[0].data, advertisementData[0].length);
    } else if (i == 6 && hasScanData) {
      setupMsgData->data[0] = scanData[0].type;
      setupMsgData->data[1] = scanData[0].length;
      memcpy(&setupMsgData->data[2], scanData[0].data, scanData[0].length);
    }

    this->sendSetupMessage(&setupMsg);
  }

  // GATT
  unsigned short gattSetupMsgOffset = 0;
  unsigned short handle             = 1;
  unsigned char  pipe               = 1;
  unsigned char  numLocalPiped      = 0;
  unsigned char  numRemotePiped     = 0;

  for (int i = 0; i < numLocalAttributes; i++) {
    BLELocalAttribute* localAttribute = localAttributes[i];
    unsigned short localAttributeType = localAttribute->type();
    BLEUuid uuid = BLEUuid(localAttribute->uuid());
    const unsigned char* uuidData = uuid.data();
    unsigned char uuidLength = uuid.length();

    if (localAttributeType == BLETypeService) {
      setupMsgData->length  = 12 + uuidLength;

      setupMsgData->data[0] = 0x04;
      setupMsgData->data[1] = 0x04;
      setupMsgData->data[2] = uuidLength;
      setupMsgData->data[3] = uuidLength;

      setupMsgData->data[4] = (handle >> 8) & 0xff;
      setupMsgData->data[5] = handle & 0xff;
      handle++;

      setupMsgData->data[6] = (localAttributeType >> 8) & 0xff;
      setupMsgData->data[7] = localAttributeType & 0xff;

      setupMsgData->data[8] = ACI_STORE_LOCAL;

      memcpy(&setupMsgData->data[9], uuidData, uuidLength);

      this->sendSetupMessage(&setupMsg, 0x2, gattSetupMsgOffset);
    } else if (localAttributeType == BLETypeCharacteristic) {
      BLECharacteristic* characteristic = (BLECharacteristic *)localAttribute;
      unsigned char properties = characteristic->properties();
      const char* characteristicUuid = characteristic->uuid();

      struct localPipeInfo* localPipeInfo = &this->_localPipeInfo[numLocalPiped];

      memset(localPipeInfo, 0, sizeof(struct localPipeInfo));

      localPipeInfo->characteristic = characteristic;

      if (properties) {
        numLocalPiped++;

        if (properties & BLEBroadcast) {
          localPipeInfo->advPipe = pipe;

          pipe++;
        }

        if (properties & BLENotify) {
          localPipeInfo->txPipe = pipe;

          pipe++;
        }

        if (properties & BLEIndicate) {
          localPipeInfo->txAckPipe = pipe;

          pipe++;
        }

        if (properties & BLEWriteWithoutResponse) {
          localPipeInfo->rxPipe = pipe;

          pipe++;
        }

        if (properties & BLEWrite) {
          localPipeInfo->rxAckPipe = pipe;

          pipe++;
        }

        if (properties & BLERead) {
          localPipeInfo->setPipe = pipe;

          pipe++;
        }
      }

      setupMsgData->length   = 15 + uuidLength;

      setupMsgData->data[0]  = 0x04;
      setupMsgData->data[1]  = 0x04;
      setupMsgData->data[2]  = 3 + uuidLength;
      setupMsgData->data[3]  = 3 + uuidLength;

      setupMsgData->data[4]  = (handle >> 8) & 0xff;
      setupMsgData->data[5]  = handle & 0xff;
      handle++;

      setupMsgData->data[6]  = (localAttributeType >> 8) & 0xff;
      setupMsgData->data[7]  = localAttributeType & 0xff;

      setupMsgData->data[8]  = ACI_STORE_LOCAL;
      setupMsgData->data[9]  = properties & 0xfe;

      setupMsgData->data[10] = handle & 0xff;
      setupMsgData->data[11] = (handle >> 8) & 0xff;
      localPipeInfo->valueHandle = handle;
      handle++;

      memcpy(&setupMsgData->data[12], uuidData, uuidLength);

      this->sendSetupMessage(&setupMsg, 0x2, gattSetupMsgOffset);

      setupMsgData->length   = 12;

      setupMsgData->data[0]  = 0x04;
      setupMsgData->data[1]  = 0x00;

      if (characteristic->fixedLength()) {
        setupMsgData->data[0] |= 0x02;
      }

      if (properties & BLERead) {
        setupMsgData->data[1] |= 0x04;
      }

      if (this->_bondStore &&
          strcmp(characteristicUuid, "2a00") != 0 &&
          strcmp(characteristicUuid, "2a01") != 0 &&
          strcmp(characteristicUuid, "2a05") != 0) {
        setupMsgData->data[1] |= 0x08;
      }

      if (properties & (BLEWrite | BLEWriteWithoutResponse)) {
        setupMsgData->data[0] |= 0x40;
        setupMsgData->data[1] |= 0x10;
      }

      if (properties & BLENotify) {
        setupMsgData->data[0] |= 0x10;
      }

      if (properties & BLEIndicate) {
        setupMsgData->data[0] |= 0x20;
      }

      unsigned char valueSize = characteristic->valueSize();
      unsigned char valueLength = characteristic->valueLength();

      setupMsgData->data[2]  = valueSize;
      if (characteristic->fixedLength()) {
        setupMsgData->data[2]++;
      }

      setupMsgData->data[3]  = valueLength;

      setupMsgData->data[4]  = (localPipeInfo->valueHandle >> 8) & 0xff;
      setupMsgData->data[5]  = localPipeInfo->valueHandle & 0xff;

      if (uuidLength == 2) {
        setupMsgData->data[6]  = uuidData[1];
        setupMsgData->data[7]  = uuidData[0];
      } else {
        setupMsgData->data[6]  = 0x00;
        setupMsgData->data[7]  = 0x00;
      }

      setupMsgData->data[8]  = ACI_STORE_LOCAL;

      this->sendSetupMessage(&setupMsg, 0x2, gattSetupMsgOffset);

      int valueOffset = 0;

      while(valueOffset < valueSize) {
        int chunkSize = min(valueSize - valueOffset, MAX_ATTRIBUTE_VALUE_PER_SETUP_MSG);
        int valueCopySize = min(valueLength - valueOffset, chunkSize);

        setupMsgData->length = 3 + chunkSize;

        memset(setupMsgData->data, 0x00, chunkSize);

        if (valueCopySize > 0) {
          for (int j = 0; j < chunkSize; j++) {
            setupMsgData->data[j] = (*characteristic)[j + valueOffset];
          }
        }

        this->sendSetupMessage(&setupMsg, 0x2, gattSetupMsgOffset);

        valueOffset += chunkSize;
      }

      if (properties & (BLENotify | BLEIndicate)) {
        setupMsgData->length   = 14;

        setupMsgData->data[0]  = 0x46;
        setupMsgData->data[1]  = 0x14;

        setupMsgData->data[2]  = 0x03;
        setupMsgData->data[3]  = 0x02;

        setupMsgData->data[4]  = (handle >> 8) & 0xff;
        setupMsgData->data[5]  = handle & 0xff;
        localPipeInfo->configHandle = handle;
        handle++;

        setupMsgData->data[6]  = 0x29;
        setupMsgData->data[7]  = 0x02;

        setupMsgData->data[8]  = ACI_STORE_LOCAL;

        setupMsgData->data[9]  = 0x00;
        setupMsgData->data[10] = 0x00;

        this->sendSetupMessage(&setupMsg, 0x2, gattSetupMsgOffset);
      }
    } else if (localAttributeType == BLETypeDescriptor) {
      BLEDescriptor* descriptor = (BLEDescriptor *)localAttribute;

      setupMsgData->length   = 12;

      setupMsgData->data[0]  = 0x04;
      setupMsgData->data[1]  = 0x04;

      unsigned char valueLength = descriptor->valueLength();

      setupMsgData->data[2]  = valueLength;
      setupMsgData->data[3]  = valueLength;

      setupMsgData->data[4]  = (handle >> 8) & 0xff;
      setupMsgData->data[5]  = handle & 0xff;
      handle++;

      setupMsgData->data[6]  = uuidData[1];
      setupMsgData->data[7]  = uuidData[0];

      setupMsgData->data[8]  = ACI_STORE_LOCAL;

      this->sendSetupMessage(&setupMsg, 0x2, gattSetupMsgOffset);

      int valueOffset = 0;

      while(valueOffset < valueLength) {
        int chunkSize = min(valueLength - valueOffset, MAX_ATTRIBUTE_VALUE_PER_SETUP_MSG);

        setupMsgData->length = 3 + chunkSize;

        for (int j = 0; j < chunkSize; j++) {
          setupMsgData->data[j] = (*descriptor)[j + valueOffset];
        }

        this->sendSetupMessage(&setupMsg, 0x2, gattSetupMsgOffset);

        valueOffset += chunkSize;
      }
    }
  }

  this->_numLocalPipeInfo = numLocalPiped;

  // terminator
  setupMsgData->length   = 4;

  setupMsgData->data[0]  = 0x00;

  this->sendSetupMessage(&setupMsg, 0x2, gattSetupMsgOffset);

  unsigned short remoteServiceSetupMsgOffset  = 0;
  unsigned char  customUuidIndex = 2;

  for (int i = 0; i < numRemoteAttributes; i++) {
    BLERemoteAttribute* remoteAttribute = remoteAttributes[i];
    BLEUuid uuid = BLEUuid(remoteAttribute->uuid());
    const unsigned char* uuidData = uuid.data();
    unsigned char uuidLength = uuid.length();

    if (remoteAttribute->type() == BLETypeService) {
      unsigned char numRemoteCharacteristics = 0;
      setupMsgData->data[3]    = (pipe - 1);

      for (int j = (i + 1); j < numRemoteAttributes; j++) {
        if (remoteAttributes[j]->type() == BLETypeCharacteristic) {
          BLERemoteCharacteristic* remoteCharateristic = (BLERemoteCharacteristic*)remoteAttributes[j];

          struct remotePipeInfo* remotePipeInfo = &this->_remotePipeInfo[numRemotePiped];
          memset(remotePipeInfo, 0, sizeof(struct remotePipeInfo));

          unsigned char properties = remoteCharateristic->properties();

          remotePipeInfo->characteristic = remoteCharateristic;

          if (properties & BLEWriteWithoutResponse) {
            remotePipeInfo->txPipe = pipe;

            pipe++;
          }

          if (properties & BLEWrite) {
            remotePipeInfo->txAckPipe = pipe;

            pipe++;
          }

          if (properties & BLERead) {
            remotePipeInfo->rxReqPipe = pipe;

            pipe++;
          }

          if (properties & BLENotify) {
            remotePipeInfo->rxPipe = pipe;

            pipe++;
          }

          if (properties & BLEIndicate) {
            remotePipeInfo->rxAckPipe = pipe;

            pipe++;
          }

          numRemoteCharacteristics++;

          numRemotePiped++;
        } else {
          break;
        }
      }

      setupMsgData->length = 8;

      if (uuidLength == 2) {
        setupMsgData->data[0]  = uuidData[1];
        setupMsgData->data[1]  = uuidData[0];
        setupMsgData->data[2]  = 0x01;
      } else {
        setupMsgData->data[0]  = uuidData[13];
        setupMsgData->data[1]  = uuidData[12];
        setupMsgData->data[2]  = customUuidIndex;

        customUuidIndex++;
      }

      setupMsgData->data[4]    = numRemoteCharacteristics;

      this->sendSetupMessage(&setupMsg, 0x3, remoteServiceSetupMsgOffset);
    }
  }

  this->_numRemotePipeInfo = numRemotePiped;

  // pipes
  unsigned short pipeSetupMsgOffset  = 0;

  for (int i = 0; i < numLocalPiped; i++) {
    struct localPipeInfo localPipeInfo = this->_localPipeInfo[i];

    setupMsgData->length   = 13;

    setupMsgData->data[0]  = 0x00;
    setupMsgData->data[1]  = 0x00;

    setupMsgData->data[2]  = 0x01;

    setupMsgData->data[3]  = 0x00;
    setupMsgData->data[4]  = 0x00;

    setupMsgData->data[5]  = 0x04;

    setupMsgData->data[6]  = (localPipeInfo.valueHandle >> 8) & 0xff;
    setupMsgData->data[7]  = localPipeInfo.valueHandle & 0xff;

    setupMsgData->data[8]  = (localPipeInfo.configHandle >> 8) & 0xff;
    setupMsgData->data[9]  = localPipeInfo.configHandle & 0xff;

    unsigned char properties = localPipeInfo.characteristic->properties();

    if (properties & BLEBroadcast) {
      setupMsgData->data[4] |= 0x01; // Adv
    }

    if (properties & BLENotify) {
      setupMsgData->data[4] |= 0x02; // TX
    }

    if (properties & BLEIndicate) {
      setupMsgData->data[4] |= 0x04; // TX Ack
    }

    if (properties & BLEWriteWithoutResponse) {
      setupMsgData->data[4] |= 0x08; // RX Ack
    }

    if (properties & BLEWrite) {
      setupMsgData->data[4] |= 0x10; // RX Ack
    }

    if (properties & BLERead) {
      setupMsgData->data[4] |= 0x80; // Set
    }

    this->sendSetupMessage(&setupMsg, 0x4, pipeSetupMsgOffset);
  }

  for (int i = 0; i < numRemotePiped; i++) {
    struct remotePipeInfo remotePipeInfo = this->_remotePipeInfo[i];

    BLERemoteCharacteristic *remoteCharacteristic = remotePipeInfo.characteristic;
    BLEUuid uuid = BLEUuid(remoteCharacteristic->uuid());
    const unsigned char* uuidData = uuid.data();
    unsigned char uuidLength = uuid.length();

    setupMsgData->length   = 13;

    if (uuidLength== 2) {
      setupMsgData->data[0]  = uuidData[1];
      setupMsgData->data[1]  = uuidData[0];
      setupMsgData->data[2]  = 0x01;
    } else {
      setupMsgData->data[0]  = uuidData[13];
      setupMsgData->data[1]  = uuidData[12];
      setupMsgData->data[2]  = customUuidIndex;

      customUuidIndex++;
    }

    setupMsgData->data[3]  = 0x00; // pipe properties
    setupMsgData->data[4]  = 0x00; // pipe properties

    setupMsgData->data[5]  = 0x04;

    setupMsgData->data[6]  = 0x00;
    setupMsgData->data[7]  = 0x00;

    setupMsgData->data[8]  = 0x00;
    setupMsgData->data[9]  = 0x00;

    unsigned char properties = remoteCharacteristic->properties();

    if (properties & BLERead) {
      setupMsgData->data[4] |= 0x40; // ACI_RX_REQ
    }

    if (properties & BLEWriteWithoutResponse) {
      setupMsgData->data[4] |= 0x02; // ACI_TX
    }

    if (properties & BLEWrite) {
      setupMsgData->data[4] |= 0x04; // ACI_TX_ACK
    }

    if (properties & BLENotify) {
      setupMsgData->data[4] |= 0x08; // ACI_RX
    }

    if (properties & BLEIndicate) {
      setupMsgData->data[4] |= 0x10; // ACI_RX_ACK
    }

    this->sendSetupMessage(&setupMsg, 0x4, pipeSetupMsgOffset);
  }

  // custom uuid's (remote only for now)
  unsigned short customUuidSetupMsgOffset = 0;

  for (int i = 0; i < numRemoteAttributes; i++) {
    BLERemoteAttribute* remoteAttribute = remoteAttributes[i];
    BLEUuid uuid = BLEUuid(remoteAttribute->uuid());
    const unsigned char* uuidData = uuid.data();
    unsigned char uuidLength = uuid.length();

    setupMsgData->length = 3 + uuidLength;
    memcpy(&setupMsgData->data, uuidData, uuidLength);

    setupMsgData->data[12]  = 0;
    setupMsgData->data[13]  = 0;

    this->sendSetupMessage(&setupMsg, 0x5, customUuidSetupMsgOffset);
  }

  // crc
  unsigned short crcOffset = 0;
  setupMsgData->length   = 6;
  setupMsgData->data[0]  = 3;

  this->sendSetupMessage(&setupMsg, 0xf, crcOffset, true);
}

void nRF8001::poll() {
  // We enter the if statement only when there is a ACI event available to be processed
  if (lib_aci_event_get(&this->_aciState, &this->_aciData)) {
    aci_evt_t* aciEvt = &this->_aciData.evt;

    switch(aciEvt->evt_opcode) {
      /**
      As soon as you reset the nRF8001 you will get an ACI Device Started Event
      */
      case ACI_EVT_DEVICE_STARTED: {
        this->_aciState.data_credit_total = aciEvt->params.device_started.credit_available;
        switch(aciEvt->params.device_started.device_mode) {
          case ACI_DEVICE_SETUP:
            /**
            When the device is in the setup mode
            */
#ifdef NRF_8001_DEBUG
            Serial.println(F("Evt Device Started: Setup"));
#endif
            break;

          case ACI_DEVICE_STANDBY:
#ifdef NRF_8001_DEBUG
            Serial.println(F("Evt Device Started: Standby"));
#endif
            //Looking for an iPhone by sending radio advertisements
            //When an iPhone connects to us we will get an ACI_EVT_CONNECTED event from the nRF8001
            if (aciEvt->params.device_started.hw_error) {
              delay(20); //Handle the HW error event correctly.
            } else if (this->_bondStore && this->_bondStore->hasData()) {
              this->_dynamicDataSequenceNo = 1;
              this->_dynamicDataOffset = 0;

              unsigned char chunkSize;
              this->_bondStore->getData(&chunkSize, this->_dynamicDataOffset, sizeof(chunkSize));
              this->_dynamicDataOffset++;

              unsigned char chunkData[DYNAMIC_DATA_MAX_CHUNK_SIZE];
              this->_bondStore->getData(chunkData, this->_dynamicDataOffset, chunkSize);
              this->_dynamicDataOffset += chunkSize;

              lib_aci_write_dynamic_data(this->_dynamicDataSequenceNo, chunkData, chunkSize);
            } else {
              this->startAdvertising();
            }
            break;

          default:
            break;
        }
      }
      break; //ACI Device Started Event

      case ACI_EVT_CMD_RSP:
        //If an ACI command response event comes with an error -> stop
        if (ACI_STATUS_SUCCESS != aciEvt->params.cmd_rsp.cmd_status &&
            ACI_STATUS_TRANSACTION_CONTINUE != aciEvt->params.cmd_rsp.cmd_status &&
            ACI_STATUS_TRANSACTION_COMPLETE != aciEvt->params.cmd_rsp.cmd_status) {
          //ACI ReadDynamicData and ACI WriteDynamicData will have status codes of
          //TRANSACTION_CONTINUE and TRANSACTION_COMPLETE
          //all other ACI commands will have status code of ACI_STATUS_SCUCCESS for a successful command
#ifdef NRF_8001_DEBUG
          Serial.print(F("ACI Command "));
          Serial.println(aciEvt->params.cmd_rsp.cmd_opcode, HEX);
          Serial.print(F("Evt Cmd respone: Status "));
          Serial.println(aciEvt->params.cmd_rsp.cmd_status, HEX);
#endif
        } else {
          switch (aciEvt->params.cmd_rsp.cmd_opcode) {
            case ACI_CMD_READ_DYNAMIC_DATA: {
#ifdef NRF_8001_DEBUG
              Serial.print(F("Dynamic data read sequence "));
              Serial.print(aciEvt->params.cmd_rsp.params.read_dynamic_data.seq_no);
              Serial.print(F(": "));
              Serial.print(aciEvt->len - 4);
              Serial.print(F(": "));

              BLEUtil::printBuffer(aciEvt->params.cmd_rsp.params.read_dynamic_data.dynamic_data, aciEvt->len - 4);
#endif
              if (aciEvt->params.cmd_rsp.params.read_dynamic_data.seq_no == 1) {
                this->_dynamicDataOffset = 0;
              }

              unsigned char chunkLength = aciEvt->len - 4;

              this->_bondStore->putData(&chunkLength, this->_dynamicDataOffset, sizeof(chunkLength));
              this->_dynamicDataOffset++;

              this->_bondStore->putData(aciEvt->params.cmd_rsp.params.read_dynamic_data.dynamic_data, this->_dynamicDataOffset, chunkLength);
              this->_dynamicDataOffset += chunkLength;

              if (aciEvt->params.cmd_rsp.cmd_status == ACI_STATUS_TRANSACTION_CONTINUE) {
                lib_aci_read_dynamic_data();
              } else if (aciEvt->params.cmd_rsp.cmd_status == ACI_STATUS_TRANSACTION_COMPLETE) {
                this->startAdvertising();
              }
              break;
            }

            case ACI_CMD_WRITE_DYNAMIC_DATA: {
#ifdef NRF_8001_DEBUG
              Serial.print(F("Dynamic data write sequence "));
              Serial.print(this->_dynamicDataSequenceNo);
              Serial.println(F(" complete"));
#endif
              if (aciEvt->params.cmd_rsp.cmd_status == ACI_STATUS_TRANSACTION_CONTINUE) {
                this->_dynamicDataSequenceNo++;

                unsigned char chunkSize;
                this->_bondStore->getData(&chunkSize, this->_dynamicDataOffset, sizeof(chunkSize));
                this->_dynamicDataOffset++;

                unsigned char chunkData[DYNAMIC_DATA_MAX_CHUNK_SIZE];
                this->_bondStore->getData(chunkData, this->_dynamicDataOffset, chunkSize);
                this->_dynamicDataOffset += chunkSize;

                lib_aci_write_dynamic_data(this->_dynamicDataSequenceNo, chunkData, chunkSize);
              } else if (aciEvt->params.cmd_rsp.cmd_status == ACI_STATUS_TRANSACTION_COMPLETE) {
                delay(20);
                this->startAdvertising();
              }
              break;
            }

            case ACI_CMD_GET_DEVICE_VERSION:
              break;

            case ACI_CMD_GET_DEVICE_ADDRESS: {
#ifdef NRF_8001_DEBUG
              char address[18];

              BLEUtil::addressToString(aciEvt->params.cmd_rsp.params.get_device_address.bd_addr_own, address);

              Serial.print(F("Device address = "));
              Serial.println(address);

              Serial.print(F("Device address type = "));
              Serial.println(aciEvt->params.cmd_rsp.params.get_device_address.bd_addr_type, DEC);
#endif
              if (this->_eventListener) {
                this->_eventListener->BLEDeviceAddressReceived(*this, aciEvt->params.cmd_rsp.params.get_device_address.bd_addr_own);
              }
              break;
            }

            case ACI_CMD_GET_BATTERY_LEVEL: {
              float batteryLevel = aciEvt->params.cmd_rsp.params.get_battery_level.battery_level * 0.00352;
#ifdef NRF_8001_DEBUG
              Serial.print(F("Battery level = "));
              Serial.println(batteryLevel);
#endif
              if (this->_eventListener) {
                this->_eventListener->BLEDeviceBatteryLevelReceived(*this, batteryLevel);
              }
              break;
            }

            case ACI_CMD_GET_TEMPERATURE: {
              float temperature = aciEvt->params.cmd_rsp.params.get_temperature.temperature_value / 4.0;
#ifdef NRF_8001_DEBUG
              Serial.print(F("Temperature = "));
              Serial.println(temperature);
#endif
              if (this->_eventListener) {
                this->_eventListener->BLEDeviceTemperatureReceived(*this, temperature);
              }
              break;
            }

            default:
              break;
          }
        }
        break;

      case ACI_EVT_CONNECTED:
#ifdef NRF_8001_DEBUG
        char address[18];
        BLEUtil::addressToString(aciEvt->params.connected.dev_addr, address);

        Serial.print(F("Evt Connected "));
        Serial.println(address);
#endif
        this->_timingChanged = false;
        this->_closedPipesCleared = false;
        this->_remoteServicesDiscovered = false;

        if (this->_eventListener) {
          this->_eventListener->BLEDeviceConnected(*this, aciEvt->params.connected.dev_addr);
        }

        this->_aciState.data_credit_available = this->_aciState.data_credit_total;
        break;

      case ACI_EVT_PIPE_STATUS: {
#ifdef NRF_8001_DEBUG
        Serial.println(F("Evt Pipe Status "));
#endif
        uint64_t openPipes;
        uint64_t closedPipes;

        memcpy(&openPipes, aciEvt->params.pipe_status.pipes_open_bitmap, sizeof(openPipes));
        memcpy(&closedPipes, aciEvt->params.pipe_status.pipes_closed_bitmap, sizeof(closedPipes));

#ifdef NRF_8001_DEBUG
        Serial.println((unsigned long)openPipes, HEX);
        Serial.println((unsigned long)closedPipes, HEX);
#endif
        if (this->_minimumConnectionInterval >= ACI_PPCP_MIN_CONN_INTVL_MIN &&
            this->_maximumConnectionInterval <= ACI_PPCP_MAX_CONN_INTVL_MAX &&
            openPipes & 0x03 &&
            !this->_timingChanged) {
          this->_timingChanged = true;
          lib_aci_change_timing(this->_minimumConnectionInterval, this->_maximumConnectionInterval, 0, 4000 / 10);
        }

        bool discoveryFinished = lib_aci_is_discovery_finished(&this->_aciState);
        if (closedPipes == 0 && !discoveryFinished) {
          this->_closedPipesCleared = true;
        }

        for (int i = 0; i < this->_numLocalPipeInfo; i++) {
          struct localPipeInfo* localPipeInfo = &this->_localPipeInfo[i];

          if (localPipeInfo->txPipe) {
            localPipeInfo->txPipeOpen = lib_aci_is_pipe_available(&this->_aciState, localPipeInfo->txPipe);
          }

          if (localPipeInfo->txAckPipe) {
            localPipeInfo->txAckPipeOpen = lib_aci_is_pipe_available(&this->_aciState, localPipeInfo->txAckPipe);
          }

          bool subscribed = (localPipeInfo->txPipeOpen || localPipeInfo->txAckPipeOpen);

          if (localPipeInfo->characteristic->subscribed() != subscribed) {
            if (this->_eventListener) {
              this->_eventListener->BLEDeviceCharacteristicSubscribedChanged(*this, *localPipeInfo->characteristic, subscribed);
            }
          }
        }

        if (this->_closedPipesCleared && discoveryFinished && !this->_remoteServicesDiscovered) {
          if (!this->_remoteServicesDiscovered && this->_eventListener) {
            this->_remoteServicesDiscovered = true;

            this->_eventListener->BLEDeviceRemoteServicesDiscovered(*this);
          }
        }
        break;
      }

      case ACI_EVT_TIMING:
#ifdef NRF_8001_DEBUG
        Serial.print(F("Timing change received conn Interval: 0x"));
        Serial.println(aciEvt->params.timing.conn_rf_interval, HEX);
#endif
        break;

      case ACI_EVT_DISCONNECTED:
#ifdef NRF_8001_DEBUG
        Serial.println(F("Evt Disconnected/Advertising timed out"));
#endif
        // all characteristics unsubscribed on disconnect
        for (int i = 0; i < this->_numLocalPipeInfo; i++) {
          struct localPipeInfo* localPipeInfo = &this->_localPipeInfo[i];

          if (localPipeInfo->characteristic->subscribed()) {
            if (this->_eventListener) {
              this->_eventListener->BLEDeviceCharacteristicSubscribedChanged(*this, *localPipeInfo->characteristic, false);
            }
          }
        }

        if (this->_eventListener) {
          this->_eventListener->BLEDeviceDisconnected(*this);
        }

        if (this->_storeDynamicData) {
          lib_aci_read_dynamic_data();

          this->_storeDynamicData = false;
        } else {
          this->startAdvertising();
        }
        break;

      case ACI_EVT_BOND_STATUS:
#ifdef NRF_8001_DEBUG
        Serial.println(F("Evt Bond Status"));
        Serial.println(aciEvt->params.bond_status.status_code);
#endif
        this->_storeDynamicData = (aciEvt->params.bond_status.status_code == ACI_BOND_STATUS_SUCCESS) &&
                                    (this->_aciState.bonded != ACI_BOND_STATUS_SUCCESS);

        this->_aciState.bonded = aciEvt->params.bond_status.status_code;

        this->_remoteServicesDiscovered = false;

        if (aciEvt->params.bond_status.status_code == ACI_BOND_STATUS_SUCCESS && this->_eventListener) {
          this->_eventListener->BLEDeviceBonded(*this);
        }
        break;

      case ACI_EVT_DATA_RECEIVED: {
        uint8_t dataLen = aciEvt->len - 2;
        uint8_t pipe = aciEvt->params.data_received.rx_data.pipe_number;
#ifdef NRF_8001_DEBUG
        Serial.print(F("Data Received, pipe = "));
        Serial.println(aciEvt->params.data_received.rx_data.pipe_number, DEC);

        BLEUtil::printBuffer(aciEvt->params.data_received.rx_data.aci_data, dataLen);
#endif

        for (int i = 0; i < this->_numLocalPipeInfo; i++) {
          struct localPipeInfo* localPipeInfo = &this->_localPipeInfo[i];

          if (localPipeInfo->rxAckPipe == pipe || localPipeInfo->rxPipe == pipe) {
            if (localPipeInfo->rxAckPipe == pipe) {
              lib_aci_send_ack(&this->_aciState, localPipeInfo->rxAckPipe);
            }

            if (this->_eventListener) {
              this->_eventListener->BLEDeviceCharacteristicValueChanged(*this, *localPipeInfo->characteristic, aciEvt->params.data_received.rx_data.aci_data, dataLen);
            }
            break;
          }
        }

        for (int i = 0; i < this->_numRemotePipeInfo; i++) {
          struct remotePipeInfo* remotePipeInfo = &this->_remotePipeInfo[i];

          if (remotePipeInfo->rxPipe == pipe || remotePipeInfo->rxAckPipe == pipe || remotePipeInfo->rxReqPipe) {
            if (remotePipeInfo->rxAckPipe == pipe) {
             lib_aci_send_ack(&this->_aciState, remotePipeInfo->rxAckPipe);
            }

            if (this->_eventListener) {
              this->_eventListener->BLEDeviceRemoteCharacteristicValueChanged(*this, *remotePipeInfo->characteristic, aciEvt->params.data_received.rx_data.aci_data, dataLen);
            }
            break;
          }
        }
        break;
      }

      case ACI_EVT_DATA_CREDIT:
        this->_aciState.data_credit_available = this->_aciState.data_credit_available + aciEvt->params.data_credit.credit;
        break;

      case ACI_EVT_PIPE_ERROR:
        //See the appendix in the nRF8001 Product Specication for details on the error codes
#ifdef NRF_8001_DEBUG
        Serial.print(F("ACI Evt Pipe Error: Pipe #:"));
        Serial.print(aciEvt->params.pipe_error.pipe_number, DEC);
        Serial.print(F("  Pipe Error Code: 0x"));
        Serial.println(aciEvt->params.pipe_error.error_code, HEX);
#endif

        //Increment the credit available as the data packet was not sent.
        //The pipe error also represents the Attribute protocol Error Response sent from the peer and that should not be counted
        //for the credit.
        if (ACI_STATUS_ERROR_PEER_ATT_ERROR != aciEvt->params.pipe_error.error_code) {
          this->_aciState.data_credit_available++;
        } else if (this->_bondStore) {
          lib_aci_bond_request();
        }
        break;

      case ACI_EVT_HW_ERROR:
#ifdef NRF_8001_DEBUG
        Serial.print(F("HW error: "));
        Serial.println(aciEvt->params.hw_error.line_num, DEC);

        for(uint8_t counter = 0; counter <= (aciEvt->len - 3); counter++) {
          Serial.write(aciEvt->params.hw_error.file_name[counter]); //uint8_t file_name[20];
        }
        Serial.println();
#endif
        this->startAdvertising();
        break;

      default:
        break;
    }
  } else {
    //Serial.println(F("No ACI Events available"));
    // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep
    // Arduino can go to sleep now
    // Wakeup from sleep from the RDYN line
  }
}

void nRF8001::end() {
  lib_aci_pin_reset();

  if (this->_localPipeInfo) {
    free(this->_localPipeInfo);
  }

  if (this->_remotePipeInfo) {
    free(this->_remotePipeInfo);
  }

  this->_numLocalPipeInfo = 0;
  this->_numRemotePipeInfo = 0;
}

bool nRF8001::updateCharacteristicValue(BLECharacteristic& characteristic) {
  bool success = true;

  struct localPipeInfo* localPipeInfo = this->localPipeInfoForCharacteristic(characteristic);

  if (localPipeInfo) {
    if (localPipeInfo->advPipe && (this->_broadcastPipe == localPipeInfo->advPipe)) {
      success &= lib_aci_set_local_data(&this->_aciState, localPipeInfo->advPipe, (uint8_t*)characteristic.value(), characteristic.valueLength());
    }

    if (localPipeInfo->setPipe) {
      success &= lib_aci_set_local_data(&this->_aciState, localPipeInfo->setPipe, (uint8_t*)characteristic.value(), characteristic.valueLength());
    }

    if (localPipeInfo->txPipe && localPipeInfo->txPipeOpen) {
      if (this->canNotifyCharacteristic(characteristic)) {
        this->_aciState.data_credit_available--;
        success &= lib_aci_send_data(localPipeInfo->txPipe, (uint8_t*)characteristic.value(), characteristic.valueLength());
      } else {
        success = false;
      }
    }

    if (localPipeInfo->txAckPipe && localPipeInfo->txAckPipeOpen) {
      if (this->canIndicateCharacteristic(characteristic)) {
        this->_aciState.data_credit_available--;
        success &= lib_aci_send_data(localPipeInfo->txAckPipe, (uint8_t*)characteristic.value(), characteristic.valueLength());
      } else {
        success = false;
      }
    }
  }

  return success;
}

bool nRF8001::broadcastCharacteristic(BLECharacteristic& characteristic) {
  bool success = false;

  struct localPipeInfo* localPipeInfo = this->localPipeInfoForCharacteristic(characteristic);

  if (localPipeInfo) {
    if (localPipeInfo->advPipe) {
      uint64_t advPipes = ((uint64_t)1) << (localPipeInfo->advPipe);

      success = lib_aci_open_adv_pipes((uint8_t*)&advPipes) &&
                  lib_aci_set_local_data(&this->_aciState, localPipeInfo->advPipe, (uint8_t*)characteristic.value(), characteristic.valueLength());

      if (success) {
        this->_broadcastPipe = localPipeInfo->advPipe;
      }
    }
  }

  return success;
}

bool nRF8001::canNotifyCharacteristic(BLECharacteristic& /*characteristic*/) {
  return (this->_aciState.data_credit_available > 0);
}

bool nRF8001::canIndicateCharacteristic(BLECharacteristic& /*characteristic*/) {
  return (this->_aciState.data_credit_available > 0);
}

bool nRF8001::canReadRemoteCharacteristic(BLERemoteCharacteristic& characteristic) {
  bool success = false;

  struct remotePipeInfo* remotePipeInfo = this->remotePipeInfoForCharacteristic(characteristic);

  if (remotePipeInfo) {
    unsigned char rxReqPipe = remotePipeInfo->rxReqPipe;

    if (rxReqPipe) {
      success = lib_aci_is_pipe_available(&this->_aciState, rxReqPipe);
    }
  }

  return success;
}

bool nRF8001::readRemoteCharacteristic(BLERemoteCharacteristic& characteristic) {
  bool success = false;

  struct remotePipeInfo* remotePipeInfo = this->remotePipeInfoForCharacteristic(characteristic);

  if (remotePipeInfo) {
    unsigned char rxReqPipe = remotePipeInfo->rxReqPipe;

    if (rxReqPipe) {
      success = lib_aci_is_pipe_available(&this->_aciState, rxReqPipe) &&
                lib_aci_request_data(&this->_aciState, rxReqPipe);
    }
  }

  return success;
}

bool nRF8001::canWriteRemoteCharacteristic(BLERemoteCharacteristic& characteristic) {
  bool success = false;

  struct remotePipeInfo* remotePipeInfo = this->remotePipeInfoForCharacteristic(characteristic);

  if (remotePipeInfo) {
    unsigned char pipe = remotePipeInfo->txAckPipe ? remotePipeInfo->txAckPipe : remotePipeInfo->txPipe;

    if (pipe) {
      success = lib_aci_is_pipe_available(&this->_aciState, pipe);
    }
  }

  return success;
}

bool nRF8001::writeRemoteCharacteristic(BLERemoteCharacteristic& characteristic, const unsigned char value[], unsigned char length) {
  bool success = false;

  struct remotePipeInfo* remotePipeInfo = this->remotePipeInfoForCharacteristic(characteristic);

  if (remotePipeInfo) {
    unsigned char pipe = remotePipeInfo->txAckPipe ? remotePipeInfo->txAckPipe : remotePipeInfo->txPipe;

    if (pipe) {
      success = lib_aci_is_pipe_available(&this->_aciState, pipe) &&
                lib_aci_send_data(pipe, (uint8_t*)value, length);
    }
  }

  return success;
}

bool nRF8001::canSubscribeRemoteCharacteristic(BLERemoteCharacteristic& characteristic) {
  bool success = false;

  struct remotePipeInfo* remotePipeInfo = this->remotePipeInfoForCharacteristic(characteristic);

  if (remotePipeInfo) {
    if (remotePipeInfo->characteristic == &characteristic) {
      unsigned char pipe = remotePipeInfo->rxPipe ? remotePipeInfo->rxPipe : remotePipeInfo->rxAckPipe;

      if (pipe) {
        success = lib_aci_is_pipe_closed(&this->_aciState, pipe);
      }
    }
  }

  return success;
}

bool nRF8001::subscribeRemoteCharacteristic(BLERemoteCharacteristic& characteristic) {
  bool success = false;

  struct remotePipeInfo* remotePipeInfo = this->remotePipeInfoForCharacteristic(characteristic);

  if (remotePipeInfo) {
    unsigned char pipe = remotePipeInfo->rxPipe ? remotePipeInfo->rxPipe : remotePipeInfo->rxAckPipe;

    if (pipe) {
      success = lib_aci_is_pipe_closed(&this->_aciState, pipe) && lib_aci_open_remote_pipe(&this->_aciState, pipe);
    }
  }

  return success;
}

bool nRF8001::canUnsubscribeRemoteCharacteristic(BLERemoteCharacteristic& characteristic) {
  return this->canSubscribeRemoteCharacteristic(characteristic);
}

bool nRF8001::unsubcribeRemoteCharacteristic(BLERemoteCharacteristic& characteristic) {
  bool success = false;

  struct remotePipeInfo* remotePipeInfo = this->remotePipeInfoForCharacteristic(characteristic);

  if (remotePipeInfo) {
    unsigned char pipe = remotePipeInfo->rxPipe ? remotePipeInfo->rxPipe : remotePipeInfo->rxAckPipe;

    if (pipe) {
      success = lib_aci_close_remote_pipe(&this->_aciState, pipe);
    }
  }

  return success;
}

bool nRF8001::setTxPower(int txPower) {
  aci_device_output_power_t outputPower;

  if (txPower <= -18) {
    outputPower = ACI_DEVICE_OUTPUT_POWER_MINUS_18DBM;
  } else if (txPower <= -12) {
    outputPower = ACI_DEVICE_OUTPUT_POWER_MINUS_12DBM;
  } else if (txPower <= -6) {
    outputPower = ACI_DEVICE_OUTPUT_POWER_MINUS_6DBM;
  } else {
    outputPower = ACI_DEVICE_OUTPUT_POWER_0DBM;
  }

  return lib_aci_set_tx_power(outputPower);
}

void nRF8001::startAdvertising() {
  uint16_t advertisingInterval = (this->_advertisingInterval * 16) / 10;

  if (this->_connectable) {
    if (this->_bondStore == NULL || this->_bondStore->hasData())   {
      lib_aci_connect(0/* in seconds, 0 means forever */, advertisingInterval);
    } else {
      lib_aci_bond(180/* in seconds, 0 means forever */, advertisingInterval);
    }
  } else {
    lib_aci_broadcast(0/* in seconds, 0 means forever */, advertisingInterval);
  }

#ifdef NRF_8001_DEBUG
  Serial.println(F("Advertising started."));
#endif
}

void nRF8001::disconnect() {
  lib_aci_disconnect(&this->_aciState, ACI_REASON_TERMINATE);
}

void nRF8001::requestAddress() {
  lib_aci_get_address();
}

void nRF8001::requestTemperature() {
  lib_aci_get_temperature();
}

void nRF8001::requestBatteryLevel() {
  lib_aci_get_battery_level();
}

void nRF8001::waitForSetupMode()
{
  bool setupMode = false;

  while (!setupMode) {
    if (lib_aci_event_get(&this->_aciState, &this->_aciData)) {
      aci_evt_t* aciEvt = &this->_aciData.evt;

      switch(aciEvt->evt_opcode) {
        case ACI_EVT_DEVICE_STARTED: {
          switch(aciEvt->params.device_started.device_mode) {
            case ACI_DEVICE_SETUP:
              /**
              When the device is in the setup mode
              */
#ifdef NRF_8001_DEBUG
              Serial.println(F("Evt Device Started: Setup"));
#endif
              setupMode = true;
              break;

            default:
              break;
          }
        }

        case ACI_EVT_CMD_RSP:
          setupMode = true;
          break;

        default:
          break;
      }
    } else {
      delay(1);
    }
  }
}

void nRF8001::sendSetupMessage(hal_aci_data_t* data, bool withCrc)
{
  this->_crcSeed = crc_16_ccitt(this->_crcSeed, data->buffer, data->buffer[0] + (withCrc ? -1 : 1));

  if (withCrc) {
    data->buffer[5] = (this->_crcSeed >> 8) & 0xff;
    data->buffer[6] = this->_crcSeed & 0xff;
  }

#ifdef NRF_8001_DEBUG
  BLEUtil::printBuffer(data->buffer, data->buffer[0] + 1);
#endif

  hal_aci_tl_send(data);

  bool setupMsgSent = false;

  while (!setupMsgSent) {
    if (lib_aci_event_get(&this->_aciState, &this->_aciData)) {
      aci_evt_t* aciEvt = &this->_aciData.evt;

      switch(aciEvt->evt_opcode) {
        case ACI_EVT_CMD_RSP: {
          switch(aciEvt->params.cmd_rsp.cmd_status) {
            case ACI_STATUS_TRANSACTION_CONTINUE:
#ifdef NRF_8001_DEBUG
              Serial.println(F("Evt Cmd Rsp: Transaction Continue"));
#endif
              setupMsgSent = true;
              break;

            case ACI_STATUS_TRANSACTION_COMPLETE:
#ifdef NRF_8001_DEBUG
              Serial.println(F("Evt Cmd Rsp: Transaction Complete"));
#endif
              setupMsgSent = true;
              break;

            default:
              break;
          }
        }

        default:
          break;
      }
    } else {
      delay(1);
    }
  }
}

void nRF8001::sendSetupMessage(hal_aci_data_t* setupMsg, unsigned char type, unsigned short& offset, bool withCrc) {
  struct setupMsgData* setupMsgData = (struct setupMsgData*)(setupMsg->buffer);

  setupMsgData->cmd      = ACI_CMD_SETUP;
  setupMsgData->type     = (type << 4) | ((offset >> 8) & 0x0f);
  setupMsgData->offset   = (offset & 0xff);

  this->sendSetupMessage(setupMsg, withCrc);

  offset += (setupMsgData->length - 3);
}

struct nRF8001::localPipeInfo* nRF8001::localPipeInfoForCharacteristic(BLECharacteristic& characteristic) {
  struct localPipeInfo* result = NULL;

  for (int i = 0; i < this->_numLocalPipeInfo; i++) {
    struct localPipeInfo* localPipeInfo = &this->_localPipeInfo[i];

    if (localPipeInfo->characteristic == &characteristic) {
      result = localPipeInfo;
      break;
    }
  }

  return result;
}

struct nRF8001::remotePipeInfo* nRF8001::remotePipeInfoForCharacteristic(BLERemoteCharacteristic& characteristic) {
  struct remotePipeInfo* result = NULL;

  for (int i = 0; i < this->_numRemotePipeInfo; i++) {
    struct remotePipeInfo* remotePipeInfo = &this->_remotePipeInfo[i];

    if (remotePipeInfo->characteristic == &characteristic) {
      result = remotePipeInfo;
      break;
    }
  }

  return result;
}

#endif