#include "project.h" #define NCS (GPIO7) #define NCS_PORT GPIOG #define SCK (GPIO3) #define SCK_PORT GPIOB #define MOSI (GPIO5) #define MOSI_PORT GPIOB static void set (int sck, int ncs, int mosi) { if (sck) SET (SCK); else CLEAR (SCK); if (ncs) SET (NCS); else CLEAR (NCS); if (mosi) SET (MOSI); else CLEAR (MOSI); // delay_us(1); //delay_us(10); } static void spip_send_8 (uint8_t wot) { int i; for (i = 0; i < 8; ++i) { set (0, 0, wot & 0x80); set (1, 0, wot & 0x80); set (0, 0, wot & 0x80); wot <<= 1; } } static int mutex = 0; static int lock (void) { if (__sync_add_and_fetch (&mutex, 1) != 1) { __sync_sub_and_fetch (&mutex, 1); return -1; } return 0; } static void unlock (void) { __sync_sub_and_fetch (&mutex, 1); } static void write_reg (uint8_t reg, uint8_t data) { while (lock()); set (0, 1, 0); set (0, 0, 0); spip_send_8 (reg); spip_send_8 (data); spip_send_8 (reg); spip_send_8 (data); spip_send_8 (reg); spip_send_8 (data); set (0, 0, 0); set (0, 1, 0); unlock(); } static void _write_regs (uint8_t reg, uint8_t *data) { while (lock()); set (0, 1, 0); set (0, 0, 0); spip_send_8 (reg); spip_send_8 (data[2]); spip_send_8 (reg); spip_send_8 (data[1]); spip_send_8 (reg); spip_send_8 (data[0]); set (0, 0, 0); set (0, 1, 0); unlock(); } static void write_regs (uint8_t reg, uint8_t d1, uint8_t d2, uint8_t d3) { uint8_t d[3] = {d1, d2, d3}; _write_regs (reg, d); } #define SDP 0x80 #define SA 0x40 #define SB 0x20 #define SC 0x10 #define SD 0x08 #define SE 0x04 #define SF 0x02 #define SG 0x01 static uint8_t hex (unsigned v) { switch (v) { case 0: case '0': return SA | SF | SB | SE | SC | SD; case 1: case '1': return SB | SC; case 2: case '2': case 'z': return SA | SB | SG | SE | SD; case 3: case '3': return SA | SB | SG | SC | SD; case 4: case '4': return SF | SG | SB | SC; case 5: case '5': case 's': return SA | SF | SG | SC | SD; case 6: case '6': return SA | SF | SG | SE | SC | SD; case 7: case '7': return SA | SB | SC; case 8: case '8': return SA | SF | SB | SG | SE | SC | SD; case 9: case '9': case 'g': return SA | SF | SB | SG | SC | SD; case 0xa: case 'a': return SA | SF | SB | SG | SE | SC; case 0xb: case 'b': return SF | SG | SE | SC | SD; case 0xc: case 'c': return SG | SE | SD; case 0xd: case 'd': return SB | SG | SE | SC | SD; case 0xe: case 'e': return SA | SF | SG | SE | SD; case 0xf: case 'f': return SA | SF | SG | SE; case 'h': return SF | SG | SE | SC; case 'i': return SE; case 'j': return SB | SC | SD; case 'k': case 'x': return SF | SB | SG | SE | SC; case 'l': return SF | SE | SD; case 'm': case 'n': return SG | SE | SC; case 'o': return SG | SE | SC | SD; case 'p': return SA | SF | SB | SG | SE; case 'q': return SA | SF | SB | SG | SC; case 'r': return SG | SE; case 't': return SF | SG | SE | SD; case 'u': case 'w': return SE | SC | SD; case 'y': return SF | SB | SG | SC | SD; case '-': return SG; case '.': return SDP; } return 0; } static void _write_triad (uint8_t reg, int *d, int *dp) { uint8_t regs0[3] = {0x0, 0x0, 0x0}; uint8_t regs1[3] = {0x0, 0x0, 0x0}; unsigned i; for (i = 0; i < 3; ++i) { if (d[i] < 0) continue; if (d[i] > 99) continue; regs0[i] = hex (d[i] % 10); regs1[i] = hex (d[i] / 10); } for (i = 0; i < 3; ++i) if (dp[i]) regs0[i] |= SDP; _write_regs (reg++, regs0); _write_regs (reg, regs1); } static void write_triad (uint8_t reg, int d1, int d2, int d3, int dp1, int dp2, int dp3) { int d[3] = {d1, d2, d3}; int dp[3] = {dp1, dp2, dp3}; _write_triad (reg, d, dp); } static void _write_triad_h (uint8_t reg, int *d, int *dp) { uint8_t regs0[3] = {0x0, 0x0, 0x0}; uint8_t regs1[3] = {0x0, 0x0, 0x0}; unsigned i; for (i = 0; i < 2; ++i) { if (d[i] < 0) continue; if (d[i] > 99) continue; regs0[i] = hex (d[i] % 10); regs1[i] = hex (d[i] / 10); } do { if (d[i] < 0) continue; if (d[i] > 0x100) continue; regs0[i] = hex (d[i] & 0xf); regs1[i] = hex (d[i] >> 4); } while (0); for (i = 0; i < 3; ++i) if (dp[i]) regs0[i] |= SDP; _write_regs (reg++, regs0); _write_regs (reg, regs1); } static void write_triad_h (uint8_t reg, int d1, int d2, int d3, int dp1, int dp2, int dp3) { int d[3] = {d1, d2, d3}; int dp[3] = {dp1, dp2, dp3}; _write_triad_h (reg, d, dp); } static void write_string_over_numbers (char *str, int d1, int d2, int d3, int d4) { unsigned reg; uint8_t digits[9] = { 0, hex (d4 % 10), hex (d4 / 10), hex (d3 % 10) | SDP, hex (d3 / 10), hex (d2 % 10) | SDP, hex (d2 / 10), hex (d1 % 10) | SDP, hex (d1 / 10) }; for (reg = 8; reg && *str; reg--, str++) write_regs (reg, hex (*str) | (!str[1] ? SDP : 0), digits[reg], 0); for (; reg; reg--) write_regs (reg, 0, digits[reg], 0); } void max7219_init (int on) { uint8_t d[3] = {0xf, 0xf, 0xf}; unsigned i; MAP_OUTPUT_PP (SCK); MAP_OUTPUT_PP (NCS); MAP_OUTPUT_PP (MOSI); set (0, 1, 0); if (on) { write_reg (0xc, 0x1); //Power up write_reg (0xf, 0x0); //normal mode write_reg (0x9, 0x0); //no decode write_reg (0xb, 0x7); //8 digits write_reg (0xa, pot_brightness); for (i = 1; i <= 8; ++i) _write_regs (i, d); } else { write_reg (0xc, 0x0); //Power up } } static int have_lock, have_dgps, have_time_lock, time_lock_enabled; void max7219_report_fix (char fix, char fix2) { have_lock = 0; if (fix == 'L') have_lock = 1; if (fix2 == 'D') have_dgps = 1; else have_dgps = 0; if (fix == 'T') { have_lock = 1; have_time_lock = 1; } } void max7219_report_svin (int valid, int active) { time_lock_enabled = 0; if (active || valid) time_lock_enabled = 1; } void max7219_dispatch (void) { uint64_t abs = ref_get(); static uint8_t last_brightness = 255; int wday; EPOCH e; UTC u; UTC gu; ST l; if (last_brightness != pot_brightness) { last_brightness = pot_brightness; write_reg (0xa, last_brightness); } if (gps_initting) write_string_over_numbers ("gps init", 0, 0, 0, 0); else if (!ref_valid) write_string_over_numbers ("gps acq", gps_sats_searching, gps_sats_inop, gps_sats_locked, gps_sats_with_e); else { static unsigned m; e = ref_decompose (abs); u = time_epoch_to_utc (e); l = time_utc_to_lst (u, gps_lon); if (have_lock) { e.s += 86400; e.s += gps_utc_diff; gu = time_epoch_to_utc (e); } else { gu.hour = 100; gu.minute = 100; gu.second = 100; } write_triad (1, u.nanosecond / 10000000, l.nanosecond / 10000000, gu.second, time_lock_enabled, have_time_lock, have_dgps); write_triad (3, u.second, l.second, gu.minute, 1, 1, 1); write_triad (5, u.minute, l.minute, gu.hour, 1, 1, 1); write_triad_h (7, u.hour, l.hour, (if0.ip_addr.addr >> 24) & 0xff, 1, 1, 1); if (u.minute == m) return; m = u.minute; printf ("LEDS: %02d.%02d.%02d.%02d %02d.%02d.%02d.%02d %02x.%02d.%02d.%02d lon %.6f\r\n", u.hour, u.minute, u.second, u.nanosecond / 10000000, l.hour, l.minute, l.second, l.nanosecond / 10000000, (int) ((if0.ip_addr.addr >> 24) & 0xff), gu.hour, gu.minute, gu.second, gps_lon); } }