📄 nxt_avr.c
字号:
#include "nxt_avr.h"#include "twi.h"#include "nxt_motors.h"#include "systick.h"#include <string.h>#define NXT_AVR_ADDRESS 1#define NXT_AVR_N_OUTPUTS 4#define NXT_AVR_N_INPUTS 4const char avr_brainwash_string[] = "\xCC" "Let's samba nxt arm in arm, (c)LEGO System A/S";static U32 nxt_avr_initialised;static struct { U8 power; U8 pwm_frequency; S8 output_percent[NXT_AVR_N_OUTPUTS]; U8 output_mode; U8 input_power;} io_to_avr;static struct { U16 adc_value[NXT_AVR_N_INPUTS]; U16 buttons; U16 battery_is_AA; U16 battery_mV; U8 avr_fw_version_major; U8 avr_fw_version_minor;} io_from_avr;static U8 data_from_avr[(2 * NXT_AVR_N_INPUTS) + 5];static U8 data_to_avr[5 + NXT_AVR_N_OUTPUTS];/* We're assuming that we get good packing */static voidnxt_avr_start_read(void){ memset(data_from_avr, 0, sizeof(data_from_avr)); twi_start_read(NXT_AVR_ADDRESS, 0, 0, data_from_avr, sizeof(data_from_avr));}static voidnxt_avr_start_send(void){ int i; U8 checkByte = 0; U8 *a = data_to_avr; U8 *b = (U8 *) (&io_to_avr); i = sizeof(io_to_avr); while (i) { *a = *b; checkByte += *b; a++; b++; i--; } *a = ~checkByte; twi_start_write(NXT_AVR_ADDRESS, 0, 0, data_to_avr, sizeof(data_to_avr));}voidnxt_avr_power_down(void){ io_to_avr.power = 0x5a; io_to_avr.pwm_frequency = 0x00;}voidnxt_avr_firmware_update_mode(void){ io_to_avr.power = 0xA5; io_to_avr.pwm_frequency = 0x5A;}voidnxt_avr_link_init(void){ twi_start_write(NXT_AVR_ADDRESS, 0, 0, (const U8 *) avr_brainwash_string, strlen(avr_brainwash_string));}static U16Unpack16(const U8 *x){ U16 retval; retval = (((U16) (x[0])) & 0xff) | ((((U16) (x[1])) << 8) & 0xff00); return retval;}static struct { U32 good_rx; U32 bad_rx; U32 resets; U32 still_busy; U32 not_ok;} nxt_avr_stats;static voidnxt_avr_unpack(void){ U8 check_sum; U8 *p; U16 buttonsVal; U32 voltageVal; int i; p = data_from_avr; for (check_sum = i = 0; i < sizeof(data_from_avr); i++) { check_sum += *p; p++; } if (check_sum != 0xff) { nxt_avr_stats.bad_rx++; return; } nxt_avr_stats.good_rx++; p = data_from_avr; // Marshall for (i = 0; i < NXT_AVR_N_INPUTS; i++) { io_from_avr.adc_value[i] = Unpack16(p); p += 2; } buttonsVal = Unpack16(p); p += 2; io_from_avr.buttons = 0; if (buttonsVal > 1023) { io_from_avr.buttons |= 1; buttonsVal -= 0x7ff; } if (buttonsVal > 720) io_from_avr.buttons |= 0x08; else if (buttonsVal > 270) io_from_avr.buttons |= 0x04; else if (buttonsVal > 60) io_from_avr.buttons |= 0x02; voltageVal = Unpack16(p); io_from_avr.battery_is_AA = (voltageVal & 0x8000) ? 1 : 0; io_from_avr.avr_fw_version_major = (voltageVal >> 13) & 3; io_from_avr.avr_fw_version_minor = (voltageVal >> 10) & 7; // Figure out voltage // The units are 13.848 mV per bit. // To prevent fp, we substitute 13.848 with 14180/1024 voltageVal &= 0x3ff; // Toss unwanted bits. voltageVal *= 14180; voltageVal >>= 10; io_from_avr.battery_mV = voltageVal;}voidnxt_avr_init(void){ twi_init(); memset(&io_to_avr, 0, sizeof(io_to_avr)); io_to_avr.power = 0; io_to_avr.pwm_frequency = 8; nxt_avr_initialised = 1;}static U32 update_count;static U32 link_init_wait;static U32 link_running;voidnxt_avr_1kHz_update(void){ if (!nxt_avr_initialised) return; if (link_init_wait) { link_init_wait--; return; } if (!twi_ok()) { nxt_avr_stats.not_ok++; link_running = 0; } if (twi_busy()) { nxt_avr_stats.still_busy++; link_running = 0; } if (!twi_ok() || twi_busy() || !link_running) { memset(data_from_avr, 0, sizeof(data_from_avr)); link_running = 1; nxt_avr_link_init(); link_init_wait = 2; update_count = 0; nxt_avr_stats.resets++; return; } if (update_count & 1) { nxt_avr_start_read(); } else { nxt_avr_unpack(); nxt_avr_start_send(); } update_count++;}U32buttons_get(void){ return io_from_avr.buttons;}U32battery_voltage(void){ return io_from_avr.battery_mV;}U32sensor_adc(U32 n){ if (n < 4) return io_from_avr.adc_value[n]; else return 0;}voidnxt_avr_set_motor(U32 n, int power_percent, int brake){ if (n < NXT_N_MOTORS) { io_to_avr.output_percent[n] = power_percent; if (brake) io_to_avr.output_mode |= (1 << n); else io_to_avr.output_mode &= ~(1 << n); }}voidnxt_avr_set_input_power(U32 n, U32 power_type){ // This does not correspond to the spec. // It is unclear how to set power always on. // Lego code has a bug in it. if (n < NXT_AVR_N_INPUTS && power_type <= 1) { io_to_avr.input_power &= ~(0x1 << (n)); io_to_avr.input_power |= (power_type << (n)); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -