[
  {
    "path": "License.md",
    "content": "Copyright (c) 2017 Jian-Hong, Pan <starnight@g.ncu.edu.tw>\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer,\n   without modification.\n2. Redistributions in binary form must reproduce at minimum a disclaimer\n   similar to the \"NO WARRANTY\" disclaimer below (\"Disclaimer\") and any\n   redistribution must be conditioned upon including a substantially\n   similar Disclaimer requirement for further binary redistribution.\n3. Neither the names of the above-listed copyright holders nor the names\n   of any contributors may be used to endorse or promote products derived\n   from this software without specific prior written permission.\n\nAlternatively, this software may be distributed under the terms of the\nGNU General Public License (\"GPL\") version 2 as published by the Free\nSoftware Foundation.\n\nNO WARRANTY\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY\nAND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL\nTHE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,\nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\nIN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\nTHE POSSIBILITY OF SUCH DAMAGES.\n"
  },
  {
    "path": "LoRa/Makefile",
    "content": "PROJ=sx1278\nobj-m := $(PROJ).o\n\nKERNEL_LOCATION=/lib/modules/$(shell uname -r)\nBUILDDIR=$(KERNEL_LOCATION)/build\n\nall:\n\tmake -C $(BUILDDIR) M=$(PWD) modules\n\ninstall:\n\tsudo make -C $(BUILDDIR) M=$(PWD) modules_install\n\t# Rebuild the kernel module dependencies for modprobe\n\tsudo depmod -a\n\nuninstall:\n\tsudo modprobe -r $(PROJ)\n\tsudo rm $(KERNEL_LOCATION)/extra/$(PROJ).ko.gz\n\t# Rebuild the kernel module dependencies for modprobe\n\tsudo depmod -a\n\ntest:\n\tmake install; echo\n\tls -l /dev/$(PROJ)*\n\tmake uninstall\n\nclean:\n\tmake -C $(BUILDDIR) M=$(PWD) clean\n"
  },
  {
    "path": "LoRa/sx1278.c",
    "content": "/*-\n * Copyright (c) 2017 Jian-Hong, Pan <starnight@g.ncu.edu.tw>\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer,\n *    without modification.\n * 2. Redistributions in binary form must reproduce at minimum a disclaimer\n *    similar to the \"NO WARRANTY\" disclaimer below (\"Disclaimer\") and any\n *    redistribution must be conditioned upon including a substantially\n *    similar Disclaimer requirement for further binary redistribution.\n * 3. Neither the names of the above-listed copyright holders nor the names\n *    of any contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * Alternatively, this software may be distributed under the terms of the\n * GNU General Public License (\"GPL\") version 2 as published by the Free\n * Software Foundation.\n *\n * NO WARRANTY\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY\n * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL\n * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,\n * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGES.\n *\n */\n\n#include <linux/module.h>\n#include <linux/timer.h>\n#include <linux/device.h>\n#include <linux/acpi.h>\n#include <linux/of_device.h>\n#include <linux/spinlock.h>\n#include <linux/spi/spi.h>\n#include <linux/regmap.h>\n#include <net/mac802154.h>\n\n/*------------------------------ LoRa Functions ------------------------------*/\n\n#ifndef F_XOSC\n#define F_XOSC\t\t32000000\n#endif\nstatic u32 xosc_frq = F_XOSC;\nmodule_param(xosc_frq, uint, 0000);\nMODULE_PARM_DESC(xosc_frq, \"Crystal oscillator frequency of the LoRa chip\");\n\n#define\t__POW_2_19\t0x80000\n\n#ifndef SX127X_SPRF\n#define SX127X_SPRF\t512\n#endif\nstatic u32 sprf = SX127X_SPRF;\nmodule_param(sprf, uint, 0000);\nMODULE_PARM_DESC(sprf, \"Spreading factor of Chirp Spread Spectrum modulation\");\n\n#ifndef SX127X_RX_BYTE_TIMEOUT\n#define SX127X_RX_BYTE_TIMEOUT\t1023\n#endif\nstatic u32 rx_timeout = SX127X_RX_BYTE_TIMEOUT;\nmodule_param(rx_timeout, uint, 0000);\nMODULE_PARM_DESC(rx_timeout, \"RX time-out value as number of symbols\");\n\n/* SX127X Registers addresses */\n#define SX127X_REG_FIFO\t\t\t\t0x00\n#define SX127X_REG_OP_MODE\t\t\t0x01\n#define SX127X_REG_FRF_MSB\t\t\t0x06\n#define SX127X_REG_FRF_MID\t\t\t0x07\n#define SX127X_REG_FRF_LSB\t\t\t0x08\n#define SX127X_REG_PA_CONFIG\t\t\t0x09\n#define SX127X_REG_PA_RAMP\t\t\t0x0A\n#define SX127X_REG_OCP\t\t\t\t0x0B\n#define SX127X_REG_LNA\t\t\t\t0x0C\n#define SX127X_REG_FIFO_ADDR_PTR\t\t0x0D\n#define SX127X_REG_FIFO_TX_BASE_ADDR\t\t0x0E\n#define SX127X_REG_FIFO_RX_BASE_ADDR\t\t0x0F\n#define SX127X_REG_FIFO_RX_CURRENT_ADDR\t\t0x10\n#define SX127X_REG_IRQ_FLAGS_MASK\t\t0x11\n#define SX127X_REG_IRQ_FLAGS\t\t\t0x12\n#define SX127X_REG_RX_NB_BYTES\t\t\t0x13\n#define SX127X_REG_RX_HEADER_CNT_VALUE_MSB\t0x14\n#define SX127X_REG_RX_HEADER_CNT_VALUE_LSB\t0x15\n#define SX127X_REG_RX_PACKET_CNT_VALUE_MSB\t0x16\n#define SX127X_REG_RX_PACKET_CNT_VALUE_LSB\t0x17\n#define SX127X_REG_MODEM_STAT\t\t\t0x18\n#define SX127X_REG_PKT_SNR_VALUE\t\t0x19\n#define SX127X_REG_PKT_RSSI_VALUE\t\t0x1A\n#define SX127X_REG_RSSI_VALUE\t\t\t0x1B\n#define SX127X_REG_HOP_CHANNEL\t\t\t0x1C\n#define SX127X_REG_MODEM_CONFIG1\t\t0x1D\n#define SX127X_REG_MODEM_CONFIG2\t\t0x1E\n#define SX127X_REG_SYMB_TIMEOUT_LSB\t\t0x1F\n#define SX127X_REG_PREAMBLE_MSB\t\t\t0x20\n#define SX127X_REG_PREAMBLE_LSB\t\t\t0x21\n#define SX127X_REG_PAYLOAD_LENGTH\t\t0x22\n#define SX127X_REG_MAX_PAYLOAD_LENGTH\t\t0x23\n#define SX127X_REG_HOP_PERIOD\t\t\t0x24\n#define SX127X_REG_FIFO_RX_BYTE_ADDR\t\t0x25\n#define SX127X_REG_MODEM_CONFIG3\t\t0x26\n#define SX127X_REG_FEI_MSB\t\t\t0x28\n#define SX127X_REG_FEI_MID\t\t\t0x29\n#define SX127X_REG_FEI_LSB\t\t\t0x2A\n#define SX127X_REG_RSSI_WIDEBAND\t\t0x2C\n#define SX127X_REG_DETECT_OPTIMIZE\t\t0x31\n#define SX127X_REG_INVERT_IRQ\t\t\t0x33\n#define SX127X_REG_DETECTION_THRESHOLD\t\t0x37\n#define SX127X_REG_SYNC_WORD\t\t\t0x39\n#define SX127X_REG_VERSION\t\t\t0x42\n#define SX127X_REG_TCXO\t\t\t\t0x4B\n#define SX127X_REG_PA_DAC\t\t\t0x4D\n#define SX127X_REG_FORMER_TEMP\t\t\t0x5B\n#define SX127X_REG_AGC_REF\t\t\t0x61\n#define SX127X_REG_AGC_THRESH1\t\t\t0x62\n#define SX127X_REG_AGC_THRESH2\t\t\t0x63\n#define SX127X_REG_AGC_THRESH3\t\t\t0x64\n#define SX127X_REG_PLL\t\t\t\t0x70\n#define SX127X_MAX_REG\t\t\t\tSX127X_REG_PLL\n\n/* SX127X's operating states in LoRa mode */\n#define SX127X_SLEEP_MODE\t\t\t0x00\n#define SX127X_STANDBY_MODE\t\t\t0x01\n#define SX127X_FSTX_MODE\t\t\t0x02\n#define SX127X_TX_MODE\t\t\t\t0x03\n#define SX127X_FSRX_MODE\t\t\t0x04\n#define SX127X_RXCONTINUOUS_MODE\t\t0x05\n#define SX127X_RXSINGLE_MODE\t\t\t0x06\n#define SX127X_CAD_MODE\t\t\t\t0x07\n\n/* SX127X's IRQ flags in LoRa mode */\n#define SX127X_FLAG_RXTIMEOUT\t\t\t0x80\n#define\tSX127X_FLAG_RXDONE\t\t\t0x40\n#define SX127X_FLAG_PAYLOADCRCERROR\t\t0x20\n#define SX127X_FLAG_VALIDHEADER\t\t\t0x10\n#define SX127X_FLAG_TXDONE\t\t\t0x08\n#define SX127X_FLAG_CADDONE\t\t\t0x04\n#define SX127X_FLAG_FHSSCHANGECHANNEL\t\t0x02\n#define SX127X_FLAG_CADDETECTED\t\t\t0x01\n\n/* SX127X's IRQ flags' mask for output pins in LoRa mode */\n#define SX127X_FLAGMASK_RXTIMEOUT\t\t0x80\n#define\tSX127X_FLAGMASK_RXDONE\t\t\t0x40\n#define SX127X_FLAGMASK_PAYLOADCRCERROR\t\t0x20\n#define SX127X_FLAGMASK_VALIDHEADER\t\t0x10\n#define SX127X_FLAGMASK_TXDONE\t\t\t0x08\n#define SX127X_FLAGMASK_CADDONE\t\t\t0x04\n#define SX127X_FLAGMASK_FHSSCHANGECHANNEL\t0x02\n#define SX127X_FLAGMASK_CADDETECTED\t\t0x01\n\n/* SX127X's RX/TX FIFO base address */\n#define SX127X_FIFO_RX_BASE_ADDRESS\t\t0x00\n#define SX127X_FIFO_TX_BASE_ADDRESS\t\t0x80\n\nstruct sx1278_phy {\n\tstruct ieee802154_hw *hw;\n\tstruct regmap *map;\n\n\tbool suspended;\n\tu8 opmode;\n\tstruct timer_list timer;\n\tstruct work_struct irqwork;\n\t/* Lock the RX and TX actions. */\n\tspinlock_t buf_lock;\n\tstruct sk_buff *tx_buf;\n\tu8 tx_delay;\n\tbool one_to_be_sent;\n\tbool post_tx_done;\n\tbool is_busy;\n};\n\n/**\n * sx127X_read_version - Get LoRa device's chip version\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tPositive / negtive values for version code / failed\n *\t\tVersion code:\tbits 7-4 full version number,\n *\t\t\t\tbits 3-0 metal mask revision number\n */\nint\nsx127X_read_version(struct regmap *map)\n{\n\tu8 v;\n\tint status;\n\n\tstatus = regmap_raw_read(map, SX127X_REG_VERSION, &v, 1);\n\n\tif ((status == 0) && (v > 0) && (v < 0xFF))\n\t\tstatus = v;\n\telse\n\t\tstatus = -ENODEV;\n\n\treturn status;\n}\n\n/**\n * sx127X_set_mode - Set LoRa device's mode register\n * @map:\tthe device as a regmap to communicate with\n * @op_mode:\tLoRa device's operation mode register value\n */\nvoid\nsx127X_set_mode(struct regmap *map, u8 op_mode)\n{\n\tregmap_raw_write(map, SX127X_REG_OP_MODE, &op_mode, 1);\n}\n\n/**\n * sx127X_get_mode - Get LoRa device's mode register\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tLoRa device's register value\n */\nu8\nsx127X_get_mode(struct regmap *map)\n{\n\tu8 op_mode;\n\n\t/* Get original OP Mode register. */\n\tregmap_raw_read(map, SX127X_REG_OP_MODE, &op_mode, 1);\n\n\treturn op_mode;\n}\n\n/**\n * sx127X_set_state - Set LoRa device's operating state\n * @map:\tthe device as a regmap to communicate with\n * @st:\t\tLoRa device's operating state going to be assigned\n */\nvoid\nsx127X_set_state(struct regmap *map, u8 st)\n{\n\tu8 op_mode;\n\n\t/* Get original OP Mode register. */\n\top_mode = sx127X_get_mode(map);\n\t/* Set device to designated state. */\n\top_mode = (op_mode & 0xF8) | (st & 0x07);\n\tregmap_raw_write(map, SX127X_REG_OP_MODE, &op_mode, 1);\n}\n\n/**\n * sx127X_get_state - Get LoRa device's operating state\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tLoRa device's operating state\n */\nu8\nsx127X_get_state(struct regmap *map)\n{\n\tu8 op_mode;\n\n\top_mode = sx127X_get_mode(map) & 0x07;\n\n\treturn op_mode;\n}\n\n/**\n * sx127X_set_lorafrq - Set RF frequency\n * @map:\tthe device as a regmap to communicate with\n * @fr:\t\tRF frequency going to be assigned in Hz\n */\nvoid\nsx127X_set_lorafrq(struct regmap *map, u32 fr)\n{\n\tu64 frt;\n\tu8 buf[3];\n\ts8 i;\n\tu32 f_xosc;\n\tu8 op_mode;\n\n#ifdef CONFIG_OF\n\t/* Set the LoRa module's crystal oscillator's clock if OF is defined. */\n\tstruct device_node *of_node = (regmap_get_device(map))->of_node;\n\n\tif (of_property_read_u32(of_node, \"clock-frequency\", &f_xosc))\n\t\tf_xosc = xosc_frq;\n#else\n\tf_xosc = xosc_frq;\n#endif\n\n\tfrt = (uint64_t)fr * (uint64_t)__POW_2_19;\n\tdo_div(frt, f_xosc);\n\n\tfor (i = 2; i >= 0; i--)\n\t\tbuf[i] = do_div(frt, 256);\n\n\top_mode = sx127X_get_mode(map);\n\t/* Set Low/High frequency bit. */\n\tif (fr >= 779000000)\n\t\top_mode &= ~0x8;\n\telse if (fr <= 525000000)\n\t\top_mode |= 0x8;\n\tsx127X_set_state(map, SX127X_SLEEP_MODE);\n\tregmap_raw_write(map, SX127X_REG_FRF_MSB, buf, 3);\n\tsx127X_set_mode(map, op_mode);\n}\n\n/**\n * sx127X_get_lorafrq - Get RF frequency\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tRF frequency in Hz\n */\nu32\nsx127X_get_lorafrq(struct regmap *map)\n{\n\tu64 frt = 0;\n\tu8 buf[3];\n\tu8 i;\n\tint status;\n\tu32 fr;\n\tu32 f_xosc;\n\n#ifdef CONFIG_OF\n\t/* Set the LoRa module's crystal oscillator's clock if OF is defined. */\n\tstruct device_node *of_node = (regmap_get_device(map))->of_node;\n\n\tif (of_property_read_u32(of_node, \"clock-frequency\", &f_xosc))\n\t\tf_xosc = xosc_frq;\n#else\n\tf_xosc = xosc_frq;\n#endif\n\n\tstatus = regmap_raw_read(map, SX127X_REG_FRF_MSB, buf, 3);\n\tif (status < 0)\n\t\treturn 0.0;\n\n\tfor (i = 0; i <= 2; i++)\n\t\tfrt = frt * 256 + buf[i];\n\n\tfr =  frt * f_xosc / __POW_2_19;\n\n\treturn fr;\n}\n\n/**\n * sx127X_set_lorapower - Set RF output power\n * @map:\tthe device as a regmap to communicate with\n * @pout:\tRF output power going to be assigned in dbm\n */\nvoid\nsx127X_set_lorapower(struct regmap *map, s32 pout)\n{\n\tu8 pacf;\n\tu8 boost;\n\tu8 output_power;\n\ts32 pmax;\n\n\tif (pout > 14) {\n\t\t/* Pout > 14dbm */\n\t\tboost = 1;\n\t\tpmax = 7;\n\t\toutput_power = pout - 2;\n\t} else if (pout < 0) {\n\t\t/* Pout < 0dbm */\n\t\tboost = 0;\n\t\tpmax = 2;\n\t\toutput_power = 3 + pout;\n\t} else {\n\t\t/* 0dbm <= Pout <= 14dbm */\n\t\tboost = 0;\n\t\tpmax = 7;\n\t\toutput_power = pout;\n\t}\n\n\tpacf = (boost << 7) | (pmax << 4) | (output_power);\n\tregmap_raw_write(map, SX127X_REG_PA_CONFIG, &pacf, 1);\n}\n\n/**\n * sx127X_get_lorapower - Get RF output power\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tRF output power in dbm\n */\ns32\nsx127X_get_lorapower(struct regmap *map)\n{\n\tu8 pac;\n\tu8 boost;\n\ts32 output_power;\n\ts32 pmax;\n\ts32 pout;\n\n\tregmap_raw_read(map, SX127X_REG_PA_CONFIG, &pac, 1);\n\tboost = (pac & 0x80) >> 7;\n\toutput_power = pac & 0x0F;\n\tif (boost) {\n\t\tpout = 2 + output_power;\n\t} else {\n\t\t/* Power max should be pmax/10.  It is 10 times for now. */\n\t\tpmax = (108 + 6 * ((pac & 0x70) >> 4));\n\t\tpout = (pmax - (150 - output_power * 10)) / 10;\n\t}\n\n\treturn pout;\n}\n\n/**\n * sx127X_dbm2mbm - dbm to mbm unit conversion\n * @dbm:\tthe value in dbm\n *\n * Return:\tthe value in mbm\n */\n#define sx127X_dbm2mbm(dbm)\t(dbm * 100)\n\n/**\n * sx127X_mbm2dbm - mbm to dbm unit conversion\n * @mbm:\tthe value in mbm\n *\n * Return:\tthe value in dbm\n */\n#define sx127X_mbm2dbm(mbm)\t(mbm / 100)\n\ns8 lna_gain[] = {\n\t 0,\n\t-6,\n\t-12,\n\t-24,\n\t-26,\n\t-48\n};\n\n/**\n * sx127X_set_loralna - Set RF LNA gain\n * @map:\tthe device as a regmap to communicate with\n * @db:\t\tRF LNA gain going to be assigned in db\n */\nvoid\nsx127X_set_loralna(struct regmap *map, s32 db)\n{\n\tu8 i, g;\n\tu8 lnacf;\n\n\tfor (i = 0; i < 5; i++) {\n\t\tif (lna_gain[i] <= db)\n\t\t\tbreak;\n\t}\n\tg = i + 1;\n\n\tregmap_raw_read(map, SX127X_REG_LNA, &lnacf, 1);\n\tlnacf = (lnacf & 0x1F) | (g << 5);\n\tregmap_raw_write(map, SX127X_REG_LNA, &lnacf, 1);\n}\n\n/**\n * sx127X_get_loralna - Get RF LNA gain\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tRF LNA gain db\n */\ns32\nsx127X_get_loralna(struct regmap *map)\n{\n\ts32 db;\n\ts8 i, g;\n\tu8 lnacf;\n\n\tregmap_raw_read(map, SX127X_REG_LNA, &lnacf, 1);\n\tg = (lnacf >> 5);\n\ti = g - 1;\n\tdb = lna_gain[i];\n\n\treturn db;\n}\n\n/**\n * sx127X_set_loralnaagc - Set RF LNA go with auto gain control or manual\n * @map:\tthe device as a regmap to communicate with\n * @yesno:\t1 / 0 for auto gain control / manual\n */\nvoid\nsx127X_set_loralnaagc(struct regmap *map, s32 yesno)\n{\n\tu8 mcf3;\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG3, &mcf3, 1);\n\tmcf3 = (yesno) ? (mcf3 | 0x04) : (mcf3 & (~0x04));\n\tregmap_raw_write(map, SX127X_REG_MODEM_CONFIG3, &mcf3, 1);\n}\n\n/**\n * sx127X_get_loraallflag - Get all of the LoRa device IRQ flags' current state\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tAll of the LoRa device's IRQ flags' current state in a byte\n */\nu8\nsx127X_get_loraallflag(struct regmap *map)\n{\n\tu8 flags;\n\n\tregmap_raw_read(map, SX127X_REG_IRQ_FLAGS, &flags, 1);\n\n\treturn flags;\n}\n\n/**\n * sx127X_get_loraallflag - Get interested LoRa device IRQ flag's current state\n * @map:\tthe device as a regmap to communicate with\n * @f:\t\tthe interested LoRa device's IRQ flag\n *\n * Return:\tThe interested LoRa device's IRQ flag's current state in a byte\n */\n#define sx127X_get_loraflag(map, f)\t(sx127X_get_loraallflag(map) & (f))\n\n/**\n * sx127X_clear_loraflag - Clear designated LoRa device's IRQ flag\n * @map:\tthe device as a regmap to communicate with\n * @f:\t\tflags going to be cleared\n */\nvoid\nsx127X_clear_loraflag(struct regmap *map, u8 f)\n{\n\tu8 flag;\n\n\t/* Get oiginal flag. */\n\tflag = sx127X_get_loraallflag(map);\n\t/* Set the designated bits of the flag. */\n\tflag |= f;\n\tregmap_raw_write(map, SX127X_REG_IRQ_FLAGS, &flag, 1);\n}\n\n/**\n * sx127X_clear_loraallflag - Clear designated LoRa device's all IRQ flags\n * @map:\tthe device as a regmap to communicate with\n */\n#define sx127X_clear_loraallflag(spi)\tsx127X_clear_loraflag(spi, 0xFF)\n\n/**\n * sx127X_set_lorasprf - Set the RF modulation's spreading factor\n * @map:\tthe device as a regmap to communicate with\n * @c_s:\tSpreading factor in chips / symbol\n */\nvoid\nsx127X_set_lorasprf(struct regmap *map, u32 c_s)\n{\n\tu8 sf;\n\tu8 mcf2;\n\n\tfor (sf = 6; sf < 12; sf++) {\n\t\tif (c_s == ((u32)1 << sf))\n\t\t\tbreak;\n\t}\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1);\n\tmcf2 = (mcf2 & 0x0F) | (sf << 4);\n\tregmap_raw_write(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1);\n}\n\n/**\n * sx127X_get_lorasprf - Get the RF modulation's spreading factor\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tSpreading factor in chips / symbol\n */\nu32\nsx127X_get_lorasprf(struct regmap *map)\n{\n\tu8 sf;\n\tu32 c_s;\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, &sf, 1);\n\tsf = sf >> 4;\n\tc_s = 1 << sf;\n\n\treturn c_s;\n}\n\nconst u32 hz[] = {\n\t  7800,\n\t 10400,\n\t 15600,\n\t 20800,\n\t 31250,\n\t 41700,\n\t 62500,\n\t125000,\n\t250000,\n\t500000\n};\n\n/**\n * sx127X_set_lorabw - Set RF bandwidth\n * @map:\tthe device as a regmap to communicate with\n * @bw:\t\tRF bandwidth going to be assigned in Hz\n */\nvoid\nsx127X_set_lorabw(struct regmap *map, u32 bw)\n{\n\tu8 i;\n\tu8 mcf1;\n\n\tfor (i = 0; i < 9; i++) {\n\t\tif (hz[i] >= bw)\n\t\t\tbreak;\n\t}\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1);\n\tmcf1 = (mcf1 & 0x0F) | (i << 4);\n\tregmap_raw_write(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1);\n}\n\n/**\n * sx127X_get_lorabw - Get RF bandwidth\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tRF bandwidth in Hz\n */\nu32\nsx127X_get_lorabw(struct regmap *map)\n{\n\tu8 mcf1;\n\tu8 bw;\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1);\n\tbw = mcf1 >> 4;\n\n\treturn hz[bw];\n}\n\n/**\n * sx127X_set_loracr  - Set LoRa package's coding rate\n * @map:\tthe device as a regmap to communicate with\n * @cr:\t\tCoding rate going to be assigned in a byte\n *\t\thigh 4 bits / low 4 bits: numerator / denominator\n */\nvoid\nsx127X_set_loracr(struct regmap *map, u8 cr)\n{\n\tu8 mcf1;\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1);\n\tmcf1 = (mcf1 & 0x0E) | (((cr & 0xF) - 4) << 1);\n\tregmap_raw_write(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1);\n}\n\n/**\n * sx127X_get_loracr - Get LoRa package's coding rate\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tCoding rate in a byte\n *\t\thigh 4 bits / low 4 bits: numerator / denominator\n */\nu8\nsx127X_get_loracr(struct regmap *map)\n{\n\tu8 mcf1;\n\tu8 cr;\t/* ex: 0x45 represents cr=4/5 */\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1);\n\tcr = 0x40 + ((mcf1 & 0x0E) >> 1) + 4;\n\n\treturn cr;\n}\n\n/**\n * sx127X_set_loraimplicit - Set LoRa packages with Explicit / Implicit Header\n * @map:\tthe device as a regmap to communicate with\n * @yesno:\t1 / 0 for Implicit Header Mode / Explicit Header Mode\n */\nvoid\nsx127X_set_loraimplicit(struct regmap *map, u8 yesno)\n{\n\tu8 mcf1;\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1);\n\tmcf1 = (yesno) ? (mcf1 | 0x01) : (mcf1 & 0xFE);\n\tregmap_raw_write(map, SX127X_REG_MODEM_CONFIG1, &mcf1, 1);\n}\n\n/**\n * sx127X_set_lorarxbytetimeout - Set RX operation time-out in terms of symbols\n * @map:\tthe device as a regmap to communicate with\n * @n:\t\tTime-out in terms of symbols (bytes) going to be assigned\n */\nvoid\nsx127X_set_lorarxbytetimeout(struct regmap *map, u32 n)\n{\n\tu8 buf[2];\n\tu8 mcf2;\n\n\tif (n < 1)\n\t\tn = 1;\n\tif (n > 1023)\n\t\tn = 1023;\n\n\t/* Read original Modem config 2. */\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1);\n\n\t/* LSB */\n\tbuf[1] = n % 256;\n\t/* MSB */\n\tbuf[0] = (mcf2 & 0xFC) | (n >> 8);\n\n\tregmap_raw_write(map, SX127X_REG_MODEM_CONFIG2, buf, 2);\n}\n\n/**\n * sx127X_set_lorarxtimeout - Set RX operation time-out seconds\n * @map:\tthe device as a regmap to communicate with\n * @ms:\t\tThe RX time-out time in ms\n */\nvoid\nsx127X_set_lorarxtimeout(struct regmap *map, u32 ms)\n{\n\tu32 n;\n\n\tn = ms * sx127X_get_lorabw(map) / (sx127X_get_lorasprf(map) * 1000);\n\n\tsx127X_set_lorarxbytetimeout(map, n);\n}\n\n/**\n * sx127X_get_lorarxbytetimeout - Get RX operation time-out in terms of symbols\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tTime-out in terms of symbols (bytes)\n */\nu32\nsx127X_get_lorarxbytetimeout(struct regmap *map)\n{\n\tu32 n;\n\tu8 buf[2];\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, buf, 2);\n\n\tn = (buf[0] & 0x03) * 256 + buf[1];\n\n\treturn n;\n}\n\n/**\n * sx127X_get_lorarxtimeout - Get RX operation time-out seconds\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tThe RX time-out time in ms\n */\nu32\nsx127X_get_lorarxtimeout(struct regmap *map)\n{\n\tu32 ms;\n\n\tms = 1000 * sx127X_get_lorarxbytetimeout(map) *\n\t\tsx127X_get_lorasprf(map) / sx127X_get_lorabw(map);\n\n\treturn ms;\n}\n\n/**\n * sx127X_set_loramaxrxbuff - Maximum payload length in LoRa packet\n * @map:\tthe device as a regmap to communicate with\n * @len:\tthe max payload length going to be assigned in bytes\n */\nvoid\nsx127X_set_loramaxrxbuff(struct regmap *map, u8 len)\n{\n\tregmap_raw_write(map, SX127X_REG_MAX_PAYLOAD_LENGTH, &len, 1);\n}\n\n/**\n * sx127X_get_loralastpktpayloadlen - Get the RX last packet payload length\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tthe actual RX last packet payload length in bytes\n */\nu8\nsx127X_get_loralastpktpayloadlen(struct regmap *map)\n{\n\tu8 len;\n\n\tregmap_raw_read(map, SX127X_REG_RX_NB_BYTES, &len, 1);\n\n\treturn len;\n}\n\n/**\n * sx127X_readloradata - Read data from LoRa device (read RX FIFO)\n * @map:\tthe device as a regmap to communicate with\n * @buf:\tbuffer going to be read data into\n * @len:\tthe length of the data going to be read in bytes\n *\n * Return:\tPositive / negtive values for the actual data length read from\n *\t\tthe LoRa device in bytes / failed\n */\nssize_t\nsx127X_readloradata(struct regmap *map, u8 *buf, size_t len)\n{\n\tu8 start_adr;\n\tint ret;\n\n\t/* Set chip FIFO pointer to FIFO last packet address. */\n\tstart_adr = SX127X_FIFO_RX_BASE_ADDRESS;\n\tregmap_raw_write(map, SX127X_REG_FIFO_ADDR_PTR, &start_adr, 1);\n\n\t/* Read LoRa packet payload. */\n\tlen = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU;\n\tret = regmap_raw_read(map, SX127X_REG_FIFO, buf, len);\n\n\treturn (ret >= 0) ? len : ret;\n}\n\n/**\n * sx127X_sendloradata - Send data through LoRa device (write TX FIFO)\n * @rm:\t\tthe device as a regmap to communicate with\n * @buf:\tbuffer going to be send\n * @len:\tthe length of the buffer in bytes\n *\n * Return:\tthe actual length written into the LoRa device in bytes\n */\nsize_t\nsx127X_sendloradata(struct regmap *map, u8 *buf, size_t len)\n{\n\tu8 base_adr;\n\tu8 blen;\n\n\t/* Set chip FIFO pointer to FIFO TX base. */\n\tbase_adr = SX127X_FIFO_TX_BASE_ADDRESS;\n\tregmap_raw_write(map, SX127X_REG_FIFO_ADDR_PTR, &base_adr, 1);\n\n\t/* Write payload synchronously to fill the FIFO of the chip. */\n\tblen = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU;\n\tregmap_raw_write(map, SX127X_REG_FIFO, buf, blen);\n\n\t/* Set the FIFO payload length. */\n\tregmap_raw_write(map, SX127X_REG_PAYLOAD_LENGTH, &blen, 1);\n\n\treturn blen;\n}\n\n/**\n * sx127X_get_loralastpktsnr - Get last LoRa packet's SNR\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tthe last LoRa packet's SNR in db\n */\ns32\nsx127X_get_loralastpktsnr(struct regmap *map)\n{\n\ts32 db;\n\ts8 snr;\n\n\tregmap_raw_read(map, SX127X_REG_PKT_SNR_VALUE, &snr, 1);\n\tdb = snr / 4;\n\n\treturn db;\n}\n\n/**\n * sx127X_get_loralastpktrssi - Get last LoRa packet's SNR\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tthe last LoRa packet's RSSI in dbm\n */\ns32\nsx127X_get_loralastpktrssi(struct regmap *map)\n{\n\ts32 dbm;\n\tu8 lhf;\n\tu8 rssi;\n\ts8 snr;\n\n\t/* Get LoRa is in high or low frequency mode. */\n\tlhf = sx127X_get_mode(map) & 0x08;\n\t/* Get RSSI value. */\n\tregmap_raw_read(map, SX127X_REG_PKT_RSSI_VALUE, &rssi, 1);\n\tdbm = (lhf) ? -164 + rssi : -157 + rssi;\n\n\t/* Adjust to correct the last packet RSSI if SNR < 0. */\n\tregmap_raw_read(map, SX127X_REG_PKT_SNR_VALUE, &snr, 1);\n\tif (snr < 0)\n\t\tdbm += snr / 4;\n\n\treturn dbm;\n}\n\n/**\n * sx127X_get_lorarssi - Get current RSSI value\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tthe current RSSI in dbm\n */\ns32\nsx127X_get_lorarssi(struct regmap *map)\n{\n\ts32 dbm;\n\tu8 lhf;\n\tu8 rssi;\n\n\t/* Get LoRa is in high or low frequency mode. */\n\tlhf = sx127X_get_mode(map) & 0x08;\n\t/* Get RSSI value. */\n\tregmap_raw_read(map, SX127X_REG_RSSI_VALUE, &rssi, 1);\n\tdbm = (lhf) ? -164 + rssi : -157 + rssi;\n\n\treturn dbm;\n}\n\n/**\n * sx127X_set_lorapreamblelen - Set LoRa preamble length\n * @map:\tthe device as a regmap to communicate with\n * @len:\tthe preamble length going to be assigned\n */\nvoid\nsx127X_set_lorapreamblelen(struct regmap *map, u32 len)\n{\n\tu8 pl[2];\n\n\tpl[1] = len % 256;\n\tpl[0] = (len >> 8) % 256;\n\n\tregmap_raw_write(map, SX127X_REG_PREAMBLE_MSB, pl, 2);\n}\n\n/**\n * sx127X_get_lorapreamblelen - Get LoRa preamble length\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\tlength of the LoRa preamble\n */\nu32\nsx127X_get_lorapreamblelen(struct regmap *map)\n{\n\tu8 pl[2];\n\tu32 len;\n\n\tregmap_raw_read(map, SX127X_REG_PREAMBLE_MSB, pl, 2);\n\tlen = pl[0] * 256 + pl[1];\n\n\treturn len;\n}\n\n/**\n * sx127X_set_loracrc - Enable CRC generation and check on received payload\n * @map:\tthe device as a regmap to communicate with\n * @yesno:\t1 / 0 for check / not check\n */\nvoid\nsx127X_set_loracrc(struct regmap *map, u8 yesno)\n{\n\tu8 mcf2;\n\n\tregmap_raw_read(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1);\n\tmcf2 = (yesno) ? mcf2 | (1 << 2) : mcf2 & (~(1 << 2));\n\tregmap_raw_write(map, SX127X_REG_MODEM_CONFIG2, &mcf2, 1);\n}\n\n/**\n * sx127X_set_boost - Set RF power amplifier boost in normal output range\n * @map:\tthe device as a regmap to communicate with\n * @yesno:\t1 / 0 for boost / not boost\n */\nvoid\nsx127X_set_boost(struct regmap *map, u8 yesno)\n{\n\tu8 pacf;\n\n\tregmap_raw_read(map, SX127X_REG_PA_CONFIG, &pacf, 1);\n\tpacf = (yesno) ? pacf | (1 << 7) : pacf & (~(1 << 7));\n\tregmap_raw_write(map, SX127X_REG_PA_CONFIG, &pacf, 1);\n}\n\n/**\n * sx127X_start_loramode - Start the device and set it in LoRa mode\n * @map:\tthe device as a regmap to communicate with\n */\nvoid\nsx127X_start_loramode(struct regmap *map)\n{\n\tu8 op_mode;\n\tu8 base_adr;\n#ifdef CONFIG_OF\n\tstruct device_node *of_node = (regmap_get_device(map))->of_node;\n#endif\n\n\t/* Get original OP Mode register. */\n\top_mode = sx127X_get_mode(map);\n\tdev_dbg(regmap_get_device(map),\n\t\t\"the original OP mode is 0x%X\\n\", op_mode);\n\n\t/* Set device to sleep state. */\n\tsx127X_set_state(map, SX127X_SLEEP_MODE);\n\t/* Set device to LoRa mode. */\n\top_mode = sx127X_get_mode(map);\n\top_mode = op_mode | 0x80;\n\tregmap_raw_write(map, SX127X_REG_OP_MODE, &op_mode, 1);\n\t/* Set device to standby state. */\n\tsx127X_set_state(map, SX127X_STANDBY_MODE);\n\top_mode = sx127X_get_mode(map);\n\tdev_dbg(regmap_get_device(map),\n\t\t\"the current OP mode is 0x%X\\n\", op_mode);\n\n\t/* Set LoRa in explicit header mode. */\n\tsx127X_set_loraimplicit(map, 0);\n\n\t/* Set chip FIFO RX base. */\n\tbase_adr = SX127X_FIFO_RX_BASE_ADDRESS;\n\tregmap_raw_write(map, SX127X_REG_FIFO_RX_BASE_ADDR, &base_adr, 1);\n\t/* Set chip FIFO TX base. */\n\tbase_adr = SX127X_FIFO_TX_BASE_ADDRESS;\n\tregmap_raw_write(map, SX127X_REG_FIFO_TX_BASE_ADDR, &base_adr, 1);\n\n\t/* Set the CSS spreading factor. */\n#ifdef CONFIG_OF\n\tof_property_read_u32(of_node, \"spreading-factor\", &sprf);\n#endif\n\tsx127X_set_lorasprf(map, sprf);\n\n\t/* Set RX time-out value. */\n\tsx127X_set_lorarxbytetimeout(map, rx_timeout);\n\n\t/* Clear all of the IRQ flags. */\n\tsx127X_clear_loraallflag(map);\n\t/* Set chip to RX state waiting for receiving. */\n\tsx127X_set_state(map, SX127X_RXSINGLE_MODE);\n}\n\n/**\n * init_sx127x - Initial the SX127X device\n * @map:\tthe device as a regmap to communicate with\n *\n * Return:\t0 / negtive values for success / failed\n */\nint\ninit_sx127x(struct regmap *map)\n{\n\tint v;\n#ifdef DEBUG\n\tu8 fv, mv;\n#endif\n\n\tdev_dbg(regmap_get_device(map), \"init sx127X\\n\");\n\n\tv = sx127X_read_version(map);\n\tif (v > 0) {\n#ifdef DEBUG\n\t\tfv = (v >> 4) & 0xF;\n\t\tmv = v & 0xF;\n\t\tdev_dbg(regmap_get_device(map), \"chip version %d.%d\\n\", fv, mv);\n#endif\n\t\treturn 0;\n\t} else {\n\t\treturn -ENODEV;\n\t}\n}\n\n/*---------------------- SX1278 IEEE 802.15.4 Functions ----------------------*/\n\n/* LoRa device's sensitivity in dbm. */\n#ifndef SX1278_IEEE_SENSITIVITY\n#define SX1278_IEEE_SENSITIVITY\t(-148)\n#endif\nstatic s32 sensitivity = SX1278_IEEE_SENSITIVITY;\nmodule_param(sensitivity, int, 0000);\nMODULE_PARM_DESC(sensitivity, \"RF receiver's sensitivity\");\n\n#define SX1278_IEEE_ENERGY_RANGE\t(-sensitivity)\n\nstatic int\nsx1278_ieee_ed(struct ieee802154_hw *hw, u8 *level)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\ts32 rssi;\n\ts32 range = SX1278_IEEE_ENERGY_RANGE - 10;\n\n\tdev_dbg(regmap_get_device(phy->map), \"%s\\n\", __func__);\n\n\t/* ED: IEEE  802.15.4-2011 8.2.5 Recevier ED. */\n\trssi = sx127X_get_lorarssi(phy->map);\n\tif (rssi < (sensitivity + 10))\n\t\t*level = 0;\n\telse if (rssi >= 0)\n\t\t*level = 255;\n\telse\n\t\t*level = ((s32)255 * (rssi + range) / range) % 255;\n\n\treturn 0;\n}\n\n#ifndef SX1278_IEEE_CHANNEL_MIN\n#define SX1278_IEEE_CHANNEL_MIN\t\t11\n#endif\nstatic u8 channel_min = SX1278_IEEE_CHANNEL_MIN;\nmodule_param(channel_min, byte, 0000);\nMODULE_PARM_DESC(channel_min, \"Minimal channel number\");\n\n#ifndef SX1278_IEEE_CHANNEL_MAX\n#define SX1278_IEEE_CHANNEL_MAX\t\t11\n#endif\nstatic u8 channel_max = SX1278_IEEE_CHANNEL_MAX;\nmodule_param(channel_max, byte, 0000);\nMODULE_PARM_DESC(channel_max, \"Maximum channel number\");\n\n#ifndef SX1278_IEEE_CENTER_CARRIER_FRQ\n#define SX1278_IEEE_CENTER_CARRIER_FRQ\t434000000\n#endif\nstatic u32 carrier_frq = SX1278_IEEE_CENTER_CARRIER_FRQ;\nmodule_param(carrier_frq, uint, 0000);\nMODULE_PARM_DESC(carrier_frq, \"Center carrier frequency in Hz\");\n\n#ifndef SX1278_IEEE_BANDWIDTH\n#define SX1278_IEEE_BANDWIDTH\t\t500000\n#endif\nstatic u32 bandwidth = SX1278_IEEE_BANDWIDTH;\nmodule_param(bandwidth, uint, 0000);\nMODULE_PARM_DESC(bandwidth, \"Bandwidth in Hz\");\n\nstruct rf_frq {\n\tu32 carrier;\n\tu32 bw;\n\tu8 ch_min;\n\tu8 ch_max;\n};\n\nvoid\nsx1278_ieee_get_rf_config(struct ieee802154_hw *hw, struct rf_frq *rf)\n{\n#ifdef CONFIG_OF\n\tstruct sx1278_phy *phy = hw->priv;\n\tstruct device_node *of_node = (regmap_get_device(phy->map))->of_node;\n\n\t/* Set the LoRa chip's center carrier frequency. */\n\tif (of_property_read_u32(of_node, \"center-carrier-frq\", &rf->carrier))\n\t\trf->carrier = carrier_frq;\n\n\t/* Set the LoRa chip's RF bandwidth. */\n\tif (of_property_read_u32(of_node, \"rf-bandwidth\", &rf->bw))\n\t\trf->bw = bandwidth;\n\n\t/* Set the LoRa chip's min & max RF channel if OF is defined. */\n\tif (of_property_read_u8(of_node, \"minimal-RF-channel\", &rf->ch_min))\n\t\trf->ch_min = channel_min;\n\n\tif (of_property_read_u8(of_node, \"maximum-RF-channel\", &rf->ch_max))\n\t\trf->ch_max = channel_max;\n#else\n\trf->carrier = carrier_frq;\n\trf->bw = bandwidth;\n\trf->ch_min = channel_min;\n\trf->ch_max = channel_max;\n#endif\n}\n\nstatic int\nsx1278_ieee_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\tstruct rf_frq rf;\n\tu32 fr;\n\ts8 d;\n\n\tdev_dbg(regmap_get_device(phy->map),\n\t\t\"%s channel: %u\\n\", __func__, channel);\n\n\tsx1278_ieee_get_rf_config(hw, &rf);\n\n\tif (channel < rf.ch_min)\n\t\tchannel = rf.ch_min;\n\telse if (channel > rf.ch_max)\n\t\tchannel = rf.ch_max;\n\n\td = channel - (rf.ch_min + rf.ch_max) / 2;\n\tfr = rf.carrier + d * rf.bw;\n\n\tsx127X_set_lorafrq(phy->map, fr);\n\tphy->opmode = sx127X_get_mode(phy->map);\n\n\treturn 0;\n}\n\n/* in mbm */\ns32 sx1278_powers[] = {\n\t-200, -100, 0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100,\n\t1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300};\n\nstatic int\nsx1278_ieee_set_txpower(struct ieee802154_hw *hw, s32 mbm)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\ts32 dbm = sx127X_mbm2dbm(mbm);\n\n\tdev_dbg(regmap_get_device(phy->map),\n\t\t\"%s TX power: %d mbm\\n\", __func__, mbm);\n\n\tsx127X_set_lorapower(phy->map, dbm);\n\n\treturn 0;\n}\n\nint\nsx1278_ieee_rx(struct ieee802154_hw *hw)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\tbool do_rx;\n\tunsigned long f;\n\n\tdev_dbg(regmap_get_device(phy->map), \"%s\\n\", __func__);\n\n\tspin_lock_irqsave(&phy->buf_lock, f);\n\tif (!phy->is_busy) {\n\t\tphy->is_busy = true;\n\t\tdo_rx = true;\n\t} else {\n\t\tdo_rx = false;\n\t}\n\tspin_unlock_irqrestore(&phy->buf_lock, f);\n\n\tif (do_rx) {\n\t\tsx127X_set_state(phy->map, SX127X_RXSINGLE_MODE);\n\t\treturn 0;\n\t} else {\n\t\tdev_dbg(regmap_get_device(phy->map),\n\t\t\t\"%s: device is busy\\n\", __func__);\n\t\treturn -EBUSY;\n\t}\n}\n\nstatic int\nsx1278_ieee_rx_complete(struct ieee802154_hw *hw)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\tstruct sk_buff *skb;\n\tu8 len;\n\tu8 lqi;\n\ts32 rssi;\n\ts32 range = SX1278_IEEE_ENERGY_RANGE;\n\tint err;\n\tunsigned long f;\n\n\tskb = dev_alloc_skb(IEEE802154_MTU);\n\tif (!skb) {\n\t\terr = -ENOMEM;\n\t\tdev_err(regmap_get_device(phy->map),\n\t\t\t\"%s: driver is out of memory\\n\", __func__);\n\t\tgoto sx1278_ieee_rx_err;\n\t}\n\n\tlen = sx127X_get_loralastpktpayloadlen(phy->map);\n\tsx127X_readloradata(phy->map, skb_put(skb, len), len);\n\n\t/* LQI: IEEE  802.15.4-2011 8.2.6 Link quality indicator. */\n\trssi = sx127X_get_loralastpktrssi(phy->map);\n\trssi = (rssi > 0) ? 0 : rssi;\n\tlqi = ((s32)255 * (rssi + range) / range) % 255;\n\n\tieee802154_rx_irqsafe(hw, skb, lqi);\n\n\tdev_dbg(regmap_get_device(phy->map),\n\t\t\"%s: len=%u LQI=%u\\n\", __func__, len, lqi);\n\n\terr = 0;\n\nsx1278_ieee_rx_err:\n\tspin_lock_irqsave(&phy->buf_lock, f);\n\tphy->is_busy = false;\n\tspin_unlock_irqrestore(&phy->buf_lock, f);\n\treturn err;\n}\n\nint\nsx1278_ieee_tx(struct ieee802154_hw *hw)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\tstruct sk_buff *tx_buf = phy->tx_buf;\n\tbool do_tx = false;\n\tunsigned long f;\n\n\tdev_dbg(regmap_get_device(phy->map),\n\t\t\"%s: len=%u\\n\", __func__, tx_buf->len);\n\n\tif (!phy->post_tx_done) {\n\t\tsx127X_sendloradata(phy->map, tx_buf->data, tx_buf->len);\n\t\tphy->post_tx_done = true;\n\t}\n\n\tspin_lock_irqsave(&phy->buf_lock, f);\n\tif (!phy->is_busy) {\n\t\tphy->is_busy = true;\n\t\tdo_tx = true;\n\t\tphy->one_to_be_sent = false;\n\t}\n\tspin_unlock_irqrestore(&phy->buf_lock, f);\n\n\tif (do_tx) {\n\t\t/* Set chip as TX state and transfer the data in FIFO. */\n\t\tphy->opmode = (phy->opmode & 0xF8) | SX127X_TX_MODE;\n\t\tregmap_write_async(phy->map, SX127X_REG_OP_MODE, phy->opmode);\n\t\treturn 0;\n\t} else {\n\t\tdev_dbg(regmap_get_device(phy->map),\n\t\t\t\"%s: device is busy\\n\", __func__);\n\t\treturn -EBUSY;\n\t}\n}\n\nstatic int\nsx1278_ieee_tx_complete(struct ieee802154_hw *hw)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\tstruct sk_buff *skb = phy->tx_buf;\n\tunsigned long f;\n\n\tdev_dbg(regmap_get_device(phy->map), \"%s\\n\", __func__);\n\n\tieee802154_xmit_complete(hw, skb, false);\n\n\tspin_lock_irqsave(&phy->buf_lock, f);\n\tphy->is_busy = false;\n\tphy->tx_buf = NULL;\n\tspin_unlock_irqrestore(&phy->buf_lock, f);\n\n\treturn 0;\n}\n\nstatic int\nsx1278_ieee_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\tint ret;\n\tunsigned long f;\n\n\tdev_dbg(regmap_get_device(phy->map), \"%s\\n\", __func__);\n\n\tWARN_ON(phy->suspended);\n\n\tspin_lock_irqsave(&phy->buf_lock, f);\n\tif (phy->tx_buf) {\n\t\tret = -EBUSY;\n\t} else {\n\t\tphy->tx_buf = skb;\n\t\tphy->one_to_be_sent = true;\n\t\tphy->post_tx_done = false;\n\t\tret = 0;\n\t}\n\tspin_unlock_irqrestore(&phy->buf_lock, f);\n\n\treturn ret;\n}\n\nstatic int\nsx1278_ieee_start(struct ieee802154_hw *hw)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\n\tdev_dbg(regmap_get_device(phy->map), \"interface up\\n\");\n\n\tsx1278_ieee_set_channel(hw, 0, hw->phy->current_channel);\n\tphy->suspended = false;\n\tsx127X_start_loramode(phy->map);\n\tphy->opmode = sx127X_get_mode(phy->map);\n\tadd_timer(&phy->timer);\n\n\treturn 0;\n}\n\nstatic void\nsx1278_ieee_stop(struct ieee802154_hw *hw)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\n\tdev_dbg(regmap_get_device(phy->map), \"interface down\\n\");\n\n\tphy->suspended = true;\n\tdel_timer(&phy->timer);\n\tsx127X_set_state(phy->map, SX127X_SLEEP_MODE);\n}\n\nstatic int\nsx1278_ieee_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)\n{\n\treturn 0;\n}\n\nvoid\nsx1278_ieee_statemachine(struct ieee802154_hw *hw)\n{\n\tstruct sx1278_phy *phy = hw->priv;\n\tu8 flags;\n\tu8 state;\n\tbool do_next_rx = false;\n\tunsigned long f;\n\n\tflags = sx127X_get_loraallflag(phy->map);\n\tstate = sx127X_get_state(phy->map);\n\n\tif (flags & (SX127X_FLAG_RXTIMEOUT | SX127X_FLAG_PAYLOADCRCERROR)) {\n\t\tsx127X_clear_loraflag(phy->map, SX127X_FLAG_RXTIMEOUT\n\t\t\t\t\t\t| SX127X_FLAG_PAYLOADCRCERROR\n\t\t\t\t\t\t| SX127X_FLAG_RXDONE);\n\t\tspin_lock_irqsave(&phy->buf_lock, f);\n\t\tphy->is_busy = false;\n\t\tspin_unlock_irqrestore(&phy->buf_lock, f);\n\t\tdo_next_rx = true;\n\t} else if (flags & SX127X_FLAG_RXDONE) {\n\t\tsx1278_ieee_rx_complete(phy->hw);\n\t\tsx127X_clear_loraflag(phy->map, SX127X_FLAG_RXDONE);\n\t\tdo_next_rx = true;\n\t}\n\n\tif (flags & SX127X_FLAG_TXDONE) {\n\t\tsx1278_ieee_tx_complete(phy->hw);\n\t\tsx127X_clear_loraflag(phy->map, SX127X_FLAG_TXDONE);\n\t\tphy->tx_delay = 10;\n\t\tdo_next_rx = true;\n\t}\n\n\tif (phy->one_to_be_sent &&\n\t    (state == SX127X_STANDBY_MODE) &&\n\t    (phy->tx_delay == 0)) {\n\t\tif (!sx1278_ieee_tx(phy->hw))\n\t\t\tdo_next_rx = false;\n\t}\n\n\tif (do_next_rx)\n\t\tsx1278_ieee_rx(phy->hw);\n\n\tif (phy->tx_delay > 0)\n\t\tphy->tx_delay -= 1;\n\n\tif (!phy->suspended) {\n\t\tphy->timer.expires = jiffies_64 + 1;\n\t\tadd_timer(&phy->timer);\n\t}\n}\n\n/**\n * sx1278_timer_irqwork - The actual work which checks the IRQ flags of the chip\n * @work:\tthe work entry listed in the workqueue\n */\nstatic void\nsx1278_timer_irqwork(struct work_struct *work)\n{\n\tstruct sx1278_phy *phy;\n\n\tphy = container_of(work, struct sx1278_phy, irqwork);\n\tsx1278_ieee_statemachine(phy->hw);\n}\n\n/**\n * sx1278_timer_isr - Callback function for the timer interrupt\n * @arg:\tthe general argument for this callback function\n */\nstatic void\nsx1278_timer_isr(struct timer_list *timer)\n{\n\tstruct sx1278_phy *phy = container_of(timer, struct sx1278_phy, timer);\n\n\tschedule_work(&phy->irqwork);\n}\n\nstatic const struct ieee802154_ops sx1278_ops = {\n\t.owner = THIS_MODULE,\n\t.xmit_async = sx1278_ieee_xmit,\n\t.ed = sx1278_ieee_ed,\n\t.set_channel = sx1278_ieee_set_channel,\n\t.set_txpower = sx1278_ieee_set_txpower,\n\t.start = sx1278_ieee_start,\n\t.stop = sx1278_ieee_stop,\n\t.set_promiscuous_mode = sx1278_ieee_set_promiscuous_mode,\n};\n\n/**\n * sx1278X_ieee_channel_mask - Get the available channels' mask of LoRa device\n * @hw:\t\tLoRa IEEE 802.15.4 device\n *\n * Return:\tThe bitwise channel mask in 4 bytes\n */\nu32\nsx1278_ieee_channel_mask(struct ieee802154_hw *hw)\n{\n\tstruct rf_frq rf;\n\tu32 mask;\n\n\tsx1278_ieee_get_rf_config(hw, &rf);\n\n\tmask = ((u32)(1 << (rf.ch_max + 1)) - (u32)(1 << rf.ch_min));\n\n\treturn mask;\n}\n\nstatic int\nsx1278_ieee_add_one(struct sx1278_phy *phy)\n{\n\tstruct ieee802154_hw *hw = phy->hw;\n\tint err;\n\n\t/* Define channels could be used. */\n\thw->phy->supported.channels[0] = sx1278_ieee_channel_mask(hw);\n\t/* SX1278 phy channel 11 as default */\n\thw->phy->current_channel = 11;\n\n\t/* Define RF power. */\n\thw->phy->supported.tx_powers = sx1278_powers;\n\thw->phy->supported.tx_powers_size = ARRAY_SIZE(sx1278_powers);\n\thw->phy->transmit_power = sx1278_powers[12];\n\n\tieee802154_random_extended_addr(&hw->phy->perm_extended_addr);\n\thw->flags = IEEE802154_HW_TX_OMIT_CKSUM\n\t\t\t| IEEE802154_HW_RX_OMIT_CKSUM\n\t\t\t| IEEE802154_HW_PROMISCUOUS;\n\n\terr = ieee802154_register_hw(hw);\n\tif (err)\n\t\tgoto err_reg;\n\n\tINIT_WORK(&phy->irqwork, sx1278_timer_irqwork);\n\n\ttimer_setup(&phy->timer, sx1278_timer_isr, 0);\n\tphy->timer.expires = jiffies_64 + HZ;\n\n\tspin_lock_init(&phy->buf_lock);\n\n\terr = init_sx127x(phy->map);\n\tif (err)\n\t\tgoto err_reg;\n\n\treturn 0;\n\nerr_reg:\n\tdev_err(regmap_get_device(phy->map),\n\t\t\"register as IEEE 802.15.4 device failed\\n\");\n\treturn err;\n}\n\nstatic void\nsx1278_ieee_del(struct sx1278_phy *phy)\n{\n\tif (!phy)\n\t\treturn;\n\n\tdel_timer(&phy->timer);\n\tflush_work(&phy->irqwork);\n\n\tieee802154_unregister_hw(phy->hw);\n\tieee802154_free_hw(phy->hw);\n}\n\n/*--------------------------- SX1278 SPI Functions ---------------------------*/\n\n/* The compatible chip array. */\n#ifdef CONFIG_OF\nstatic const struct of_device_id sx1278_dt_ids[] = {\n\t{ .compatible = \"semtech,sx1276\" },\n\t{ .compatible = \"semtech,sx1277\" },\n\t{ .compatible = \"semtech,sx1278\" },\n\t{ .compatible = \"semtech,sx1279\" },\n\t{ .compatible = \"sx1278\" },\n\t{},\n};\nMODULE_DEVICE_TABLE(of, sx1278_dt_ids);\n#endif\n\n/* The compatible ACPI device array. */\n#ifdef CONFIG_ACPI\nstatic const struct acpi_device_id sx1278_acpi_ids[] = {\n\t{ .id = \"sx1278\" },\n\t{},\n};\nMODULE_DEVICE_TABLE(acpi, sx1278_acpi_ids);\n#endif\n\n/* The compatible SPI device id array. */\nstatic const struct spi_device_id sx1278_spi_ids[] = {\n\t{ .name = \"sx1278\" },\n\t{},\n};\nMODULE_DEVICE_TABLE(spi, sx1278_spi_ids);\n\nbool sx1278_reg_volatile(struct device *dev, unsigned int reg)\n{\n\treturn true;\n}\n\n/* The SX1278 regmap config. */\nstruct regmap_config sx1278_regmap_config = {\n\t.reg_bits = 8,\n\t.val_bits = 8,\n\t.max_register = SX127X_MAX_REG,\n\t.read_flag_mask = 0x00,\n\t.write_flag_mask = 0x80,\n\t.volatile_reg = sx1278_reg_volatile,\n};\n\n/* The SPI probe callback function. */\nstatic int sx1278_spi_probe(struct spi_device *spi)\n{\n\tstruct ieee802154_hw *hw;\n\tstruct sx1278_phy *phy;\n\tint err;\n\n\thw = ieee802154_alloc_hw(sizeof(*phy), &sx1278_ops);\n\tif (!hw) {\n\t\tdev_err(&spi->dev, \"not enough memory\\n\");\n\t\treturn -ENOMEM;\n\t}\n\n\tphy = hw->priv;\n\tphy->hw = hw;\n\thw->parent = &spi->dev;\n\tphy->map = devm_regmap_init_spi(spi, &sx1278_regmap_config);\n\n\t/* Set the SPI device's driver data for later usage. */\n\tspi_set_drvdata(spi, phy);\n\n\terr = sx1278_ieee_add_one(phy);\n\tif (err < 0) {\n\t\tdev_err(&spi->dev, \"no SX1278 compatible device\\n\");\n\t\tgoto sx1278_spi_probe_err;\n\t}\n\n\tdev_info(&spi->dev,\n\t\t \"add an IEEE 802.15.4 over LoRa SX1278 compatible device\\n\");\n\n\treturn 0;\n\nsx1278_spi_probe_err:\n\tsx1278_ieee_del(phy);\n\treturn err;\n}\n\n/* The SPI remove callback function. */\nstatic int sx1278_spi_remove(struct spi_device *spi)\n{\n\tstruct sx1278_phy *phy = spi_get_drvdata(spi);\n\n\tsx1278_ieee_del(phy);\n\n\treturn 0;\n}\n\n#define __DRIVER_NAME\t\"sx1278\"\n\n/* The SPI driver which acts as a protocol driver in this kernel module. */\nstatic struct spi_driver sx1278_spi_driver = {\n\t.driver = {\n\t\t.name = __DRIVER_NAME,\n\t\t.owner = THIS_MODULE,\n#ifdef CONFIG_OF\n\t\t.of_match_table = of_match_ptr(sx1278_dt_ids),\n#endif\n#ifdef CONFIG_ACPI\n\t\t.acpi_match_table = ACPI_PTR(sx1278_acpi_ids),\n#endif\n\t},\n\t.probe = sx1278_spi_probe,\n\t.remove = sx1278_spi_remove,\n\t.id_table = sx1278_spi_ids,\n};\n\n/* Register SX1278 kernel module. */\nmodule_spi_driver(sx1278_spi_driver);\n\nMODULE_AUTHOR(\"Jian-Hong Pan, <starnight@g.ncu.edu.tw>\");\nMODULE_DESCRIPTION(\"LoRa device SX1278 driver with IEEE 802.15.4 interface\");\nMODULE_LICENSE(\"Dual BSD/GPL\");\n"
  },
  {
    "path": "README.md",
    "content": "# LoRa\nThis is a LoRa device driver as a Linux kernel module with IEEE 802.15.4 MAC interfaces.\n\nThe driver with file operation interfaces could be found at the *[file-ops branch](https://github.com/starnight/LoRa/tree/file-ops)*.\n\n## Compatible Chips\n* Semtech SX1276/77/78/79\n\n## Folders\n* LoRa: The LoRa source and build files.\n* dts-overlay: The device tree overlayers with the boards and operating systems.\n* test-application: The user space applications for testing or demo.\n\n## Build and Install\n\n1. Build\n```sh\ncd LoRa\nmake\n```\n\n2. Install\n```sh\nmake install\n```\n\n3. Load module\n```sh\nmodprobe sx1278\n```\n  If the target uses Device Tree mechanism like some embedded systems, Raspberry Pi for example.\n  Its device tree may need to be updated first.\n  There is a device tree overlay for Raspberry Pi in the dts-overlay folder for example.\n  Just ``` make ``` in the folder, than it will compile and install the device tree overlay, and reboot is needed.\n\n4. Check the installed module\n```sh\ndmesg\n```\n\n## License\nUnder Dual BSD/GPL\n\n## Contributors\n* Jian-Hong, Pan <starnight AT g.ncu.edu.tw>\n* Dmitry Shmidt <dimitrysh AT google.com>\n"
  },
  {
    "path": "dts-overlay/Makefile",
    "content": "OVERLAY_SRC=rpi-lora-spi-overlay.dts\nOVERLAY_BIN=rpi-lora-spi-overlay.dtbo\nOVERLAY_DST=/boot/overlays/rpi-lora-spi.dtbo\n\nall:\n\tdtc -I dts -O dtb -@ -o $(OVERLAY_BIN) $(OVERLAY_SRC)\n\ninstall:\n\tsudo cp $(OVERLAY_BIN) $(OVERLAY_DST)\n\nuninstall:\n\tsudo rm $(OVERLAY_DST)\n\ntest:\n\tdtc -I fs /proc/device-tree\n\nclean:\n\trm $(OVERLAY_BIN)\n"
  },
  {
    "path": "dts-overlay/README.md",
    "content": "# SX1278 Compatible Radio Device Tree\n\n## Required properties:\n  - compatible:\t\tshould be \"semtech,sx1276\", \"semtech,sx1277\",\n\t\t\t\"semtech,sx1277\" or \"semtech,sx1279\" depends on your\n\t\t\ttransceiver board\n  - spi-max-frequency:\tmaximal bus speed, should be set something under or\n\t\t\tequal 10000000 Hz\n  - reg:\t\tthe chipselect index\n  - clock-frequency:\tthe external crystal oscillator frequency in Hz of the\n\t\t\ttransceiver\n  - center-carrier-frq:\tthe RF center carrier frequency in Hz\n\n## Optional properties:\n  - rf-bandwidth:\tthe RF bandwidth in Hz\n  - minimal-RF-channel:\tthe minimal RF channel number and the value must be with\n\t\t\tprefix \"/bits/ 8\" because of being a byte datatype\n  - maximum-RF-channel: the maximum RF channel number and the value must be with\n\t\t\tprefix \"/bits/ 8\" because of being a byte datatype\n  - spreading-factor:\tthe spreading factor of Chirp Spread Spectrum modulation\n\n## Example:\n\n\tsx1278@0 {\n\t\tcompatible = \"semtech,sx1278\";\n\t\tspi-max-frequency = <15200>;\n\t\treg = <0>;\n\t\tclock-frequency = <32000000>;\n\t\tcenter-carrier-frq = <434000000>;\n\t\tminimal-RF-channel = /bits/ 8 <11>;\n\t\tmaximum-RF-channel = /bits/ 8 <11>;\n\t};\n\n## Build Device Tree Overlay\n1. Build: `make`\n2. Install the DT overlay: `make install` or copy the built DT overlay to\n   `/boot/overlays/rpi-lora-spi.dtbo` on the target board manually.  (The\n   system's DT overlay folder path may be variant.  It is according to the\n   distribution's loader.)\n3. Make sure the SPI interface and DT overlay is enabled.  For example, check\n   the [/boot/config.txt](https://www.raspberrypi.org/documentation/configuration/config-txt/) in Raspberry Pi.\n   PS. [Device Trees, overlays, and parameters](https://www.raspberrypi.org/documentation/configuration/device-tree.md)\n"
  },
  {
    "path": "dts-overlay/rpi-lora-spi-overlay.dts",
    "content": "/dts-v1/;\n/plugin/;\n\n/ {\n\tfragment@0 {\n\t\ttarget = <&spi>;\n\t\t__overlay__ {\n\t\t\t#address-cells = <1>;\n\t\t\t#size-cells = <0>;\n\n\t\t\tspidev@0 {\n\t\t\t\tstatus = \"disabled\";\n\t\t\t};\n\n\t\t\tspidev@1 {\n\t\t\t\tstatus = \"disabled\";\n\t\t\t};\n\t\t\t\n\t\t\tsx1278@0 {\n\t\t\t\tcompatible = \"sx1278\";\n\t\t\t\treg = <0>;\n\t\t\t\tstatus = \"okay\";\n\t\t\t\tspi-max-frequency = <0x3b60>;\n\t\t\t\tcenter-carrier-frq = <434000000>;\n\t\t\t\tclock-frequency = <32000000>;\n\t\t\t\tminimal-RF-channel = /bits/ 8 <11>;\n\t\t\t\tmaximum-RF-channel = /bits/ 8 <11>;\n\t\t\t};\n\n\t\t\tsx1278@1 {\n\t\t\t\tcompatible = \"sx1278\";\n\t\t\t\treg = <1>;\n\t\t\t\tstatus = \"okay\";\n\t\t\t\tspi-max-frequency = <0x3b60>;\n\t\t\t\tcenter-carrier-frq = <434000000>;\n\t\t\t\tclock-frequency = <32000000>;\n\t\t\t\tminimal-RF-channel = /bits/ 8 <11>;\n\t\t\t\tmaximum-RF-channel = /bits/ 8 <11>;\n\t\t\t};\n\t\t};\n\t};\n};\n"
  },
  {
    "path": "test-application/Makefile",
    "content": "CC=cc\nCFLAGS=-O2\n\nall:\n\t$(CC) server.c $(CFLAGS) -o server\n\t$(CC) client.c $(CFLAGS) -o client\n\nclean:\n\trm server client\n"
  },
  {
    "path": "test-application/README.md",
    "content": "# Test Applications\n\nThese applications communicate through UDP/IPv6 socket in simple client-server model.\n\n1. Client will send a data string to server.\n2. Server will capitalize the recieved data string from the client and send back to the client.\n3. Client will receive the capitalized data string and print it out.\n\n## Setup a 6LoWPAN Test Network\n\nRefer to: linux-wpan http://wpan.cakelab.org/\n\n### wpan-tools\n\n1. Could be founded at https://github.com/linux-wpan/wpan-tools\n2. The dependencies will be listed during building\n\n### Have a lowpan interface from a wpan interface\n\n**SX1278 driver** and **6LoWPAN kernel module** should be inserted or loaded before this action.\n\nDo these works with the granted privilege.\n\n```sh\n# Private Area Network ID\npanid=\"0xbeef\"\n# Index of the wpan interface\ni=0\n\n# Set the PANID of the wpan interface\niwpan dev wpan${i} set pan_id $panid\n# Create a lowpan interface over the wpan interface\nip link add link wpan${i} name lowpan${i} type lowpan\n# Bring up the wpan and lowpan interfaces\nip link set wpan${i} up\nip link set lowpan${i} up\n```\n\n```ip addr``` will show the IPv6 addresses of the interfaces.\n\n## Test Applications\n\n### Build test applications\n\n```make``` will produce **server** and **client**.\n\n### server\n\n```server <listening IPv6 address> <listening port>```\n\n- listening IPv6 address:\n  Listening on which IPv6 address\n\n- listening port:\n  Listening on which UDP port\n\n### client\n\n```client <src IPv6 address> <dst IPv6 address> <dst port> <data string>```\n\n- src IPv6 address:\n  Send with the source IPv6 address\n\n- dst IPv6 address:\n  Send to the server's IPv6 address\n\n- dst port:\n  Send to the server's UDP port\n\n- data string:\n  Send the data string to the server\n"
  },
  {
    "path": "test-application/client.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include <unistd.h>\n#include <netdb.h>\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#include <netinet/in.h>\n\nvoid show_addr_info(struct sockaddr_in6 *addr)\n{\n\tchar ipv6[INET6_ADDRSTRLEN];\n\tint port;\n\n\tinet_ntop(AF_INET6, &(addr->sin6_addr), ipv6, INET6_ADDRSTRLEN);\n\tport = ntohs(addr->sin6_port);\n\n\tprintf(\"address %s port %d\\n\", ipv6, port);\n}\n\nstruct addrinfo * have_addr(char *ipv6, char *port)\n{\n\tstruct addrinfo hints;\n        struct addrinfo *addr;\n\tint status;\n\n\tmemset(&hints, 0, sizeof(struct addrinfo));\n\thints.ai_family = PF_INET6;\n\thints.ai_socktype = SOCK_DGRAM;\n\n\tstatus = getaddrinfo(ipv6, port, &hints, &addr);\n\tif (status) {\n\t\tperror(\"getaddrinfo failed\");\n\t\treturn NULL;\n\t}\n\tif (!addr) {\n\t\tfprintf(stderr, \"no interface with %s\\n\", ipv6);\n\t\treturn NULL;\n\t}\n\n\treturn addr;\n}\n\nint have_bound_socket(char *ipv6, char *port)\n{\n\tint s;\n\tstruct addrinfo *addr;\n\n\taddr = have_addr(ipv6, port);\n\tif (!addr)\n\t\treturn -1;\n\n\ts = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);\n\tif (bind(s, addr->ai_addr, addr->ai_addrlen)) {\n\t\tperror(\"bind socket failed\");\n\t\treturn -1;\n\t}\n\n\tfreeaddrinfo(addr);\n\n\treturn s;\n}\n\nint main(int argc, char *argv[])\n{\n\tint conn;\n\tstruct addrinfo *dst_addr;\n\tstruct sockaddr_in6 peer_addr;\n\tsocklen_t addrlen;\n\n#define\tBUFLEN\t\t(1024)\n\tchar buf[BUFLEN];\n\tssize_t buflen;\n\n\tif (argc < 5) {\n\t\tprintf(\"Usage: client <src_addr> <dst_addr> <dst_port> <msg>\\n\");\n\t\treturn 0;\n\t}\n\n\tchar *src_ip = argv[1];\n\tchar *dst_ip = argv[2];\n\tchar *dst_port = argv[3];\n\tchar *data_str = argv[4];\n\n\t/* Have the server socket. */\n\tconn = have_bound_socket(src_ip, NULL);\n\tif (conn < 0)\n\t\treturn conn;\n\n\t/* Have server's address information structure. */\n\tdst_addr = have_addr(dst_ip, dst_port);\n\t/* Send the data string to server. */\n\tprintf(\"Send %s with in %zu bytes\\n\", data_str, strlen(data_str));\n\tif (sendto(conn, data_str, strlen(data_str), 0,\n\t\t   dst_addr->ai_addr, dst_addr->ai_addrlen) < 0) {\n\t\tperror(\"send to server failed\");\n\t\tfreeaddrinfo(dst_addr);\n\t\treturn -1;\n\t}\n\tfreeaddrinfo(dst_addr);\n\n\t/* Prepare and receive from server. */\n\tmemset(buf, 0, BUFLEN);\n\taddrlen = sizeof(peer_addr);\n\tbuflen = recvfrom(conn, buf, BUFLEN, 0,\n\t\t\t  (struct sockaddr *)&peer_addr, &addrlen);\n\tif (buflen < 0) {\n\t\tperror(\"receive from server failed\");\n\t\treturn -1;\n\t}\n\tprintf(\"Recv %s with in %zd bytes\\n\", buf, buflen);\n\n\tclose(conn);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "test-application/server.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include <ctype.h>\n#include <unistd.h>\n#include <netdb.h>\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#include <netinet/in.h>\n\nvoid show_addr_info(struct sockaddr_in6 *addr)\n{\n\tchar ipv6[INET6_ADDRSTRLEN];\n\tint port;\n\n\tinet_ntop(AF_INET6, &(addr->sin6_addr), ipv6, INET6_ADDRSTRLEN);\n\tport = ntohs(addr->sin6_port);\n\n\tprintf(\"address %s port %d\\n\", ipv6, port);\n}\n\nstruct addrinfo * have_addr(char *ipv6, char *port)\n{\n\tstruct addrinfo hints;\n        struct addrinfo *addr;\n\tint status;\n\n\tmemset(&hints, 0, sizeof(struct addrinfo));\n\thints.ai_family = PF_INET6;\n\thints.ai_socktype = SOCK_DGRAM;\n\n\tstatus = getaddrinfo(ipv6, port, &hints, &addr);\n\tif (status) {\n\t\tperror(\"getaddrinfo failed\");\n\t\treturn NULL;\n\t}\n\tif (!addr) {\n\t\tfprintf(stderr, \"no interface with %s\\n\", ipv6);\n\t\treturn NULL;\n\t}\n\n\treturn addr;\n}\n\nint have_bound_socket(char *ipv6, char *port)\n{\n\tint s;\n\tstruct addrinfo *addr;\n\tint yes = 1;\n\n\taddr = have_addr(ipv6, port);\n\tif (!addr)\n\t\treturn -1;\n\n\ts = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);\n\tsetsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));\n\tif (bind(s, addr->ai_addr, addr->ai_addrlen)) {\n\t\tperror(\"bind socket failed\");\n\t\treturn -1;\n\t}\n\n\tfreeaddrinfo(addr);\n\n\treturn s;\n}\n\nint main(int argc, char *argv[])\n{\n\tint srvsock;\n\tstruct sockaddr_in6 cli_addr;\n\tsocklen_t addrlen;\n\n#define\tBUFLEN\t\t(1024)\n\tchar buf[BUFLEN];\n\tssize_t buflen;\n\tint i;\n\n\tif (argc < 3) {\n\t\tprintf(\"Usage: server <srv_addr> <srv_port>\\n\");\n\t\treturn 0;\n\t}\n\tchar *srv_ip = argv[1];\n\tchar *srv_port = argv[2];\n\n\t/* Have the server socket. */\n\tsrvsock = have_bound_socket(srv_ip, srv_port);\n\tif (srvsock < 0)\n\t\treturn srvsock;\n\n\tprintf(\"Server is started!!! Listening on %s UDP port %s\\n\",\n\t       srv_ip, srv_port);\n\twhile (1) {\n\t\t/* Prepare and receive from client. */\n\t\tmemset(buf, 0, BUFLEN);\n\t\taddrlen = sizeof(cli_addr);\n\t\tbuflen = recvfrom(srvsock, buf, BUFLEN, 0,\n\t\t\t\t  (struct sockaddr *)&cli_addr, &addrlen);\n\t\tif (buflen < 0) {\n\t\t\tperror(\"receive from client failed\");\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t/* Show client's information. */\n\t\tprintf(\"Client \");\n\t\tshow_addr_info(&cli_addr);\n\t\tprintf(\"\\tRecv %s with in %zd bytes\\n\", buf, buflen);\n\n\t\t/* Uppercase received characters in buffer. */\n\t\tfor (i = 0; buf[i] != 0; i++)\n\t\t\tbuf[i] = toupper(buf[i]);\n\n\t\t/* Send the processed buffer back to client. */\n\t\tprintf(\"\\tSend %s with in %zu bytes\\n\", buf, strlen(buf));\n\t\tif (sendto(srvsock, buf, strlen(buf), 0,\n\t\t\t   (struct sockaddr *)&cli_addr, addrlen) < 0) {\n\t\t\tperror(\"send to client failed\");\n\t\t}\n\t}\n\n\tclose(srvsock);\n\n\treturn 0;\n}\n"
  }
]