示例#1
0
文件: main.c 项目: elovalo/elovalo
void init_current_effect(void) {
    // Disable flipping until first frame is drawn
    allow_flipping(false);

    /* Restore front and back buffer pointers to point to
     * different locations */
    gs_restore_bufs();

    // Set up rng
    srand_from_clock();

    // Run initializer
    init_t init = (init_t)pgm_get(effect->init, word);
    if (init != NULL) init();
    gs_buf_swap();

    /* If NO_FLIP, we "broke" flipping if required by pointing
     * both buffers to the same location */
    if (pgm_get(effect->flip_buffers, byte) == NO_FLIP) {
        gs_buf_back = gs_buf_front;
    }

    // Restart tick counter and FPS limiter
    reset_time();
    next_draw_at = 0;
}
示例#2
0
文件: main.c 项目: elovalo/elovalo
void select_playlist_item(uint8_t index) {
    active_effect = index;
    const playlistitem_t *item = master_playlist + index;
    uint8_t e_id = pgm_get(item->id,byte);
    effect = effects + e_id;
    effect_length = pgm_get(item->length,word);
    custom_data = (void*)pgm_get(item->data,word);
}
示例#3
0
文件: main.c 项目: elovalo/elovalo
static void next_effect() {
    if (active_effect+1 == master_playlist_len ||
            active_effect+1 == pgm_get(playlists[active_playlist+1],byte)) {
        // End reached. Go to the first item of the playlist.
        select_playlist_item(pgm_get(playlists[active_playlist],byte));
    } else {
        // Advance to the next item in playlist
        select_playlist_item(active_effect + 1);
    }
}
示例#4
0
文件: main.c 项目: elovalo/elovalo
uint8_t change_playlist(uint8_t i) {
    if (i >= playlists_len) {
        return 1;
    }

    active_playlist = i;

    // Change mode and run init
    mode = MODE_PLAYLIST;
    select_playlist_item(pgm_get(playlists[i],byte));
    init_current_effect();

    return 0;
}
示例#5
0
文件: main.c 项目: elovalo/elovalo
void use_stored_playlist(void)
{
    if (mode != MODE_PLAYLIST) return;
    if (!(modified.playlist || modified.mode)) return;

    uint8_t new_playlist = read_playlist();
    // Avoid dangling pointers and extra initialization
    if (new_playlist >= playlists_len) new_playlist = 0;

    // Activate
    active_playlist = new_playlist;
    select_playlist_item(pgm_get(playlists[new_playlist],byte));
    init_current_effect();
}
示例#6
0
文件: main.c 项目: elovalo/elovalo
void use_stored_effect(void)
{
    if (mode != MODE_EFFECT) return;
    if (!(modified.effect || modified.mode ||
            (modified.text && pgm_get(effect->dynamic_text, byte))))
    {
        return;
    }

    uint8_t new_effect = read_effect();
    // Avoid dangling pointers and extra initialization
    if (new_effect >= effects_len) new_effect = 0;

    effect = effects + new_effect;
    custom_data = NULL; // Used in playlists only
    init_current_effect();
}
示例#7
0
文件: main.c 项目: elovalo/elovalo
int main() {
    cli();

    wdt_disable(); // To make sure nothing weird happens
    init_tlc5940();
    init_spi();
    init_ps();

    init_blank_timer();
    init_effect_timer();

    init_playlist();

    initUSART();
    sei();

    hcsr04_start_continuous_meas();
    adc_start();

    serial_boot_report();

    // Select correct startup mode
    pick_startup_mode();

    while(1) {
        /* Serial processing is implementation specific and defined in
         * serial_common.c */
        process_serial();

        switch (mode) {
        case MODE_SLEEP:
        // Fall through to MODE_IDLE
        case MODE_IDLE:
            // No operation
            sleep_if_no_traffic();
            break;
        case MODE_PLAYLIST:
            ticks = centisecs();
            if (ticks > effect_length) {
                next_effect();
                init_current_effect();
            }

        // no need to break!
        // fall to MODE_EFFECT on purpose
        case MODE_EFFECT:
            // If a buffer is not yet flipped, wait interrupts
            if (flags.may_flip) {
                sleep_if_no_traffic();
                break;
            }

            // Update clock
            ticks = centisecs();

            /* Go back to serial handler if drawing time
             * is reached. By doing this we avoid serial
             * port slowdown when FPS is low */
            if (ticks < next_draw_at ) {
                sleep_if_no_traffic();
                break;
            }

            /* Restart effect if maximum ticks is
             * reached. This may result a glitch but is
             * better than the effect to stop. */
            if (ticks == ~0) {
                init_current_effect();
                ticks = 0;
            }

            // Update sensor values
            sensors.distance1 = hcsr04_get_distance_in_cm();
            sensors.distance2 = hcsr04_get_distance_in_cm(); //TODO: use separate sensor
            sensors.ambient_light = adc_get(0) >> 2;
            sensors.sound_pressure_level = adc_get(1) >> 2;

            // Do the actual drawing
            draw_t draw = (draw_t)pgm_get(effect->draw,word);
            if (draw != NULL) {
                draw();
                allow_flipping(true);
            }

            // Update time when next drawing is allowed
            next_draw_at = ticks + pgm_get(effect->minimum_ticks,byte);

            break;
        }
    }

    return 0;
}
示例#8
0
文件: main.c 项目: tazjel/elovalo
int main() {
	cli();

	wdt_disable(); // To make sure nothing weird happens
	init_tlc5940();
	init_spi();
	init_ps();

	init_blank_timer();
	init_effect_timer();
	
	init_playlist();
	
	initUSART();
	sei();

	hcsr04_start_continuous_meas();
	adc_start();

	serial_elo_init();
	
	// Select correct startup mode
	pick_startup_mode();

	while(1) {
		if(serial_available()) {
			uint8_t cmd = serial_read();
#if defined AVR_ZCL
			serial_zcl_process(cmd);
#elif defined AVR_ELO
			serial_elo_process(cmd);
#elif defined SIMU
			// Do nothing
#else
#error Unsupported serial communication type
#endif
		}

		switch (mode) {
		case MODE_SLEEP:
			// Fall through to MODE_IDLE
		case MODE_IDLE:
			// No operation
			sleep_mode();
			break;
		case MODE_PLAYLIST:
			ticks = centisecs();
			if (ticks > effect_length) {
				next_effect();
				init_current_effect();
			}

			// no need to break!
			// fall to MODE_EFFECT on purpose
		case MODE_EFFECT:
			// If a buffer is not yet flipped
			if (flags.may_flip) break;

			// Update clock and sensor values
			ticks = centisecs();
			sensors.distance1 = hcsr04_get_distance_in_cm();
			sensors.distance2 = hcsr04_get_distance_in_cm(); //TODO: use separate sensor
			sensors.ambient_light = adc_get(0) >> 2;
			sensors.sound_pressure_level = adc_get(1) >> 2;

			// Do the actual drawing
			draw_t draw = (draw_t)pgm_get(effect->draw,word);
			if (draw != NULL) {
				draw();
				allow_flipping(true);
			}

			// Slow down drawing if FPS is going to be too high
			uint16_t target_ticks =
				ticks + pgm_get(effect->minimum_ticks,byte);
			while (centisecs() < target_ticks ) {
				sleep_mode();
			}

			break;
		}
	}

	return 0;
}
示例#9
0
static bool process_read_cmd() {
	send_zcl_header(CMDID_READ_RESPONSE);

	while(msg_available()) {
		uint16_t attr;
		attr = msg_get_16();
		
		if (zcl.packet.cluster == CLUSTERID_BASIC) {
			switch(attr) {
			case ATTR_DEVICE_ENABLED:
				send_attr_resp_header(ATTR_DEVICE_ENABLED, TYPE_BOOLEAN);
				send_payload(get_mode());
				break;
			case ATTR_ALARM_MASK:
				send_attr_resp_header(ATTR_ALARM_MASK, TYPE_BOOLEAN);
				send_payload(0); //FIXME: implement
				break;
			default:
				send_cmd_status(attr, STATUS_UNSUPPORTED_ATTRIBUTE);
				break;
			}
		} else if (zcl.packet.cluster == CLUSTERID_ELOVALO) {
			switch(attr) {
			case ATTR_IEEE_ADDRESS:
			{
				send_attr_resp_header(ATTR_IEEE_ADDRESS, TYPE_IEEE_ADDRESS);
				send_64(mac);
				break;
			}
			case ATTR_OPERATING_MODE:
			{
				send_attr_resp_header(ATTR_OPERATING_MODE, TYPE_ENUM);
				send_payload(get_mode());
				break;
			}
			case ATTR_EFFECT_TEXT:
				send_cmd_status(ATTR_EFFECT_TEXT, STATUS_WRITE_ONLY);
				break;
			case ATTR_PLAYLIST:
				send_attr_resp_header(ATTR_PLAYLIST, TYPE_UINT8);
				send_payload(read_playlist());
				break;
			case ATTR_TIMEZONE:
				send_attr_resp_header(ATTR_TIMEZONE, TYPE_INT32);
				send_i32(get_timezone());
				break;
			case ATTR_TIME:
				send_attr_resp_header(ATTR_TIME, TYPE_UTC_TIME);
				send_32(time(NULL)-ZIGBEE_TIME_OFFSET);
				break;
			case ATTR_EFFECT_NAMES:
				send_attr_resp_header(ATTR_EFFECT_NAMES,
						      TYPE_LONG_OCTET_STRING);
				send_effect_names();
				break;
			case ATTR_PLAYLIST_NAMES:
				send_attr_resp_header(ATTR_PLAYLIST_NAMES,
						      TYPE_LONG_OCTET_STRING);
				send_16(playlists_json_len);
				send_pgm_string_direct(playlists_json);

				break;
			case ATTR_PLAYLIST_EFFECTS:
			{
				send_attr_resp_header(ATTR_PLAYLIST_EFFECTS, TYPE_OCTET_STRING);
				 // current playlist index
				uint8_t pl_begin = pgm_get(playlists[active_playlist], byte);
				// End index to playlist, not included to playlist
				uint8_t pl_end;

				if (active_playlist == playlists_len - 1) {
					pl_end = master_playlist_len;
				} else {
					pl_end = pgm_get(playlists[active_playlist + 1], byte);
				}
				//Send string length
				send_payload(pl_end - pl_begin);
				for (uint8_t i = pl_begin; i < pl_end; i++) {
					send_payload(pgm_get(master_playlist[i].id, byte));
					//send_payload(i);
				}

				break;
			}
			case ATTR_EFFECT:
				send_attr_resp_header(ATTR_EFFECT, TYPE_UINT8);
				send_payload(read_effect());
				break;
			case ATTR_HW_VERSION:
				send_attr_resp_header(ATTR_HW_VERSION, TYPE_OCTET_STRING);
				send_local_pgm_str(hw_resp);
				break;
			case ATTR_SW_VERSION:
				send_attr_resp_header(ATTR_SW_VERSION, TYPE_OCTET_STRING);
				send_local_pgm_str(sw_resp);
				break;
			case ATTR_PLAYLIST_POSITION:
				send_attr_resp_header(ATTR_PLAYLIST_POSITION, TYPE_UINT8);
				uint8_t start = pgm_get(playlists[active_playlist],byte);
				send_payload(active_effect-start);
				break;
			default:
				send_cmd_status(attr, STATUS_UNSUPPORTED_ATTRIBUTE);
				break;
			}
		} else {
			// FIXME: See if correct way to handle incorrect cluster
			if (!zcl.packet.disable_def_resp) {
				send_default_response(CMDID_READ,
					STATUS_UNSUP_CLUSTER_COMMAND);
			}
			return true;
		}
	}
	return true;
}
示例#10
0
void process_serial(void)
{
	if (zcl_ati()) {
		// ATI command response
		for (uint8_t i = 0; i < sizeof(ati_resp)-1; i++) {
			char c = pgm_get(ati_resp[i],byte);
			serial_send(c);
		}

		// MAC address, big endian, colon separated
		serial_send_hex(mac >> 56);
		serial_send(':');
		serial_send_hex(mac >> 48);
		serial_send(':');
		serial_send_hex(mac >> 40);
		serial_send(':');
		serial_send_hex(mac >> 32);
		serial_send(':');
		serial_send_hex(mac >> 24);
		serial_send(':');
		serial_send_hex(mac >> 16);
		serial_send(':');
		serial_send_hex(mac >> 8);
		serial_send(':');
		serial_send_hex(mac >> 0);
		serial_send('\n');

		// May continue to packet processing
	}

	if (zcl_own_fault()) {
		/* If buffer overflow or other internal error
		 * happened, there is not much to do. TODO Maybe there
		 * should be some internal flag? Or proper ZigBee
		 * error? */
		serial_send(ACK);
		zcl_receiver_reset();
		return;
	}	

	if (!zcl_packet_available()) return;

	// We have a packet. Checking CRC.
	uint16_t *msg_crc = (uint16_t *)(zcl.raw + zcl.packet.length + 2);
	uint16_t crc = 0xffff;
	for (uint16_t i = 0; i < zcl.packet.length; i++) {
		crc = _crc_xmodem_update(crc, zcl.raw[i+2]);
	}

	/* Answering ACK and processing the answer if it was
	 * correct. Otherwise just send NAK and let the sender to
	 * resend it later */
	if (*msg_crc == crc) {
		serial_send(ACK);
		process_payload();
	} else {
		serial_send(NAK);
	}
	
	// Re-enable the receiver
	zcl_receiver_reset();
}