case statements inside a while loop,
but needed functionality can be implemented with combination of label_address() and
goto_address() functions.
Thus "lc" header file shall look like:
/*
* Copyright (c) 2004-2005, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
...
*/
/**
* \file
* Implementation of local continuations based on the label_address()
* and goto_address() functions of CCS
* \author
* Igor Lesik
*
* This implementation of local continuations is based on
* the label_address() and goto_address() functions of CCS. This
* feature allows assigning pointers with the address of the code
* corresponding to a particular C label.
*
* For more information, see the CCS documentation:
* http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
*
*/
#ifndef __LC_ADDRLABELS_PIC_CCS_H__
#define __LC_ADDRLABELS_PIC_CCS_H__
/** \hideinitializer */
typedef void * lc_t;
#define LC_INIT(s) s = 0
#define LC_RESUME(s) \
do { \
if(s != 0) { \
goto_address(s); \
} \
} while(0)
#define LC_CONCAT2(s1, s2) s1##s2
#define LC_CONCAT(s1, s2) LC_CONCAT2(s1, s2)
#define LC_SET(s) \
do { \
LC_CONCAT(LC_LABEL, __LINE__): \
(s) = label_address(LC_CONCAT(LC_LABEL, __LINE__)); \
} while(0)
#define LC_END(s)
#endif /* __LC_ADDRLABELS_PIC_CCS_H__ */
Below is an example of using Protothreads on PICKit2 board with 16F690 microcontroller. Compare to CCS RTOS tasks (#use rtos) Protothreads demonstrated significant generated code space improvement.
//
//
// author: Igor Lesik
//
// Example from http://eigenclass.org/hiki/threadring-with-protothreads
//
//
#include "PICKit2_app1.h"
#define LC_INCLUDE "lc-addrlabels-pic-ccs.h"
#include "../../../pt.h"
#include "../../../pt-sem.h"
// LEDs on PICKit2 board
#define LED1 PIN_C0
#define LED2 PIN_C1
#define LED3 PIN_C2
#define LED4 PIN_C3
#define toggle_led(pin, state) {if(state) output_high(pin); else output_low(pin);}
void switch_LED(int pin, int state){
switch(pin){
case 0: toggle_led(LED1, state); break;
case 1: toggle_led(LED2, state); break;
case 2: toggle_led(LED3, state); break;
case 3: toggle_led(LED4, state); break;
}
}
inline void setup()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_oscillator(OSC_8MHZ);
port_a_pullups(FALSE);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
}
#define NUM_THREADS (10)
#define SEED_TOKEN (9) // 0 <= N < NUM_THREADS
typedef struct pt pt_t;
typedef struct pt_sem pt_sem_t;
pt_t thread_context[NUM_THREADS];
int data[NUM_THREADS];
struct pt_sem mutex[NUM_THREADS];
PT_THREAD(thread(struct pt *pt, int id))
{
static int token;
static int r;
static pt_sem_t* sem_ptr;
PT_BEGIN(pt);
while( 1 ) {
sem_ptr=&mutex[id];
PT_SEM_WAIT(pt, sem_ptr);
token = data[id];
r = (id + 1) % NUM_THREADS;
if(token) {
data[r] = token - 1;
sem_ptr=&mutex[r];
PT_SEM_SIGNAL(pt, sem_ptr);
} else {
switch_LED(id%4, 1); // switch LED on
// GAME IS OVER, LED SEED_TOKEN%4 must be ON
}
}
PT_END(pt);
}
void main()
{
int i;
pt_t* pt_ptr; pt_sem_t* sem_ptr;
setup();
data[0] = SEED_TOKEN % NUM_THREADS; // 0 <= N < NUM_THREADS
for(i = 0; i < NUM_THREADS; i++) {
sem_ptr=&mutex[i];
PT_SEM_INIT(sem_ptr, 0);
pt_ptr = &thread_context[i];
PT_INIT(pt_ptr);
switch_LED(i%4, 0); // switch all 4 LEDs off
data[i]=data[0];
}
sem_ptr=&mutex[0];
PT_SEM_INIT(sem_ptr, 1);
while(1) {
for(i = 0; i < NUM_THREADS; i++){
pt_ptr = &thread_context[i];
thread(pt_ptr, i);
}
}
}