From 1d5e806cbe3000c72799f1a4a39d67435967745c Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Fri, 18 Oct 2024 02:42:10 -0600 Subject: [PATCH] fixes max ping bug --- lora_sx127_rpi4.c => lora_sx127.c | 1069 ++++++++++++++++++++++++++++- lora_sx127_rpi3.c | 812 ---------------------- setup-lora_pi3.c | 13 - 3 files changed, 1050 insertions(+), 844 deletions(-) rename lora_sx127_rpi4.c => lora_sx127.c (51%) delete mode 100644 lora_sx127_rpi3.c delete mode 100755 setup-lora_pi3.c diff --git a/lora_sx127_rpi4.c b/lora_sx127.c similarity index 51% rename from lora_sx127_rpi4.c rename to lora_sx127.c index f0ed080..afbb50a 100644 --- a/lora_sx127_rpi4.c +++ b/lora_sx127.c @@ -177,6 +177,1031 @@ MODULE_PARM_DESC(rx_timeout, "RX time-out value as number of symbols"); #define POLL_JIFFIES (msecs_to_jiffies(10)) +/*stct sx1278_phy { + struct ieee802154_hw *hw; + struct regmap *map; + + bool suspended; + u8 opmode; + struct timer_list timer; + struct work_struct irqwork; + + spinlock_t buf_lock; + struct sk_buff *tx_buf; + u8 tx_delay; + bool one_to_be_sent; + bool post_tx_done; + bool is_busy; +}; + +int +sx127X_read_version(struct regmap *map) +{ + u8 v; + int status; + + status = sx127x_reg_read(hw, SX127X_REG_VERSION, &v); + + if ((status == 0) && (v > 0) && (v < 0xFF)) + status = v; + else + status = -ENODEV; + + return status; +} + +void +sx127X_set_mode(struct regmap *map, u8 op_mode) +{ + sx127x_reg_write(hw, SX127X_REG_OP_MODE, op_mode); +} + +u8 +sx127X_get_mode(struct regmap *map) +{ + u8 op_mode; + + sx127x_reg_read(hw, SX127X_REG_OP_MODE, &op_mode); + + return op_mode; +} + +void +sx127X_set_state(struct regmap *map, u8 st) +{ + u8 op_mode; + + op_mode = sx127X_get_mode(map); + op_mode = (op_mode & 0xF8) | (st & 0x07); + sx127x_reg_write(hw, SX127X_REG_OP_MODE, op_mode); +} + +u8 +sx127X_get_state(struct regmap *map) +{ + u8 op_mode; + + op_mode = sx127X_get_mode(map) & 0x07; + + return op_mode; +} + +void +sx127X_set_lorafrq(struct regmap *map, u32 fr) +{ + u64 frt; + u8 buf[3]; + s8 i; + u32 f_xosc; + u8 op_mode; + + struct device_node *of_node = (regmap_get_device(map))->of_node; + + if (of_property_read_u32(of_node, "clock-frequency", &f_xosc)) + f_xosc = xosc_frq; + + frt = (uint64_t)fr * (uint64_t)__POW_2_19; + do_div(frt, f_xosc); + + for (i = 2; i >= 0; i--) + buf[i] = do_div(frt, 256); + + op_mode = sx127X_get_mode(map); + if (fr >= 779000000) + op_mode &= ~0x8; + else if (fr <= 525000000) + op_mode |= 0x8; + sx127X_set_state(map, SX127X_SLEEP_MODE); + regmap_raw_write(map, SX127X_REG_FRF_MSB, buf, 3); + sx127X_set_mode(map, op_mode); +} + +u32 +sx127X_get_lorafrq(struct regmap *map) +{ + u64 frt = 0; + u8 buf[3]; + u8 i; + int status; + u32 fr; + u32 f_xosc; + + struct device_node *of_node = (regmap_get_device(map))->of_node; + + if (of_property_read_u32(of_node, "clock-frequency", &f_xosc)) + f_xosc = xosc_frq; + + status = regmap_raw_read(map, SX127X_REG_FRF_MSB, buf, 3); + if (status < 0) + return 0.0; + + for (i = 0; i <= 2; i++) + frt = frt * 256 + buf[i]; + + fr = frt * f_xosc / __POW_2_19; + + return fr; +} + +void +sx127X_set_lorapower(struct regmap *map, s32 pout) +{ + u8 pacf; + u8 boost; + u8 output_power; + s32 pmax; + + if (pout > 14) { + boost = 1; + pmax = 7; + output_power = pout - 2; + } else if (pout < 0) { + boost = 0; + pmax = 2; + output_power = 3 + pout; + } else { + boost = 0; + pmax = 7; + output_power = pout; + } + + pacf = (boost << 7) | (pmax << 4) | (output_power); + sx127x_reg_write(hw, SX127X_REG_PA_CONFIG, pacf); +} + +s32 +sx127X_get_lorapower(struct regmap *map) +{ + u8 pac; + u8 boost; + s32 output_power; + s32 pmax; + s32 pout; + + sx127x_reg_read(hw, SX127X_REG_PA_CONFIG, &pac); + boost = (pac & 0x80) >> 7; + output_power = pac & 0x0F; + if (boost) { + pout = 2 + output_power; + } else { + pmax = (108 + 6 * ((pac & 0x70) >> 4)); + pout = (pmax - (150 - output_power * 10)) / 10; + } + + return pout; +} + +#define sx127X_dbm2mbm(dbm) (dbm * 100) + +#define sx127X_mbm2dbm(mbm) (mbm / 100) + +s8 lna_gain[] = { + 0, + -6, + -12, + -24, + -26, + -48 +}; + +void +sx127X_set_loralna(struct regmap *map, s32 db) +{ + u8 i, g; + u8 lnacf; + + for (i = 0; i < 5; i++) { + if (lna_gain[i] <= db) + break; + } + g = i + 1; + + sx127x_reg_read(hw, SX127X_REG_LNA, &lnacf); + lnacf = (lnacf & 0x1F) | (g << 5); + sx127x_reg_write(hw, SX127X_REG_LNA, lnacf); +} + +s32 +sx127X_get_loralna(struct regmap *map) +{ + s32 db; + s8 i, g; + u8 lnacf; + + sx127x_reg_read(hw, SX127X_REG_LNA, &lnacf); + g = (lnacf >> 5); + i = g - 1; + db = lna_gain[i]; + + return db; +} + +void +sx127X_set_loralnaagc(struct regmap *map, s32 yesno) +{ + u8 mcf3; + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG3, &mcf3); + mcf3 = (yesno) ? (mcf3 | 0x04) : (mcf3 & (~0x04)); + sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG3, mcf3); +} + +u8 +sx127X_get_loraallflag(struct regmap *map) +{ + u8 flags; + + sx127x_reg_read(hw, SX127X_REG_IRQ_FLAGS, &flags); + + return flags; +} + +#define sx127X_get_loraflag(map, f) (sx127X_get_loraallflag(map) & (f)) + +void +sx127X_clear_loraflag(struct regmap *map, u8 f) +{ + u8 flag; + + flag = sx127X_get_loraallflag(map); + flag |= f; + sx127x_reg_write(hw, SX127X_REG_IRQ_FLAGS, flag); +} + +#define sx127X_clear_loraallflag(spi) sx127X_clear_loraflag(spi, 0xFF) + +void +sx127X_set_lorasprf(struct regmap *map, u32 c_s) +{ + u8 sf; + u8 mcf2; + + for (sf = 6; sf < 12; sf++) { + if (c_s == ((u32)1 << sf)) + break; + } + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG2, &mcf2); + mcf2 = (mcf2 & 0x0F) | (sf << 4); + sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG2, mcf2); +} + +u32 +sx127X_get_lorasprf(struct regmap *map) +{ + u8 sf; + u32 c_s; + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG2, &sf); + sf = sf >> 4; + c_s = 1 << sf; + + return c_s; +} + +const u32 hz[] = { + 7800, + 10400, + 15600, + 20800, + 31250, + 41700, + 62500, + 125000, + 250000, + 500000 +}; + +void +sx127X_set_lorabw(struct regmap *map, u32 bw) +{ + u8 i; + u8 mcf1; + + for (i = 0; i < 9; i++) { + if (hz[i] >= bw) + break; + } + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); + mcf1 = (mcf1 & 0x0F) | (i << 4); + sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG1, mcf1); +} + +u32 +sx127X_get_lorabw(struct regmap *map) +{ + u8 mcf1; + u8 bw; + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); + bw = mcf1 >> 4; + + return hz[bw]; +} + +void +sx127X_set_loracr(struct regmap *map, u8 cr) +{ + u8 mcf1; + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); + mcf1 = (mcf1 & 0x0E) | (((cr & 0xF) - 4) << 1); + sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG1, mcf1); +} + +u8 +sx127X_get_loracr(struct regmap *map) +{ + u8 mcf1; + u8 cr; + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); + cr = 0x40 + ((mcf1 & 0x0E) >> 1) + 4; + + return cr; +} + +void +sx127X_set_loraimplicit(struct regmap *map, u8 yesno) +{ + u8 mcf1; + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &mcf1); + mcf1 = (yesno) ? (mcf1 | 0x01) : (mcf1 & 0xFE); + sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG1, mcf1); +} + +void +sx127X_set_lorarxbytetimeout(struct regmap *map, u32 n) +{ + u8 buf[2]; + u8 mcf2; + + if (n < 1) + n = 1; + if (n > 1023) + n = 1023; + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG2, &mcf2); + + buf[1] = n % 256; + buf[0] = (mcf2 & 0xFC) | (n >> 8); + + regmap_raw_write(map, SX127X_REG_MODEM_CONFIG2, buf, 2); +} + +void +sx127X_set_lorarxtimeout(struct regmap *map, u32 ms) +{ + u32 n; + + n = ms * sx127X_get_lorabw(map) / (sx127X_get_lorasprf(map) * 1000); + + sx127X_set_lorarxbytetimeout(map, n); +} + +u32 +sx127X_get_lorarxbytetimeout(struct regmap *map) +{ + u32 n; + u8 buf[2]; + + regmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, buf, 2); + + n = (buf[0] & 0x03) * 256 + buf[1]; + + return n; +} + +u32 +sx127X_get_lorarxtimeout(struct regmap *map) +{ + u32 ms; + + ms = 1000 * sx127X_get_lorarxbytetimeout(map) * + sx127X_get_lorasprf(map) / sx127X_get_lorabw(map); + + return ms; +} + +void +sx127X_set_loramaxrxbuff(struct regmap *map, u8 len) +{ + sx127x_reg_write(hw, SX127X_REG_MAX_PAYLOAD_LENGTH, len); +} + +u8 +sx127X_get_loralastpktpayloadlen(struct regmap *map) +{ + u8 len; + + sx127x_reg_read(hw, SX127X_REG_RX_NB_BYTES, &len); + + return len; +} + +ssize_t +sx127X_readloradata(struct regmap *map, u8 *buf, size_t len) +{ + u8 start_adr; + int ret; + + start_adr = SX127X_FIFO_RX_BASE_ADDRESS; + sx127x_reg_write(hw, SX127X_REG_FIFO_ADDR_PTR, start_adr); + + len = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU; + ret = regmap_raw_read(map, SX127X_REG_FIFO, buf, len); + + return (ret >= 0) ? len : ret; +} + +size_t +sx127X_sendloradata(struct regmap *map, u8 *buf, size_t len) +{ + u8 base_adr; + u8 blen; + + base_adr = SX127X_FIFO_TX_BASE_ADDRESS; + sx127x_reg_write(hw, SX127X_REG_FIFO_ADDR_PTR, base_adr); + + blen = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU; + regmap_raw_write(map, SX127X_REG_FIFO, buf, blen); + + sx127x_reg_write(hw, SX127X_REG_PAYLOAD_LENGTH, blen); + + return blen; +} + +s32 +sx127X_get_loralastpktsnr(struct regmap *map) +{ + s32 db; + s8 snr; + + sx127x_reg_read(hw, SX127X_REG_PKT_SNR_VALUE, &snr); + db = snr / 4; + + return db; +} + +s32 +sx127X_get_loralastpktrssi(struct regmap *map) +{ + s32 dbm; + u8 lhf; + u8 rssi; + s8 snr; + + lhf = sx127X_get_mode(map) & 0x08; + sx127x_reg_read(hw, SX127X_REG_PKT_RSSI_VALUE, &rssi); + dbm = (lhf) ? -164 + rssi : -157 + rssi; + + sx127x_reg_read(hw, SX127X_REG_PKT_SNR_VALUE, &snr); + if (snr < 0) + dbm += snr / 4; + + return dbm; +} + +s32 +sx127X_get_lorarssi(struct regmap *map) +{ + s32 dbm; + u8 lhf; + u8 rssi; + + lhf = sx127X_get_mode(map) & 0x08; + sx127x_reg_read(hw, SX127X_REG_RSSI_VALUE, &rssi); + dbm = (lhf) ? -164 + rssi : -157 + rssi; + + return dbm; +} + +void +sx127X_set_lorapreamblelen(struct regmap *map, u32 len) +{ + u8 pl[2]; + + pl[1] = len % 256; + pl[0] = (len >> 8) % 256; + + regmap_raw_write(map, SX127X_REG_PREAMBLE_MSB, pl, 2); +} + +u32 +sx127X_get_lorapreamblelen(struct regmap *map) +{ + u8 pl[2]; + u32 len; + + regmap_raw_read(map, SX127X_REG_PREAMBLE_MSB, pl, 2); + len = pl[0] * 256 + pl[1]; + + return len; +} + +sx127X_set_loracrc(struct regmap *map, u8 yesno) +{ + u8 mcf2; + + sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG2, &mcf2); + mcf2 = (yesno) ? mcf2 | (1 << 2) : mcf2 & (~(1 << 2)); + sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG2, mcf2); +} + +void +sx127X_set_boost(struct regmap *map, u8 yesno) +{ + u8 pacf; + + sx127x_reg_read(hw, SX127X_REG_PA_CONFIG, &pacf); + pacf = (yesno) ? pacf | (1 << 7) : pacf & (~(1 << 7)); + sx127x_reg_write(hw, SX127X_REG_PA_CONFIG, pacf); +} + +void +sx127X_start_loramode(struct regmap *map) +{ + u8 op_mode; + u8 base_adr; + struct device_node *of_node = (regmap_get_device(map))->of_node; + + op_mode = sx127X_get_mode(map); + dev_dbg(regmap_get_device(map), + "the original OP mode is 0x%X\n", op_mode); + + sx127X_set_state(map, SX127X_SLEEP_MODE); + op_mode = sx127X_get_mode(map); + op_mode = op_mode | 0x80; + sx127x_reg_write(hw, SX127X_REG_OP_MODE, op_mode); + sx127X_set_state(map, SX127X_STANDBY_MODE); + op_mode = sx127X_get_mode(map); + dev_dbg(regmap_get_device(map), + "the current OP mode is 0x%X\n", op_mode); + + sx127X_set_loraimplicit(map, 0); + + base_adr = SX127X_FIFO_RX_BASE_ADDRESS; + sx127x_reg_write(hw, SX127X_REG_FIFO_RX_BASE_ADDR, base_adr); + base_adr = SX127X_FIFO_TX_BASE_ADDRESS; + sx127x_reg_write(hw, SX127X_REG_FIFO_TX_BASE_ADDR, base_adr); + + of_property_read_u32(of_node, "spreading-factor", &sprf); + sx127X_set_lorasprf(map, sprf); + + sx127X_set_lorarxbytetimeout(map, rx_timeout); + + sx127X_clear_loraallflag(map); + sx127X_set_state(map, SX127X_RXSINGLE_MODE); +} + +int +init_sx127x(struct regmap *map) +{ + int v; +#ifdef DEBUG + u8 fv, mv; +#endif + + dev_dbg(regmap_get_device(map), "init sx127X\n"); + + v = sx127X_read_version(map); + if (v > 0) { +#ifdef DEBUG + fv = (v >> 4) & 0xF; + mv = v & 0xF; + dev_dbg(regmap_get_device(map), "chip version %d.%d\n", fv, mv); +#endif + return 0; + } else { + return -ENODEV; + } +} + +#ifndef SX1278_IEEE_SENSITIVITY +#define SX1278_IEEE_SENSITIVITY (-148) +#endif +static s32 sensitivity = SX1278_IEEE_SENSITIVITY; +module_param(sensitivity, int, 0000); +MODULE_PARM_DESC(sensitivity, "RF receiver's sensitivity"); + +#define SX1278_IEEE_ENERGY_RANGE (-sensitivity) + +static int +sx1278_ieee_ed(struct ieee802154_hw *hw, u8 *level) +{ + struct sx1278_phy *phy = hw->priv; + s32 rssi; + s32 range = SX1278_IEEE_ENERGY_RANGE - 10; + + dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); + + rssi = sx127X_get_lorarssi(phy->map); + if (rssi < (sensitivity + 10)) + *level = 0; + else if (rssi >= 0) + *level = 255; + else + *level = ((s32)255 * (rssi + range) / range) % 255; + + return 0; +} + +#ifndef SX1278_IEEE_CHANNEL_MIN +#define SX1278_IEEE_CHANNEL_MIN 11 +#endif +static u8 channel_min = SX1278_IEEE_CHANNEL_MIN; +module_param(channel_min, byte, 0000); +MODULE_PARM_DESC(channel_min, "Minimal channel number"); + +#ifndef SX1278_IEEE_CHANNEL_MAX +#define SX1278_IEEE_CHANNEL_MAX 11 +#endif +static u8 channel_max = SX1278_IEEE_CHANNEL_MAX; +module_param(channel_max, byte, 0000); +MODULE_PARM_DESC(channel_max, "Maximum channel number"); + +#ifndef SX1278_IEEE_CENTER_CARRIER_FRQ +#define SX1278_IEEE_CENTER_CARRIER_FRQ 434000000 +#endif +static u32 carrier_frq = SX1278_IEEE_CENTER_CARRIER_FRQ; +module_param(carrier_frq, uint, 0000); +MODULE_PARM_DESC(carrier_frq, "Center carrier frequency in Hz"); + +#ifndef SX1278_IEEE_BANDWIDTH +#define SX1278_IEEE_BANDWIDTH 500000 +#endif +static u32 bandwidth = SX1278_IEEE_BANDWIDTH; +module_param(bandwidth, uint, 0000); +MODULE_PARM_DESC(bandwidth, "Bandwidth in Hz"); + +struct rf_frq { + u32 carrier; + u32 bw; + u8 ch_min; + u8 ch_max; +}; + +void +sx1278_ieee_get_rf_config(struct ieee802154_hw *hw, struct rf_frq *rf) +{ + struct sx1278_phy *phy = hw->priv; + struct device_node *of_node = (regmap_get_device(phy->map))->of_node; + + if (of_property_read_u32(of_node, "center-carrier-frq", &rf->carrier)) + rf->carrier = carrier_frq; + + if (of_property_read_u32(of_node, "rf-bandwidth", &rf->bw)) + rf->bw = bandwidth; + + if (of_property_read_u8(of_node, "minimal-RF-channel", &rf->ch_min)) + rf->ch_min = channel_min; + + if (of_property_read_u8(of_node, "maximum-RF-channel", &rf->ch_max)) + rf->ch_max = channel_max; +} + +static int +sx1278_ieee_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel) +{ + struct sx1278_phy *phy = hw->priv; + struct rf_frq rf; + u32 fr; + s8 d; + + dev_dbg(regmap_get_device(phy->map), + "%s channel: %u\n", __func__, channel); + + sx1278_ieee_get_rf_config(hw, &rf); + + if (channel < rf.ch_min) + channel = rf.ch_min; + else if (channel > rf.ch_max) + channel = rf.ch_max; + + d = channel - (rf.ch_min + rf.ch_max) / 2; + fr = rf.carrier + d * rf.bw; + + sx127X_set_lorafrq(phy->map, fr); + phy->opmode = sx127X_get_mode(phy->map); + + return 0; +} + +static int +sx1278_ieee_set_txpower(struct ieee802154_hw *hw, s32 mbm) +{ + struct sx1278_phy *phy = hw->priv; + s32 dbm = sx127X_mbm2dbm(mbm); + + dev_dbg(regmap_get_device(phy->map), + "%s TX power: %d mbm\n", __func__, mbm); + + sx127X_set_lorapower(phy->map, dbm); + + return 0; +} + +int +sx1278_ieee_rx(struct ieee802154_hw *hw) +{ + struct sx1278_phy *phy = hw->priv; + bool do_rx; + unsigned long f; + + dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); + + spin_lock_irqsave(&phy->buf_lock, f); + if (!phy->is_busy) { + phy->is_busy = true; + do_rx = true; + } else { + do_rx = false; + } + spin_unlock_irqrestore(&phy->buf_lock, f); + + if (do_rx) { + sx127X_set_state(phy->map, SX127X_RXSINGLE_MODE); + return 0; + } else { + dev_dbg(regmap_get_device(phy->map), + "%s: device is busy\n", __func__); + return -EBUSY; + } +} + +static int +sx1278_ieee_rx_complete(struct ieee802154_hw *hw) +{ + struct sx1278_phy *phy = hw->priv; + struct sk_buff *skb; + u8 len; + u8 lqi; + s32 rssi; + s32 range = SX1278_IEEE_ENERGY_RANGE; + int err; + unsigned long f; + + skb = dev_alloc_skb(IEEE802154_MTU); + if (!skb) { + err = -ENOMEM; + dev_err(regmap_get_device(phy->map), + "%s: driver is out of memory\n", __func__); + goto sx1278_ieee_rx_err; + } + + len = sx127X_get_loralastpktpayloadlen(phy->map); + sx127X_readloradata(phy->map, skb_put(skb, len), len); + + rssi = sx127X_get_loralastpktrssi(phy->map); + rssi = (rssi > 0) ? 0 : rssi; + lqi = ((s32)255 * (rssi + range) / range) % 255; + + ieee802154_rx_irqsafe(hw, skb, lqi); + + dev_dbg(regmap_get_device(phy->map), + "%s: len=%u LQI=%u\n", __func__, len, lqi); + + err = 0; + +sx1278_ieee_rx_err: + spin_lock_irqsave(&phy->buf_lock, f); + phy->is_busy = false; + spin_unlock_irqrestore(&phy->buf_lock, f); + return err; +} + +int +sx1278_ieee_tx(struct ieee802154_hw *hw) +{ + struct sx1278_phy *phy = hw->priv; + struct sk_buff *tx_buf = phy->tx_buf; + bool do_tx = false; + unsigned long f; + + dev_dbg(regmap_get_device(phy->map), + "%s: len=%u\n", __func__, tx_buf->len); + + if (!phy->post_tx_done) { + sx127X_sendloradata(phy->map, tx_buf->data, tx_buf->len); + phy->post_tx_done = true; + } + + spin_lock_irqsave(&phy->buf_lock, f); + if (!phy->is_busy) { + phy->is_busy = true; + do_tx = true; + phy->one_to_be_sent = false; + } + spin_unlock_irqrestore(&phy->buf_lock, f); + + if (do_tx) { + phy->opmode = (phy->opmode & 0xF8) | SX127X_TX_MODE; + regmap_write_async(phy->map, SX127X_REG_OP_MODE, phy->opmode); + return 0; + } else { + dev_dbg(regmap_get_device(phy->map), + "%s: device is busy\n", __func__); + return -EBUSY; + } +} + +static int +sx1278_ieee_tx_complete(struct ieee802154_hw *hw) +{ + struct sx1278_phy *phy = hw->priv; + struct sk_buff *skb = phy->tx_buf; + unsigned long f; + + dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); + + ieee802154_xmit_complete(hw, skb, false); + + spin_lock_irqsave(&phy->buf_lock, f); + phy->is_busy = false; + phy->tx_buf = NULL; + spin_unlock_irqrestore(&phy->buf_lock, f); + + return 0; +} + +static int +sx1278_ieee_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) +{ + struct sx1278_phy *phy = hw->priv; + int ret; + unsigned long f; + + dev_dbg(regmap_get_device(phy->map), "%s\n", __func__); + + WARN_ON(phy->suspended); + + spin_lock_irqsave(&phy->buf_lock, f); + if (phy->tx_buf) { + ret = -EBUSY; + } else { + phy->tx_buf = skb; + phy->one_to_be_sent = true; + phy->post_tx_done = false; + ret = 0; + } + spin_unlock_irqrestore(&phy->buf_lock, f); + + return ret; +} + +static int +sx1278_ieee_start(struct ieee802154_hw *hw) +{ + struct sx1278_phy *phy = hw->priv; + + dev_dbg(regmap_get_device(phy->map), "interface up\n"); + + sx1278_ieee_set_channel(hw, 0, hw->phy->current_channel); + phy->suspended = false; + sx127X_start_loramode(phy->map); + phy->opmode = sx127X_get_mode(phy->map); + add_timer(&phy->timer); + + return 0; +} + +static void +sx1278_ieee_stop(struct ieee802154_hw *hw) +{ + struct sx1278_phy *phy = hw->priv; + + dev_dbg(regmap_get_device(phy->map), "interface down\n"); + + phy->suspended = true; + del_timer(&phy->timer); + sx127X_set_state(phy->map, SX127X_SLEEP_MODE); +} + +static int +sx1278_ieee_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on) +{ + return 0; +} + +void +sx1278_ieee_statemachine(struct ieee802154_hw *hw) +{ + struct sx1278_phy *phy = hw->priv; + u8 flags; + u8 state; + bool do_next_rx = false; + unsigned long f; + + flags = sx127X_get_loraallflag(phy->map); + state = sx127X_get_state(phy->map); + + if (flags & (SX127X_FLAG_RXTIMEOUT | SX127X_FLAG_PAYLOADCRCERROR)) { + sx127X_clear_loraflag(phy->map, SX127X_FLAG_RXTIMEOUT + | SX127X_FLAG_PAYLOADCRCERROR + | SX127X_FLAG_RXDONE); + spin_lock_irqsave(&phy->buf_lock, f); + phy->is_busy = false; + spin_unlock_irqrestore(&phy->buf_lock, f); + do_next_rx = true; + } else if (flags & SX127X_FLAG_RXDONE) { + sx1278_ieee_rx_complete(phy->hw); + sx127X_clear_loraflag(phy->map, SX127X_FLAG_RXDONE); + do_next_rx = true; + } + + if (flags & SX127X_FLAG_TXDONE) { + sx1278_ieee_tx_complete(phy->hw); + sx127X_clear_loraflag(phy->map, SX127X_FLAG_TXDONE); + phy->tx_delay = 10; + do_next_rx = true; + } + + if (phy->one_to_be_sent && + (state == SX127X_STANDBY_MODE) && + (phy->tx_delay == 0)) { + if (!sx1278_ieee_tx(phy->hw)) + do_next_rx = false; + } + + if (do_next_rx) + sx1278_ieee_rx(phy->hw); + + if (phy->tx_delay > 0) + phy->tx_delay -= 1; + + if (!phy->suspended) { + phy->timer.expires = jiffies_64 + 1; + add_timer(&phy->timer); + } +} + +static void +sx1278_timer_irqwork(struct work_struct *work) +{ + struct sx1278_phy *phy; + + phy = container_of(work, struct sx1278_phy, irqwork); + sx1278_ieee_statemachine(phy->hw); +} + +static void +sx1278_timer_isr(struct timer_list *timer) +{ + struct sx1278_phy *phy = container_of(timer, struct sx1278_phy, timer); + + schedule_work(&phy->irqwork); +} + +u32 +sx1278_ieee_channel_mask(struct ieee802154_hw *hw) +{ + struct rf_frq rf; + u32 mask; + + sx1278_ieee_get_rf_config(hw, &rf); + + mask = ((u32)(1 << (rf.ch_max + 1)) - (u32)(1 << rf.ch_min)); + + return mask; +} + +static int +sx1278_ieee_add_one(struct sx1278_phy *phy) +{ + INIT_WORK(&phy->irqwork, sx1278_timer_irqwork); + + timer_setup(&phy->timer, sx1278_timer_isr, 0); + phy->timer.expires = jiffies_64 + HZ; + + spin_lock_init(&phy->buf_lock); + + err = init_sx127x(phy->map); + if (err) + goto err_reg; + + return 0; + +err_reg: + dev_err(regmap_get_device(phy->map), + "register as IEEE 802.15.4 device failed\n"); + return err; +} + +static void +sx1278_ieee_del(struct sx1278_phy *phy) +{ + del_timer(&phy->timer); + flush_work(&phy->irqwork); +}*/ + +///////////////////////// +// Frontera Chino/Soto // +// Frontera Chino/Soto // +// Frontera Chino/Soto // +///////////////////////// + struct sx127x { struct regmap *regmap; struct ieee802154_hw *ieee; @@ -428,6 +1453,10 @@ static void sx127x_tx_work(struct work_struct *work) } // reset FIFO address and payload length + ret = sx127x_reg_write(hw, SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDRESS); + if (ret < 0) + goto exit_busy; + ret = sx127x_reg_write(hw, SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDRESS); if (ret < 0) goto exit_busy; @@ -443,32 +1472,23 @@ static void sx127x_tx_work(struct work_struct *work) if (ret < 0) goto exit_busy; - ret = sx127x_reg_read(hw, SX127X_REG_OP_MODE, &mode); - if (ret < 0) - goto exit_busy; - - if ((mode & SX127X_MODE_MASK) == SX127X_STANDBY_MODE - || (mode & SX127X_MODE_MASK) == SX127X_RXCONTINUOUS_MODE) - ret = sx127x_mode(hw, SX127X_TX_MODE); - else - hw->delayed_tx_length = size; + hw->delayed_tx_length = size; exit_busy: spin_lock_irqsave(&hw->lock, spin_irq); if (set_busy) hw->busy = false; - if (tx_skb) + if (ret && tx_skb) hw->tx_skb = NULL; spin_unlock_irqrestore(&hw->lock, spin_irq); - if (tx_skb) { -#ifndef SX127X_LEGACY_KERNEL - if (ret) - ieee802154_xmit_error(hw->ieee, tx_skb, ret); - else + if (ret && tx_skb) { +#ifdef SX127X_LEGACY_KERNEL + ieee802154_xmit_complete(hw->ieee, tx_skb, false); +#else + ieee802154_xmit_error(hw->ieee, tx_skb, ret); #endif - ieee802154_xmit_complete(hw->ieee, tx_skb, false); } (void) ret; @@ -480,13 +1500,15 @@ static void sx127x_poll_work(struct work_struct *work) bool do_rx = false, was_busy = false; unsigned long spin_irq; struct sx127x *hw = container_of(work, struct sx127x, poll_work); - struct sk_buff *rx_skb = NULL; + struct sk_buff *rx_skb = NULL, *tx_skb = NULL; spin_lock_irqsave(&hw->lock, spin_irq); if (!hw->busy) hw->busy = true; else was_busy = true; + + tx_skb = hw->tx_skb; spin_unlock_irqrestore(&hw->lock, spin_irq); if (was_busy) @@ -496,9 +1518,11 @@ static void sx127x_poll_work(struct work_struct *work) goto exit_busy; ack_flags = 0; - + if (read_flags & SX127X_FLAG_TXDONE) ack_flags |= SX127X_FLAG_TXDONE; + else + tx_skb = NULL; if (read_flags & SX127X_FLAG_RXDONE) { do_rx = true; @@ -563,8 +1587,13 @@ exit_busy: if (rx_skb) kfree_skb(rx_skb); + if (tx_skb) + ieee802154_xmit_complete(hw->ieee, tx_skb, false); + spin_lock_irqsave(&hw->lock, spin_irq); hw->busy = false; + if (tx_skb) + hw->tx_skb = NULL; spin_unlock_irqrestore(&hw->lock, spin_irq); } @@ -583,7 +1612,7 @@ static int sx127x_802154_xmit_async(struct ieee802154_hw *ieee, struct sk_buff * spin_lock_irqsave(&hw->lock, spin_irq); if (!hw->tx_skb) - hw->tx_skb = skb_get(skb); + hw->tx_skb = skb; else ret = -EBUSY; spin_unlock_irqrestore(&hw->lock, spin_irq); @@ -625,6 +1654,7 @@ static int sx127x_802154_start(struct ieee802154_hw *ieee) } mod_timer(&hw->poll_timer, jiffies + POLL_JIFFIES); + dev_dbg(regmap_get_device(hw->regmap), "%s\n", __func__); return 0; } @@ -636,6 +1666,7 @@ static void sx127x_802154_stop(struct ieee802154_hw *ieee) cancel_work_sync(&hw->poll_work); (void) sx127x_mode(hw, SX127X_SLEEP_MODE); + dev_dbg(regmap_get_device(hw->regmap), "%s\n", __func__); } static int sx127x_802154_set_promiscuous_mode(struct ieee802154_hw *ieee, const bool on) diff --git a/lora_sx127_rpi3.c b/lora_sx127_rpi3.c deleted file mode 100644 index 8200ac7..0000000 --- a/lora_sx127_rpi3.c +++ /dev/null @@ -1,812 +0,0 @@ -/*- - * Copyright (c) 2017 Jian-Hong, Pan - * Copyright (c) 2024 Fabian Montero - * - * 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, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any - * redistribution must be conditioned upon including a substantially - * similar Disclaimer requirement for further binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGES. - * - */ - -#define DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef F_XOSC -#define F_XOSC 32000000 -#endif -static u32 xosc_frq = F_XOSC; -module_param(xosc_frq, uint, 0000); -MODULE_PARM_DESC(xosc_frq, "Crystal oscillator frequency of the LoRa chip"); - -#define __POW_2_19 0x80000 - -#ifndef SX127X_SPRF -#define SX127X_SPRF 512 -#endif -static u32 sprf = SX127X_SPRF; -module_param(sprf, uint, 0000); -MODULE_PARM_DESC(sprf, "Spreading factor of Chirp Spread Spectrum modulation"); - -#ifndef SX127X_RX_BYTE_TIMEOUT -#define SX127X_RX_BYTE_TIMEOUT 1023 -#endif -static u32 rx_timeout = SX127X_RX_BYTE_TIMEOUT; -module_param(rx_timeout, uint, 0000); -MODULE_PARM_DESC(rx_timeout, "RX time-out value as number of symbols"); - -/* SX127X Registers addresses */ -#define SX127X_REG_FIFO 0x00 -#define SX127X_REG_OP_MODE 0x01 -#define SX127X_REG_FRF_MSB 0x06 -#define SX127X_REG_FRF_MID 0x07 -#define SX127X_REG_FRF_LSB 0x08 -#define SX127X_REG_PA_CONFIG 0x09 -#define SX127X_REG_PA_RAMP 0x0A -#define SX127X_REG_OCP 0x0B -#define SX127X_REG_LNA 0x0C -#define SX127X_REG_FIFO_ADDR_PTR 0x0D -#define SX127X_REG_FIFO_TX_BASE_ADDR 0x0E -#define SX127X_REG_FIFO_RX_BASE_ADDR 0x0F -#define SX127X_REG_FIFO_RX_CURRENT_ADDR 0x10 -#define SX127X_REG_IRQ_FLAGS_MASK 0x11 -#define SX127X_REG_IRQ_FLAGS 0x12 -#define SX127X_REG_RX_NB_BYTES 0x13 -#define SX127X_REG_RX_HEADER_CNT_VALUE_MSB 0x14 -#define SX127X_REG_RX_HEADER_CNT_VALUE_LSB 0x15 -#define SX127X_REG_RX_PACKET_CNT_VALUE_MSB 0x16 -#define SX127X_REG_RX_PACKET_CNT_VALUE_LSB 0x17 -#define SX127X_REG_MODEM_STAT 0x18 -#define SX127X_REG_PKT_SNR_VALUE 0x19 -#define SX127X_REG_PKT_RSSI_VALUE 0x1A -#define SX127X_REG_RSSI_VALUE 0x1B -#define SX127X_REG_HOP_CHANNEL 0x1C -#define SX127X_REG_MODEM_CONFIG1 0x1D -#define SX127X_REG_MODEM_CONFIG2 0x1E -#define SX127X_REG_SYMB_TIMEOUT_LSB 0x1F -#define SX127X_REG_PREAMBLE_MSB 0x20 -#define SX127X_REG_PREAMBLE_LSB 0x21 -#define SX127X_REG_PAYLOAD_LENGTH 0x22 -#define SX127X_REG_MAX_PAYLOAD_LENGTH 0x23 -#define SX127X_REG_HOP_PERIOD 0x24 -#define SX127X_REG_FIFO_RX_BYTE_ADDR 0x25 -#define SX127X_REG_MODEM_CONFIG3 0x26 -#define SX127X_REG_FEI_MSB 0x28 -#define SX127X_REG_FEI_MID 0x29 -#define SX127X_REG_FEI_LSB 0x2A -#define SX127X_REG_RSSI_WIDEBAND 0x2C -#define SX127X_REG_DETECT_OPTIMIZE 0x31 -#define SX127X_REG_INVERT_IRQ 0x33 -#define SX127X_REG_DETECTION_THRESHOLD 0x37 -#define SX127X_REG_SYNC_WORD 0x39 -#define SX127X_REG_VERSION 0x42 -#define SX127X_REG_TCXO 0x4B -#define SX127X_REG_PA_DAC 0x4D -#define SX127X_REG_FORMER_TEMP 0x5B -#define SX127X_REG_AGC_REF 0x61 -#define SX127X_REG_AGC_THRESH1 0x62 -#define SX127X_REG_AGC_THRESH2 0x63 -#define SX127X_REG_AGC_THRESH3 0x64 -#define SX127X_REG_PLL 0x70 -#define SX127X_MAX_REG SX127X_REG_PLL - -/* SX127X's operating states in LoRa mode */ -#define SX127X_MODE_MASK 0x07 -#define SX127X_SLEEP_MODE 0x00 -#define SX127X_STANDBY_MODE 0x01 -#define SX127X_FSTX_MODE 0x02 -#define SX127X_TX_MODE 0x03 -#define SX127X_FSRX_MODE 0x04 -#define SX127X_RXCONTINUOUS_MODE 0x05 -#define SX127X_RXSINGLE_MODE 0x06 -#define SX127X_CAD_MODE 0x07 -#define SX127X_LORA_MODE 0x80 - -/* SX127X_REG_OCP flags */ -#define SX127X_FLAG_OCPON 0x20 - -/* SX127X's IRQ flags in LoRa mode */ -#define SX127X_FLAG_RXTIMEOUT 0x80 -#define SX127X_FLAG_RXDONE 0x40 -#define SX127X_FLAG_PAYLOADCRCERROR 0x20 -#define SX127X_FLAG_VALIDHEADER 0x10 -#define SX127X_FLAG_TXDONE 0x08 -#define SX127X_FLAG_CADDONE 0x04 -#define SX127X_FLAG_FHSSCHANGECHANNEL 0x02 -#define SX127X_FLAG_CADDETECTED 0x01 - -/* SX127X's IRQ flags' mask for output pins in LoRa mode */ -#define SX127X_FLAGMASK_RXTIMEOUT 0x80 -#define SX127X_FLAGMASK_RXDONE 0x40 -#define SX127X_FLAGMASK_PAYLOADCRCERROR 0x20 -#define SX127X_FLAGMASK_VALIDHEADER 0x10 -#define SX127X_FLAGMASK_TXDONE 0x08 -#define SX127X_FLAGMASK_CADDONE 0x04 -#define SX127X_FLAGMASK_FHSSCHANGECHANNEL 0x02 -#define SX127X_FLAGMASK_CADDETECTED 0x01 - -#define SX127X_MODEM_CONFIG1_HEADER_MODE_MASK 0x01 -#define SX127X_MODEM_CONFIG1_HEADER_MODE_EXPLICIT 0x00 -#define SX127X_MODEM_CONFIG1_HEADER_MODE_IMPLICIT 0x01 - -/* SX127X's RX/TX FIFO base address */ -#define SX127X_FIFO_RX_BASE_ADDRESS 0x00 -#define SX127X_FIFO_TX_BASE_ADDRESS 0x80 - -#define POLL_JIFFIES (msecs_to_jiffies(10)) - -struct sx127x { - struct regmap *regmap; - struct ieee802154_hw *ieee; - struct spi_device *spi; - - spinlock_t lock; - bool busy; - struct sk_buff *tx_skb; - size_t delayed_tx_length; - - struct timer_list poll_timer; - struct work_struct poll_work; - struct work_struct tx_work; - - u32 oscillator_freq; -}; - -static int sx127x_reg_read(struct sx127x *hw, unsigned int address, u8 *data) -{ - int ret = regmap_raw_read(hw->regmap, address, data, 1); - if (ret < 0) - dev_err(&hw->spi->dev, "regmap_raw_read(0x%x) failed: %d\n", address, ret); - - return ret; -} - -static int sx127x_reg_write(struct sx127x *hw, unsigned int address, u8 data) -{ - int ret = regmap_raw_write(hw->regmap, address, &data, 1); - if (ret < 0) - dev_err(&hw->spi->dev, "regmap_raw_write(0x%x) failed: %d\n", address, ret); - - return ret; -} - -static int sx127x_mode(struct sx127x *hw, unsigned int mode) -{ - return sx127x_reg_write(hw, SX127X_REG_OP_MODE, SX127X_LORA_MODE | mode); -} - -static int sx127x_set_frequency(struct sx127x *hw, unsigned long frequency) -{ - u8 msb_mid_lsb[3]; - int i; - u64 frf; - - frf = (((u64) frequency) << 19) / hw->oscillator_freq; - for (i = sizeof msb_mid_lsb - 1; i >= 0; --i) { - msb_mid_lsb[i] = (frf & 0xff); - frf >>= 8; - } - - return regmap_raw_write(hw->regmap, SX127X_REG_FRF_MSB, msb_mid_lsb, sizeof msb_mid_lsb); -} - -static int sx127x_get_frequency(struct sx127x *hw, unsigned long *frequency) -{ - u8 msb_mid_lsb[3]; - int i, ret; - u64 frt; - - ret = regmap_raw_read(hw->regmap, SX127X_REG_FRF_MSB, msb_mid_lsb, sizeof msb_mid_lsb); - if (ret < 0) - return ret; - - frt = 0; - for (i = 0; i < sizeof msb_mid_lsb; ++i) - frt = (frt << 8) | msb_mid_lsb[i]; - - *frequency = (frt * hw->oscillator_freq) >> 19; - return 0; -} - -static int sx127x_set_ocp(struct sx127x *hw, u8 current_ma) -{ - u8 ocp_trim; - - /* P. 109 - * - * Trimming of OCP current: - * Imax = 45+5*OcpTrim [mA] if OcpTrim <= 15 (120 mA) / - * Imax = -30+10*OcpTrim [mA] if 15 < OcpTrim <= 27 (130 to - * 240 mA) - * Imax = 240mA for higher settings - * Default Imax = 100mA - */ - if (current_ma <= 45) - ocp_trim = 0; - else if (current_ma <= 120) - ocp_trim = (current_ma - 45) / 5; - else if (current_ma <= 240) - ocp_trim = (current_ma + 30) / 10; - else - ocp_trim = 28; - - return sx127x_reg_write(hw, SX127X_REG_OCP, SX127X_FLAG_OCPON | ocp_trim); -} - -static int sx127x_set_tx_power(struct sx127x *hw, int level) -{ - int ret; - - // PA BOOST - if (level > 17) { - if (level > 20) - level = 20; - - // subtract 3 from level, so 18 - 20 maps to 15 - 17 - level -= 3; - - // High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.) - ret = sx127x_reg_write(hw, SX127X_REG_PA_DAC, 0x87); - if (ret < 0) - return ret; - - ret = sx127x_set_ocp(hw, 140); - if (ret < 0) - return ret; - } else { - if (level < 2) - level = 2; - - // Default value PA_HF/LF or +17dBm - ret = sx127x_reg_write(hw, SX127X_REG_PA_DAC, 0x84); - if (ret < 0) - return ret; - - ret = sx127x_set_ocp(hw, 100); - if (ret < 0) - return ret; - } - - // PA_CONFIG -#define PA_BOOST 0x80 - return sx127x_reg_write(hw, SX127X_REG_PA_CONFIG, PA_BOOST | (level - 2)); -} - -static int sx127x_init(struct sx127x *hw, u8 *major, u8 *minor) -{ - u8 modem_config1, lna, version; - int ret; - - ret = sx127x_reg_read(hw, SX127X_REG_VERSION, &version); - if (ret < 0) - return ret; - - if (version != 0x12) { - dev_err(&hw->spi->dev, "%s: bad version 0x%02x\n", __func__, version); - return -ENODEV; - } - - *major = (version >> 4) & 0xf; - *minor = (version >> 0) & 0xf; - - ret = sx127x_mode(hw, SX127X_SLEEP_MODE); - if (ret < 0) { - dev_err(&hw->spi->dev, "%s: sx127x_mode() failed: %d\n", __func__, ret); - return ret; - } - - ret = sx127x_reg_write(hw, SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDRESS); - if (ret < 0) - return ret; - - ret = sx127x_reg_write(hw, SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDRESS); - if (ret < 0) - return ret; - - ret = sx127x_reg_read(hw, SX127X_REG_LNA, &lna); - if (ret < 0) - return ret; - - lna |= 0x3; // ???, pero lo hace el sketch - ret = sx127x_reg_write(hw, SX127X_REG_LNA, lna); - if (ret < 0) - return ret; - - ret = sx127x_reg_read(hw, SX127X_REG_MODEM_CONFIG1, &modem_config1); - if (ret < 0) - return ret; - - modem_config1 &= ~SX127X_MODEM_CONFIG1_HEADER_MODE_MASK; - modem_config1 |= SX127X_MODEM_CONFIG1_HEADER_MODE_EXPLICIT; - - ret = sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG1, modem_config1); - if (ret < 0) - return ret; - - ret = sx127x_reg_write(hw, SX127X_REG_MODEM_CONFIG3, 0x4); - if (ret < 0) - return ret; - - return 0; -} - -static void sx127x_tx_work(struct work_struct *work) -{ - u8 mode; - int ret = 0; - bool set_busy = false; - size_t i, size; - const u8 *buffer; - struct sx127x *hw = container_of(work, struct sx127x, tx_work); - struct sk_buff *tx_skb; - unsigned long spin_irq; - - spin_lock_irqsave(&hw->lock, spin_irq); - - tx_skb = hw->tx_skb; - if (!hw->busy && !hw->delayed_tx_length) { - hw->busy = true; - set_busy = true; - } - - spin_unlock_irqrestore(&hw->lock, spin_irq); - - if (!set_busy) { - ret = -EBUSY; - goto exit_busy; - } else if (!tx_skb) { - ret = -EINVAL; - goto exit_busy; - } - - size = tx_skb->len; - buffer = tx_skb->data; - - if (!size || size > 128) { - ret = -EINVAL; - goto exit_busy; - } - - ret = sx127x_reg_read(hw, SX127X_REG_OP_MODE, &mode); - if (ret < 0) - goto exit_busy; - - if ((mode & SX127X_MODE_MASK) == SX127X_TX_MODE) { - ret = -EBUSY; - goto exit_busy; - } - - // reset FIFO address and payload length - ret = sx127x_reg_write(hw, SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDRESS); - if (ret < 0) - goto exit_busy; - - // write data - for (i = 0; i < size; i++) { - ret = sx127x_reg_write(hw, SX127X_REG_FIFO, buffer[i]); - if (ret < 0) - goto exit_busy; - } - - ret = sx127x_reg_write(hw, SX127X_REG_PAYLOAD_LENGTH, (u8) size); - if (ret < 0) - goto exit_busy; - - ret = sx127x_reg_read(hw, SX127X_REG_OP_MODE, &mode); - if (ret < 0) - goto exit_busy; - - if ((mode & SX127X_MODE_MASK) == SX127X_STANDBY_MODE - || (mode & SX127X_MODE_MASK) == SX127X_RXCONTINUOUS_MODE) - ret = sx127x_mode(hw, SX127X_TX_MODE); - else - hw->delayed_tx_length = size; - -exit_busy: - spin_lock_irqsave(&hw->lock, spin_irq); - if (set_busy) - hw->busy = false; - - if (tx_skb) - hw->tx_skb = NULL; - spin_unlock_irqrestore(&hw->lock, spin_irq); - - if (tx_skb) { -#ifndef SX127X_LEGACY_KERNEL - if (ret) - ieee802154_xmit_error(hw->ieee, tx_skb, ret); - else -#endif - ieee802154_xmit_complete(hw->ieee, tx_skb, false); - } - - (void) ret; -} - -static void sx127x_poll_work(struct work_struct *work) -{ - u8 ack_flags, lqi, mode, read_flags, rx_base, *rx_data, rx_length; - bool do_rx = false, was_busy = false; - unsigned long spin_irq; - struct sx127x *hw = container_of(work, struct sx127x, poll_work); - struct sk_buff *rx_skb = NULL; - - spin_lock_irqsave(&hw->lock, spin_irq); - if (!hw->busy) - hw->busy = true; - else - was_busy = true; - spin_unlock_irqrestore(&hw->lock, spin_irq); - - if (was_busy) - return; - - if (sx127x_reg_read(hw, SX127X_REG_IRQ_FLAGS, &read_flags) < 0) - goto exit_busy; - - ack_flags = 0; - - if (read_flags & SX127X_FLAG_TXDONE) - ack_flags |= SX127X_FLAG_TXDONE; - - if (read_flags & SX127X_FLAG_RXDONE) { - do_rx = true; - ack_flags |= SX127X_FLAG_RXDONE; - - if (read_flags & SX127X_FLAG_VALIDHEADER) - ack_flags |= SX127X_FLAG_VALIDHEADER; - else - do_rx = false; - - if (read_flags & SX127X_FLAG_PAYLOADCRCERROR) { - do_rx = false; - ack_flags |= SX127X_FLAG_PAYLOADCRCERROR; - } - } - - if (do_rx) { - if (sx127x_reg_read(hw, SX127X_REG_FIFO_RX_CURRENT_ADDR, &rx_base) < 0 - || sx127x_reg_read(hw, SX127X_REG_RX_NB_BYTES, &rx_length) < 0) - goto exit_busy; - - if (sx127x_reg_write(hw, SX127X_REG_FIFO_ADDR_PTR, rx_base) < 0) - goto exit_busy; - - rx_skb = dev_alloc_skb(IEEE802154_MTU); - if (!rx_skb) - goto exit_busy; - - rx_data = skb_put(rx_skb, rx_length); - while (rx_length--) - if (sx127x_reg_read(hw, SX127X_REG_FIFO, rx_data++) < 0) - goto exit_busy; - - if (sx127x_reg_write(hw, SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDRESS) < 0) - goto exit_busy; - } - - if (sx127x_reg_write(hw, SX127X_REG_IRQ_FLAGS, ack_flags) < 0) - goto exit_busy; - - if (sx127x_reg_read(hw, SX127X_REG_OP_MODE, &mode) < 0) - goto exit_busy; - - if ((mode & SX127X_MODE_MASK) != SX127X_TX_MODE) { - if (hw->delayed_tx_length) { - sx127x_mode(hw, SX127X_TX_MODE); - hw->delayed_tx_length = 0; - } else if ((mode & SX127X_MODE_MASK) != SX127X_RXCONTINUOUS_MODE) - sx127x_mode(hw, SX127X_RXCONTINUOUS_MODE); - } - - if (rx_skb) { - lqi = 69; //TODO - ieee802154_rx_irqsafe(hw->ieee, rx_skb, lqi); - rx_skb = NULL; // rx_skb ownership transferred to the mac802154 layer - } - -exit_busy: - if (rx_skb) - kfree_skb(rx_skb); - - spin_lock_irqsave(&hw->lock, spin_irq); - hw->busy = false; - spin_unlock_irqrestore(&hw->lock, spin_irq); -} - -static void sx127x_poll_timer(struct timer_list *timer) -{ - struct sx127x *hw = container_of(timer, struct sx127x, poll_timer); - schedule_work(&hw->poll_work); - mod_timer(&hw->poll_timer, jiffies + POLL_JIFFIES); -} - -static int sx127x_802154_xmit_async(struct ieee802154_hw *ieee, struct sk_buff *skb) -{ - int ret = 0; - struct sx127x *hw = ieee->priv; - unsigned long spin_irq; - - spin_lock_irqsave(&hw->lock, spin_irq); - if (!hw->tx_skb) - hw->tx_skb = skb_get(skb); - else - ret = -EBUSY; - spin_unlock_irqrestore(&hw->lock, spin_irq); - - schedule_work(&hw->tx_work); - return ret; -} - -static int sx127x_802154_ed(struct ieee802154_hw *ieee, u8 *level) -{ - struct sx127x *hw = ieee->priv; - (void) hw; - return -ENOSYS; -} - -static int sx127x_802154_set_channel(struct ieee802154_hw *ieee, u8 page, u8 channel) -{ - struct sx127x *hw = ieee->priv; - (void) hw; - return -ENOSYS; -} - -static int sx127x_802154_set_txpower(struct ieee802154_hw *ieee, s32 mbm) -{ - struct sx127x *hw = ieee->priv; - (void) hw; - return -ENOSYS; -} - -static int sx127x_802154_start(struct ieee802154_hw *ieee) -{ - int ret; - struct sx127x *hw = ieee->priv; - - ret = sx127x_mode(hw, SX127X_STANDBY_MODE); - if (ret < 0) { - dev_err(&hw->spi->dev, "%s: sx127x_mode() failed: %d\n", __func__, ret); - return ret; - } - - mod_timer(&hw->poll_timer, jiffies + POLL_JIFFIES); - return 0; -} - -static void sx127x_802154_stop(struct ieee802154_hw *ieee) -{ - struct sx127x *hw = ieee->priv; - - del_timer_sync(&hw->poll_timer); - cancel_work_sync(&hw->poll_work); - - (void) sx127x_mode(hw, SX127X_SLEEP_MODE); -} - -static int sx127x_802154_set_promiscuous_mode(struct ieee802154_hw *ieee, const bool on) -{ - return 0; -} - -static const struct ieee802154_ops sx127x_802154_ops = { - .owner = THIS_MODULE, - .xmit_async = sx127x_802154_xmit_async, - .ed = sx127x_802154_ed, - .set_channel = sx127x_802154_set_channel, - .set_txpower = sx127x_802154_set_txpower, - .start = sx127x_802154_start, - .stop = sx127x_802154_stop, - .set_promiscuous_mode = sx127x_802154_set_promiscuous_mode, -}; - -static bool sx127x_reg_volatile(struct device *dev, unsigned int reg) -{ - return true; -} - -static const struct regmap_config sx127x_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = SX127X_MAX_REG, - .read_flag_mask = 0x00, - .write_flag_mask = 0x80, - .volatile_reg = sx127x_reg_volatile, -}; - -/* in mbm */ -static const s32 sx127x_tx_powers[] = { - -200, -100, 0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, - 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300}; - -static int sx127x_spi_probe(struct spi_device *spi) -{ - u8 major, minor; - int ret = 0; - struct sx127x *hw; - unsigned long frequency; - struct ieee802154_hw *ieee; - struct device_node *of_node; - - dev_dbg(&spi->dev, "%s hello\n", __func__); - - ieee = ieee802154_alloc_hw(sizeof *hw, &sx127x_802154_ops); - if (!ieee) { - dev_err(&spi->dev, "ieee802154_alloc_hw(): out of memory\n"); - return -ENOMEM; - } - - hw = ieee->priv; - hw->spi = spi; - hw->ieee = ieee; - hw->busy = false; - hw->delayed_tx_length = 0; - spin_lock_init(&hw->lock); - - INIT_WORK(&hw->tx_work, sx127x_tx_work); - INIT_WORK(&hw->poll_work, sx127x_poll_work); - timer_setup(&hw->poll_timer, sx127x_poll_timer, 0); - - hw->regmap = devm_regmap_init_spi(spi, &sx127x_regmap_config); - if (IS_ERR(hw->regmap)) { - dev_err(&spi->dev, "%s: devm_regmap_init_spi() failed: %d\n", __func__, ret); - return PTR_ERR(hw->regmap); - } - - of_node = regmap_get_device(hw->regmap)->of_node; - if (of_property_read_u32(of_node, "clock-frequency", &hw->oscillator_freq)) { - dev_err(&spi->dev, "%s: 'clock-frequency' missing from DT node\n", __func__); - return -EINVAL; - } - - ieee->parent = &spi->dev; - spi_set_drvdata(spi, hw); - - //TODO: pin de reset - - ieee802154_random_extended_addr(&ieee->phy->perm_extended_addr); - - ieee->flags = IEEE802154_HW_TX_OMIT_CKSUM - | IEEE802154_HW_RX_OMIT_CKSUM - | IEEE802154_HW_PROMISCUOUS; - - ieee->phy->flags = WPAN_PHY_FLAG_TXPOWER; - ieee->phy->transmit_power = sx127x_tx_powers[12]; - ieee->phy->supported.tx_powers = sx127x_tx_powers; - ieee->phy->supported.tx_powers_size = ARRAY_SIZE(sx127x_tx_powers); - - /* SX1278 phy channel 11 as default */ - ieee->phy->current_channel = 11; - /* Define channels could be used. */ - ieee->phy->supported.channels[0] = 1 << 11; /*TODO: sx1278_ieee_channel_mask(hw);*/ - - ret = sx127x_init(hw, &major, &minor); - if (ret < 0) { - dev_err(&spi->dev, "%s: sx127x_init() failed: %d\n", __func__, ret); - goto fail_init; - } - - dev_info(&spi->dev, "IEEE 802.15.4 over LoRa SX127x compatible device v%u.%u\n", major, minor); - - // Valor viene del sketch - ret = sx127x_set_frequency(hw, 434000000); - if (ret < 0) { - dev_err(&spi->dev, "%s: sx127x_set_frequency() failed: %d\n", __func__, ret); - goto fail_init; - } - - ret = sx127x_get_frequency(hw, &frequency); - if (ret < 0) { - dev_err(&spi->dev, "%s: sx127x_get_frequency() failed: %d\n", __func__, ret); - goto fail_init; - } - - dev_dbg(&spi->dev, "%s: frequency sanity test: %lu Hz\n", __func__, frequency); - - ret = sx127x_set_tx_power(hw, 17); // 17 dBm - if (ret < 0) { - dev_err(&spi->dev, "%s: sx127x_set_tx_power() failed: %d\n", __func__, ret); - goto fail_init; - } - - ret = ieee802154_register_hw(ieee); - if (ret < 0) - dev_err(&spi->dev, "ieee802154_register_hw() failed: %d\n", ret); - - return ret; - -fail_init: - ieee802154_free_hw(ieee); - return ret; -} - -#ifdef SX127X_LEGACY_KERNEL -static int sx127x_spi_remove(struct spi_device *spi) -#else -static void sx127x_spi_remove(struct spi_device *spi) -#endif -{ - struct sx127x *hw = spi_get_drvdata(spi); - - dev_dbg(&hw->spi->dev, "%s bye\n", __func__); - - ieee802154_unregister_hw(hw->ieee); - ieee802154_free_hw(hw->ieee); - -#ifdef SX127X_LEGACY_KERNEL - return 0; -#endif -} - -static const struct of_device_id sx127x_of_ids[] = { - { .compatible = "semtech,sx1276" }, - { .compatible = "semtech,sx1277" }, - { .compatible = "semtech,sx1278" }, - { .compatible = "semtech,sx1279" }, - {}, -}; -MODULE_DEVICE_TABLE(of, sx127x_of_ids); - -static const struct spi_device_id sx127x_spi_ids[] = { - { .name = "sx1276" }, - { .name = "sx1277" }, - { .name = "sx1278" }, - { .name = "sx1279" }, - {}, -}; -MODULE_DEVICE_TABLE(spi, sx127x_spi_ids); - -static struct spi_driver sx127x_spi_driver = { - .driver = { - .name = "sx127x", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(sx127x_of_ids), - }, - .probe = sx127x_spi_probe, - .remove = sx127x_spi_remove, - .id_table = sx127x_spi_ids, -}; - -module_spi_driver(sx127x_spi_driver); - -MODULE_AUTHOR("Jian-Hong Pan, "); -MODULE_AUTHOR("Fabian Montero "); -MODULE_DESCRIPTION("Semtech SX127x LoRa PHY driver with IEEE 802.15.4 MAC interface"); -MODULE_LICENSE("GPL"); diff --git a/setup-lora_pi3.c b/setup-lora_pi3.c deleted file mode 100755 index a52c732..0000000 --- a/setup-lora_pi3.c +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -e - -modprobe regmap_spi -modprobe mac802154 -insmod /home/loro/LoRo/LoRo/loro.ko -sleep 1 -ip link set down wpan0 -iwpan dev wpan0 set pan_id 0xbeef -ip link add link wpan0 name lowpan0 type lowpan -ip link set up wpan0 -ip link set up lowpan0