Skip to content

Commit

Permalink
added IKEA ansluta example
Browse files Browse the repository at this point in the history
  • Loading branch information
msloth committed Jun 10, 2016
1 parent e2d133f commit a951b28
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 0 deletions.
32 changes: 32 additions & 0 deletions examples/launchpad/ikea-ansluta/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Example Makefile for Contiki projects
# Author Marcus Linderoth

# this defines where to find the Contiki root folder compared with this folder
# I prefer to have my Contiki projects under eg /contiki/projects/myproject/
# in which case CONTIKI = ../.. is a proper setting
CONTIKI = ../../..

# this sets the compilation target (hardware) to be Launchpad
ifndef TARGET
TARGET=launchpad
endif

# Change this to the main file of your project (NB without file ending)
PROJECT = ikea-cc2500-setter

# if you have more than one source file to include, list them here
#PROJECT_SOURCEFILES += button.c

# if files are in several folders, list them here
#PROJECT_FOLDERS += ./example ./example/deep/deeper

# any overridden Contiki source file (in this project) is listed here
#CONTIKI_SOURCEFILES +=

CFLAGS += -Wl,--oihex

all: $(PROJECT)
@msp430-size $(PROJECT).launchpad

# must be here, it makes sure Contiki is included :)
include $(CONTIKI)/Makefile.include
171 changes: 171 additions & 0 deletions examples/launchpad/ikea-ansluta/ikea-cc2500-setter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#include <stdlib.h>
#include <stdio.h>
#include "contiki.h"
#include "dev/spi.h"
#include "dev/cc2500-arch.h"
#include "dev/cc2500-const.h"
#include "watchdog.h"
/*---------------------------------------------------------------------------*/
/*
* This application toggles an IKEA Ansluta remote control LED light. The Ansluta
* uses a cc2500 radio. The remote control radio usage was sniffed with a logic
* analyzer which is mirrored here. The Ansluta can only switch between 0, 35, 100%
* dim levels, which is set using a specific byte in the packet.
* The logic sniff was performed on a remote that was already paired, so the
* pairing information is included in the packet, but unclear now exactly what
* bytes is the pairing info.
*
* todo and notes:
* set PATABLE to 0xff for highest transmission power setting
* SCLK was inverted against the capture
* -- no, mine is right, it should be SCLK initially low, but the IKEA one
* is initial high, which is against the datasheet. MOSI is latched on CLK
* low->high transition.
* IKEA: initial low, set MOSI at clk high->low, flip CLK low->high in the middle
*/
/*---------------------------------------------------------------------------*/
static void
strobe(uint8_t s)
{
cc2500_strobe(s);
}
/*---------------------------------------------------------------------------*/
static uint8_t
status(void)
{
return cc2500_strobe(CC2500_SNOP);
}
/*---------------------------------------------------------------------------*/
static void
write_burst(uint8_t *src, uint8_t len)
{
// uint8_t s;
int i;
/* sth (the button?) sets the MISO pin so lets reset all pins we need */
SPI_PORT(SEL) |= SPI_MISO | SPI_MOSI | SPI_SCL;
SPI_PORT(SEL2) |= SPI_MISO | SPI_MOSI | SPI_SCL;

CC2500_SPI_ENABLE();
SPI_WRITE(src[0]);
// s = SPI_RXBUF;
for(i = 1; i < len; i += 1) {
SPI_WRITE_FAST(src[i]);
}
SPI_WAIT_WHILE_BUSY();
CC2500_SPI_DISABLE();
}
/*---------------------------------------------------------------------------*/
// here reg is including the write bit set, so reg == adr | WRITE
static uint8_t
write_single(uint8_t reg, uint8_t val)
{
uint8_t s;
/* sth (the button?) sets the MISO pin so lets reset all pins we need */
SPI_PORT(SEL) |= SPI_MISO | SPI_MOSI | SPI_SCL;
SPI_PORT(SEL2) |= SPI_MISO | SPI_MOSI | SPI_SCL;

CC2500_SPI_ENABLE();
SPI_WRITE(reg);
s = SPI_RXBUF;
SPI_WRITE(val);
CC2500_SPI_DISABLE();
return s;
}
/*---------------------------------------------------------------------------*/
static void
init_chip(void)
{
int i;
// note, logic seems flaky, may be off, refer to the other logic captures
uint8_t regs[] = {0x00, 0x02, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21,
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2C, 0x2D,
0x2E, 0x7E};
uint8_t values[] = {0x2D, 0x06, 0xFF, 0x04, 0x05, 0x01, 0x10, 0x09, 0x00, 0x5D,
0x93, 0xB1, 0x2D, 0x3B, 0x73, 0xA2, 0xF8, 0x01, 0x07, 0x30,
0x18, 0x1D, 0x1C, 0xC7, 0x00, 0xB2, 0x87, 0x6B, 0xF8, 0xB6,
0x10, 0xEA, 0x0A, 0x00, 0x11, 0x41, 0x00, 0x59, 0x88, 0x31,
0x0B, 0xFF};
#define REGSET_LEN 42
for(i = 0; i < REGSET_LEN; i++) {
write_single(regs[i], values[i]);
}
write_single(PATABLE, 0xff);
}
/*---------------------------------------------------------------------------*/
static void
send_setting_once(uint8_t *setting, int len)
{
// the IKEA remote does, for each packet:
// strobe idle
// strobe flush tx fifo
// burstwrite 8 bytes to fifo (0x7f)
// strobe tx
// then just 1.7 ms wait (no SPI, perhaps GDOx?)

strobe(CC2500_SIDLE);
strobe(CC2500_SFTX);
write_burst(setting, len);
strobe(CC2500_STX);
while((status() & CC2500_STATUSBYTE_STATUSBITS) != CC2500_STATE_TX);
while((status() & CC2500_STATUSBYTE_STATUSBITS) == CC2500_STATE_TX);
}
/*---------------------------------------------------------------------------*/
#define NUM_TRANSMISSIONS 50

static void
send_setting(uint8_t setting)
{
int i;
uint8_t spibuf[9] = {
0x7f,
0x06,
0x55,
0x01,
0x6a,
0x99,
0x01, // <- setting {0, 35, 100%} == {0x01, 0x02, 0x03}
0xaa,
0xff
};
/* change the 'setting'-byte */
spibuf[6] = setting;

// the IKEA remote does, for each press of the remote button:
watchdog_periodic();
strobe(CC2500_SRES);
init_chip();
for(i = 0; i < NUM_TRANSMISSIONS; i++) {
watchdog_periodic();
send_setting_once(spibuf, 9);

while(/*SENDING*/0) {
}
}
strobe(CC2500_SPWD);
}
/*---------------------------------------------------------------------------*/
PROCESS(ikea_process, "My Process");
AUTOSTART_PROCESSES(&ikea_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(ikea_process, ev, data)
{
PROCESS_BEGIN();
static struct etimer et;
static uint8_t setting = 0;

while(1) {
/* toggle settings every 2 seconds */
setting++;
if(setting > 3) {
setting = 0;
}
send_setting(setting);

etimer_set(&et, CLOCK_SECOND * 2);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

0 comments on commit a951b28

Please sign in to comment.